equivalent.hpp 22 KB

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