table.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  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_ALL_HPP_INCLUDED
  6. #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
  7. #include <boost/unordered/detail/buckets.hpp>
  8. #include <boost/unordered/detail/util.hpp>
  9. #include <boost/type_traits/aligned_storage.hpp>
  10. #include <boost/type_traits/alignment_of.hpp>
  11. #include <cmath>
  12. #if defined(BOOST_MSVC)
  13. #pragma warning(push)
  14. #pragma warning(disable:4127) // conditional expression is constant
  15. #endif
  16. #if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
  17. #if defined(__EDG__)
  18. #elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__)
  19. #pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.")
  20. #elif defined(__GNUC__) || defined(__HP_aCC) || \
  21. defined(__SUNPRO_CC) || defined(__IBMCPP__)
  22. #warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported."
  23. #endif
  24. #endif
  25. namespace boost { namespace unordered { namespace detail {
  26. ////////////////////////////////////////////////////////////////////////////
  27. // convert double to std::size_t
  28. inline std::size_t double_to_size(double f)
  29. {
  30. return f >= static_cast<double>(
  31. (std::numeric_limits<std::size_t>::max)()) ?
  32. (std::numeric_limits<std::size_t>::max)() :
  33. static_cast<std::size_t>(f);
  34. }
  35. // The space used to store values in a node.
  36. template <typename ValueType>
  37. struct value_base
  38. {
  39. typedef ValueType value_type;
  40. typename boost::aligned_storage<
  41. sizeof(value_type),
  42. boost::alignment_of<value_type>::value>::type data_;
  43. void* address() {
  44. return this;
  45. }
  46. value_type& value() {
  47. return *(ValueType*) this;
  48. }
  49. value_type* value_ptr() {
  50. return (ValueType*) this;
  51. }
  52. private:
  53. value_base& operator=(value_base const&);
  54. };
  55. template <typename NodeAlloc>
  56. struct copy_nodes
  57. {
  58. typedef boost::unordered::detail::allocator_traits<NodeAlloc>
  59. node_allocator_traits;
  60. node_constructor<NodeAlloc> constructor;
  61. explicit copy_nodes(NodeAlloc& a) : constructor(a) {}
  62. typename node_allocator_traits::pointer create(
  63. typename node_allocator_traits::value_type::value_type const& v)
  64. {
  65. constructor.construct_with_value2(v);
  66. return constructor.release();
  67. }
  68. };
  69. template <typename NodeAlloc>
  70. struct move_nodes
  71. {
  72. typedef boost::unordered::detail::allocator_traits<NodeAlloc>
  73. node_allocator_traits;
  74. node_constructor<NodeAlloc> constructor;
  75. explicit move_nodes(NodeAlloc& a) : constructor(a) {}
  76. typename node_allocator_traits::pointer create(
  77. typename node_allocator_traits::value_type::value_type& v)
  78. {
  79. constructor.construct_with_value2(boost::move(v));
  80. return constructor.release();
  81. }
  82. };
  83. template <typename Buckets>
  84. struct assign_nodes
  85. {
  86. node_holder<typename Buckets::node_allocator> holder;
  87. explicit assign_nodes(Buckets& b) : holder(b) {}
  88. typename Buckets::node_pointer create(
  89. typename Buckets::value_type const& v)
  90. {
  91. return holder.copy_of(v);
  92. }
  93. };
  94. template <typename Buckets>
  95. struct move_assign_nodes
  96. {
  97. node_holder<typename Buckets::node_allocator> holder;
  98. explicit move_assign_nodes(Buckets& b) : holder(b) {}
  99. typename Buckets::node_pointer create(
  100. typename Buckets::value_type& v)
  101. {
  102. return holder.move_copy_of(v);
  103. }
  104. };
  105. template <typename Types>
  106. struct table :
  107. boost::unordered::detail::functions<
  108. typename Types::hasher,
  109. typename Types::key_equal>
  110. {
  111. private:
  112. table(table const&);
  113. table& operator=(table const&);
  114. public:
  115. typedef typename Types::node node;
  116. typedef typename Types::bucket bucket;
  117. typedef typename Types::hasher hasher;
  118. typedef typename Types::key_equal key_equal;
  119. typedef typename Types::key_type key_type;
  120. typedef typename Types::extractor extractor;
  121. typedef typename Types::value_type value_type;
  122. typedef typename Types::table table_impl;
  123. typedef typename Types::link_pointer link_pointer;
  124. typedef typename Types::policy policy;
  125. typedef boost::unordered::detail::functions<
  126. typename Types::hasher,
  127. typename Types::key_equal> functions;
  128. typedef typename functions::set_hash_functions set_hash_functions;
  129. typedef typename Types::allocator allocator;
  130. typedef typename boost::unordered::detail::
  131. rebind_wrap<allocator, node>::type node_allocator;
  132. typedef typename boost::unordered::detail::
  133. rebind_wrap<allocator, bucket>::type bucket_allocator;
  134. typedef boost::unordered::detail::allocator_traits<node_allocator>
  135. node_allocator_traits;
  136. typedef boost::unordered::detail::allocator_traits<bucket_allocator>
  137. bucket_allocator_traits;
  138. typedef typename node_allocator_traits::pointer
  139. node_pointer;
  140. typedef typename node_allocator_traits::const_pointer
  141. const_node_pointer;
  142. typedef typename bucket_allocator_traits::pointer
  143. bucket_pointer;
  144. typedef boost::unordered::detail::node_constructor<node_allocator>
  145. node_constructor;
  146. typedef boost::unordered::iterator_detail::
  147. iterator<node> iterator;
  148. typedef boost::unordered::iterator_detail::
  149. c_iterator<node, const_node_pointer> c_iterator;
  150. typedef boost::unordered::iterator_detail::
  151. l_iterator<node, policy> l_iterator;
  152. typedef boost::unordered::iterator_detail::
  153. cl_iterator<node, const_node_pointer, policy> cl_iterator;
  154. ////////////////////////////////////////////////////////////////////////
  155. // Members
  156. boost::unordered::detail::compressed<bucket_allocator, node_allocator>
  157. allocators_;
  158. std::size_t bucket_count_;
  159. std::size_t size_;
  160. float mlf_;
  161. std::size_t max_load_;
  162. bucket_pointer buckets_;
  163. ////////////////////////////////////////////////////////////////////////
  164. // Data access
  165. bucket_allocator const& bucket_alloc() const
  166. {
  167. return allocators_.first();
  168. }
  169. node_allocator const& node_alloc() const
  170. {
  171. return allocators_.second();
  172. }
  173. bucket_allocator& bucket_alloc()
  174. {
  175. return allocators_.first();
  176. }
  177. node_allocator& node_alloc()
  178. {
  179. return allocators_.second();
  180. }
  181. std::size_t max_bucket_count() const
  182. {
  183. // -1 to account for the start bucket.
  184. return policy::prev_bucket_count(
  185. bucket_allocator_traits::max_size(bucket_alloc()) - 1);
  186. }
  187. bucket_pointer get_bucket(std::size_t bucket_index) const
  188. {
  189. BOOST_ASSERT(buckets_);
  190. return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
  191. }
  192. link_pointer get_previous_start() const
  193. {
  194. return get_bucket(bucket_count_)->first_from_start();
  195. }
  196. link_pointer get_previous_start(std::size_t bucket_index) const
  197. {
  198. return get_bucket(bucket_index)->next_;
  199. }
  200. iterator begin() const
  201. {
  202. return size_ ? iterator(get_previous_start()->next_) : iterator();
  203. }
  204. iterator begin(std::size_t bucket_index) const
  205. {
  206. if (!size_) return iterator();
  207. link_pointer prev = get_previous_start(bucket_index);
  208. return prev ? iterator(prev->next_) : iterator();
  209. }
  210. std::size_t hash_to_bucket(std::size_t hash) const
  211. {
  212. return policy::to_bucket(bucket_count_, hash);
  213. }
  214. float load_factor() const
  215. {
  216. BOOST_ASSERT(bucket_count_ != 0);
  217. return static_cast<float>(size_)
  218. / static_cast<float>(bucket_count_);
  219. }
  220. std::size_t bucket_size(std::size_t index) const
  221. {
  222. iterator it = begin(index);
  223. if (!it.node_) return 0;
  224. std::size_t count = 0;
  225. while(it.node_ && hash_to_bucket(it.node_->hash_) == index)
  226. {
  227. ++count;
  228. ++it;
  229. }
  230. return count;
  231. }
  232. ////////////////////////////////////////////////////////////////////////
  233. // Load methods
  234. std::size_t max_size() const
  235. {
  236. using namespace std;
  237. // size < mlf_ * count
  238. return boost::unordered::detail::double_to_size(ceil(
  239. static_cast<double>(mlf_) *
  240. static_cast<double>(max_bucket_count())
  241. )) - 1;
  242. }
  243. void recalculate_max_load()
  244. {
  245. using namespace std;
  246. // From 6.3.1/13:
  247. // Only resize when size >= mlf_ * count
  248. max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil(
  249. static_cast<double>(mlf_) *
  250. static_cast<double>(bucket_count_)
  251. )) : 0;
  252. }
  253. void max_load_factor(float z)
  254. {
  255. BOOST_ASSERT(z > 0);
  256. mlf_ = (std::max)(z, minimum_max_load_factor);
  257. recalculate_max_load();
  258. }
  259. std::size_t min_buckets_for_size(std::size_t size) const
  260. {
  261. BOOST_ASSERT(mlf_ >= minimum_max_load_factor);
  262. using namespace std;
  263. // From 6.3.1/13:
  264. // size < mlf_ * count
  265. // => count > size / mlf_
  266. //
  267. // Or from rehash post-condition:
  268. // count > size / mlf_
  269. return policy::new_bucket_count(
  270. boost::unordered::detail::double_to_size(floor(
  271. static_cast<double>(size) /
  272. static_cast<double>(mlf_))) + 1);
  273. }
  274. ////////////////////////////////////////////////////////////////////////
  275. // Constructors
  276. table(std::size_t num_buckets,
  277. hasher const& hf,
  278. key_equal const& eq,
  279. node_allocator const& a) :
  280. functions(hf, eq),
  281. allocators_(a,a),
  282. bucket_count_(policy::new_bucket_count(num_buckets)),
  283. size_(0),
  284. mlf_(1.0f),
  285. max_load_(0),
  286. buckets_()
  287. {}
  288. table(table const& x, node_allocator const& a) :
  289. functions(x),
  290. allocators_(a,a),
  291. bucket_count_(x.min_buckets_for_size(x.size_)),
  292. size_(0),
  293. mlf_(x.mlf_),
  294. max_load_(0),
  295. buckets_()
  296. {}
  297. table(table& x, boost::unordered::detail::move_tag m) :
  298. functions(x, m),
  299. allocators_(x.allocators_, m),
  300. bucket_count_(x.bucket_count_),
  301. size_(x.size_),
  302. mlf_(x.mlf_),
  303. max_load_(x.max_load_),
  304. buckets_(x.buckets_)
  305. {
  306. x.buckets_ = bucket_pointer();
  307. x.size_ = 0;
  308. x.max_load_ = 0;
  309. }
  310. table(table& x, node_allocator const& a,
  311. boost::unordered::detail::move_tag m) :
  312. functions(x, m),
  313. allocators_(a, a),
  314. bucket_count_(x.bucket_count_),
  315. size_(0),
  316. mlf_(x.mlf_),
  317. max_load_(x.max_load_),
  318. buckets_()
  319. {}
  320. ////////////////////////////////////////////////////////////////////////
  321. // Initialisation.
  322. void init(table const& x)
  323. {
  324. if (x.size_) {
  325. create_buckets(bucket_count_);
  326. copy_nodes<node_allocator> copy(node_alloc());
  327. table_impl::fill_buckets(x.begin(), *this, copy);
  328. }
  329. }
  330. void move_init(table& x)
  331. {
  332. if(node_alloc() == x.node_alloc()) {
  333. move_buckets_from(x);
  334. }
  335. else if(x.size_) {
  336. // TODO: Could pick new bucket size?
  337. create_buckets(bucket_count_);
  338. move_nodes<node_allocator> move(node_alloc());
  339. node_holder<node_allocator> nodes(x);
  340. table_impl::fill_buckets(nodes.begin(), *this, move);
  341. }
  342. }
  343. ////////////////////////////////////////////////////////////////////////
  344. // Create buckets
  345. void create_buckets(std::size_t new_count)
  346. {
  347. boost::unordered::detail::array_constructor<bucket_allocator>
  348. constructor(bucket_alloc());
  349. // Creates an extra bucket to act as the start node.
  350. constructor.construct(bucket(), new_count + 1);
  351. if (buckets_)
  352. {
  353. // Copy the nodes to the new buckets, including the dummy
  354. // node if there is one.
  355. (constructor.get() +
  356. static_cast<std::ptrdiff_t>(new_count))->next_ =
  357. (buckets_ + static_cast<std::ptrdiff_t>(
  358. bucket_count_))->next_;
  359. destroy_buckets();
  360. }
  361. else if (bucket::extra_node)
  362. {
  363. node_constructor a(node_alloc());
  364. a.construct();
  365. (constructor.get() +
  366. static_cast<std::ptrdiff_t>(new_count))->next_ =
  367. a.release();
  368. }
  369. bucket_count_ = new_count;
  370. buckets_ = constructor.release();
  371. recalculate_max_load();
  372. }
  373. ////////////////////////////////////////////////////////////////////////
  374. // Swap and Move
  375. void swap_allocators(table& other, false_type)
  376. {
  377. boost::unordered::detail::func::ignore_unused_variable_warning(other);
  378. // According to 23.2.1.8, if propagate_on_container_swap is
  379. // false the behaviour is undefined unless the allocators
  380. // are equal.
  381. BOOST_ASSERT(node_alloc() == other.node_alloc());
  382. }
  383. void swap_allocators(table& other, true_type)
  384. {
  385. allocators_.swap(other.allocators_);
  386. }
  387. // Only swaps the allocators if propagate_on_container_swap
  388. void swap(table& x)
  389. {
  390. set_hash_functions op1(*this, x);
  391. set_hash_functions op2(x, *this);
  392. // I think swap can throw if Propagate::value,
  393. // since the allocators' swap can throw. Not sure though.
  394. swap_allocators(x,
  395. boost::unordered::detail::integral_constant<bool,
  396. allocator_traits<node_allocator>::
  397. propagate_on_container_swap::value>());
  398. boost::swap(buckets_, x.buckets_);
  399. boost::swap(bucket_count_, x.bucket_count_);
  400. boost::swap(size_, x.size_);
  401. std::swap(mlf_, x.mlf_);
  402. std::swap(max_load_, x.max_load_);
  403. op1.commit();
  404. op2.commit();
  405. }
  406. void move_buckets_from(table& other)
  407. {
  408. BOOST_ASSERT(node_alloc() == other.node_alloc());
  409. BOOST_ASSERT(!buckets_);
  410. buckets_ = other.buckets_;
  411. bucket_count_ = other.bucket_count_;
  412. size_ = other.size_;
  413. other.buckets_ = bucket_pointer();
  414. other.size_ = 0;
  415. other.max_load_ = 0;
  416. }
  417. ////////////////////////////////////////////////////////////////////////
  418. // Delete/destruct
  419. ~table()
  420. {
  421. delete_buckets();
  422. }
  423. void delete_node(link_pointer prev)
  424. {
  425. node_pointer n = static_cast<node_pointer>(prev->next_);
  426. prev->next_ = n->next_;
  427. boost::unordered::detail::func::destroy_value_impl(node_alloc(),
  428. n->value_ptr());
  429. node_allocator_traits::destroy(node_alloc(),
  430. boost::addressof(*n));
  431. node_allocator_traits::deallocate(node_alloc(), n, 1);
  432. --size_;
  433. }
  434. std::size_t delete_nodes(link_pointer prev, link_pointer end)
  435. {
  436. BOOST_ASSERT(prev->next_ != end);
  437. std::size_t count = 0;
  438. do {
  439. delete_node(prev);
  440. ++count;
  441. } while (prev->next_ != end);
  442. return count;
  443. }
  444. void delete_buckets()
  445. {
  446. if(buckets_) {
  447. if (size_) delete_nodes(get_previous_start(), link_pointer());
  448. if (bucket::extra_node) {
  449. node_pointer n = static_cast<node_pointer>(
  450. get_bucket(bucket_count_)->next_);
  451. node_allocator_traits::destroy(node_alloc(),
  452. boost::addressof(*n));
  453. node_allocator_traits::deallocate(node_alloc(), n, 1);
  454. }
  455. destroy_buckets();
  456. buckets_ = bucket_pointer();
  457. max_load_ = 0;
  458. }
  459. BOOST_ASSERT(!size_);
  460. }
  461. void clear()
  462. {
  463. if (!size_) return;
  464. delete_nodes(get_previous_start(), link_pointer());
  465. clear_buckets();
  466. BOOST_ASSERT(!size_);
  467. }
  468. void clear_buckets()
  469. {
  470. bucket_pointer end = get_bucket(bucket_count_);
  471. for(bucket_pointer it = buckets_; it != end; ++it)
  472. {
  473. it->next_ = node_pointer();
  474. }
  475. }
  476. void destroy_buckets()
  477. {
  478. bucket_pointer end = get_bucket(bucket_count_ + 1);
  479. for(bucket_pointer it = buckets_; it != end; ++it)
  480. {
  481. bucket_allocator_traits::destroy(bucket_alloc(),
  482. boost::addressof(*it));
  483. }
  484. bucket_allocator_traits::deallocate(bucket_alloc(),
  485. buckets_, bucket_count_ + 1);
  486. }
  487. ////////////////////////////////////////////////////////////////////////
  488. // Fix buckets after delete
  489. //
  490. std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev)
  491. {
  492. link_pointer end = prev->next_;
  493. std::size_t bucket_index2 = bucket_index;
  494. if (end)
  495. {
  496. bucket_index2 = hash_to_bucket(
  497. static_cast<node_pointer>(end)->hash_);
  498. // If begin and end are in the same bucket, then
  499. // there's nothing to do.
  500. if (bucket_index == bucket_index2) return bucket_index2;
  501. // Update the bucket containing end.
  502. get_bucket(bucket_index2)->next_ = prev;
  503. }
  504. // Check if this bucket is now empty.
  505. bucket_pointer this_bucket = get_bucket(bucket_index);
  506. if (this_bucket->next_ == prev)
  507. this_bucket->next_ = link_pointer();
  508. return bucket_index2;
  509. }
  510. ////////////////////////////////////////////////////////////////////////
  511. // Assignment
  512. void assign(table const& x)
  513. {
  514. if (this != boost::addressof(x))
  515. {
  516. assign(x,
  517. boost::unordered::detail::integral_constant<bool,
  518. allocator_traits<node_allocator>::
  519. propagate_on_container_copy_assignment::value>());
  520. }
  521. }
  522. void assign(table const& x, false_type)
  523. {
  524. // Strong exception safety.
  525. set_hash_functions new_func_this(*this, x);
  526. new_func_this.commit();
  527. mlf_ = x.mlf_;
  528. recalculate_max_load();
  529. if (!size_ && !x.size_) return;
  530. if (x.size_ >= max_load_) {
  531. create_buckets(min_buckets_for_size(x.size_));
  532. }
  533. else {
  534. clear_buckets();
  535. }
  536. // assign_nodes takes ownership of the container's elements,
  537. // assigning to them if possible, and deleting any that are
  538. // left over.
  539. assign_nodes<table> assign(*this);
  540. table_impl::fill_buckets(x.begin(), *this, assign);
  541. }
  542. void assign(table const& x, true_type)
  543. {
  544. if (node_alloc() == x.node_alloc()) {
  545. allocators_.assign(x.allocators_);
  546. assign(x, false_type());
  547. }
  548. else {
  549. set_hash_functions new_func_this(*this, x);
  550. // Delete everything with current allocators before assigning
  551. // the new ones.
  552. delete_buckets();
  553. allocators_.assign(x.allocators_);
  554. // Copy over other data, all no throw.
  555. new_func_this.commit();
  556. mlf_ = x.mlf_;
  557. bucket_count_ = min_buckets_for_size(x.size_);
  558. max_load_ = 0;
  559. // Finally copy the elements.
  560. if (x.size_) {
  561. create_buckets(bucket_count_);
  562. copy_nodes<node_allocator> copy(node_alloc());
  563. table_impl::fill_buckets(x.begin(), *this, copy);
  564. }
  565. }
  566. }
  567. void move_assign(table& x)
  568. {
  569. if (this != boost::addressof(x))
  570. {
  571. move_assign(x,
  572. boost::unordered::detail::integral_constant<bool,
  573. allocator_traits<node_allocator>::
  574. propagate_on_container_move_assignment::value>());
  575. }
  576. }
  577. void move_assign(table& x, true_type)
  578. {
  579. delete_buckets();
  580. allocators_.move_assign(x.allocators_);
  581. move_assign_no_alloc(x);
  582. }
  583. void move_assign(table& x, false_type)
  584. {
  585. if (node_alloc() == x.node_alloc()) {
  586. delete_buckets();
  587. move_assign_no_alloc(x);
  588. }
  589. else {
  590. set_hash_functions new_func_this(*this, x);
  591. new_func_this.commit();
  592. mlf_ = x.mlf_;
  593. recalculate_max_load();
  594. if (!size_ && !x.size_) return;
  595. if (x.size_ >= max_load_) {
  596. create_buckets(min_buckets_for_size(x.size_));
  597. }
  598. else {
  599. clear_buckets();
  600. }
  601. // move_assign_nodes takes ownership of the container's
  602. // elements, assigning to them if possible, and deleting
  603. // any that are left over.
  604. move_assign_nodes<table> assign(*this);
  605. node_holder<node_allocator> nodes(x);
  606. table_impl::fill_buckets(nodes.begin(), *this, assign);
  607. }
  608. }
  609. void move_assign_no_alloc(table& x)
  610. {
  611. set_hash_functions new_func_this(*this, x);
  612. // No throw from here.
  613. mlf_ = x.mlf_;
  614. max_load_ = x.max_load_;
  615. move_buckets_from(x);
  616. new_func_this.commit();
  617. }
  618. // Accessors
  619. key_type const& get_key(value_type const& x) const
  620. {
  621. return extractor::extract(x);
  622. }
  623. std::size_t hash(key_type const& k) const
  624. {
  625. return policy::apply_hash(this->hash_function(), k);
  626. }
  627. // Find Node
  628. template <typename Key, typename Hash, typename Pred>
  629. iterator generic_find_node(
  630. Key const& k,
  631. Hash const& hf,
  632. Pred const& eq) const
  633. {
  634. return static_cast<table_impl const*>(this)->
  635. find_node_impl(policy::apply_hash(hf, k), k, eq);
  636. }
  637. iterator find_node(
  638. std::size_t key_hash,
  639. key_type const& k) const
  640. {
  641. return static_cast<table_impl const*>(this)->
  642. find_node_impl(key_hash, k, this->key_eq());
  643. }
  644. iterator find_node(key_type const& k) const
  645. {
  646. return static_cast<table_impl const*>(this)->
  647. find_node_impl(hash(k), k, this->key_eq());
  648. }
  649. iterator find_matching_node(iterator n) const
  650. {
  651. // TODO: Does this apply to C++11?
  652. //
  653. // For some stupid reason, I decided to support equality comparison
  654. // when different hash functions are used. So I can't use the hash
  655. // value from the node here.
  656. return find_node(get_key(*n));
  657. }
  658. // Reserve and rehash
  659. void reserve_for_insert(std::size_t);
  660. void rehash(std::size_t);
  661. void reserve(std::size_t);
  662. };
  663. ////////////////////////////////////////////////////////////////////////////
  664. // Reserve & Rehash
  665. // basic exception safety
  666. template <typename Types>
  667. inline void table<Types>::reserve_for_insert(std::size_t size)
  668. {
  669. if (!buckets_) {
  670. create_buckets((std::max)(bucket_count_,
  671. min_buckets_for_size(size)));
  672. }
  673. // According to the standard this should be 'size >= max_load_',
  674. // but I think this is better, defect report filed.
  675. else if(size > max_load_) {
  676. std::size_t num_buckets
  677. = min_buckets_for_size((std::max)(size,
  678. size_ + (size_ >> 1)));
  679. if (num_buckets != bucket_count_)
  680. static_cast<table_impl*>(this)->rehash_impl(num_buckets);
  681. }
  682. }
  683. // if hash function throws, basic exception safety
  684. // strong otherwise.
  685. template <typename Types>
  686. inline void table<Types>::rehash(std::size_t min_buckets)
  687. {
  688. using namespace std;
  689. if(!size_) {
  690. delete_buckets();
  691. bucket_count_ = policy::new_bucket_count(min_buckets);
  692. }
  693. else {
  694. min_buckets = policy::new_bucket_count((std::max)(min_buckets,
  695. boost::unordered::detail::double_to_size(floor(
  696. static_cast<double>(size_) /
  697. static_cast<double>(mlf_))) + 1));
  698. if(min_buckets != bucket_count_)
  699. static_cast<table_impl*>(this)->rehash_impl(min_buckets);
  700. }
  701. }
  702. template <typename Types>
  703. inline void table<Types>::reserve(std::size_t num_elements)
  704. {
  705. rehash(static_cast<std::size_t>(
  706. std::ceil(static_cast<double>(num_elements) / mlf_)));
  707. }
  708. }}}
  709. #if defined(BOOST_MSVC)
  710. #pragma warning(pop)
  711. #endif
  712. #endif