COMMON: Add a size_type to HashMap.

This commit is contained in:
Johannes Schickel 2012-02-22 20:13:33 +01:00
parent 5eabc4a2f3
commit dac6ac66ad

View file

@ -67,7 +67,7 @@ template<class T> class IteratorImpl;
/** /**
* HashMap<Key,Val> maps objects of type Key to objects of type Val. * HashMap<Key,Val> maps objects of type Key to objects of type Val.
* For each used Key type, we need an "uint hashit(Key,uint)" function * For each used Key type, we need an "size_type hashit(Key,size_type)" function
* that computes a hash for the given Key object and returns it as an * that computes a hash for the given Key object and returns it as an
* an integer from 0 to hashsize-1, and also an "equality functor". * an integer from 0 to hashsize-1, and also an "equality functor".
* that returns true if if its two arguments are to be considered * that returns true if if its two arguments are to be considered
@ -80,6 +80,9 @@ template<class T> class IteratorImpl;
*/ */
template<class Key, class Val, class HashFunc = Hash<Key>, class EqualFunc = EqualTo<Key> > template<class Key, class Val, class HashFunc = Hash<Key>, class EqualFunc = EqualTo<Key> >
class HashMap { class HashMap {
public:
typedef uint size_type;
private: private:
typedef HashMap<Key, Val, HashFunc, EqualFunc> HM_t; typedef HashMap<Key, Val, HashFunc, EqualFunc> HM_t;
@ -111,9 +114,9 @@ private:
#endif #endif
Node **_storage; ///< hashtable of size arrsize. Node **_storage; ///< hashtable of size arrsize.
uint _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one size_type _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one
uint _size; size_type _size;
uint _deleted; ///< Number of deleted elements (_dummyNodes) size_type _deleted; ///< Number of deleted elements (_dummyNodes)
HashFunc _hash; HashFunc _hash;
EqualFunc _equal; EqualFunc _equal;
@ -146,9 +149,9 @@ private:
} }
void assign(const HM_t &map); void assign(const HM_t &map);
uint lookup(const Key &key) const; size_type lookup(const Key &key) const;
uint lookupAndCreateIfMissing(const Key &key); size_type lookupAndCreateIfMissing(const Key &key);
void expandStorage(uint newCapacity); void expandStorage(size_type newCapacity);
#if !defined(__sgi) || defined(__GNUC__) #if !defined(__sgi) || defined(__GNUC__)
template<class T> friend class IteratorImpl; template<class T> friend class IteratorImpl;
@ -168,11 +171,11 @@ private:
protected: protected:
typedef const HashMap hashmap_t; typedef const HashMap hashmap_t;
uint _idx; size_type _idx;
hashmap_t *_hashmap; hashmap_t *_hashmap;
protected: protected:
IteratorImpl(uint idx, hashmap_t *hashmap) : _idx(idx), _hashmap(hashmap) {} IteratorImpl(size_type idx, hashmap_t *hashmap) : _idx(idx), _hashmap(hashmap) {}
NodeType *deref() const { NodeType *deref() const {
assert(_hashmap != 0); assert(_hashmap != 0);
@ -200,7 +203,7 @@ private:
_idx++; _idx++;
} while (_idx <= _hashmap->_mask && (_hashmap->_storage[_idx] == 0 || _hashmap->_storage[_idx] == HASHMAP_DUMMY_NODE)); } while (_idx <= _hashmap->_mask && (_hashmap->_storage[_idx] == 0 || _hashmap->_storage[_idx] == HASHMAP_DUMMY_NODE));
if (_idx > _hashmap->_mask) if (_idx > _hashmap->_mask)
_idx = (uint)-1; _idx = (size_type)-1;
return *this; return *this;
} }
@ -247,41 +250,41 @@ public:
void erase(iterator entry); void erase(iterator entry);
void erase(const Key &key); void erase(const Key &key);
uint size() const { return _size; } size_type size() const { return _size; }
iterator begin() { iterator begin() {
// Find and return the first non-empty entry // Find and return the first non-empty entry
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (size_type ctr = 0; ctr <= _mask; ++ctr) {
if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE) if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
return iterator(ctr, this); return iterator(ctr, this);
} }
return end(); return end();
} }
iterator end() { iterator end() {
return iterator((uint)-1, this); return iterator((size_type)-1, this);
} }
const_iterator begin() const { const_iterator begin() const {
// Find and return the first non-empty entry // Find and return the first non-empty entry
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (size_type ctr = 0; ctr <= _mask; ++ctr) {
if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE) if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
return const_iterator(ctr, this); return const_iterator(ctr, this);
} }
return end(); return end();
} }
const_iterator end() const { const_iterator end() const {
return const_iterator((uint)-1, this); return const_iterator((size_type)-1, this);
} }
iterator find(const Key &key) { iterator find(const Key &key) {
uint ctr = lookup(key); size_type ctr = lookup(key);
if (_storage[ctr]) if (_storage[ctr])
return iterator(ctr, this); return iterator(ctr, this);
return end(); return end();
} }
const_iterator find(const Key &key) const { const_iterator find(const Key &key) const {
uint ctr = lookup(key); size_type ctr = lookup(key);
if (_storage[ctr]) if (_storage[ctr])
return const_iterator(ctr, this); return const_iterator(ctr, this);
return end(); return end();
@ -346,7 +349,7 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
*/ */
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() { HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
for (uint ctr = 0; ctr <= _mask; ++ctr) for (size_type ctr = 0; ctr <= _mask; ++ctr)
freeNode(_storage[ctr]); freeNode(_storage[ctr]);
delete[] _storage; delete[] _storage;
@ -373,7 +376,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
// Simply clone the map given to us, one by one. // Simply clone the map given to us, one by one.
_size = 0; _size = 0;
_deleted = 0; _deleted = 0;
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (size_type ctr = 0; ctr <= _mask; ++ctr) {
if (map._storage[ctr] == HASHMAP_DUMMY_NODE) { if (map._storage[ctr] == HASHMAP_DUMMY_NODE) {
_storage[ctr] = HASHMAP_DUMMY_NODE; _storage[ctr] = HASHMAP_DUMMY_NODE;
_deleted++; _deleted++;
@ -391,7 +394,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) { void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (size_type ctr = 0; ctr <= _mask; ++ctr) {
freeNode(_storage[ctr]); freeNode(_storage[ctr]);
_storage[ctr] = NULL; _storage[ctr] = NULL;
} }
@ -414,13 +417,13 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
} }
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) { void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(size_type newCapacity) {
assert(newCapacity > _mask+1); assert(newCapacity > _mask+1);
#ifndef NDEBUG #ifndef NDEBUG
const uint old_size = _size; const size_type old_size = _size;
#endif #endif
const uint old_mask = _mask; const size_type old_mask = _mask;
Node **old_storage = _storage; Node **old_storage = _storage;
// allocate a new array // allocate a new array
@ -432,7 +435,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
memset(_storage, 0, newCapacity * sizeof(Node *)); memset(_storage, 0, newCapacity * sizeof(Node *));
// rehash all the old elements // rehash all the old elements
for (uint ctr = 0; ctr <= old_mask; ++ctr) { for (size_type ctr = 0; ctr <= old_mask; ++ctr) {
if (old_storage[ctr] == NULL || old_storage[ctr] == HASHMAP_DUMMY_NODE) if (old_storage[ctr] == NULL || old_storage[ctr] == HASHMAP_DUMMY_NODE)
continue; continue;
@ -440,9 +443,9 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// Since we know that no key exists twice in the old table, we // Since we know that no key exists twice in the old table, we
// can do this slightly better than by calling lookup, since we // can do this slightly better than by calling lookup, since we
// don't have to call _equal(). // don't have to call _equal().
const uint hash = _hash(old_storage[ctr]->_key); const size_type hash = _hash(old_storage[ctr]->_key);
uint idx = hash & _mask; size_type idx = hash & _mask;
for (uint perturb = hash; _storage[idx] != NULL && _storage[idx] != HASHMAP_DUMMY_NODE; perturb >>= HASHMAP_PERTURB_SHIFT) { for (size_type perturb = hash; _storage[idx] != NULL && _storage[idx] != HASHMAP_DUMMY_NODE; perturb >>= HASHMAP_PERTURB_SHIFT) {
idx = (5 * idx + perturb + 1) & _mask; idx = (5 * idx + perturb + 1) & _mask;
} }
@ -460,10 +463,10 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
} }
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
uint HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const { typename HashMap<Key, Val, HashFunc, EqualFunc>::size_type HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
const uint hash = _hash(key); const size_type hash = _hash(key);
uint ctr = hash & _mask; size_type ctr = hash & _mask;
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
if (_storage[ctr] == NULL) if (_storage[ctr] == NULL)
break; break;
if (_storage[ctr] == HASHMAP_DUMMY_NODE) { if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
@ -491,13 +494,13 @@ uint HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
} }
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
uint HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) { typename HashMap<Key, Val, HashFunc, EqualFunc>::size_type HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) {
const uint hash = _hash(key); const size_type hash = _hash(key);
uint ctr = hash & _mask; size_type ctr = hash & _mask;
const uint NONE_FOUND = _mask + 1; const size_type NONE_FOUND = _mask + 1;
uint first_free = NONE_FOUND; size_type first_free = NONE_FOUND;
bool found = false; bool found = false;
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
if (_storage[ctr] == NULL) if (_storage[ctr] == NULL)
break; break;
if (_storage[ctr] == HASHMAP_DUMMY_NODE) { if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
@ -537,7 +540,7 @@ uint HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key
// Keep the load factor below a certain threshold. // Keep the load factor below a certain threshold.
// Deleted nodes are also counted // Deleted nodes are also counted
uint capacity = _mask + 1; size_type capacity = _mask + 1;
if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR > if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR >
capacity * HASHMAP_LOADFACTOR_NUMERATOR) { capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
capacity = capacity < 500 ? (capacity * 4) : (capacity * 2); capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
@ -553,7 +556,7 @@ uint HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const { bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const {
uint ctr = lookup(key); size_type ctr = lookup(key);
return (_storage[ctr] != NULL); return (_storage[ctr] != NULL);
} }
@ -569,7 +572,7 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) co
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) { Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) {
uint ctr = lookupAndCreateIfMissing(key); size_type ctr = lookupAndCreateIfMissing(key);
assert(_storage[ctr] != NULL); assert(_storage[ctr] != NULL);
return _storage[ctr]->_value; return _storage[ctr]->_value;
} }
@ -581,7 +584,7 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key, const Val &defaultVal) const { const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key, const Val &defaultVal) const {
uint ctr = lookup(key); size_type ctr = lookup(key);
if (_storage[ctr] != NULL) if (_storage[ctr] != NULL)
return _storage[ctr]->_value; return _storage[ctr]->_value;
else else
@ -590,7 +593,7 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key, const
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) { void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) {
uint ctr = lookupAndCreateIfMissing(key); size_type ctr = lookupAndCreateIfMissing(key);
assert(_storage[ctr] != NULL); assert(_storage[ctr] != NULL);
_storage[ctr]->_value = val; _storage[ctr]->_value = val;
} }
@ -599,7 +602,7 @@ template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::erase(iterator entry) { void HashMap<Key, Val, HashFunc, EqualFunc>::erase(iterator entry) {
// Check whether we have a valid iterator // Check whether we have a valid iterator
assert(entry._hashmap == this); assert(entry._hashmap == this);
const uint ctr = entry._idx; const size_type ctr = entry._idx;
assert(ctr <= _mask); assert(ctr <= _mask);
Node * const node = _storage[ctr]; Node * const node = _storage[ctr];
assert(node != NULL); assert(node != NULL);
@ -615,7 +618,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::erase(iterator entry) {
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) { void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) {
uint ctr = lookup(key); size_type ctr = lookup(key);
if (_storage[ctr] == NULL) if (_storage[ctr] == NULL)
return; return;