2 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
3 // Copyright (C) 2005-2011 Daniel James
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
8 #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
10 #include <boost/unordered/detail/buckets.hpp>
11 #include <boost/unordered/detail/util.hpp>
12 #include <boost/type_traits/aligned_storage.hpp>
13 #include <boost/type_traits/alignment_of.hpp>
14 #include <boost/iterator.hpp>
17 namespace boost { namespace unordered { namespace iterator_detail {
19 ////////////////////////////////////////////////////////////////////////////
24 template <typename NodePointer, typename Value> struct iterator;
25 template <typename ConstNodePointer, typename NodePointer,
26 typename Value> struct c_iterator;
27 template <typename NodePointer, typename Value> struct l_iterator;
28 template <typename ConstNodePointer, typename NodePointer,
29 typename Value> struct cl_iterator;
35 template <typename NodePointer, typename Value>
37 : public boost::iterator<
38 std::forward_iterator_tag, Value, std::ptrdiff_t,
41 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
42 template <typename ConstNodePointer, typename NodePointer2,
44 friend struct boost::unordered::iterator_detail::cl_iterator;
47 typedef NodePointer node_pointer;
50 std::size_t bucket_count_;
54 l_iterator() : ptr_() {}
56 l_iterator(node_pointer x, std::size_t b, std::size_t c)
57 : ptr_(x), bucket_(b), bucket_count_(c) {}
59 Value& operator*() const {
63 Value* operator->() const {
64 return ptr_->value_ptr();
67 l_iterator& operator++() {
68 ptr_ = static_cast<node_pointer>(ptr_->next_);
69 if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_)
70 ptr_ = node_pointer();
74 l_iterator operator++(int) {
75 l_iterator tmp(*this);
80 bool operator==(l_iterator x) const {
81 return ptr_ == x.ptr_;
84 bool operator!=(l_iterator x) const {
85 return ptr_ != x.ptr_;
89 template <typename ConstNodePointer, typename NodePointer, typename Value>
91 : public boost::iterator<
92 std::forward_iterator_tag, Value, std::ptrdiff_t,
93 ConstNodePointer, Value const&>
95 friend struct boost::unordered::iterator_detail::l_iterator
99 typedef NodePointer node_pointer;
102 std::size_t bucket_count_;
106 cl_iterator() : ptr_() {}
108 cl_iterator(node_pointer x, std::size_t b, std::size_t c) :
109 ptr_(x), bucket_(b), bucket_count_(c) {}
111 cl_iterator(boost::unordered::iterator_detail::l_iterator<
112 NodePointer, Value> const& x) :
113 ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
118 return ptr_->value();
121 Value const* operator->() const {
122 return ptr_->value_ptr();
125 cl_iterator& operator++() {
126 ptr_ = static_cast<node_pointer>(ptr_->next_);
127 if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_)
128 ptr_ = node_pointer();
132 cl_iterator operator++(int) {
133 cl_iterator tmp(*this);
138 friend bool operator==(cl_iterator const& x, cl_iterator const& y) {
139 return x.ptr_ == y.ptr_;
142 friend bool operator!=(cl_iterator const& x, cl_iterator const& y) {
143 return x.ptr_ != y.ptr_;
147 template <typename NodePointer, typename Value>
149 : public boost::iterator<
150 std::forward_iterator_tag, Value, std::ptrdiff_t,
153 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
154 template <typename ConstNodePointer, typename NodePointer2,
156 friend struct boost::unordered::iterator_detail::c_iterator;
159 typedef NodePointer node_pointer;
164 iterator() : node_() {}
166 explicit iterator(node_pointer const& x) : node_(x) {}
168 Value& operator*() const {
169 return node_->value();
172 Value* operator->() const {
173 return &node_->value();
176 iterator& operator++() {
177 node_ = static_cast<node_pointer>(node_->next_);
181 iterator operator++(int) {
183 node_ = static_cast<node_pointer>(node_->next_);
187 bool operator==(iterator const& x) const {
188 return node_ == x.node_;
191 bool operator!=(iterator const& x) const {
192 return node_ != x.node_;
196 template <typename ConstNodePointer, typename NodePointer, typename Value>
198 : public boost::iterator<
199 std::forward_iterator_tag, Value, std::ptrdiff_t,
200 ConstNodePointer, Value const&>
202 friend struct boost::unordered::iterator_detail::iterator<
205 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
206 template <typename K, typename T, typename H, typename P, typename A>
207 friend class boost::unordered::unordered_map;
208 template <typename K, typename T, typename H, typename P, typename A>
209 friend class boost::unordered::unordered_multimap;
210 template <typename T, typename H, typename P, typename A>
211 friend class boost::unordered::unordered_set;
212 template <typename T, typename H, typename P, typename A>
213 friend class boost::unordered::unordered_multiset;
218 typedef NodePointer node_pointer;
223 c_iterator() : node_() {}
225 explicit c_iterator(node_pointer const& x) : node_(x) {}
227 c_iterator(boost::unordered::iterator_detail::iterator<
228 NodePointer, Value> const& x) : node_(x.node_) {}
230 Value const& operator*() const {
231 return node_->value();
234 Value const* operator->() const {
235 return &node_->value();
238 c_iterator& operator++() {
239 node_ = static_cast<node_pointer>(node_->next_);
243 c_iterator operator++(int) {
244 c_iterator tmp(node_);
245 node_ = static_cast<node_pointer>(node_->next_);
249 friend bool operator==(c_iterator const& x, c_iterator const& y) {
250 return x.node_ == y.node_;
253 friend bool operator!=(c_iterator const& x, c_iterator const& y) {
254 return x.node_ != y.node_;
259 namespace boost { namespace unordered { namespace detail {
261 ////////////////////////////////////////////////////////////////////////////
262 // convert double to std::size_t
264 inline std::size_t double_to_size(double f)
266 return f >= static_cast<double>(
267 (std::numeric_limits<std::size_t>::max)()) ?
268 (std::numeric_limits<std::size_t>::max)() :
269 static_cast<std::size_t>(f);
272 // The space used to store values in a node.
274 template <typename ValueType>
277 typedef ValueType value_type;
279 typename boost::aligned_storage<
281 boost::alignment_of<value_type>::value>::type data_;
287 value_type& value() {
288 return *(ValueType*) this;
291 value_type* value_ptr() {
292 return (ValueType*) this;
297 value_base& operator=(value_base const&);
300 template <typename Types>
302 boost::unordered::detail::buckets<
303 typename Types::allocator,
304 typename Types::bucket,
305 typename Types::node>,
306 boost::unordered::detail::functions<
307 typename Types::hasher,
308 typename Types::key_equal>
312 table& operator=(table const&);
314 typedef typename Types::hasher hasher;
315 typedef typename Types::key_equal key_equal;
316 typedef typename Types::key_type key_type;
317 typedef typename Types::extractor extractor;
318 typedef typename Types::value_type value_type;
319 typedef typename Types::table table_impl;
320 typedef typename Types::link_pointer link_pointer;
322 typedef boost::unordered::detail::functions<
323 typename Types::hasher,
324 typename Types::key_equal> functions;
326 typedef boost::unordered::detail::buckets<
327 typename Types::allocator,
328 typename Types::bucket,
329 typename Types::node> buckets;
331 typedef typename buckets::node_allocator node_allocator;
332 typedef typename buckets::node_allocator_traits node_allocator_traits;
333 typedef typename buckets::node_pointer node_pointer;
334 typedef typename buckets::const_node_pointer const_node_pointer;
336 typedef boost::unordered::iterator_detail::
337 iterator<node_pointer, value_type> iterator;
338 typedef boost::unordered::iterator_detail::
339 c_iterator<const_node_pointer, node_pointer, value_type> c_iterator;
340 typedef boost::unordered::iterator_detail::
341 l_iterator<node_pointer, value_type> l_iterator;
342 typedef boost::unordered::iterator_detail::
343 cl_iterator<const_node_pointer, node_pointer, value_type>
349 std::size_t max_load_; // Only use if this->buckets_.
351 ////////////////////////////////////////////////////////////////////////
354 std::size_t max_size() const
358 // size < mlf_ * count
359 return boost::unordered::detail::double_to_size(ceil(
360 static_cast<double>(this->mlf_) *
361 static_cast<double>(this->max_bucket_count())
365 std::size_t calculate_max_load()
370 // Only resize when size >= mlf_ * count
371 return boost::unordered::detail::double_to_size(ceil(
372 static_cast<double>(this->mlf_) *
373 static_cast<double>(this->bucket_count_)
377 void max_load_factor(float z)
380 mlf_ = (std::max)(z, minimum_max_load_factor);
382 this->max_load_ = this->calculate_max_load();
385 std::size_t min_buckets_for_size(std::size_t size) const
387 BOOST_ASSERT(this->mlf_ != 0);
392 // size < mlf_ * count
393 // => count > size / mlf_
395 // Or from rehash post-condition:
396 // count > size / mlf_
398 return boost::unordered::detail::next_prime(
399 boost::unordered::detail::double_to_size(floor(
400 static_cast<double>(size) /
401 static_cast<double>(mlf_))) + 1);
404 ////////////////////////////////////////////////////////////////////////
407 table(std::size_t num_buckets,
410 node_allocator const& a) :
411 buckets(a, boost::unordered::detail::next_prime(num_buckets)),
417 table(table const& x, node_allocator const& a) :
418 buckets(a, x.min_buckets_for_size(x.size_)),
424 table_impl::copy_buckets_to(x, *this);
425 this->max_load_ = calculate_max_load();
429 // TODO: Why calculate_max_load?
430 table(table& x, boost::unordered::detail::move_tag m) :
434 max_load_(calculate_max_load())
437 // TODO: Why not calculate_max_load?
438 // TODO: Why do I use x's bucket count?
439 table(table& x, node_allocator const& a,
440 boost::unordered::detail::move_tag m) :
441 buckets(a, x.bucket_count_),
444 max_load_(x.max_load_)
446 if(a == x.node_alloc()) {
447 this->buckets::swap(x, false_type());
450 // Use a temporary table because move_buckets_to leaves the
451 // source container in a complete mess.
454 table_impl::move_buckets_to(tmp, *this);
455 this->max_load_ = calculate_max_load();
461 node_pointer begin() const {
462 return !this->buckets_ ?
463 node_pointer() : this->get_start();
468 void assign(table const& x)
471 boost::unordered::detail::integral_constant<bool,
472 allocator_traits<node_allocator>::
473 propagate_on_container_copy_assignment::value>());
476 void assign(table const& x, false_type)
478 table tmp(x, this->node_alloc());
479 this->swap(tmp, false_type());
482 void assign(table const& x, true_type)
484 table tmp(x, x.node_alloc());
485 // Need to delete before setting the allocator so that buckets
486 // aren't deleted with the wrong allocator.
487 if(this->buckets_) this->delete_buckets();
488 // TODO: Can allocator assignment throw?
489 this->allocators_.assign(x.allocators_);
490 this->swap(tmp, false_type());
493 void move_assign(table& x)
496 boost::unordered::detail::integral_constant<bool,
497 allocator_traits<node_allocator>::
498 propagate_on_container_move_assignment::value>());
501 void move_assign(table& x, true_type)
503 if(this->buckets_) this->delete_buckets();
504 this->allocators_.move_assign(x.allocators_);
505 move_assign_no_alloc(x);
508 void move_assign(table& x, false_type)
510 if(this->node_alloc() == x.node_alloc()) {
511 if(this->buckets_) this->delete_buckets();
512 move_assign_no_alloc(x);
515 boost::unordered::detail::set_hash_functions<hasher, key_equal>
516 new_func_this(*this, x);
519 buckets b(this->node_alloc(),
520 x.min_buckets_for_size(x.size_));
521 buckets tmp(x, move_tag());
522 table_impl::move_buckets_to(tmp, b);
530 if (this->buckets_) this->max_load_ = calculate_max_load();
531 new_func_this.commit();
535 void move_assign_no_alloc(table& x)
537 boost::unordered::detail::set_hash_functions<hasher, key_equal>
538 new_func_this(*this, x);
539 // No throw from here.
540 this->move_buckets_from(x);
542 this->max_load_ = x.max_load_;
543 new_func_this.commit();
546 ////////////////////////////////////////////////////////////////////////
552 boost::unordered::detail::integral_constant<bool,
553 allocator_traits<node_allocator>::
554 propagate_on_container_swap::value>());
557 // Only swaps the allocators if Propagate::value
558 template <typename Propagate>
559 void swap(table& x, Propagate p)
561 boost::unordered::detail::set_hash_functions<hasher, key_equal>
563 boost::unordered::detail::set_hash_functions<hasher, key_equal>
565 // I think swap can throw if Propagate::value,
566 // since the allocators' swap can throw. Not sure though.
567 this->buckets::swap(x, p);
568 std::swap(this->mlf_, x.mlf_);
569 std::swap(this->max_load_, x.max_load_);
574 // Swap everything but the allocators, and the functions objects.
575 void swap_contents(table& x)
577 this->buckets::swap(x, false_type());
578 std::swap(this->mlf_, x.mlf_);
579 std::swap(this->max_load_, x.max_load_);
584 key_type const& get_key(value_type const& x) const
586 return extractor::extract(x);
591 template <typename Key, typename Hash, typename Pred>
592 node_pointer generic_find_node(
594 Hash const& hash_function,
595 Pred const& eq) const
597 if (!this->size_) return node_pointer();
598 return static_cast<table_impl const*>(this)->
599 find_node_impl(hash_function(k), k, eq);
602 node_pointer find_node(
604 key_type const& k) const
606 if (!this->size_) return node_pointer();
607 return static_cast<table_impl const*>(this)->
608 find_node_impl(hash, k, this->key_eq());
611 node_pointer find_node(key_type const& k) const
613 if (!this->size_) return node_pointer();
614 return static_cast<table_impl const*>(this)->
615 find_node_impl(this->hash_function()(k), k, this->key_eq());
618 node_pointer find_matching_node(node_pointer n) const
620 // TODO: Does this apply to C++11?
622 // For some stupid reason, I decided to support equality comparison
623 // when different hash functions are used. So I can't use the hash
624 // value from the node here.
626 return find_node(get_key(n->value()));
629 // Reserve and rehash
631 void reserve_for_insert(std::size_t);
632 void rehash(std::size_t);
635 ////////////////////////////////////////////////////////////////////////////
638 // basic exception safety
639 template <typename Types>
640 inline void table<Types>::reserve_for_insert(std::size_t size)
642 if (!this->buckets_) {
643 this->bucket_count_ = (std::max)(this->bucket_count_,
644 this->min_buckets_for_size(size));
645 this->create_buckets();
646 this->max_load_ = this->calculate_max_load();
648 else if(size >= max_load_) {
649 std::size_t num_buckets
650 = this->min_buckets_for_size((std::max)(size,
651 this->size_ + (this->size_ >> 1)));
652 if (num_buckets != this->bucket_count_) {
653 static_cast<table_impl*>(this)->rehash_impl(num_buckets);
654 this->max_load_ = this->calculate_max_load();
659 // if hash function throws, basic exception safety
662 template <typename Types>
663 void table<Types>::rehash(std::size_t min_buckets)
668 if(this->buckets_) this->delete_buckets();
669 this->bucket_count_ = next_prime(min_buckets);
672 min_buckets = next_prime((std::max)(min_buckets,
673 boost::unordered::detail::double_to_size(floor(
674 static_cast<double>(this->size_) /
675 static_cast<double>(mlf_))) + 1));
677 if(min_buckets != this->bucket_count_) {
678 static_cast<table_impl*>(this)->rehash_impl(min_buckets);
679 this->max_load_ = this->calculate_max_load();