// 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 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include #include #include #include #include #include #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; }}} 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 boost::iterator< std::forward_iterator_tag, Value, std::ptrdiff_t, NodePointer, Value&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::iterator_detail::cl_iterator; private: #endif typedef NodePointer node_pointer; typedef boost::unordered::iterator_detail::iterator iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; public: l_iterator() : ptr_() {} l_iterator(iterator x, std::size_t b, std::size_t c) : ptr_(x.node_), bucket_(b), bucket_count_(c) {} Value& operator*() const { return ptr_->value(); } Value* 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 { return ptr_ == x.ptr_; } bool operator!=(l_iterator x) const { return ptr_ != x.ptr_; } }; template struct cl_iterator : public boost::iterator< std::forward_iterator_tag, Value, std::ptrdiff_t, ConstNodePointer, Value const&> { friend struct boost::unordered::iterator_detail::l_iterator ; private: typedef NodePointer node_pointer; typedef boost::unordered::iterator_detail::iterator iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; public: cl_iterator() : ptr_() {} cl_iterator(iterator x, std::size_t b, std::size_t c) : ptr_(x.node_), bucket_(b), bucket_count_(c) {} cl_iterator(boost::unordered::iterator_detail::l_iterator< NodePointer, Value, Policy> const& x) : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) {} Value const& operator*() const { return ptr_->value(); } Value 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) { return x.ptr_ == y.ptr_; } friend bool operator!=(cl_iterator const& x, cl_iterator const& y) { return x.ptr_ != y.ptr_; } }; template struct iterator : public boost::iterator< std::forward_iterator_tag, Value, std::ptrdiff_t, NodePointer, Value&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::iterator_detail::c_iterator; template friend struct boost::unordered::iterator_detail::l_iterator; template friend struct boost::unordered::iterator_detail::cl_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 NodePointer node_pointer; node_pointer node_; public: iterator() : node_() {} explicit iterator(node_pointer const& x) : node_(x) {} Value& operator*() const { return node_->value(); } Value* operator->() const { return &node_->value(); } 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 { return node_ == x.node_; } bool operator!=(iterator const& x) const { return node_ != x.node_; } }; template struct c_iterator : public boost::iterator< std::forward_iterator_tag, Value, std::ptrdiff_t, ConstNodePointer, Value const&> { friend struct boost::unordered::iterator_detail::iterator< NodePointer, Value>; #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 NodePointer node_pointer; typedef boost::unordered::iterator_detail::iterator iterator; node_pointer node_; public: c_iterator() : node_() {} explicit c_iterator(node_pointer const& x) : node_(x) {} c_iterator(boost::unordered::iterator_detail::iterator< NodePointer, Value> const& x) : node_(x.node_) {} Value const& operator*() const { return node_->value(); } Value const* operator->() const { return &node_->value(); } 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) { return x.node_ == y.node_; } friend bool operator!=(c_iterator const& x, c_iterator const& y) { return x.node_ != y.node_; } }; }}} namespace boost { namespace unordered { namespace detail { /////////////////////////////////////////////////////////////////// // // Node construction template struct node_constructor { 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; protected: node_allocator& alloc_; private: node_pointer node_; bool node_constructed_; bool value_constructed_; public: node_constructor(node_allocator& n) : alloc_(n), node_(), node_constructed_(false), value_constructed_(false) { } ~node_constructor(); void construct(); template void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS) { construct(); boost::unordered::detail::construct_value_impl( alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); value_constructed_ = true; } template void construct_with_value2(BOOST_FWD_REF(A0) a0) { construct(); boost::unordered::detail::construct_value_impl( alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward(a0))); value_constructed_ = true; } value_type const& value() const { BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); return node_->value(); } // no throw node_pointer release() { BOOST_ASSERT(node_ && node_constructed_); node_pointer p = node_; node_ = node_pointer(); return p; } private: node_constructor(node_constructor const&); node_constructor& operator=(node_constructor const&); }; template node_constructor::~node_constructor() { if (node_) { if (value_constructed_) { boost::unordered::detail::destroy_value_impl(alloc_, node_->value_ptr()); } if (node_constructed_) { node_allocator_traits::destroy(alloc_, boost::addressof(*node_)); } node_allocator_traits::deallocate(alloc_, node_, 1); } } template void node_constructor::construct() { if(!node_) { node_constructed_ = false; value_constructed_ = false; node_ = node_allocator_traits::allocate(alloc_, 1); node_allocator_traits::construct(alloc_, boost::addressof(*node_), node()); node_->init(static_cast(node_)); node_constructed_ = true; } else { BOOST_ASSERT(node_constructed_); if (value_constructed_) { boost::unordered::detail::destroy_value_impl(alloc_, node_->value_ptr()); value_constructed_ = false; } } } /////////////////////////////////////////////////////////////////// // // Node Holder // // Temporary store for nodes. Deletes any that aren't used. template struct node_holder : private node_constructor { private: typedef node_constructor base; 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_pointer nodes_; public: template explicit node_holder(Table& b) : base(b.node_alloc()), nodes_() { if (b.size_) { typename Table::previous_pointer prev = b.get_previous_start(); nodes_ = static_cast(prev->next_); prev->next_ = link_pointer(); b.size_ = 0; } } ~node_holder(); template inline void assign_impl(T const& v) { nodes_->value() = v; } template inline void assign_impl(std::pair const& v) { const_cast(nodes_->value().first) = v.first; nodes_->value().second = v.second; } template inline void move_assign_impl(T& v) { nodes_->value() = boost::move(v); } template inline void move_assign_impl(std::pair& v) { // TODO: Move key as well? const_cast(nodes_->value().first) = boost::move(const_cast(v.first)); nodes_->value().second = boost::move(v.second); } node_pointer copy_of(value_type const& v) { if (nodes_) { assign_impl(v); node_pointer p = nodes_; nodes_ = static_cast(p->next_); p->init(static_cast(p)); p->next_ = link_pointer(); return p; } else { this->construct_with_value2(v); return base::release(); } } node_pointer move_copy_of(value_type& v) { if (nodes_) { move_assign_impl(v); node_pointer p = nodes_; nodes_ = static_cast(p->next_); p->init(static_cast(p)); p->next_ = link_pointer(); return p; } else { this->construct_with_value2(boost::move(v)); return base::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::destroy_value_impl(this->alloc_, p->value_ptr()); node_allocator_traits::destroy(this->alloc_, boost::addressof(*p)); node_allocator_traits::deallocate(this->alloc_, p, 1); } } /////////////////////////////////////////////////////////////////// // // Bucket template struct bucket { typedef NodePointer previous_pointer; previous_pointer next_; bucket() : next_() {} previous_pointer first_from_start() { return next_; } enum { extra_node = true }; }; struct ptr_bucket { typedef ptr_bucket* previous_pointer; previous_pointer next_; ptr_bucket() : next_(0) {} previous_pointer first_from_start() { return this; } enum { extra_node = false }; }; /////////////////////////////////////////////////////////////////// // // Hash Policy // // Don't really want table to derive from this, but will for now. 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; }; struct pick_policy : pick_policy_impl< std::numeric_limits::digits, std::numeric_limits::radix> {}; //////////////////////////////////////////////////////////////////////////// // 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 { 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_])); } 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) { new((void*) &funcs_[which]) function_pair(f); } void destroy(bool which) { boost::unordered::detail::destroy((function_pair*)(&funcs_[which])); } public: functions(H const& hf, P const& eq) : current_(false) { construct(current_, hf, eq); } functions(functions const& bf) : current_(false) { construct(current_, bf.current()); } ~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&); functions& functions_; bool tmp_functions_; public: set_hash_functions(functions& f, H const& h, P const& p) : functions_(f), tmp_functions_(!f.current_) { f.construct(tmp_functions_, h, p); } set_hash_functions(functions& f, functions 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_; } }; //////////////////////////////////////////////////////////////////////////// // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter // e.g. for int #if !defined(BOOST_NO_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