hash_map.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. //
  2. // hash_map.hpp
  3. // ~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_HASH_MAP_HPP
  11. #define BOOST_ASIO_DETAIL_HASH_MAP_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <cassert>
  18. #include <list>
  19. #include <utility>
  20. #include <vector>
  21. #include <boost/functional/hash.hpp>
  22. #include <boost/asio/detail/pop_options.hpp>
  23. #include <boost/asio/detail/noncopyable.hpp>
  24. #include <boost/asio/detail/socket_types.hpp>
  25. namespace boost {
  26. namespace asio {
  27. namespace detail {
  28. template <typename T>
  29. inline std::size_t calculate_hash_value(const T& t)
  30. {
  31. return boost::hash_value(t);
  32. }
  33. #if defined(_WIN64)
  34. inline std::size_t calculate_hash_value(SOCKET s)
  35. {
  36. return static_cast<std::size_t>(s);
  37. }
  38. #endif // defined(_WIN64)
  39. // Note: assumes K and V are POD types.
  40. template <typename K, typename V>
  41. class hash_map
  42. : private noncopyable
  43. {
  44. public:
  45. // The type of a value in the map.
  46. typedef std::pair<K, V> value_type;
  47. // The type of a non-const iterator over the hash map.
  48. typedef typename std::list<value_type>::iterator iterator;
  49. // The type of a const iterator over the hash map.
  50. typedef typename std::list<value_type>::const_iterator const_iterator;
  51. // Constructor.
  52. hash_map()
  53. : size_(0)
  54. {
  55. rehash(hash_size(0));
  56. }
  57. // Get an iterator for the beginning of the map.
  58. iterator begin()
  59. {
  60. return values_.begin();
  61. }
  62. // Get an iterator for the beginning of the map.
  63. const_iterator begin() const
  64. {
  65. return values_.begin();
  66. }
  67. // Get an iterator for the end of the map.
  68. iterator end()
  69. {
  70. return values_.end();
  71. }
  72. // Get an iterator for the end of the map.
  73. const_iterator end() const
  74. {
  75. return values_.end();
  76. }
  77. // Check whether the map is empty.
  78. bool empty() const
  79. {
  80. return values_.empty();
  81. }
  82. // Find an entry in the map.
  83. iterator find(const K& k)
  84. {
  85. size_t bucket = calculate_hash_value(k) % buckets_.size();
  86. iterator it = buckets_[bucket].first;
  87. if (it == values_.end())
  88. return values_.end();
  89. iterator end = buckets_[bucket].last;
  90. ++end;
  91. while (it != end)
  92. {
  93. if (it->first == k)
  94. return it;
  95. ++it;
  96. }
  97. return values_.end();
  98. }
  99. // Find an entry in the map.
  100. const_iterator find(const K& k) const
  101. {
  102. size_t bucket = calculate_hash_value(k) % buckets_.size();
  103. const_iterator it = buckets_[bucket].first;
  104. if (it == values_.end())
  105. return it;
  106. const_iterator end = buckets_[bucket].last;
  107. ++end;
  108. while (it != end)
  109. {
  110. if (it->first == k)
  111. return it;
  112. ++it;
  113. }
  114. return values_.end();
  115. }
  116. // Insert a new entry into the map.
  117. std::pair<iterator, bool> insert(const value_type& v)
  118. {
  119. if (size_ + 1 >= buckets_.size())
  120. rehash(hash_size(size_ + 1));
  121. size_t bucket = calculate_hash_value(v.first) % buckets_.size();
  122. iterator it = buckets_[bucket].first;
  123. if (it == values_.end())
  124. {
  125. buckets_[bucket].first = buckets_[bucket].last =
  126. values_insert(values_.end(), v);
  127. ++size_;
  128. return std::pair<iterator, bool>(buckets_[bucket].last, true);
  129. }
  130. iterator end = buckets_[bucket].last;
  131. ++end;
  132. while (it != end)
  133. {
  134. if (it->first == v.first)
  135. return std::pair<iterator, bool>(it, false);
  136. ++it;
  137. }
  138. buckets_[bucket].last = values_insert(end, v);
  139. ++size_;
  140. return std::pair<iterator, bool>(buckets_[bucket].last, true);
  141. }
  142. // Erase an entry from the map.
  143. void erase(iterator it)
  144. {
  145. assert(it != values_.end());
  146. size_t bucket = calculate_hash_value(it->first) % buckets_.size();
  147. bool is_first = (it == buckets_[bucket].first);
  148. bool is_last = (it == buckets_[bucket].last);
  149. if (is_first && is_last)
  150. buckets_[bucket].first = buckets_[bucket].last = values_.end();
  151. else if (is_first)
  152. ++buckets_[bucket].first;
  153. else if (is_last)
  154. --buckets_[bucket].last;
  155. values_erase(it);
  156. --size_;
  157. }
  158. // Remove all entries from the map.
  159. void clear()
  160. {
  161. // Clear the values.
  162. values_.clear();
  163. size_ = 0;
  164. // Initialise all buckets to empty.
  165. for (size_t i = 0; i < buckets_.size(); ++i)
  166. buckets_[i].first = buckets_[i].last = values_.end();
  167. }
  168. private:
  169. // Calculate the hash size for the specified number of elements.
  170. static std::size_t hash_size(std::size_t num_elems)
  171. {
  172. static std::size_t sizes[] =
  173. {
  174. #if defined(BOOST_ASIO_HASH_MAP_BUCKETS)
  175. BOOST_ASIO_HASH_MAP_BUCKETS
  176. #else // BOOST_ASIO_HASH_MAP_BUCKETS
  177. 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
  178. 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
  179. 12582917, 25165843
  180. #endif // BOOST_ASIO_HASH_MAP_BUCKETS
  181. };
  182. const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1;
  183. for (std::size_t i = 0; i < nth_size; ++i)
  184. if (num_elems < sizes[i])
  185. return sizes[i];
  186. return sizes[nth_size];
  187. }
  188. // Re-initialise the hash from the values already contained in the list.
  189. void rehash(std::size_t num_buckets)
  190. {
  191. if (num_buckets == buckets_.size())
  192. return;
  193. iterator end = values_.end();
  194. // Update number of buckets and initialise all buckets to empty.
  195. buckets_.resize(num_buckets);
  196. for (std::size_t i = 0; i < buckets_.size(); ++i)
  197. buckets_[i].first = buckets_[i].last = end;
  198. // Put all values back into the hash.
  199. iterator iter = values_.begin();
  200. while (iter != end)
  201. {
  202. std::size_t bucket = calculate_hash_value(iter->first) % buckets_.size();
  203. if (buckets_[bucket].last == end)
  204. {
  205. buckets_[bucket].first = buckets_[bucket].last = iter++;
  206. }
  207. else if (++buckets_[bucket].last == iter)
  208. {
  209. ++iter;
  210. }
  211. else
  212. {
  213. values_.splice(buckets_[bucket].last, values_, iter++);
  214. --buckets_[bucket].last;
  215. }
  216. }
  217. }
  218. // Insert an element into the values list by splicing from the spares list,
  219. // if a spare is available, and otherwise by inserting a new element.
  220. iterator values_insert(iterator it, const value_type& v)
  221. {
  222. if (spares_.empty())
  223. {
  224. return values_.insert(it, v);
  225. }
  226. else
  227. {
  228. spares_.front() = v;
  229. values_.splice(it, spares_, spares_.begin());
  230. return --it;
  231. }
  232. }
  233. // Erase an element from the values list by splicing it to the spares list.
  234. void values_erase(iterator it)
  235. {
  236. *it = value_type();
  237. spares_.splice(spares_.begin(), values_, it);
  238. }
  239. // The number of elements in the hash.
  240. std::size_t size_;
  241. // The list of all values in the hash map.
  242. std::list<value_type> values_;
  243. // The list of spare nodes waiting to be recycled. Assumes that POD types only
  244. // are stored in the hash map.
  245. std::list<value_type> spares_;
  246. // The type for a bucket in the hash table.
  247. struct bucket_type
  248. {
  249. bucket_type() {}
  250. bucket_type(const bucket_type&) { /* noop */ }
  251. iterator first;
  252. iterator last;
  253. };
  254. // The buckets in the hash.
  255. std::vector<bucket_type> buckets_;
  256. };
  257. } // namespace detail
  258. } // namespace asio
  259. } // namespace boost
  260. #include <boost/asio/detail/pop_options.hpp>
  261. #endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP