123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- //
- // SimpleHashTable.h
- //
- // Library: Foundation
- // Package: Hashing
- // Module: SimpleHashTable
- //
- // Definition of the SimpleHashTable class.
- //
- // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
- // and Contributors.
- //
- // SPDX-License-Identifier: BSL-1.0
- //
- #ifndef Foundation_SimpleHashTable_INCLUDED
- #define Foundation_SimpleHashTable_INCLUDED
- #include "Poco/Foundation.h"
- #include "Poco/Exception.h"
- #include "Poco/HashFunction.h"
- #include "Poco/HashStatistic.h"
- #include <vector>
- #include <map>
- #include <cstddef>
- #include <algorithm>
- namespace Poco {
- //@ deprecated
- template <class Key, class Value, class KeyHashFunction = HashFunction<Key> >
- class SimpleHashTable
- /// A SimpleHashTable stores a key value pair that can be looked up via a hashed key.
- ///
- /// In comparision to a HashTable, this class handles collisions by sequentially searching the next
- /// free location. This also means that the maximum size of this table is limited, i.e. if the hash table
- /// is full, it will throw an exception and that this class does not support remove operations.
- /// On the plus side it is faster than the HashTable.
- ///
- /// This class is NOT thread safe.
- {
- public:
- class HashEntry
- {
- public:
- Key key;
- Value value;
- HashEntry(const Key k, const Value v): key(k), value(v)
- {
- }
- };
- typedef std::vector<HashEntry*> HashTableVector;
- SimpleHashTable(UInt32 capacity = 251): _entries(capacity, 0), _size(0), _capacity(capacity)
- /// Creates the SimpleHashTable.
- {
- }
- SimpleHashTable(const SimpleHashTable& ht):
- _size(ht._size),
- _capacity(ht._capacity)
- {
- _entries.reserve(ht._capacity);
- for (typename HashTableVector::iterator it = ht._entries.begin(); it != ht._entries.end(); ++it)
- {
- if (*it)
- _entries.push_back(new HashEntry(*it));
- else
- _entries.push_back(0);
- }
- }
- ~SimpleHashTable()
- /// Destroys the SimpleHashTable.
- {
- clear();
- }
- SimpleHashTable& operator = (const SimpleHashTable& ht)
- {
- if (this != &ht)
- {
- SimpleHashTable tmp(ht);
- swap(tmp);
- }
- return *this;
- }
-
- void swap(SimpleHashTable& ht)
- {
- using std::swap;
- swap(_entries, ht._entries);
- swap(_size, ht._size);
- swap(_capacity, ht._capacity);
- }
- void clear()
- {
- for (typename HashTableVector::iterator it = _entries.begin(); it != _entries.end(); ++it)
- {
- delete *it;
- *it = 0;
- }
- _size = 0;
- }
- UInt32 insert(const Key& key, const Value& value)
- /// Returns the hash value of the inserted item.
- /// Throws an exception if the entry was already inserted
- {
- UInt32 hsh = hash(key);
- insertRaw(key, hsh, value);
- return hsh;
- }
- Value& insertRaw(const Key& key, UInt32 hsh, const Value& value)
- /// Returns the hash value of the inserted item.
- /// Throws an exception if the entry was already inserted
- {
- UInt32 pos = hsh;
- if (!_entries[pos])
- _entries[pos] = new HashEntry(key, value);
- else
- {
- UInt32 origHash = hsh;
- while (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- throw ExistsException();
- if (hsh - origHash > _capacity)
- throw PoolOverflowException("SimpleHashTable full");
- hsh++;
- }
- pos = hsh % _capacity;
- _entries[pos] = new HashEntry(key, value);
- }
- _size++;
- return _entries[pos]->value;
- }
- UInt32 update(const Key& key, const Value& value)
- /// Returns the hash value of the inserted item.
- /// Replaces an existing entry if it finds one
- {
- UInt32 hsh = hash(key);
- updateRaw(key, hsh, value);
- return hsh;
- }
- void updateRaw(const Key& key, UInt32 hsh, const Value& value)
- /// Returns the hash value of the inserted item.
- /// Replaces an existing entry if it finds one
- {
- if (!_entries[hsh])
- _entries[hsh] = new HashEntry(key, value);
- else
- {
- UInt32 origHash = hsh;
- while (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- {
- _entries[hsh % _capacity]->value = value;
- return;
- }
- if (hsh - origHash > _capacity)
- throw PoolOverflowException("SimpleHashTable full");
- hsh++;
- }
- _entries[hsh % _capacity] = new HashEntry(key, value);
- }
- _size++;
- }
- UInt32 hash(const Key& key) const
- {
- return _hash(key, _capacity);
- }
- const Value& get(const Key& key) const
- /// Throws an exception if the value does not exist
- {
- UInt32 hsh = hash(key);
- return getRaw(key, hsh);
- }
- const Value& getRaw(const Key& key, UInt32 hsh) const
- /// Throws an exception if the value does not exist
- {
- UInt32 origHash = hsh;
- while (true)
- {
- if (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- {
- return _entries[hsh % _capacity]->value;
- }
- }
- else
- throw InvalidArgumentException("value not found");
- if (hsh - origHash > _capacity)
- throw InvalidArgumentException("value not found");
- hsh++;
- }
- }
- Value& get(const Key& key)
- /// Throws an exception if the value does not exist
- {
- UInt32 hsh = hash(key);
- return const_cast<Value&>(getRaw(key, hsh));
- }
-
- const Value& operator [] (const Key& key) const
- {
- return get(key);
- }
-
- Value& operator [] (const Key& key)
- {
- UInt32 hsh = hash(key);
- UInt32 origHash = hsh;
- while (true)
- {
- if (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- {
- return _entries[hsh % _capacity]->value;
- }
- }
- else return insertRaw(key, hsh, Value());
- if (hsh - origHash > _capacity)
- return insertRaw(key, hsh, Value());
- hsh++;
- }
- }
- const Key& getKeyRaw(const Key& key, UInt32 hsh)
- /// Throws an exception if the key does not exist. returns a reference to the internally
- /// stored key. Useful when someone does an insert and wants for performance reason only to store
- /// a pointer to the key in another collection
- {
- UInt32 origHash = hsh;
- while (true)
- {
- if (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- {
- return _entries[hsh % _capacity]->key;
- }
- }
- else
- throw InvalidArgumentException("key not found");
- if (hsh - origHash > _capacity)
- throw InvalidArgumentException("key not found");
- hsh++;
- }
- }
- bool get(const Key& key, Value& v) const
- /// Sets v to the found value, returns false if no value was found
- {
- UInt32 hsh = hash(key);
- return getRaw(key, hsh, v);
- }
- bool getRaw(const Key& key, UInt32 hsh, Value& v) const
- /// Sets v to the found value, returns false if no value was found
- {
- UInt32 origHash = hsh;
- while (true)
- {
- if (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- {
- v = _entries[hsh % _capacity]->value;
- return true;
- }
- }
- else
- return false;
- if (hsh - origHash > _capacity)
- return false;
- hsh++;
- }
- }
- bool exists(const Key& key) const
- {
- UInt32 hsh = hash(key);
- return existsRaw(key, hsh);
- }
- bool existsRaw(const Key& key, UInt32 hsh) const
- {
- UInt32 origHash = hsh;
- while (true)
- {
- if (_entries[hsh % _capacity])
- {
- if (_entries[hsh % _capacity]->key == key)
- {
- return true;
- }
- }
- else
- return false;
- if (hsh - origHash > _capacity)
- return false;
- hsh++;
- }
- }
- std::size_t size() const
- /// Returns the number of elements already inserted into the SimpleHashTable
- {
- return _size;
- }
-
- UInt32 capacity() const
- {
- return _capacity;
- }
- void resize(UInt32 newSize)
- /// Resizes the hashtable, rehashes all existing entries. Expensive!
- {
- if (_capacity != newSize)
- {
- SimpleHashTable tmp(newSize);
- swap(tmp);
- for (typename HashTableVector::const_iterator it = tmp._entries.begin(); it != tmp._entries.end(); ++it)
- {
- if (*it)
- {
- insertRaw((*it)->key, hash((*it)->key), (*it)->value);
- }
- }
- }
- }
- HashStatistic currentState(bool details = false) const
- /// Returns the current internal state
- {
- UInt32 numberOfEntries = (UInt32)_size;
- UInt32 numZeroEntries = 0;
- UInt32 maxEntriesPerHash = 0;
- std::vector<UInt32> detailedEntriesPerHash;
- #ifdef _DEBUG
- UInt32 totalSize = 0;
- #endif
- for (int i=0; i < _capacity; ++i)
- {
- if (_entries[i])
- {
- maxEntriesPerHash = 1;
- UInt32 size = 1;
- if (details)
- detailedEntriesPerHash.push_back(size);
- #ifdef _DEBUG
- totalSize += size;
- #endif
- }
- else
- {
- numZeroEntries++;
- if (details)
- detailedEntriesPerHash.push_back(0);
- }
- }
- #ifdef _DEBUG
- poco_assert_dbg(totalSize == numberOfEntries);
- #endif
- return HashStatistic(_capacity, numberOfEntries, numZeroEntries, maxEntriesPerHash, detailedEntriesPerHash);
- }
- private:
- HashTableVector _entries;
- std::size_t _size;
- UInt32 _capacity;
- KeyHashFunction _hash;
- };
- } // namespace Poco
- #endif // Foundation_HashTable_INCLUDED
|