SimpleHashTable.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //
  2. // SimpleHashTable.h
  3. //
  4. // Library: Foundation
  5. // Package: Hashing
  6. // Module: SimpleHashTable
  7. //
  8. // Definition of the SimpleHashTable class.
  9. //
  10. // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #ifndef Foundation_SimpleHashTable_INCLUDED
  16. #define Foundation_SimpleHashTable_INCLUDED
  17. #include "Poco/Foundation.h"
  18. #include "Poco/Exception.h"
  19. #include "Poco/HashFunction.h"
  20. #include "Poco/HashStatistic.h"
  21. #include <vector>
  22. #include <map>
  23. #include <cstddef>
  24. #include <algorithm>
  25. namespace Poco {
  26. //@ deprecated
  27. template <class Key, class Value, class KeyHashFunction = HashFunction<Key> >
  28. class SimpleHashTable
  29. /// A SimpleHashTable stores a key value pair that can be looked up via a hashed key.
  30. ///
  31. /// In comparision to a HashTable, this class handles collisions by sequentially searching the next
  32. /// free location. This also means that the maximum size of this table is limited, i.e. if the hash table
  33. /// is full, it will throw an exception and that this class does not support remove operations.
  34. /// On the plus side it is faster than the HashTable.
  35. ///
  36. /// This class is NOT thread safe.
  37. {
  38. public:
  39. class HashEntry
  40. {
  41. public:
  42. Key key;
  43. Value value;
  44. HashEntry(const Key k, const Value v): key(k), value(v)
  45. {
  46. }
  47. };
  48. typedef std::vector<HashEntry*> HashTableVector;
  49. SimpleHashTable(UInt32 capacity = 251): _entries(capacity, 0), _size(0), _capacity(capacity)
  50. /// Creates the SimpleHashTable.
  51. {
  52. }
  53. SimpleHashTable(const SimpleHashTable& ht):
  54. _size(ht._size),
  55. _capacity(ht._capacity)
  56. {
  57. _entries.reserve(ht._capacity);
  58. for (typename HashTableVector::iterator it = ht._entries.begin(); it != ht._entries.end(); ++it)
  59. {
  60. if (*it)
  61. _entries.push_back(new HashEntry(*it));
  62. else
  63. _entries.push_back(0);
  64. }
  65. }
  66. ~SimpleHashTable()
  67. /// Destroys the SimpleHashTable.
  68. {
  69. clear();
  70. }
  71. SimpleHashTable& operator = (const SimpleHashTable& ht)
  72. {
  73. if (this != &ht)
  74. {
  75. SimpleHashTable tmp(ht);
  76. swap(tmp);
  77. }
  78. return *this;
  79. }
  80. void swap(SimpleHashTable& ht)
  81. {
  82. using std::swap;
  83. swap(_entries, ht._entries);
  84. swap(_size, ht._size);
  85. swap(_capacity, ht._capacity);
  86. }
  87. void clear()
  88. {
  89. for (typename HashTableVector::iterator it = _entries.begin(); it != _entries.end(); ++it)
  90. {
  91. delete *it;
  92. *it = 0;
  93. }
  94. _size = 0;
  95. }
  96. UInt32 insert(const Key& key, const Value& value)
  97. /// Returns the hash value of the inserted item.
  98. /// Throws an exception if the entry was already inserted
  99. {
  100. UInt32 hsh = hash(key);
  101. insertRaw(key, hsh, value);
  102. return hsh;
  103. }
  104. Value& insertRaw(const Key& key, UInt32 hsh, const Value& value)
  105. /// Returns the hash value of the inserted item.
  106. /// Throws an exception if the entry was already inserted
  107. {
  108. UInt32 pos = hsh;
  109. if (!_entries[pos])
  110. _entries[pos] = new HashEntry(key, value);
  111. else
  112. {
  113. UInt32 origHash = hsh;
  114. while (_entries[hsh % _capacity])
  115. {
  116. if (_entries[hsh % _capacity]->key == key)
  117. throw ExistsException();
  118. if (hsh - origHash > _capacity)
  119. throw PoolOverflowException("SimpleHashTable full");
  120. hsh++;
  121. }
  122. pos = hsh % _capacity;
  123. _entries[pos] = new HashEntry(key, value);
  124. }
  125. _size++;
  126. return _entries[pos]->value;
  127. }
  128. UInt32 update(const Key& key, const Value& value)
  129. /// Returns the hash value of the inserted item.
  130. /// Replaces an existing entry if it finds one
  131. {
  132. UInt32 hsh = hash(key);
  133. updateRaw(key, hsh, value);
  134. return hsh;
  135. }
  136. void updateRaw(const Key& key, UInt32 hsh, const Value& value)
  137. /// Returns the hash value of the inserted item.
  138. /// Replaces an existing entry if it finds one
  139. {
  140. if (!_entries[hsh])
  141. _entries[hsh] = new HashEntry(key, value);
  142. else
  143. {
  144. UInt32 origHash = hsh;
  145. while (_entries[hsh % _capacity])
  146. {
  147. if (_entries[hsh % _capacity]->key == key)
  148. {
  149. _entries[hsh % _capacity]->value = value;
  150. return;
  151. }
  152. if (hsh - origHash > _capacity)
  153. throw PoolOverflowException("SimpleHashTable full");
  154. hsh++;
  155. }
  156. _entries[hsh % _capacity] = new HashEntry(key, value);
  157. }
  158. _size++;
  159. }
  160. UInt32 hash(const Key& key) const
  161. {
  162. return _hash(key, _capacity);
  163. }
  164. const Value& get(const Key& key) const
  165. /// Throws an exception if the value does not exist
  166. {
  167. UInt32 hsh = hash(key);
  168. return getRaw(key, hsh);
  169. }
  170. const Value& getRaw(const Key& key, UInt32 hsh) const
  171. /// Throws an exception if the value does not exist
  172. {
  173. UInt32 origHash = hsh;
  174. while (true)
  175. {
  176. if (_entries[hsh % _capacity])
  177. {
  178. if (_entries[hsh % _capacity]->key == key)
  179. {
  180. return _entries[hsh % _capacity]->value;
  181. }
  182. }
  183. else
  184. throw InvalidArgumentException("value not found");
  185. if (hsh - origHash > _capacity)
  186. throw InvalidArgumentException("value not found");
  187. hsh++;
  188. }
  189. }
  190. Value& get(const Key& key)
  191. /// Throws an exception if the value does not exist
  192. {
  193. UInt32 hsh = hash(key);
  194. return const_cast<Value&>(getRaw(key, hsh));
  195. }
  196. const Value& operator [] (const Key& key) const
  197. {
  198. return get(key);
  199. }
  200. Value& operator [] (const Key& key)
  201. {
  202. UInt32 hsh = hash(key);
  203. UInt32 origHash = hsh;
  204. while (true)
  205. {
  206. if (_entries[hsh % _capacity])
  207. {
  208. if (_entries[hsh % _capacity]->key == key)
  209. {
  210. return _entries[hsh % _capacity]->value;
  211. }
  212. }
  213. else return insertRaw(key, hsh, Value());
  214. if (hsh - origHash > _capacity)
  215. return insertRaw(key, hsh, Value());
  216. hsh++;
  217. }
  218. }
  219. const Key& getKeyRaw(const Key& key, UInt32 hsh)
  220. /// Throws an exception if the key does not exist. returns a reference to the internally
  221. /// stored key. Useful when someone does an insert and wants for performance reason only to store
  222. /// a pointer to the key in another collection
  223. {
  224. UInt32 origHash = hsh;
  225. while (true)
  226. {
  227. if (_entries[hsh % _capacity])
  228. {
  229. if (_entries[hsh % _capacity]->key == key)
  230. {
  231. return _entries[hsh % _capacity]->key;
  232. }
  233. }
  234. else
  235. throw InvalidArgumentException("key not found");
  236. if (hsh - origHash > _capacity)
  237. throw InvalidArgumentException("key not found");
  238. hsh++;
  239. }
  240. }
  241. bool get(const Key& key, Value& v) const
  242. /// Sets v to the found value, returns false if no value was found
  243. {
  244. UInt32 hsh = hash(key);
  245. return getRaw(key, hsh, v);
  246. }
  247. bool getRaw(const Key& key, UInt32 hsh, Value& v) const
  248. /// Sets v to the found value, returns false if no value was found
  249. {
  250. UInt32 origHash = hsh;
  251. while (true)
  252. {
  253. if (_entries[hsh % _capacity])
  254. {
  255. if (_entries[hsh % _capacity]->key == key)
  256. {
  257. v = _entries[hsh % _capacity]->value;
  258. return true;
  259. }
  260. }
  261. else
  262. return false;
  263. if (hsh - origHash > _capacity)
  264. return false;
  265. hsh++;
  266. }
  267. }
  268. bool exists(const Key& key) const
  269. {
  270. UInt32 hsh = hash(key);
  271. return existsRaw(key, hsh);
  272. }
  273. bool existsRaw(const Key& key, UInt32 hsh) const
  274. {
  275. UInt32 origHash = hsh;
  276. while (true)
  277. {
  278. if (_entries[hsh % _capacity])
  279. {
  280. if (_entries[hsh % _capacity]->key == key)
  281. {
  282. return true;
  283. }
  284. }
  285. else
  286. return false;
  287. if (hsh - origHash > _capacity)
  288. return false;
  289. hsh++;
  290. }
  291. }
  292. std::size_t size() const
  293. /// Returns the number of elements already inserted into the SimpleHashTable
  294. {
  295. return _size;
  296. }
  297. UInt32 capacity() const
  298. {
  299. return _capacity;
  300. }
  301. void resize(UInt32 newSize)
  302. /// Resizes the hashtable, rehashes all existing entries. Expensive!
  303. {
  304. if (_capacity != newSize)
  305. {
  306. SimpleHashTable tmp(newSize);
  307. swap(tmp);
  308. for (typename HashTableVector::const_iterator it = tmp._entries.begin(); it != tmp._entries.end(); ++it)
  309. {
  310. if (*it)
  311. {
  312. insertRaw((*it)->key, hash((*it)->key), (*it)->value);
  313. }
  314. }
  315. }
  316. }
  317. HashStatistic currentState(bool details = false) const
  318. /// Returns the current internal state
  319. {
  320. UInt32 numberOfEntries = (UInt32)_size;
  321. UInt32 numZeroEntries = 0;
  322. UInt32 maxEntriesPerHash = 0;
  323. std::vector<UInt32> detailedEntriesPerHash;
  324. #ifdef _DEBUG
  325. UInt32 totalSize = 0;
  326. #endif
  327. for (int i=0; i < _capacity; ++i)
  328. {
  329. if (_entries[i])
  330. {
  331. maxEntriesPerHash = 1;
  332. UInt32 size = 1;
  333. if (details)
  334. detailedEntriesPerHash.push_back(size);
  335. #ifdef _DEBUG
  336. totalSize += size;
  337. #endif
  338. }
  339. else
  340. {
  341. numZeroEntries++;
  342. if (details)
  343. detailedEntriesPerHash.push_back(0);
  344. }
  345. }
  346. #ifdef _DEBUG
  347. poco_assert_dbg(totalSize == numberOfEntries);
  348. #endif
  349. return HashStatistic(_capacity, numberOfEntries, numZeroEntries, maxEntriesPerHash, detailedEntriesPerHash);
  350. }
  351. private:
  352. HashTableVector _entries;
  353. std::size_t _size;
  354. UInt32 _capacity;
  355. KeyHashFunction _hash;
  356. };
  357. } // namespace Poco
  358. #endif // Foundation_HashTable_INCLUDED