#ifndef EINTHASHOF_H
#define EINTHASHOF_H

#include "eutils.h"

#include "einthashof_dec.h"
#include "ehashmap_dec.h"
#include "evar_dec.h"




template <class T>
void einthashof<T>::addvar(evar& var)
{
  addref(0u,&var.get<T>());
}
template <class T>
void einthashof<T>::addvar(evar& evarkey,evar& var)
{
  addref(evarkey.get<unsigned int>(),&var.get<T>());
}
template <class T>
evar einthashof<T>::getvar(size_t i) const
{
//  return(evar((T*)&values(i)));
  return(evar());
}
template <class T>
evar einthashof<T>::getvarkey(size_t i) const
{
  return(evar());
//  return(evar((K*)&keys(i)));
}
template <class T>
void einthashof<T>::erase(size_t i)
{
  einthashof<T>::iter it=begin();
  for (; i>0 && it!=end(); ++it,--i);
  if (it!=end()) erase(it);
}

template <class T>
evar einthashof<T>::getvarByKey(const evar& var) const
{
  if (var.getTypeid()==typeid(int))
    return(evar(&values(var.get<int>())));
  return(evar());
}


#include "logger.h"

const size_t INTHASH_INIT_COUNT=256;

template <class T>
einthashof<T>::iter::iter(): hashmap(0x00), hitem(0x00), bucket(0) {}

template <class T>
typename einthashof<T>::iter& einthashof<T>::iter::operator++()
{
  hitem=hitem->next;
  
  if (hitem) return(*this);

  ++bucket;
  while (bucket<hashmap->_hashcount && hashmap->_hashitems[bucket]==0x00) ++bucket;

  if (bucket < hashmap->_hashcount)
    hitem=hashmap->_hashitems[bucket];
  return(*this); 
}

template <class T>
unsigned int einthashof<T>::iter::key() const
{
  lddieif(hitem==0x00,"trying to access end iterator");
  return(hitem->key);
}

template <class T>
T& einthashof<T>::iter::value() const
{
  lddieif(hitem==0x00,"trying to access end iterator");
  return(*hitem->value);
}

template <class T>
T& einthashof<T>::iter::operator*() const
{
  lddieif(hitem==0x00,"trying to access end iterator");
  return(*hitem->value);
}

template <class T>
T* einthashof<T>::iter::operator->() const
{
  lddieif(hitem==0x00,"trying to access end iterator");
  return(hitem->value);
}

template <class T>
bool einthashof<T>::iter::operator==(const einthashof<T>::iter& i) const
{
  return(hashmap==i.hashmap && hitem==i.hitem);
}

template <class T>
bool einthashof<T>::iter::operator!=(const einthashof<T>::iter& i) const
{
  return(hashmap!=i.hashmap || hitem!=i.hitem);
}

template <class T>
typename einthashof<T>::iter& einthashof<T>::iter::operator=(const einthashof<T>::iter& i)
{
  hashmap=i.hashmap;
  bucket=i.bucket;
  hitem=i.hitem;
  return(*this);
}




template <class T>
einthashof<T>::einthashof(): count(0)
{
  _hashcount = INTHASH_INIT_COUNT;
  _hashitems=new ehashitem<unsigned int,T>*[_hashcount];
  size_t i;
  for (i=0; i<_hashcount; ++i)
    _hashitems[i]=0x00;
}

template <class T>
einthashof<T>::einthashof(const einthashof<T>& oldhm): count(oldhm.count)
{
  _hashcount = oldhm._hashcount;
  _hashitems=new ehashitem<unsigned int,T>*[_hashcount];

  ehashitem<unsigned int,T> *oldhmitem;
  size_t i;
  for (i=0; i<_hashcount; ++i){
    _hashitems[i]=0x00;
    for (oldhmitem=oldhm._hashitems[i]; oldhmitem!=0x00; oldhmitem=oldhmitem->next)
      _hashitems[i]=new ehashitem<unsigned int,T>(oldhmitem->key,new T(*oldhmitem->value),_hashitems[i]);
  }
}




template <class T>
einthashof<T>::~einthashof()
{
  clear();
  delete[] _hashitems;
}

template <class T>
typename einthashof<T>::iter einthashof<T>::get(unsigned int key) const
{
  typename einthashof<T>::iter it;

  it.hashmap=this;
  it.bucket=key%_hashcount;
  it.hitem=_hashitems[it.bucket];

  while (it.hitem!=0x00){
    if (key == it.hitem->key)   // there is no collision
      return(it);
    it.hitem=it.hitem->next;
  }

  return(end());
}

template <class T>
typename einthashof<T>::iter einthashof<T>::begin() const
{
  typename einthashof<T>::iter i;
  i.hashmap=this;
  i.bucket=0;
  i.hitem=0x00;
  while (i.bucket<_hashcount && _hashitems[i.bucket]==0x00) ++i.bucket;

  if (i.bucket==_hashcount)
    return(end());

  i.hitem=_hashitems[i.bucket];
  return(i);
}

template <class T>
typename einthashof<T>::iter einthashof<T>::end() const
{
  typename einthashof<T>::iter i;
  i.hashmap=this;
  i.bucket=0;
  i.hitem=0x00;
  return(i);
}

template <class T>
void einthashof<T>::reserve(size_t i)
{
  size_t a;
  size_t c=1;
  a=0x01;
  while (i>0){
    i=i>>1;
    a=(a<<1)|0x01;
    ++c;
  }

  if (c>=sizeof(size_t)*8){
    lwarn("reached limit of hash table index size");
    a=0x8000000000000000u-0x01u;
  }
  
  resizehash(a);
}

template <class T>
void einthashof<T>::resizehash(size_t newcount) const
{
  size_t thashcount;
  ehashitem<unsigned int,T> **thashitems;

  if (newcount < _hashcount) return;

  ldinfo("resizing hash table");

  if (newcount==0) 
    thashcount = (_hashcount << 1);
  else
    thashcount = newcount;

  thashitems=new ehashitem<unsigned int,T>*[thashcount];
  ldieif(thashitems==0x00,"unable to allocate memory for hashmap");
  size_t i;
  for (i=0; i<thashcount; ++i)
    thashitems[i]=0x00;

  size_t khash;
  ehashitem<unsigned int,T>* hitem;

  typename einthashof<T>::iter it;
  for (it=begin(); it!=end(); ++it){
    hitem = _hashitems[it.key()%_hashcount]; //gethashitem(khash%_hashcount,it.key());

    if (hitem->prev)
      hitem->prev->next=hitem->next;
    else
      _hashitems[hitem->key%_hashcount]=hitem->next;
    if (hitem->next)
      hitem->next->prev=hitem->prev;

    hitem->prev=0x00;
    hitem->next=thashitems[hitem->key%thashcount];
    thashitems[hitem->key%thashcount]=hitem;
    if (hitem->next)
      hitem->next->prev=hitem;
  } 

  delete[] _hashitems;
  _hashcount=thashcount;
  _hashitems=thashitems;
  ldinfo("finished resize");
}

template <class T>
ehashitem<unsigned int,T>* einthashof<T>::gethashitem(unsigned int key) const
{
  ehashitem<unsigned int,T>* hitem;
  hitem = _hashitems[key%_hashcount];
  while (hitem != 0x00){
    if (hitem->key == key)
      return(hitem);
    hitem=hitem->next;
  }
  lderror("einthashof: did not find key");
  return(0x00); 
}


template <class T>
void einthashof<T>::clear()
{
  size_t i;
  ehashitem<unsigned int,T> *hitem;
  for (i=0; i<_hashcount; ++i){
    while (_hashitems[i]){
      hitem=_hashitems[i];
      _hashitems[i]=hitem->next;
      delete hitem->value;
      delete hitem;
    }
  }
  count=0;
}

template <class T>
bool einthashof<T>::exists(unsigned int key) const
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key)
      return(true);
    hitem=hitem->next;
  }
  // non existent value
  return(false);
}

template <class T>
void einthashof<T>::erase(const typename einthashof<T>::iter& it)
{
  ldieif(it.hitem==0x00,"trying to delete empty iterator");
  if (it.hitem->prev) it.hitem->prev->next=it.hitem->next;
  else _hashitems[it.bucket]=it.hitem->next;
  if (it.hitem->next) it.hitem->next->prev=it.hitem->prev;
  delete it.hitem->value;
  delete it.hitem;
//  it.hitem=0x00;
  --count;
}

template <class T>
void einthashof<T>::remove(unsigned int key)
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  i=key%_hashcount;
  hitem=_hashitems[i];

  size_t j;
  while (hitem!=0x00){
    if (key == hitem->key){
      if (hitem->prev) hitem->prev->next=hitem->next;
      else _hashitems[i]=hitem->next;
      if (hitem->next) hitem->next->prev=hitem->prev;
      delete hitem->value;
      delete hitem;
      --count;
      return;
    }
    hitem=hitem->next;
  }
  lddie("tried to delete key from hashmap that does not exist");
  // non existent value
}

template <class T>
einthashof<T>& einthashof<T>::operator+=(const einthashof<T>& hm)
{
  size_t i;
  for (i=0; i<hm.size(); ++i)
    add(hm.keys(i),hm.values(hm.keys(i)));
  return(*this);
}


template <class T>
T& einthashof<T>::addref(unsigned int key,T* value)
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  if (size() > (3u*(_hashcount))>>2u) resizehash();

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key){   // there is no collision
      hitem->value = value;
      return(*hitem->value);
    }
    hitem=hitem->next;
  }

  // non existent value
  ++count;
  _hashitems[i]=new ehashitem<unsigned int,T>(key,value,_hashitems[i]);
  return(*_hashitems[i]->value);
}

template <class T>
T& einthashof<T>::add(unsigned int key,const T& value)
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  if (size() > (3u*(_hashcount))>>2u) resizehash();

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key){   // there is no collision
      hitem->value=new T(value);
      return(*hitem->value);
    }
    hitem=hitem->next;
  }

  // non existent value
  ++count;
  _hashitems[i]=new ehashitem<unsigned int,T>(key,new T(value),_hashitems[i]);
  return(*_hashitems[i]->value);
/*
  operator[](key) = value;
  return(operator[](key));
*/
}

template <class T>
const T& einthashof<T>::operator[](unsigned int key) const
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  if (size() > (3u*(_hashcount))>>2u) resizehash();

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key)   // there is no collision
      return(*hitem->value);
    hitem=hitem->next;
  }

  // non existent value
//  ++count;
  _hashitems[i]=new ehashitem<unsigned int,T>(key,new T,_hashitems[i]);
  return(*_hashitems[i]->value);
}

/*
template <class T>
const T& einthashof<T>::operator[](int ind) const
{
  int i;
  ehashitem<T>* hitem;

  lddieif(ind > _keys.size(),"einthashof: index out of bounds");
  i=hash(_keys.at(ind));
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (_keys.at(ind) == hitem->key)   // there is no collision
      return(*hitem->value);
    hitem=hitem->next;
  }

  ldie("einthashof: index out of bounds: "+estr(ind));
//  return(*(T*)0x00);
}
*/

template <class T>
T& einthashof<T>::operator[](unsigned int key)
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  if (size() > (3u*(_hashcount))>>2u) resizehash();

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key)   // there is no collision
      return(*hitem->value);
    hitem=hitem->next;
  }

//  lerror("key not found");
//  throw "key not found";

  // non existent value
  ++count;
  _hashitems[i]=new ehashitem<unsigned int,T>(key,new T,_hashitems[i]);
  return(*_hashitems[i]->value);
}

//#pragma GCC diagnostic ignored "-Wreturn-type"
template <class T>
const T& einthashof<T>::values(unsigned int key) const
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  if (size() > (3u*(_hashcount))>>2u) resizehash();

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key)   // there is no collision
      return(*hitem->value);
    hitem=hitem->next;
  }

  lerror("einthashof: key not found");
  throw "einthashof: key not found";
//  return(*(T*)0x00);
}

template <class T>
T& einthashof<T>::values(unsigned int key)
{
  size_t i;
  ehashitem<unsigned int,T>* hitem;

  if (size() > (3u*(_hashcount))>>2u) resizehash();

  i=key%_hashcount;
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (key == hitem->key)   // there is no collision
      return(*hitem->value);
    hitem=hitem->next;
  }
  
  lerror("einthashof: key not found");
  throw "einthashof: key not found";
//  return(*(T*)0x00);
}






template <class T>
void elonghashof<T>::addvar(evar& var)
{
	addref(0u, &var.get<T>());
}
template <class T>
void elonghashof<T>::addvar(evar& evarkey, evar& var)
{
	addref(evarkey.get<unsigned long>(), &var.get<T>());
}
template <class T>
evar elonghashof<T>::getvar(size_t i) const
{
	//  return(evar((T*)&values(i)));
	return(evar());
}
template <class T>
evar elonghashof<T>::getvarkey(size_t i) const
{
	return(evar());
	//  return(evar((K*)&keys(i)));
}
template <class T>
void elonghashof<T>::erase(size_t i)
{
	elonghashof<T>::iter it = begin();
	for (; i > 0 && it != end(); ++it, --i);
	if (it != end()) erase(it);
}

template <class T>
evar elonghashof<T>::getvarByKey(const evar& var) const
{
	if (var.getTypeid() == typeid(long))
		return(evar(&values(var.get<long>())));
	return(evar());
}


template <class T>
elonghashof<T>::iter::iter() : hashmap(0x00), hitem(0x00), bucket(0) {}

template <class T>
typename elonghashof<T>::iter& elonghashof<T>::iter::operator++()
{
	hitem = hitem->next;

	if (hitem) return(*this);

	++bucket;
	while (bucket < hashmap->_hashcount && hashmap->_hashitems[bucket] == 0x00) ++bucket;

	if (bucket < hashmap->_hashcount)
		hitem = hashmap->_hashitems[bucket];
	return(*this);
}

template <class T>
unsigned long elonghashof<T>::iter::key() const
{
	lddieif(hitem == 0x00, "trying to access end iterator");
	return(hitem->key);
}

template <class T>
T& elonghashof<T>::iter::value() const
{
	lddieif(hitem == 0x00, "trying to access end iterator");
	return(*hitem->value);
}

template <class T>
T& elonghashof<T>::iter::operator*() const
{
	lddieif(hitem == 0x00, "trying to access end iterator");
	return(*hitem->value);
}

template <class T>
T* elonghashof<T>::iter::operator->() const
{
	lddieif(hitem == 0x00, "trying to access end iterator");
	return(hitem->value);
}

template <class T>
bool elonghashof<T>::iter::operator==(const elonghashof<T>::iter& i) const
{
	return(hashmap == i.hashmap && hitem == i.hitem);
}

template <class T>
bool elonghashof<T>::iter::operator!=(const elonghashof<T>::iter& i) const
{
	return(hashmap != i.hashmap || hitem != i.hitem);
}

template <class T>
typename elonghashof<T>::iter& elonghashof<T>::iter::operator=(const elonghashof<T>::iter& i)
{
	hashmap = i.hashmap;
	bucket = i.bucket;
	hitem = i.hitem;
	return(*this);
}




template <class T>
elonghashof<T>::elonghashof() : count(0)
{
	_hashcount = INTHASH_INIT_COUNT;
	_hashitems = new ehashitem<unsigned long, T>*[_hashcount];
	size_t i;
	for (i = 0; i < _hashcount; ++i)
		_hashitems[i] = 0x00;
}

template <class T>
elonghashof<T>::elonghashof(const elonghashof<T>& oldhm) : count(oldhm.count)
{
	_hashcount = oldhm._hashcount;
	_hashitems = new ehashitem<unsigned long, T>*[_hashcount];

	ehashitem<unsigned long, T> *oldhmitem;
	size_t i;
	for (i = 0; i < _hashcount; ++i) {
		_hashitems[i] = 0x00;
		for (oldhmitem = oldhm._hashitems[i]; oldhmitem != 0x00; oldhmitem = oldhmitem->next)
			_hashitems[i] = new ehashitem<unsigned long, T>(oldhmitem->key, new T(*oldhmitem->value), _hashitems[i]);
	}
}




template <class T>
elonghashof<T>::~elonghashof()
{
	clear();
	delete[] _hashitems;
}

template <class T>
typename elonghashof<T>::iter elonghashof<T>::get(unsigned long key) const
{
	typename elonghashof<T>::iter it;

	it.hashmap = this;
	it.bucket = key % _hashcount;
	it.hitem = _hashitems[it.bucket];

	while (it.hitem != 0x00) {
		if (key == it.hitem->key)   // there is no collision
			return(it);
		it.hitem = it.hitem->next;
	}

	return(end());
}

template <class T>
typename elonghashof<T>::iter elonghashof<T>::begin() const
{
	typename elonghashof<T>::iter i;
	i.hashmap = this;
	i.bucket = 0;
	i.hitem = 0x00;
	while (i.bucket < _hashcount && _hashitems[i.bucket] == 0x00) ++i.bucket;

	if (i.bucket == _hashcount)
		return(end());

	i.hitem = _hashitems[i.bucket];
	return(i);
}

template <class T>
typename elonghashof<T>::iter elonghashof<T>::end() const
{
	typename elonghashof<T>::iter i;
	i.hashmap = this;
	i.bucket = 0;
	i.hitem = 0x00;
	return(i);
}

template <class T>
void elonghashof<T>::reserve(size_t i)
{
	size_t a;
	size_t c = 1;
	a = 0x01;
	while (i > 0) {
		i = i >> 1;
		a = (a << 1) | 0x01;
		++c;
	}

	if (c >= sizeof(size_t) * 8) {
		lwarn("reached limit of hash table index size");
		a = 0x8000000000000000u - 0x01u;
	}

	resizehash(a);
}

template <class T>
void elonghashof<T>::resizehash(size_t newcount) const
{
	size_t thashcount;
	ehashitem<unsigned long, T> **thashitems;

	if (newcount < _hashcount) return;

	ldinfo("resizing hash table");

	if (newcount == 0)
		thashcount = (_hashcount << 1);
	else
		thashcount = newcount;

	thashitems = new ehashitem<unsigned long, T>*[thashcount];
	ldieif(thashitems == 0x00, "unable to allocate memory for hashmap");
	size_t i;
	for (i = 0; i < thashcount; ++i)
		thashitems[i] = 0x00;

	size_t khash;
	ehashitem<unsigned long, T>* hitem;

	typename elonghashof<T>::iter it;
	for (it = begin(); it != end(); ++it) {
		hitem = _hashitems[it.key() % _hashcount]; //gethashitem(khash%_hashcount,it.key());

		if (hitem->prev)
			hitem->prev->next = hitem->next;
		else
			_hashitems[hitem->key%_hashcount] = hitem->next;
		if (hitem->next)
			hitem->next->prev = hitem->prev;

		hitem->prev = 0x00;
		hitem->next = thashitems[hitem->key%thashcount];
		thashitems[hitem->key%thashcount] = hitem;
		if (hitem->next)
			hitem->next->prev = hitem;
	}

	delete[] _hashitems;
	_hashcount = thashcount;
	_hashitems = thashitems;
	ldinfo("finished resize");
}

template <class T>
ehashitem<unsigned long, T>* elonghashof<T>::gethashitem(unsigned long key) const
{
	ehashitem<unsigned long, T>* hitem;
	hitem = _hashitems[key%_hashcount];
	while (hitem != 0x00) {
		if (hitem->key == key)
			return(hitem);
		hitem = hitem->next;
	}
	lderror("einthashof: did not find key");
	return(0x00);
}


template <class T>
void elonghashof<T>::clear()
{
	size_t i;
	ehashitem<unsigned long, T> *hitem;
	for (i = 0; i < _hashcount; ++i) {
		while (_hashitems[i]) {
			hitem = _hashitems[i];
			_hashitems[i] = hitem->next;
			delete hitem->value;
			delete hitem;
		}
	}
	count = 0;
}

template <class T>
bool elonghashof<T>::exists(unsigned long key) const
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key)
			return(true);
		hitem = hitem->next;
	}
	// non existent value
	return(false);
}

template <class T>
void elonghashof<T>::erase(const typename elonghashof<T>::iter& it)
{
	ldieif(it.hitem == 0x00, "trying to delete empty iterator");
	if (it.hitem->prev) it.hitem->prev->next = it.hitem->next;
	else _hashitems[it.bucket] = it.hitem->next;
	if (it.hitem->next) it.hitem->next->prev = it.hitem->prev;
	delete it.hitem->value;
	delete it.hitem;
	//  it.hitem=0x00;
	--count;
}

template <class T>
void elonghashof<T>::remove(unsigned long key)
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	i = key % _hashcount;
	hitem = _hashitems[i];

	size_t j;
	while (hitem != 0x00) {
		if (key == hitem->key) {
			if (hitem->prev) hitem->prev->next = hitem->next;
			else _hashitems[i] = hitem->next;
			if (hitem->next) hitem->next->prev = hitem->prev;
			delete hitem->value;
			delete hitem;
			--count;
			return;
		}
		hitem = hitem->next;
	}
	lddie("tried to delete key from hashmap that does not exist");
	// non existent value
}

template <class T>
elonghashof<T>& elonghashof<T>::operator+=(const elonghashof<T>& hm)
{
	size_t i;
	for (i = 0; i < hm.size(); ++i)
		add(hm.keys(i), hm.values(hm.keys(i)));
	return(*this);
}


template <class T>
T& elonghashof<T>::addref(unsigned long key, T* value)
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	if (size() > (3u * (_hashcount)) >> 2u) resizehash();

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key) {   // there is no collision
			hitem->value = value;
			return(*hitem->value);
		}
		hitem = hitem->next;
	}

	// non existent value
	++count;
	_hashitems[i] = new ehashitem<unsigned long, T>(key, value, _hashitems[i]);
	return(*_hashitems[i]->value);
}

template <class T>
T& elonghashof<T>::add(unsigned long key, const T& value)
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	if (size() > (3u * (_hashcount)) >> 2u) resizehash();

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key) {   // there is no collision
			hitem->value = new T(value);
			return(*hitem->value);
		}
		hitem = hitem->next;
	}

	// non existent value
	++count;
	_hashitems[i] = new ehashitem<unsigned long, T>(key, new T(value), _hashitems[i]);
	return(*_hashitems[i]->value);
	/*
	  operator[](key) = value;
	  return(operator[](key));
	*/
}

template <class T>
const T& elonghashof<T>::operator[](unsigned long key) const
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	if (size() > (3u * (_hashcount)) >> 2u) resizehash();

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key)   // there is no collision
			return(*hitem->value);
		hitem = hitem->next;
	}

	// non existent value
  //  ++count;
	_hashitems[i] = new ehashitem<unsigned long, T>(key, new T, _hashitems[i]);
	return(*_hashitems[i]->value);
}

/*
template <class T>
const T& einthashof<T>::operator[](int ind) const
{
  int i;
  ehashitem<T>* hitem;

  lddieif(ind > _keys.size(),"einthashof: index out of bounds");
  i=hash(_keys.at(ind));
  hitem=_hashitems[i];

  while (hitem!=0x00){
	if (_keys.at(ind) == hitem->key)   // there is no collision
	  return(*hitem->value);
	hitem=hitem->next;
  }

  ldie("einthashof: index out of bounds: "+estr(ind));
//  return(*(T*)0x00);
}
*/

template <class T>
T& elonghashof<T>::operator[](unsigned long key)
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	if (size() > (3u * (_hashcount)) >> 2u) resizehash();

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key)   // there is no collision
			return(*hitem->value);
		hitem = hitem->next;
	}

	//  lerror("key not found");
	//  throw "key not found";

	  // non existent value
	++count;
	_hashitems[i] = new ehashitem<unsigned long, T>(key, new T, _hashitems[i]);
	return(*_hashitems[i]->value);
}

//#pragma GCC diagnostic ignored "-Wreturn-type"
template <class T>
const T& elonghashof<T>::values(unsigned long key) const
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	if (size() > (3u * (_hashcount)) >> 2u) resizehash();

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key)   // there is no collision
			return(*hitem->value);
		hitem = hitem->next;
	}

	lerror("einthashof: key not found");
	throw "einthashof: key not found";
	//  return(*(T*)0x00);
}

template <class T>
T& elonghashof<T>::values(unsigned long key)
{
	size_t i;
	ehashitem<unsigned long, T>* hitem;

	if (size() > (3u * (_hashcount)) >> 2u) resizehash();

	i = key % _hashcount;
	hitem = _hashitems[i];

	while (hitem != 0x00) {
		if (key == hitem->key)   // there is no collision
			return(*hitem->value);
		hitem = hitem->next;
	}

	lerror("einthashof: key not found");
	throw "einthashof: key not found";
	//  return(*(T*)0x00);
}




/*
template <class T>
T& einthashof<T>::operator[](int ind)
{
  int i;
  ehashitem<T>* hitem;

  i=hash(_keys.at(ind));
  hitem=_hashitems[i];

  while (hitem!=0x00){
    if (_keys.at(ind) == hitem->key)   // there is no collision
      return(*hitem->value);
    hitem=hitem->next;
  }

  ldie("einthashof: index out of bounds: "+estr(ind));
  return(*(T*)0x00);
}
//#pragma GCC diagnostic warning "-Wreturn-type"
*/

/*
template <unsigned int (*hashfunc)(const evar&)>
void einthashof<evar,evar>::addvar(evar& key,evar& var)
{
  add(key,var);
}

template <unsigned int (*hashfunc)(const evar&)>
evar einthashof<evar,evar>::getvar(int i) const
{
  return(evar());
//  return(values(i));
}

template <unsigned int (*hashfunc)(const evar&)>
evar einthashof<evar,evar>::getvarkey(int i) const
{
  return(evar());
//  return(keys(i));
}
*/

#endif

