equivalent.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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_EQUIVALENT_HPP_INCLUDED
  6. #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
  7. #include <boost/config.hpp>
  8. #if defined(BOOST_HAS_PRAGMA_ONCE)
  9. #pragma once
  10. #endif
  11. #include <boost/unordered/detail/table.hpp>
  12. #include <boost/unordered/detail/extract_key.hpp>
  13. namespace boost { namespace unordered { namespace detail {
  14. template <typename A, typename T> struct grouped_node;
  15. template <typename T> struct grouped_ptr_node;
  16. template <typename Types> struct grouped_table_impl;
  17. template <typename A, typename T>
  18. struct grouped_node :
  19. boost::unordered::detail::value_base<T>
  20. {
  21. typedef typename ::boost::unordered::detail::rebind_wrap<
  22. A, grouped_node<A, T> >::type allocator;
  23. typedef typename ::boost::unordered::detail::
  24. allocator_traits<allocator>::pointer node_pointer;
  25. typedef node_pointer link_pointer;
  26. link_pointer next_;
  27. node_pointer group_prev_;
  28. std::size_t hash_;
  29. grouped_node() :
  30. next_(),
  31. group_prev_(),
  32. hash_(0)
  33. {}
  34. void init(node_pointer self)
  35. {
  36. group_prev_ = self;
  37. }
  38. private:
  39. grouped_node& operator=(grouped_node const&);
  40. };
  41. template <typename T>
  42. struct grouped_ptr_node :
  43. boost::unordered::detail::ptr_bucket
  44. {
  45. typedef T value_type;
  46. typedef boost::unordered::detail::ptr_bucket bucket_base;
  47. typedef grouped_ptr_node<T>* node_pointer;
  48. typedef ptr_bucket* link_pointer;
  49. node_pointer group_prev_;
  50. std::size_t hash_;
  51. boost::unordered::detail::value_base<T> value_base_;
  52. grouped_ptr_node() :
  53. bucket_base(),
  54. group_prev_(0),
  55. hash_(0)
  56. {}
  57. void init(node_pointer self)
  58. {
  59. group_prev_ = self;
  60. }
  61. void* address() { return value_base_.address(); }
  62. value_type& value() { return value_base_.value(); }
  63. value_type* value_ptr() { return value_base_.value_ptr(); }
  64. private:
  65. grouped_ptr_node& operator=(grouped_ptr_node const&);
  66. };
  67. // If the allocator uses raw pointers use grouped_ptr_node
  68. // Otherwise use grouped_node.
  69. template <typename A, typename T, typename NodePtr, typename BucketPtr>
  70. struct pick_grouped_node2
  71. {
  72. typedef boost::unordered::detail::grouped_node<A, T> node;
  73. typedef typename boost::unordered::detail::allocator_traits<
  74. typename boost::unordered::detail::rebind_wrap<A, node>::type
  75. >::pointer node_pointer;
  76. typedef boost::unordered::detail::bucket<node_pointer> bucket;
  77. typedef node_pointer link_pointer;
  78. };
  79. template <typename A, typename T>
  80. struct pick_grouped_node2<A, T,
  81. boost::unordered::detail::grouped_ptr_node<T>*,
  82. boost::unordered::detail::ptr_bucket*>
  83. {
  84. typedef boost::unordered::detail::grouped_ptr_node<T> node;
  85. typedef boost::unordered::detail::ptr_bucket bucket;
  86. typedef bucket* link_pointer;
  87. };
  88. template <typename A, typename T>
  89. struct pick_grouped_node
  90. {
  91. typedef boost::unordered::detail::allocator_traits<
  92. typename boost::unordered::detail::rebind_wrap<A,
  93. boost::unordered::detail::grouped_ptr_node<T> >::type
  94. > tentative_node_traits;
  95. typedef boost::unordered::detail::allocator_traits<
  96. typename boost::unordered::detail::rebind_wrap<A,
  97. boost::unordered::detail::ptr_bucket >::type
  98. > tentative_bucket_traits;
  99. typedef pick_grouped_node2<A, T,
  100. typename tentative_node_traits::pointer,
  101. typename tentative_bucket_traits::pointer> pick;
  102. typedef typename pick::node node;
  103. typedef typename pick::bucket bucket;
  104. typedef typename pick::link_pointer link_pointer;
  105. };
  106. template <typename A, typename T, typename H, typename P>
  107. struct multiset
  108. {
  109. typedef boost::unordered::detail::multiset<A, T, H, P> types;
  110. typedef A allocator;
  111. typedef T value_type;
  112. typedef H hasher;
  113. typedef P key_equal;
  114. typedef T key_type;
  115. typedef boost::unordered::detail::allocator_traits<allocator> traits;
  116. typedef boost::unordered::detail::pick_grouped_node<allocator,
  117. value_type> pick;
  118. typedef typename pick::node node;
  119. typedef typename pick::bucket bucket;
  120. typedef typename pick::link_pointer link_pointer;
  121. typedef boost::unordered::detail::grouped_table_impl<types> table;
  122. typedef boost::unordered::detail::set_extractor<value_type> extractor;
  123. typedef typename boost::unordered::detail::pick_policy<T>::type policy;
  124. };
  125. template <typename A, typename K, typename M, typename H, typename P>
  126. struct multimap
  127. {
  128. typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
  129. typedef A allocator;
  130. typedef std::pair<K const, M> value_type;
  131. typedef H hasher;
  132. typedef P key_equal;
  133. typedef K key_type;
  134. typedef boost::unordered::detail::allocator_traits<allocator> traits;
  135. typedef boost::unordered::detail::pick_grouped_node<allocator,
  136. value_type> pick;
  137. typedef typename pick::node node;
  138. typedef typename pick::bucket bucket;
  139. typedef typename pick::link_pointer link_pointer;
  140. typedef boost::unordered::detail::grouped_table_impl<types> table;
  141. typedef boost::unordered::detail::map_extractor<key_type, value_type>
  142. extractor;
  143. typedef typename boost::unordered::detail::pick_policy<K>::type policy;
  144. };
  145. template <typename Types>
  146. struct grouped_table_impl : boost::unordered::detail::table<Types>
  147. {
  148. typedef boost::unordered::detail::table<Types> table;
  149. typedef typename table::value_type value_type;
  150. typedef typename table::bucket bucket;
  151. typedef typename table::policy policy;
  152. typedef typename table::node_pointer node_pointer;
  153. typedef typename table::node_allocator node_allocator;
  154. typedef typename table::node_allocator_traits node_allocator_traits;
  155. typedef typename table::bucket_pointer bucket_pointer;
  156. typedef typename table::link_pointer link_pointer;
  157. typedef typename table::hasher hasher;
  158. typedef typename table::key_equal key_equal;
  159. typedef typename table::key_type key_type;
  160. typedef typename table::node_constructor node_constructor;
  161. typedef typename table::extractor extractor;
  162. typedef typename table::iterator iterator;
  163. typedef typename table::c_iterator c_iterator;
  164. // Constructors
  165. grouped_table_impl(std::size_t n,
  166. hasher const& hf,
  167. key_equal const& eq,
  168. node_allocator const& a)
  169. : table(n, hf, eq, a)
  170. {}
  171. grouped_table_impl(grouped_table_impl const& x)
  172. : table(x, node_allocator_traits::
  173. select_on_container_copy_construction(x.node_alloc()))
  174. {
  175. this->init(x);
  176. }
  177. grouped_table_impl(grouped_table_impl const& x,
  178. node_allocator const& a)
  179. : table(x, a)
  180. {
  181. this->init(x);
  182. }
  183. grouped_table_impl(grouped_table_impl& x,
  184. boost::unordered::detail::move_tag m)
  185. : table(x, m)
  186. {}
  187. grouped_table_impl(grouped_table_impl& x,
  188. node_allocator const& a,
  189. boost::unordered::detail::move_tag m)
  190. : table(x, a, m)
  191. {
  192. this->move_init(x);
  193. }
  194. // Accessors
  195. template <class Key, class Pred>
  196. iterator find_node_impl(
  197. std::size_t key_hash,
  198. Key const& k,
  199. Pred const& eq) const
  200. {
  201. std::size_t bucket_index = this->hash_to_bucket(key_hash);
  202. iterator n = this->begin(bucket_index);
  203. for (;;)
  204. {
  205. if (!n.node_) return n;
  206. std::size_t node_hash = n.node_->hash_;
  207. if (key_hash == node_hash)
  208. {
  209. if (eq(k, this->get_key(*n)))
  210. return n;
  211. }
  212. else
  213. {
  214. if (this->hash_to_bucket(node_hash) != bucket_index)
  215. return iterator();
  216. }
  217. n = iterator(n.node_->group_prev_->next_);
  218. }
  219. }
  220. std::size_t count(key_type const& k) const
  221. {
  222. iterator n = this->find_node(k);
  223. if (!n.node_) return 0;
  224. std::size_t x = 0;
  225. node_pointer it = n.node_;
  226. do {
  227. it = it->group_prev_;
  228. ++x;
  229. } while(it != n.node_);
  230. return x;
  231. }
  232. std::pair<iterator, iterator>
  233. equal_range(key_type const& k) const
  234. {
  235. iterator n = this->find_node(k);
  236. return std::make_pair(
  237. n, n.node_ ? iterator(n.node_->group_prev_->next_) : n);
  238. }
  239. // Equality
  240. bool equals(grouped_table_impl const& other) const
  241. {
  242. if(this->size_ != other.size_) return false;
  243. for(iterator n1 = this->begin(); n1.node_;)
  244. {
  245. iterator n2 = other.find_matching_node(n1);
  246. if (!n2.node_) return false;
  247. iterator end1(n1.node_->group_prev_->next_);
  248. iterator end2(n2.node_->group_prev_->next_);
  249. if (!group_equals(n1, end1, n2, end2)) return false;
  250. n1 = end1;
  251. }
  252. return true;
  253. }
  254. static bool group_equals(iterator n1, iterator end1,
  255. iterator n2, iterator end2)
  256. {
  257. for(;;)
  258. {
  259. if (*n1 != *n2) break;
  260. ++n1;
  261. ++n2;
  262. if (n1 == end1) return n2 == end2;
  263. if (n2 == end2) return false;
  264. }
  265. for(iterator n1a = n1, n2a = n2;;)
  266. {
  267. ++n1a;
  268. ++n2a;
  269. if (n1a == end1)
  270. {
  271. if (n2a == end2) break;
  272. else return false;
  273. }
  274. if (n2a == end2) return false;
  275. }
  276. iterator start = n1;
  277. for(;n1 != end1; ++n1)
  278. {
  279. value_type const& v = *n1;
  280. if (find(start, n1, v)) continue;
  281. std::size_t matches = count_equal(n2, end2, v);
  282. if (!matches) return false;
  283. iterator next = n1;
  284. ++next;
  285. if (matches != 1 + count_equal(next, end1, v)) return false;
  286. }
  287. return true;
  288. }
  289. static bool find(iterator n, iterator end, value_type const& v)
  290. {
  291. for(;n != end; ++n)
  292. if (*n == v)
  293. return true;
  294. return false;
  295. }
  296. static std::size_t count_equal(iterator n, iterator end,
  297. value_type const& v)
  298. {
  299. std::size_t count = 0;
  300. for(;n != end; ++n)
  301. if (*n == v) ++count;
  302. return count;
  303. }
  304. // Emplace/Insert
  305. static inline void add_after_node(
  306. node_pointer n,
  307. node_pointer pos)
  308. {
  309. n->next_ = pos->group_prev_->next_;
  310. n->group_prev_ = pos->group_prev_;
  311. pos->group_prev_->next_ = n;
  312. pos->group_prev_ = n;
  313. }
  314. inline iterator add_node(
  315. node_constructor& a,
  316. std::size_t key_hash,
  317. iterator pos)
  318. {
  319. node_pointer n = a.release();
  320. n->hash_ = key_hash;
  321. if (pos.node_) {
  322. this->add_after_node(n, pos.node_);
  323. if (n->next_) {
  324. std::size_t next_bucket = this->hash_to_bucket(
  325. static_cast<node_pointer>(n->next_)->hash_);
  326. if (next_bucket != this->hash_to_bucket(key_hash)) {
  327. this->get_bucket(next_bucket)->next_ = n;
  328. }
  329. }
  330. }
  331. else {
  332. bucket_pointer b = this->get_bucket(
  333. this->hash_to_bucket(key_hash));
  334. if (!b->next_)
  335. {
  336. link_pointer start_node = this->get_previous_start();
  337. if (start_node->next_) {
  338. this->get_bucket(this->hash_to_bucket(
  339. static_cast<node_pointer>(start_node->next_)->hash_
  340. ))->next_ = n;
  341. }
  342. b->next_ = start_node;
  343. n->next_ = start_node->next_;
  344. start_node->next_ = n;
  345. }
  346. else
  347. {
  348. n->next_ = b->next_->next_;
  349. b->next_->next_ = n;
  350. }
  351. }
  352. ++this->size_;
  353. return iterator(n);
  354. }
  355. iterator emplace_impl(node_constructor& a)
  356. {
  357. key_type const& k = this->get_key(a.value());
  358. std::size_t key_hash = this->hash(k);
  359. iterator position = this->find_node(key_hash, k);
  360. // reserve has basic exception safety if the hash function
  361. // throws, strong otherwise.
  362. this->reserve_for_insert(this->size_ + 1);
  363. return this->add_node(a, key_hash, position);
  364. }
  365. void emplace_impl_no_rehash(node_constructor& a)
  366. {
  367. key_type const& k = this->get_key(a.value());
  368. std::size_t key_hash = this->hash(k);
  369. this->add_node(a, key_hash, this->find_node(key_hash, k));
  370. }
  371. #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  372. # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  373. iterator emplace(boost::unordered::detail::emplace_args1<
  374. boost::unordered::detail::please_ignore_this_overload> const&)
  375. {
  376. BOOST_ASSERT(false);
  377. return iterator();
  378. }
  379. # else
  380. iterator emplace(
  381. boost::unordered::detail::please_ignore_this_overload const&)
  382. {
  383. BOOST_ASSERT(false);
  384. return iterator();
  385. }
  386. # endif
  387. #endif
  388. template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
  389. iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
  390. {
  391. node_constructor a(this->node_alloc());
  392. a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
  393. return iterator(emplace_impl(a));
  394. }
  395. ////////////////////////////////////////////////////////////////////////
  396. // Insert range methods
  397. // if hash function throws, or inserting > 1 element, basic exception
  398. // safety. Strong otherwise
  399. template <class I>
  400. typename boost::unordered::detail::enable_if_forward<I, void>::type
  401. insert_range(I i, I j)
  402. {
  403. if(i == j) return;
  404. std::size_t distance = boost::unordered::detail::distance(i, j);
  405. if(distance == 1) {
  406. node_constructor a(this->node_alloc());
  407. a.construct_with_value2(*i);
  408. emplace_impl(a);
  409. }
  410. else {
  411. // Only require basic exception safety here
  412. this->reserve_for_insert(this->size_ + distance);
  413. node_constructor a(this->node_alloc());
  414. for (; i != j; ++i) {
  415. a.construct_with_value2(*i);
  416. emplace_impl_no_rehash(a);
  417. }
  418. }
  419. }
  420. template <class I>
  421. typename boost::unordered::detail::disable_if_forward<I, void>::type
  422. insert_range(I i, I j)
  423. {
  424. node_constructor a(this->node_alloc());
  425. for (; i != j; ++i) {
  426. a.construct_with_value2(*i);
  427. emplace_impl(a);
  428. }
  429. }
  430. ////////////////////////////////////////////////////////////////////////
  431. // Erase
  432. //
  433. // no throw
  434. std::size_t erase_key(key_type const& k)
  435. {
  436. if(!this->size_) return 0;
  437. std::size_t key_hash = this->hash(k);
  438. std::size_t bucket_index = this->hash_to_bucket(key_hash);
  439. link_pointer prev = this->get_previous_start(bucket_index);
  440. if (!prev) return 0;
  441. for (;;)
  442. {
  443. if (!prev->next_) return 0;
  444. std::size_t node_hash =
  445. static_cast<node_pointer>(prev->next_)->hash_;
  446. if (this->hash_to_bucket(node_hash) != bucket_index)
  447. return 0;
  448. if (node_hash == key_hash &&
  449. this->key_eq()(k, this->get_key(
  450. static_cast<node_pointer>(prev->next_)->value())))
  451. break;
  452. prev = static_cast<node_pointer>(prev->next_)->group_prev_;
  453. }
  454. node_pointer first_node = static_cast<node_pointer>(prev->next_);
  455. link_pointer end = first_node->group_prev_->next_;
  456. std::size_t deleted_count = this->delete_nodes(prev, end);
  457. this->fix_bucket(bucket_index, prev);
  458. return deleted_count;
  459. }
  460. iterator erase(c_iterator r)
  461. {
  462. BOOST_ASSERT(r.node_);
  463. iterator next(r.node_);
  464. ++next;
  465. erase_nodes(r.node_, next.node_);
  466. return next;
  467. }
  468. iterator erase_range(c_iterator r1, c_iterator r2)
  469. {
  470. if (r1 == r2) return iterator(r2.node_);
  471. erase_nodes(r1.node_, r2.node_);
  472. return iterator(r2.node_);
  473. }
  474. link_pointer erase_nodes(node_pointer i, node_pointer j)
  475. {
  476. std::size_t bucket_index = this->hash_to_bucket(i->hash_);
  477. // Split the groups containing 'i' and 'j'.
  478. // And get the pointer to the node before i while
  479. // we're at it.
  480. link_pointer prev = split_groups(i, j);
  481. // If we don't have a 'prev' it means that i is at the
  482. // beginning of a block, so search through the blocks in the
  483. // same bucket.
  484. if (!prev) {
  485. prev = this->get_previous_start(bucket_index);
  486. while (prev->next_ != i)
  487. prev = static_cast<node_pointer>(prev->next_)->group_prev_;
  488. }
  489. // Delete the nodes.
  490. do {
  491. link_pointer group_end =
  492. static_cast<node_pointer>(prev->next_)->group_prev_->next_;
  493. this->delete_nodes(prev, group_end);
  494. bucket_index = this->fix_bucket(bucket_index, prev);
  495. } while(prev->next_ != j);
  496. return prev;
  497. }
  498. static link_pointer split_groups(node_pointer i, node_pointer j)
  499. {
  500. node_pointer prev = i->group_prev_;
  501. if (prev->next_ != i) prev = node_pointer();
  502. if (j) {
  503. node_pointer first = j;
  504. while (first != i && first->group_prev_->next_ == first) {
  505. first = first->group_prev_;
  506. }
  507. boost::swap(first->group_prev_, j->group_prev_);
  508. if (first == i) return prev;
  509. }
  510. if (prev) {
  511. node_pointer first = prev;
  512. while (first->group_prev_->next_ == first) {
  513. first = first->group_prev_;
  514. }
  515. boost::swap(first->group_prev_, i->group_prev_);
  516. }
  517. return prev;
  518. }
  519. ////////////////////////////////////////////////////////////////////////
  520. // fill_buckets
  521. template <class NodeCreator>
  522. static void fill_buckets(iterator n, table& dst,
  523. NodeCreator& creator)
  524. {
  525. link_pointer prev = dst.get_previous_start();
  526. while (n.node_) {
  527. std::size_t key_hash = n.node_->hash_;
  528. iterator group_end(n.node_->group_prev_->next_);
  529. node_pointer first_node = creator.create(*n);
  530. node_pointer end = first_node;
  531. first_node->hash_ = key_hash;
  532. prev->next_ = first_node;
  533. ++dst.size_;
  534. for (++n; n != group_end; ++n)
  535. {
  536. end = creator.create(*n);
  537. end->hash_ = key_hash;
  538. add_after_node(end, first_node);
  539. ++dst.size_;
  540. }
  541. prev = place_in_bucket(dst, prev, end);
  542. }
  543. }
  544. // strong otherwise exception safety
  545. void rehash_impl(std::size_t num_buckets)
  546. {
  547. BOOST_ASSERT(this->buckets_);
  548. this->create_buckets(num_buckets);
  549. link_pointer prev = this->get_previous_start();
  550. while (prev->next_)
  551. prev = place_in_bucket(*this, prev,
  552. static_cast<node_pointer>(prev->next_)->group_prev_);
  553. }
  554. // Iterate through the nodes placing them in the correct buckets.
  555. // pre: prev->next_ is not null.
  556. static link_pointer place_in_bucket(table& dst,
  557. link_pointer prev, node_pointer end)
  558. {
  559. bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_));
  560. if (!b->next_) {
  561. b->next_ = prev;
  562. return end;
  563. }
  564. else {
  565. link_pointer next = end->next_;
  566. end->next_ = b->next_->next_;
  567. b->next_->next_ = prev->next_;
  568. prev->next_ = next;
  569. return prev;
  570. }
  571. }
  572. };
  573. }}}
  574. #endif