Hash table bug fix, and add copy constructor and assignment operator for principle of least surprise.

This commit is contained in:
Adam Ierymenko 2015-09-03 17:33:06 -07:00
parent 4838cbc350
commit da9a720c3f
2 changed files with 102 additions and 11 deletions

View file

@ -29,6 +29,7 @@
#include <stdlib.h>
#include <stdexcept>
#include <vector>
namespace ZeroTier {
@ -47,9 +48,11 @@ private:
{
_Bucket(const K &k,const V &v) : k(k),v(v) {}
_Bucket(const K &k) : k(k),v() {}
_Bucket(const _Bucket &b) : k(b.k),v(b.v) {}
inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; }
K k;
V v;
_Bucket *next;
_Bucket *next; // must be set manually for each _Bucket
};
public:
@ -115,12 +118,47 @@ public:
_t[i] = (_Bucket *)0;
}
Hashtable(const Hashtable<K,V> &ht) :
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))),
_bc(ht._bc),
_s(ht._s)
{
if (!_t)
throw std::bad_alloc();
for(unsigned long i=0;i<_bc;++i)
_t[i] = (_Bucket *)0;
for(unsigned long i=0;i<_bc;++i) {
const _Bucket *b = ht._t[i];
while (b) {
_Bucket *nb = new _Bucket(*b);
nb->next = _t[i];
_t[i] = nb;
b = b->next;
}
}
}
~Hashtable()
{
clear();
this->clear();
::free(_t);
}
inline Hashtable &operator=(const Hashtable<K,V> &ht)
{
this->clear();
if (ht._s) {
for(unsigned long i=0;i<ht._bc;++i) {
const _Bucket *b = ht._t[i];
while (b) {
this->set(b->k,b->v);
b = b->next;
}
}
}
return *this;
}
/**
* Erase all entries
*/
@ -140,6 +178,24 @@ public:
}
}
/**
* @return Vector of all keys
*/
inline typename std::vector<K> keys()
{
typename std::vector<K> k;
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
while (b) {
k.push_back(b->k);
b = b->next;
}
}
}
return k;
}
/**
* @param k Key
* @return Pointer to value or NULL if not found
@ -187,7 +243,8 @@ public:
*/
inline V &set(const K &k,const V &v)
{
const unsigned long bidx = _hc(k) % _bc;
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx];
while (b) {
@ -198,8 +255,10 @@ public:
b = b->next;
}
if (_s >= _bc)
if (_s >= _bc) {
_grow();
bidx = h % _bc;
}
b = new _Bucket(k,v);
b->next = _t[bidx];
@ -215,7 +274,8 @@ public:
*/
inline V &operator[](const K &k)
{
const unsigned long bidx = _hc(k) % _bc;
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx];
while (b) {
@ -224,8 +284,10 @@ public:
b = b->next;
}
if (_s >= _bc)
if (_s >= _bc) {
_grow();
bidx = h % _bc;
}
b = new _Bucket(k);
b->next = _t[bidx];