unique.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
  2. // Copyright (C) 2005-2011 Daniel James
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
  6. #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
  7. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  8. # pragma once
  9. #endif
  10. #include <boost/unordered/detail/table.hpp>
  11. #include <boost/unordered/detail/extract_key.hpp>
  12. #include <boost/throw_exception.hpp>
  13. #include <stdexcept>
  14. namespace boost { namespace unordered { namespace detail {
  15. template <typename A, typename T> struct unique_node;
  16. template <typename T> struct ptr_node;
  17. template <typename Types> struct table_impl;
  18. template <typename A, typename T>
  19. struct unique_node :
  20. boost::unordered::detail::value_base<T>
  21. {
  22. typedef typename ::boost::unordered::detail::rebind_wrap<
  23. A, unique_node<A, T> >::type::pointer node_pointer;
  24. typedef node_pointer link_pointer;
  25. link_pointer next_;
  26. std::size_t hash_;
  27. unique_node() :
  28. next_(),
  29. hash_(0)
  30. {}
  31. void init(node_pointer)
  32. {
  33. }
  34. private:
  35. unique_node& operator=(unique_node const&);
  36. };
  37. template <typename T>
  38. struct ptr_node :
  39. boost::unordered::detail::value_base<T>,
  40. boost::unordered::detail::ptr_bucket
  41. {
  42. typedef boost::unordered::detail::ptr_bucket bucket_base;
  43. typedef ptr_node<T>* node_pointer;
  44. typedef ptr_bucket* link_pointer;
  45. std::size_t hash_;
  46. ptr_node() :
  47. bucket_base(),
  48. hash_(0)
  49. {}
  50. void init(node_pointer)
  51. {
  52. }
  53. private:
  54. ptr_node& operator=(ptr_node const&);
  55. };
  56. // If the allocator uses raw pointers use ptr_node
  57. // Otherwise use node.
  58. template <typename A, typename T, typename NodePtr, typename BucketPtr>
  59. struct pick_node2
  60. {
  61. typedef boost::unordered::detail::unique_node<A, T> node;
  62. typedef typename boost::unordered::detail::allocator_traits<
  63. typename boost::unordered::detail::rebind_wrap<A, node>::type
  64. >::pointer node_pointer;
  65. typedef boost::unordered::detail::bucket<node_pointer> bucket;
  66. typedef node_pointer link_pointer;
  67. };
  68. template <typename A, typename T>
  69. struct pick_node2<A, T,
  70. boost::unordered::detail::ptr_node<T>*,
  71. boost::unordered::detail::ptr_bucket*>
  72. {
  73. typedef boost::unordered::detail::ptr_node<T> node;
  74. typedef boost::unordered::detail::ptr_bucket bucket;
  75. typedef bucket* link_pointer;
  76. };
  77. template <typename A, typename T>
  78. struct pick_node
  79. {
  80. typedef boost::unordered::detail::allocator_traits<
  81. typename boost::unordered::detail::rebind_wrap<A,
  82. boost::unordered::detail::ptr_node<T> >::type
  83. > tentative_node_traits;
  84. typedef boost::unordered::detail::allocator_traits<
  85. typename boost::unordered::detail::rebind_wrap<A,
  86. boost::unordered::detail::ptr_bucket >::type
  87. > tentative_bucket_traits;
  88. typedef pick_node2<A, T,
  89. typename tentative_node_traits::pointer,
  90. typename tentative_bucket_traits::pointer> pick;
  91. typedef typename pick::node node;
  92. typedef typename pick::bucket bucket;
  93. typedef typename pick::link_pointer link_pointer;
  94. };
  95. template <typename A, typename T, typename H, typename P>
  96. struct set
  97. {
  98. typedef boost::unordered::detail::set<A, T, H, P> types;
  99. typedef A allocator;
  100. typedef T value_type;
  101. typedef H hasher;
  102. typedef P key_equal;
  103. typedef T key_type;
  104. typedef boost::unordered::detail::allocator_traits<allocator> traits;
  105. typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
  106. typedef typename pick::node node;
  107. typedef typename pick::bucket bucket;
  108. typedef typename pick::link_pointer link_pointer;
  109. typedef boost::unordered::detail::table_impl<types> table;
  110. typedef boost::unordered::detail::set_extractor<value_type> extractor;
  111. typedef boost::unordered::detail::pick_policy::type policy;
  112. };
  113. template <typename A, typename K, typename M, typename H, typename P>
  114. struct map
  115. {
  116. typedef boost::unordered::detail::map<A, K, M, H, P> types;
  117. typedef A allocator;
  118. typedef std::pair<K const, M> value_type;
  119. typedef H hasher;
  120. typedef P key_equal;
  121. typedef K key_type;
  122. typedef boost::unordered::detail::allocator_traits<allocator>
  123. traits;
  124. typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
  125. typedef typename pick::node node;
  126. typedef typename pick::bucket bucket;
  127. typedef typename pick::link_pointer link_pointer;
  128. typedef boost::unordered::detail::table_impl<types> table;
  129. typedef boost::unordered::detail::map_extractor<key_type, value_type>
  130. extractor;
  131. typedef boost::unordered::detail::pick_policy::type policy;
  132. };
  133. template <typename Types>
  134. struct table_impl : boost::unordered::detail::table<Types>
  135. {
  136. typedef boost::unordered::detail::table<Types> table;
  137. typedef typename table::value_type value_type;
  138. typedef typename table::bucket bucket;
  139. typedef typename table::policy policy;
  140. typedef typename table::node_pointer node_pointer;
  141. typedef typename table::node_allocator node_allocator;
  142. typedef typename table::node_allocator_traits node_allocator_traits;
  143. typedef typename table::bucket_pointer bucket_pointer;
  144. typedef typename table::link_pointer link_pointer;
  145. typedef typename table::hasher hasher;
  146. typedef typename table::key_equal key_equal;
  147. typedef typename table::key_type key_type;
  148. typedef typename table::node_constructor node_constructor;
  149. typedef typename table::extractor extractor;
  150. typedef typename table::iterator iterator;
  151. typedef typename table::c_iterator c_iterator;
  152. typedef std::pair<iterator, bool> emplace_return;
  153. // Constructors
  154. table_impl(std::size_t n,
  155. hasher const& hf,
  156. key_equal const& eq,
  157. node_allocator const& a)
  158. : table(n, hf, eq, a)
  159. {}
  160. table_impl(table_impl const& x)
  161. : table(x, node_allocator_traits::
  162. select_on_container_copy_construction(x.node_alloc()))
  163. {
  164. this->init(x);
  165. }
  166. table_impl(table_impl const& x,
  167. node_allocator const& a)
  168. : table(x, a)
  169. {
  170. this->init(x);
  171. }
  172. table_impl(table_impl& x,
  173. boost::unordered::detail::move_tag m)
  174. : table(x, m)
  175. {}
  176. table_impl(table_impl& x,
  177. node_allocator const& a,
  178. boost::unordered::detail::move_tag m)
  179. : table(x, a, m)
  180. {
  181. this->move_init(x);
  182. }
  183. // Accessors
  184. template <class Key, class Pred>
  185. iterator find_node_impl(
  186. std::size_t key_hash,
  187. Key const& k,
  188. Pred const& eq) const
  189. {
  190. std::size_t bucket_index = this->hash_to_bucket(key_hash);
  191. iterator n = this->begin(bucket_index);
  192. for (;;)
  193. {
  194. if (!n.node_) return n;
  195. std::size_t node_hash = n.node_->hash_;
  196. if (key_hash == node_hash)
  197. {
  198. if (eq(k, this->get_key(*n)))
  199. return n;
  200. }
  201. else
  202. {
  203. if (this->hash_to_bucket(node_hash) != bucket_index)
  204. return iterator();
  205. }
  206. ++n;
  207. }
  208. }
  209. std::size_t count(key_type const& k) const
  210. {
  211. return this->find_node(k).node_ ? 1 : 0;
  212. }
  213. value_type& at(key_type const& k) const
  214. {
  215. if (this->size_) {
  216. iterator it = this->find_node(k);
  217. if (it.node_) return *it;
  218. }
  219. boost::throw_exception(
  220. std::out_of_range("Unable to find key in unordered_map."));
  221. }
  222. std::pair<iterator, iterator>
  223. equal_range(key_type const& k) const
  224. {
  225. iterator n = this->find_node(k);
  226. iterator n2 = n;
  227. if (n2.node_) ++n2;
  228. return std::make_pair(n, n2);
  229. }
  230. // equals
  231. bool equals(table_impl const& other) const
  232. {
  233. if(this->size_ != other.size_) return false;
  234. for(iterator n1 = this->begin(); n1.node_; ++n1)
  235. {
  236. iterator n2 = other.find_matching_node(n1);
  237. if (!n2.node_ || *n1 != *n2)
  238. return false;
  239. }
  240. return true;
  241. }
  242. // Emplace/Insert
  243. inline iterator add_node(
  244. node_constructor& a,
  245. std::size_t key_hash)
  246. {
  247. node_pointer n = a.release();
  248. n->hash_ = key_hash;
  249. bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
  250. if (!b->next_)
  251. {
  252. link_pointer start_node = this->get_previous_start();
  253. if (start_node->next_) {
  254. this->get_bucket(this->hash_to_bucket(
  255. static_cast<node_pointer>(start_node->next_)->hash_)
  256. )->next_ = n;
  257. }
  258. b->next_ = start_node;
  259. n->next_ = start_node->next_;
  260. start_node->next_ = n;
  261. }
  262. else
  263. {
  264. n->next_ = b->next_->next_;
  265. b->next_->next_ = n;
  266. }
  267. ++this->size_;
  268. return iterator(n);
  269. }
  270. value_type& operator[](key_type const& k)
  271. {
  272. std::size_t key_hash = this->hash(k);
  273. iterator pos = this->find_node(key_hash, k);
  274. if (pos.node_) return *pos;
  275. // Create the node before rehashing in case it throws an
  276. // exception (need strong safety in such a case).
  277. node_constructor a(this->node_alloc());
  278. a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3(
  279. boost::unordered::piecewise_construct,
  280. boost::make_tuple(k),
  281. boost::make_tuple()));
  282. this->reserve_for_insert(this->size_ + 1);
  283. return *add_node(a, key_hash);
  284. }
  285. #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  286. # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  287. emplace_return emplace(boost::unordered::detail::emplace_args1<
  288. boost::unordered::detail::please_ignore_this_overload> const&)
  289. {
  290. BOOST_ASSERT(false);
  291. return emplace_return(this->begin(), false);
  292. }
  293. # else
  294. emplace_return emplace(
  295. boost::unordered::detail::please_ignore_this_overload const&)
  296. {
  297. BOOST_ASSERT(false);
  298. return emplace_return(this->begin(), false);
  299. }
  300. # endif
  301. #endif
  302. template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
  303. emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
  304. {
  305. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  306. return emplace_impl(
  307. extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
  308. BOOST_UNORDERED_EMPLACE_FORWARD);
  309. #else
  310. return emplace_impl(
  311. extractor::extract(args.a0, args.a1),
  312. BOOST_UNORDERED_EMPLACE_FORWARD);
  313. #endif
  314. }
  315. #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  316. template <typename A0>
  317. emplace_return emplace(
  318. boost::unordered::detail::emplace_args1<A0> const& args)
  319. {
  320. return emplace_impl(extractor::extract(args.a0), args);
  321. }
  322. #endif
  323. template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
  324. emplace_return emplace_impl(key_type const& k,
  325. BOOST_UNORDERED_EMPLACE_ARGS)
  326. {
  327. std::size_t key_hash = this->hash(k);
  328. iterator pos = this->find_node(key_hash, k);
  329. if (pos.node_) return emplace_return(pos, false);
  330. // Create the node before rehashing in case it throws an
  331. // exception (need strong safety in such a case).
  332. node_constructor a(this->node_alloc());
  333. a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
  334. // reserve has basic exception safety if the hash function
  335. // throws, strong otherwise.
  336. this->reserve_for_insert(this->size_ + 1);
  337. return emplace_return(this->add_node(a, key_hash), true);
  338. }
  339. emplace_return emplace_impl_with_node(node_constructor& a)
  340. {
  341. key_type const& k = this->get_key(a.value());
  342. std::size_t key_hash = this->hash(k);
  343. iterator pos = this->find_node(key_hash, k);
  344. if (pos.node_) return emplace_return(pos, false);
  345. // reserve has basic exception safety if the hash function
  346. // throws, strong otherwise.
  347. this->reserve_for_insert(this->size_ + 1);
  348. return emplace_return(this->add_node(a, key_hash), true);
  349. }
  350. template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
  351. emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
  352. {
  353. // Don't have a key, so construct the node first in order
  354. // to be able to lookup the position.
  355. node_constructor a(this->node_alloc());
  356. a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
  357. return emplace_impl_with_node(a);
  358. }
  359. ////////////////////////////////////////////////////////////////////////
  360. // Insert range methods
  361. //
  362. // if hash function throws, or inserting > 1 element, basic exception
  363. // safety strong otherwise
  364. template <class InputIt>
  365. void insert_range(InputIt i, InputIt j)
  366. {
  367. if(i != j)
  368. return insert_range_impl(extractor::extract(*i), i, j);
  369. }
  370. template <class InputIt>
  371. void insert_range_impl(key_type const& k, InputIt i, InputIt j)
  372. {
  373. node_constructor a(this->node_alloc());
  374. insert_range_impl2(a, k, i, j);
  375. while(++i != j) {
  376. // Note: can't use get_key as '*i' might not be value_type - it
  377. // could be a pair with first_types as key_type without const or
  378. // a different second_type.
  379. //
  380. // TODO: Might be worth storing the value_type instead of the
  381. // key here. Could be more efficient if '*i' is expensive. Could
  382. // be less efficient if copying the full value_type is
  383. // expensive.
  384. insert_range_impl2(a, extractor::extract(*i), i, j);
  385. }
  386. }
  387. template <class InputIt>
  388. void insert_range_impl2(node_constructor& a, key_type const& k,
  389. InputIt i, InputIt j)
  390. {
  391. // No side effects in this initial code
  392. std::size_t key_hash = this->hash(k);
  393. iterator pos = this->find_node(key_hash, k);
  394. if (!pos.node_) {
  395. a.construct_with_value2(*i);
  396. if(this->size_ + 1 > this->max_load_)
  397. this->reserve_for_insert(this->size_ +
  398. boost::unordered::detail::insert_size(i, j));
  399. // Nothing after this point can throw.
  400. this->add_node(a, key_hash);
  401. }
  402. }
  403. template <class InputIt>
  404. void insert_range_impl(no_key, InputIt i, InputIt j)
  405. {
  406. node_constructor a(this->node_alloc());
  407. do {
  408. a.construct_with_value2(*i);
  409. emplace_impl_with_node(a);
  410. } while(++i != j);
  411. }
  412. ////////////////////////////////////////////////////////////////////////
  413. // Erase
  414. //
  415. // no throw
  416. std::size_t erase_key(key_type const& k)
  417. {
  418. if(!this->size_) return 0;
  419. std::size_t key_hash = this->hash(k);
  420. std::size_t bucket_index = this->hash_to_bucket(key_hash);
  421. link_pointer prev = this->get_previous_start(bucket_index);
  422. if (!prev) return 0;
  423. for (;;)
  424. {
  425. if (!prev->next_) return 0;
  426. std::size_t node_hash =
  427. static_cast<node_pointer>(prev->next_)->hash_;
  428. if (this->hash_to_bucket(node_hash) != bucket_index)
  429. return 0;
  430. if (node_hash == key_hash &&
  431. this->key_eq()(k, this->get_key(
  432. static_cast<node_pointer>(prev->next_)->value())))
  433. break;
  434. prev = prev->next_;
  435. }
  436. link_pointer end = static_cast<node_pointer>(prev->next_)->next_;
  437. std::size_t count = this->delete_nodes(prev, end);
  438. this->fix_bucket(bucket_index, prev);
  439. return count;
  440. }
  441. iterator erase(c_iterator r)
  442. {
  443. BOOST_ASSERT(r.node_);
  444. iterator next(r.node_);
  445. ++next;
  446. erase_nodes(r.node_, next.node_);
  447. return next;
  448. }
  449. iterator erase_range(c_iterator r1, c_iterator r2)
  450. {
  451. if (r1 == r2) return iterator(r2.node_);
  452. erase_nodes(r1.node_, r2.node_);
  453. return iterator(r2.node_);
  454. }
  455. void erase_nodes(node_pointer begin, node_pointer end)
  456. {
  457. std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
  458. // Find the node before begin.
  459. link_pointer prev = this->get_previous_start(bucket_index);
  460. while(prev->next_ != begin) prev = prev->next_;
  461. // Delete the nodes.
  462. do {
  463. this->delete_node(prev);
  464. bucket_index = this->fix_bucket(bucket_index, prev);
  465. } while (prev->next_ != end);
  466. }
  467. ////////////////////////////////////////////////////////////////////////
  468. // fill_buckets
  469. template <class NodeCreator>
  470. static void fill_buckets(iterator n, table& dst,
  471. NodeCreator& creator)
  472. {
  473. link_pointer prev = dst.get_previous_start();
  474. while (n.node_) {
  475. node_pointer node = creator.create(*n);
  476. node->hash_ = n.node_->hash_;
  477. prev->next_ = node;
  478. ++dst.size_;
  479. ++n;
  480. prev = place_in_bucket(dst, prev);
  481. }
  482. }
  483. // strong otherwise exception safety
  484. void rehash_impl(std::size_t num_buckets)
  485. {
  486. BOOST_ASSERT(this->buckets_);
  487. this->create_buckets(num_buckets);
  488. link_pointer prev = this->get_previous_start();
  489. while (prev->next_)
  490. prev = place_in_bucket(*this, prev);
  491. }
  492. // Iterate through the nodes placing them in the correct buckets.
  493. // pre: prev->next_ is not null.
  494. static link_pointer place_in_bucket(table& dst, link_pointer prev)
  495. {
  496. node_pointer n = static_cast<node_pointer>(prev->next_);
  497. bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_));
  498. if (!b->next_) {
  499. b->next_ = prev;
  500. return n;
  501. }
  502. else {
  503. prev->next_ = n->next_;
  504. n->next_ = b->next_->next_;
  505. b->next_->next_ = n;
  506. return prev;
  507. }
  508. }
  509. };
  510. }}}
  511. #endif