SimpleHashTable.h 8.6 KB

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