|
|
|
|
@ -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]; |
|
|
|
|
|