// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2005-2011 Daniel James // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #include #if defined(BOOST_HAS_PRAGMA_ONCE) #pragma once #endif #include #include namespace boost { namespace unordered { namespace detail { template struct table; template struct bucket; struct ptr_bucket; template struct table_impl; template struct grouped_table_impl; }}} // The 'iterator_detail' namespace was a misguided attempt at avoiding ADL // in the detail namespace. It didn't work because the template parameters // were in detail. I'm not changing it at the moment to be safe. I might // do in the future if I change the iterator types. namespace boost { namespace unordered { namespace iterator_detail { //////////////////////////////////////////////////////////////////////////// // Iterators // // all no throw template struct iterator; template struct c_iterator; template struct l_iterator; template struct cl_iterator; // Local Iterators // // all no throw template struct l_iterator : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, typename Node::value_type*, typename Node::value_type&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::iterator_detail::cl_iterator; private: #endif typedef typename Node::node_pointer node_pointer; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; public: typedef typename Node::value_type value_type; l_iterator() BOOST_NOEXCEPT : ptr_() {} l_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT : ptr_(n), bucket_(b), bucket_count_(c) {} value_type& operator*() const { return ptr_->value(); } value_type* operator->() const { return ptr_->value_ptr(); } l_iterator& operator++() { ptr_ = static_cast(ptr_->next_); if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) ptr_ = node_pointer(); return *this; } l_iterator operator++(int) { l_iterator tmp(*this); ++(*this); return tmp; } bool operator==(l_iterator x) const BOOST_NOEXCEPT { return ptr_ == x.ptr_; } bool operator!=(l_iterator x) const BOOST_NOEXCEPT { return ptr_ != x.ptr_; } }; template struct cl_iterator : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, typename Node::value_type const*, typename Node::value_type const&> { friend struct boost::unordered::iterator_detail::l_iterator ; private: typedef typename Node::node_pointer node_pointer; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; public: typedef typename Node::value_type value_type; cl_iterator() BOOST_NOEXCEPT : ptr_() {} cl_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT : ptr_(n), bucket_(b), bucket_count_(c) {} cl_iterator(boost::unordered::iterator_detail::l_iterator< Node, Policy> const& x) BOOST_NOEXCEPT : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) {} value_type const& operator*() const { return ptr_->value(); } value_type const* operator->() const { return ptr_->value_ptr(); } cl_iterator& operator++() { ptr_ = static_cast(ptr_->next_); if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) ptr_ = node_pointer(); return *this; } cl_iterator operator++(int) { cl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(cl_iterator const& x, cl_iterator const& y) BOOST_NOEXCEPT { return x.ptr_ == y.ptr_; } friend bool operator!=(cl_iterator const& x, cl_iterator const& y) BOOST_NOEXCEPT { return x.ptr_ != y.ptr_; } }; template struct iterator : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, typename Node::value_type*, typename Node::value_type&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::iterator_detail::c_iterator; template friend struct boost::unordered::detail::table; template friend struct boost::unordered::detail::table_impl; template friend struct boost::unordered::detail::grouped_table_impl; private: #endif typedef typename Node::node_pointer node_pointer; node_pointer node_; public: typedef typename Node::value_type value_type; iterator() BOOST_NOEXCEPT : node_() {} explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : node_(static_cast(x)) {} value_type& operator*() const { return node_->value(); } value_type* operator->() const { return node_->value_ptr(); } iterator& operator++() { node_ = static_cast(node_->next_); return *this; } iterator operator++(int) { iterator tmp(node_); node_ = static_cast(node_->next_); return tmp; } bool operator==(iterator const& x) const BOOST_NOEXCEPT { return node_ == x.node_; } bool operator!=(iterator const& x) const BOOST_NOEXCEPT { return node_ != x.node_; } }; template struct c_iterator : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, typename Node::value_type const*, typename Node::value_type const&> { friend struct boost::unordered::iterator_detail::iterator; #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::detail::table; template friend struct boost::unordered::detail::table_impl; template friend struct boost::unordered::detail::grouped_table_impl; private: #endif typedef typename Node::node_pointer node_pointer; typedef boost::unordered::iterator_detail::iterator n_iterator; node_pointer node_; public: typedef typename Node::value_type value_type; c_iterator() BOOST_NOEXCEPT : node_() {} explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : node_(static_cast(x)) {} c_iterator(n_iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} value_type const& operator*() const { return node_->value(); } value_type const* operator->() const { return node_->value_ptr(); } c_iterator& operator++() { node_ = static_cast(node_->next_); return *this; } c_iterator operator++(int) { c_iterator tmp(node_); node_ = static_cast(node_->next_); return tmp; } friend bool operator==(c_iterator const& x, c_iterator const& y) BOOST_NOEXCEPT { return x.node_ == y.node_; } friend bool operator!=(c_iterator const& x, c_iterator const& y) BOOST_NOEXCEPT { return x.node_ != y.node_; } }; }}} namespace boost { namespace unordered { namespace detail { /////////////////////////////////////////////////////////////////// // // Node Holder // // Temporary store for nodes. Deletes any that aren't used. template struct node_holder { private: typedef NodeAlloc node_allocator; typedef boost::unordered::detail::allocator_traits node_allocator_traits; typedef typename node_allocator_traits::value_type node; typedef typename node_allocator_traits::pointer node_pointer; typedef typename node::value_type value_type; typedef typename node::link_pointer link_pointer; typedef boost::unordered::iterator_detail::iterator iterator; node_constructor constructor_; node_pointer nodes_; public: template explicit node_holder(Table& b) : constructor_(b.node_alloc()), nodes_() { if (b.size_) { typename Table::link_pointer prev = b.get_previous_start(); nodes_ = static_cast(prev->next_); prev->next_ = link_pointer(); b.size_ = 0; } } ~node_holder(); node_pointer pop_node() { node_pointer n = nodes_; nodes_ = static_cast(nodes_->next_); n->init(n); n->next_ = link_pointer(); return n; } template inline node_pointer copy_of(T const& v) { if (nodes_) { constructor_.reclaim(pop_node()); } else { constructor_.create_node(); } boost::unordered::detail::func::call_construct( constructor_.alloc_, constructor_.node_->value_ptr(), v); return constructor_.release(); } template inline node_pointer move_copy_of(T& v) { if (nodes_) { constructor_.reclaim(pop_node()); } else { constructor_.create_node(); } boost::unordered::detail::func::call_construct( constructor_.alloc_, constructor_.node_->value_ptr(), boost::move(v)); return constructor_.release(); } iterator begin() const { return iterator(nodes_); } }; template node_holder::~node_holder() { while (nodes_) { node_pointer p = nodes_; nodes_ = static_cast(p->next_); boost::unordered::detail::func::call_destroy(constructor_.alloc_, p->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*p)); node_allocator_traits::deallocate(constructor_.alloc_, p, 1); } } /////////////////////////////////////////////////////////////////// // // Bucket template struct bucket { typedef NodePointer link_pointer; link_pointer next_; bucket() : next_() {} link_pointer first_from_start() { return next_; } enum { extra_node = true }; }; struct ptr_bucket { typedef ptr_bucket* link_pointer; link_pointer next_; ptr_bucket() : next_(0) {} link_pointer first_from_start() { return this; } enum { extra_node = false }; }; /////////////////////////////////////////////////////////////////// // // Hash Policy template struct prime_policy { template static inline SizeT apply_hash(Hash const& hf, T const& x) { return hf(x); } static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { return hash % bucket_count; } static inline SizeT new_bucket_count(SizeT min) { return boost::unordered::detail::next_prime(min); } static inline SizeT prev_bucket_count(SizeT max) { return boost::unordered::detail::prev_prime(max); } }; template struct mix64_policy { template static inline SizeT apply_hash(Hash const& hf, T const& x) { SizeT key = hf(x); key = (~key) + (key << 21); // key = (key << 21) - key - 1; key = key ^ (key >> 24); key = (key + (key << 3)) + (key << 8); // key * 265 key = key ^ (key >> 14); key = (key + (key << 2)) + (key << 4); // key * 21 key = key ^ (key >> 28); key = key + (key << 31); return key; } static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { return hash & (bucket_count - 1); } static inline SizeT new_bucket_count(SizeT min) { if (min <= 4) return 4; --min; min |= min >> 1; min |= min >> 2; min |= min >> 4; min |= min >> 8; min |= min >> 16; min |= min >> 32; return min + 1; } static inline SizeT prev_bucket_count(SizeT max) { max |= max >> 1; max |= max >> 2; max |= max >> 4; max |= max >> 8; max |= max >> 16; max |= max >> 32; return (max >> 1) + 1; } }; template struct pick_policy_impl { typedef prime_policy type; }; template <> struct pick_policy_impl<64, 2> { typedef mix64_policy type; }; template struct pick_policy : pick_policy_impl< std::numeric_limits::digits, std::numeric_limits::radix> {}; // While the mix policy is generally faster, the prime policy is a lot // faster when a large number consecutive integers are used, because // there are no collisions. Since that is probably quite common, use // prime policy for integeral types. But not the smaller ones, as they // don't have enough unique values for this to be an issue. template <> struct pick_policy { typedef prime_policy type; }; template <> struct pick_policy { typedef prime_policy type; }; template <> struct pick_policy { typedef prime_policy type; }; template <> struct pick_policy { typedef prime_policy type; }; // TODO: Maybe not if std::size_t is smaller than long long. #if !defined(BOOST_NO_LONG_LONG) template <> struct pick_policy { typedef prime_policy type; }; template <> struct pick_policy { typedef prime_policy type; }; #endif //////////////////////////////////////////////////////////////////////////// // Functions // Assigning and swapping the equality and hash function objects // needs strong exception safety. To implement that normally we'd // require one of them to be known to not throw and the other to // guarantee strong exception safety. Unfortunately they both only // have basic exception safety. So to acheive strong exception // safety we have storage space for two copies, and assign the new // copies to the unused space. Then switch to using that to use // them. This is implemented in 'set_hash_functions' which // atomically assigns the new function objects in a strongly // exception safe manner. template class set_hash_functions; template class functions { public: static const bool nothrow_move_assignable = boost::is_nothrow_move_assignable::value && boost::is_nothrow_move_assignable

::value; static const bool nothrow_move_constructible = boost::is_nothrow_move_constructible::value && boost::is_nothrow_move_constructible

::value; private: friend class boost::unordered::detail::set_hash_functions; functions& operator=(functions const&); typedef compressed function_pair; typedef typename boost::aligned_storage< sizeof(function_pair), boost::alignment_of::value>::type aligned_function; bool current_; // The currently active functions. aligned_function funcs_[2]; function_pair const& current() const { return *static_cast( static_cast(&funcs_[current_])); } function_pair& current() { return *static_cast( static_cast(&funcs_[current_])); } void construct(bool which, H const& hf, P const& eq) { new((void*) &funcs_[which]) function_pair(hf, eq); } void construct(bool which, function_pair const& f, boost::unordered::detail::false_type = boost::unordered::detail::false_type()) { new((void*) &funcs_[which]) function_pair(f); } void construct(bool which, function_pair& f, boost::unordered::detail::true_type) { new((void*) &funcs_[which]) function_pair(f, boost::unordered::detail::move_tag()); } void destroy(bool which) { boost::unordered::detail::func::destroy((function_pair*)(&funcs_[which])); } public: typedef boost::unordered::detail::set_hash_functions set_hash_functions; functions(H const& hf, P const& eq) : current_(false) { construct(current_, hf, eq); } functions(functions const& bf) : current_(false) { construct(current_, bf.current()); } functions(functions& bf, boost::unordered::detail::move_tag) : current_(false) { construct(current_, bf.current(), boost::unordered::detail::integral_constant()); } ~functions() { this->destroy(current_); } H const& hash_function() const { return current().first(); } P const& key_eq() const { return current().second(); } }; template class set_hash_functions { set_hash_functions(set_hash_functions const&); set_hash_functions& operator=(set_hash_functions const&); typedef functions functions_type; functions_type& functions_; bool tmp_functions_; public: set_hash_functions(functions_type& f, H const& h, P const& p) : functions_(f), tmp_functions_(!f.current_) { f.construct(tmp_functions_, h, p); } set_hash_functions(functions_type& f, functions_type const& other) : functions_(f), tmp_functions_(!f.current_) { f.construct(tmp_functions_, other.current()); } ~set_hash_functions() { functions_.destroy(tmp_functions_); } void commit() { functions_.current_ = tmp_functions_; tmp_functions_ = !tmp_functions_; } }; template class set_hash_functions { set_hash_functions(set_hash_functions const&); set_hash_functions& operator=(set_hash_functions const&); typedef functions functions_type; functions_type& functions_; H hash_; P pred_; public: set_hash_functions(functions_type& f, H const& h, P const& p) : functions_(f), hash_(h), pred_(p) {} set_hash_functions(functions_type& f, functions_type const& other) : functions_(f), hash_(other.hash_function()), pred_(other.key_eq()) {} void commit() { functions_.current().first() = boost::move(hash_); functions_.current().second() = boost::move(pred_); } }; //////////////////////////////////////////////////////////////////////////// // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter // e.g. for int #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) # define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) #else struct please_ignore_this_overload { typedef please_ignore_this_overload type; }; template struct rv_ref_impl { typedef BOOST_RV_REF(T) type; }; template struct rv_ref : boost::detail::if_true< boost::is_class::value >::BOOST_NESTED_TEMPLATE then < boost::unordered::detail::rv_ref_impl, please_ignore_this_overload >::type {}; # define BOOST_UNORDERED_RV_REF(T) \ typename boost::unordered::detail::rv_ref::type #endif }}} #endif