From 6b7cecb9d3e9e2e9428bbd3200e67a76a5087242 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 2 Aug 2014 03:09:48 +0100 Subject: [PATCH 1/7] Workaround initialiser list bug in gcc 4.4. --- test/unordered/insert_tests.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index e80a8c1c..872bfc12 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -9,6 +9,7 @@ #include "../helpers/postfix.hpp" #include "../helpers/test.hpp" +#include #include #include "../objects/test.hpp" #include "../helpers/random_values.hpp" @@ -598,7 +599,11 @@ UNORDERED_AUTO_TEST(insert_initializer_list_set) boost::unordered_set set2; +#if BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4,5,0) + set2.insert({{1, 2}}); +#else set2.insert({1, 2}); +#endif BOOST_TEST(set2.size() == 1); BOOST_TEST(set2.find({1,2}) != set2.end()); BOOST_TEST(set2.find({2,1}) == set2.end()); From e1b39bbbfb7b1a8af988254eb38ea8fd0e30c04e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 19 Aug 2014 16:41:10 +0100 Subject: [PATCH 2/7] Combine some of the headers. --- include/boost/unordered/detail/buckets.hpp | 928 ---------------- include/boost/unordered/detail/table.hpp | 1159 +++++++++++++++++++- include/boost/unordered/detail/util.hpp | 266 ----- include/boost/unordered/unordered_map.hpp | 1 - include/boost/unordered/unordered_set.hpp | 1 - 5 files changed, 1156 insertions(+), 1199 deletions(-) delete mode 100644 include/boost/unordered/detail/buckets.hpp delete mode 100644 include/boost/unordered/detail/util.hpp diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp deleted file mode 100644 index fd038b7b..00000000 --- a/include/boost/unordered/detail/buckets.hpp +++ /dev/null @@ -1,928 +0,0 @@ - -// 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 -#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; - -}}} - -// 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::node_pointer, - 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; - typedef boost::unordered::iterator_detail::iterator iterator; - 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(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT - : ptr_(x.node_), 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - ConstNodePointer, - typename Node::value_type const&> - { - friend struct boost::unordered::iterator_detail::l_iterator - ; - private: - - typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator iterator; - 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(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : - ptr_(x.node_), 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::node_pointer, - 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::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 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(); - } - - 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - ConstNodePointer, - 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 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(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} - - value_type const& operator*() const { - return node_->value(); - } - - value_type 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) - 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 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_; - 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::func::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::func::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::func::destroy_value_impl(alloc_, - node_->value_ptr()); - } - - if (node_constructed_) { - boost::unordered::detail::func::destroy( - 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); - - new ((void*) boost::addressof(*node_)) node(); - node_->init(node_); - node_constructed_ = true; - } - else { - BOOST_ASSERT(node_constructed_); - - if (value_constructed_) - { - boost::unordered::detail::func::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::link_pointer prev = b.get_previous_start(); - nodes_ = static_cast(prev->next_); - prev->next_ = link_pointer(); - b.size_ = 0; - } - } - - ~node_holder(); - - void node_for_assignment() - { - if (!this->node_ && nodes_) { - this->node_ = nodes_; - nodes_ = static_cast(nodes_->next_); - this->node_->init(this->node_); - this->node_->next_ = link_pointer(); - - this->node_constructed_ = true; - this->value_constructed_ = true; - } - } - - template - inline void assign_impl(T const& v) { - if (this->node_ && this->value_constructed_) { - this->node_->value() = v; - } - else { - this->construct_with_value2(v); - } - } - - template - inline void assign_impl(std::pair const& v) { - this->construct_with_value2(v); - } - - template - inline void move_assign_impl(T& v) { - if (this->node_ && this->value_constructed_) { - this->node_->value() = boost::move(v); - } - else { - this->construct_with_value2(boost::move(v)); - } - } - - template - inline void move_assign_impl(std::pair& v) { - this->construct_with_value2(boost::move(v)); - } - - node_pointer copy_of(value_type const& v) - { - node_for_assignment(); - assign_impl(v); - return base::release(); - } - - node_pointer move_copy_of(value_type& v) - { - node_for_assignment(); - move_assign_impl(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::func::destroy_value_impl(this->alloc_, - p->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*p)); - node_allocator_traits::deallocate(this->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 diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 7b4cc0ec..6d71afdb 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011 Daniel James +// Copyright (C) 2005-2011, 2014 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) @@ -12,10 +12,23 @@ #pragma once #endif -#include -#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #if defined(BOOST_MSVC) @@ -37,6 +50,1146 @@ namespace boost { namespace unordered { namespace detail { + static const float minimum_max_load_factor = 1e-3f; + static const std::size_t default_bucket_count = 11; + struct move_tag {}; + struct empty_emplace {}; + + namespace func { + template + inline void ignore_unused_variable_warning(T const&) {} + } + + //////////////////////////////////////////////////////////////////////////// + // iterator SFINAE + + template + struct is_forward : + boost::is_convertible< + typename boost::iterator_traversal::type, + boost::forward_traversal_tag> + {}; + + template + struct enable_if_forward : + boost::enable_if_c< + boost::unordered::detail::is_forward::value, + ReturnType> + {}; + + template + struct disable_if_forward : + boost::disable_if_c< + boost::unordered::detail::is_forward::value, + ReturnType> + {}; + + //////////////////////////////////////////////////////////////////////////// + // primes + +#define BOOST_UNORDERED_PRIMES \ + (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ + (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ + (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ + (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ + (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ + (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ + (1610612741ul)(3221225473ul)(4294967291ul) + + template struct prime_list_template + { + static std::size_t const value[]; + +#if !defined(SUNPRO_CC) + static std::ptrdiff_t const length; +#else + static std::ptrdiff_t const length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif + }; + + template + std::size_t const prime_list_template::value[] = { + BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) + }; + +#if !defined(SUNPRO_CC) + template + std::ptrdiff_t const prime_list_template::length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif + +#undef BOOST_UNORDERED_PRIMES + + typedef prime_list_template prime_list; + + // no throw + inline std::size_t next_prime(std::size_t num) { + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = prime_list_begin + + prime_list::length; + std::size_t const* bound = + std::lower_bound(prime_list_begin, prime_list_end, num); + if(bound == prime_list_end) + bound--; + return *bound; + } + + // no throw + inline std::size_t prev_prime(std::size_t num) { + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = prime_list_begin + + prime_list::length; + std::size_t const* bound = + std::upper_bound(prime_list_begin,prime_list_end, num); + if(bound != prime_list_begin) + bound--; + return *bound; + } + + //////////////////////////////////////////////////////////////////////////// + // insert_size/initial_size + +#if !defined(BOOST_NO_STD_DISTANCE) + + using ::std::distance; + +#else + + template + inline std::size_t distance(ForwardIterator i, ForwardIterator j) { + std::size_t x; + std::distance(i, j, x); + return x; + } + +#endif + + template + inline typename + boost::unordered::detail::enable_if_forward::type + insert_size(I i, I j) + { + return std::distance(i, j); + } + + template + inline typename + boost::unordered::detail::disable_if_forward::type + insert_size(I, I) + { + return 1; + } + + template + inline std::size_t initial_size(I i, I j, + std::size_t num_buckets = + boost::unordered::detail::default_bucket_count) + { + // TODO: Why +1? + return (std::max)( + boost::unordered::detail::insert_size(i, j) + 1, + num_buckets); + } + + //////////////////////////////////////////////////////////////////////////// + // compressed + + template + struct compressed_base : private T + { + compressed_base(T const& x) : T(x) {} + compressed_base(T& x, move_tag) : T(boost::move(x)) {} + + T& get() { return *this; } + T const& get() const { return *this; } + }; + + template + struct uncompressed_base + { + uncompressed_base(T const& x) : value_(x) {} + uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} + + T& get() { return value_; } + T const& get() const { return value_; } + private: + T value_; + }; + + template + struct generate_base + : boost::detail::if_true< + boost::is_empty::value + >:: BOOST_NESTED_TEMPLATE then< + boost::unordered::detail::compressed_base, + boost::unordered::detail::uncompressed_base + > + {}; + + template + struct compressed + : private boost::unordered::detail::generate_base::type, + private boost::unordered::detail::generate_base::type + { + typedef typename generate_base::type base1; + typedef typename generate_base::type base2; + + typedef T1 first_type; + typedef T2 second_type; + + first_type& first() { + return static_cast(this)->get(); + } + + first_type const& first() const { + return static_cast(this)->get(); + } + + second_type& second() { + return static_cast(this)->get(); + } + + second_type const& second() const { + return static_cast(this)->get(); + } + + template + compressed(First const& x1, Second const& x2) + : base1(x1), base2(x2) {} + + compressed(compressed const& x) + : base1(x.first()), base2(x.second()) {} + + compressed(compressed& x, move_tag m) + : base1(x.first(), m), base2(x.second(), m) {} + + void assign(compressed const& x) + { + first() = x.first(); + second() = x.second(); + } + + void move_assign(compressed& x) + { + first() = boost::move(x.first()); + second() = boost::move(x.second()); + } + + void swap(compressed& x) + { + boost::swap(first(), x.first()); + boost::swap(second(), x.second()); + } + + private: + // Prevent assignment just to make use of assign or + // move_assign explicit. + compressed& operator=(compressed const&); + }; +}}} + +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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + typename Node::node_pointer, + 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; + typedef boost::unordered::iterator_detail::iterator iterator; + 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(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT + : ptr_(x.node_), 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + ConstNodePointer, + typename Node::value_type const&> + { + friend struct boost::unordered::iterator_detail::l_iterator + ; + private: + + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator iterator; + 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(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : + ptr_(x.node_), 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + typename Node::node_pointer, + 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::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 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(); + } + + 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + ConstNodePointer, + 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 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(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} + + value_type const& operator*() const { + return node_->value(); + } + + value_type 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) + 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 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_; + 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::func::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::func::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::func::destroy_value_impl(alloc_, + node_->value_ptr()); + } + + if (node_constructed_) { + boost::unordered::detail::func::destroy( + 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); + + new ((void*) boost::addressof(*node_)) node(); + node_->init(node_); + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_); + + if (value_constructed_) + { + boost::unordered::detail::func::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::link_pointer prev = b.get_previous_start(); + nodes_ = static_cast(prev->next_); + prev->next_ = link_pointer(); + b.size_ = 0; + } + } + + ~node_holder(); + + void node_for_assignment() + { + if (!this->node_ && nodes_) { + this->node_ = nodes_; + nodes_ = static_cast(nodes_->next_); + this->node_->init(this->node_); + this->node_->next_ = link_pointer(); + + this->node_constructed_ = true; + this->value_constructed_ = true; + } + } + + template + inline void assign_impl(T const& v) { + if (this->node_ && this->value_constructed_) { + this->node_->value() = v; + } + else { + this->construct_with_value2(v); + } + } + + template + inline void assign_impl(std::pair const& v) { + this->construct_with_value2(v); + } + + template + inline void move_assign_impl(T& v) { + if (this->node_ && this->value_constructed_) { + this->node_->value() = boost::move(v); + } + else { + this->construct_with_value2(boost::move(v)); + } + } + + template + inline void move_assign_impl(std::pair& v) { + this->construct_with_value2(boost::move(v)); + } + + node_pointer copy_of(value_type const& v) + { + node_for_assignment(); + assign_impl(v); + return base::release(); + } + + node_pointer move_copy_of(value_type& v) + { + node_for_assignment(); + move_assign_impl(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::func::destroy_value_impl(this->alloc_, + p->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*p)); + node_allocator_traits::deallocate(this->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 + //////////////////////////////////////////////////////////////////////////// // convert double to std::size_t diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp deleted file mode 100644 index 3428ed7a..00000000 --- a/include/boost/unordered/detail/util.hpp +++ /dev/null @@ -1,266 +0,0 @@ - -// 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_UTIL_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED - -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { namespace unordered { namespace detail { - - static const float minimum_max_load_factor = 1e-3f; - static const std::size_t default_bucket_count = 11; - struct move_tag {}; - struct empty_emplace {}; - - namespace func { - template - inline void ignore_unused_variable_warning(T const&) {} - } - - //////////////////////////////////////////////////////////////////////////// - // iterator SFINAE - - template - struct is_forward : - boost::is_convertible< - typename boost::iterator_traversal::type, - boost::forward_traversal_tag> - {}; - - template - struct enable_if_forward : - boost::enable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; - - template - struct disable_if_forward : - boost::disable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; - - //////////////////////////////////////////////////////////////////////////// - // primes - -#define BOOST_UNORDERED_PRIMES \ - (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ - (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ - (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ - (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ - (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ - (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ - (1610612741ul)(3221225473ul)(4294967291ul) - - template struct prime_list_template - { - static std::size_t const value[]; - -#if !defined(SUNPRO_CC) - static std::ptrdiff_t const length; -#else - static std::ptrdiff_t const length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - }; - - template - std::size_t const prime_list_template::value[] = { - BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) - }; - -#if !defined(SUNPRO_CC) - template - std::ptrdiff_t const prime_list_template::length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - -#undef BOOST_UNORDERED_PRIMES - - typedef prime_list_template prime_list; - - // no throw - inline std::size_t next_prime(std::size_t num) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::lower_bound(prime_list_begin, prime_list_end, num); - if(bound == prime_list_end) - bound--; - return *bound; - } - - // no throw - inline std::size_t prev_prime(std::size_t num) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::upper_bound(prime_list_begin,prime_list_end, num); - if(bound != prime_list_begin) - bound--; - return *bound; - } - - //////////////////////////////////////////////////////////////////////////// - // insert_size/initial_size - -#if !defined(BOOST_NO_STD_DISTANCE) - - using ::std::distance; - -#else - - template - inline std::size_t distance(ForwardIterator i, ForwardIterator j) { - std::size_t x; - std::distance(i, j, x); - return x; - } - -#endif - - template - inline typename - boost::unordered::detail::enable_if_forward::type - insert_size(I i, I j) - { - return std::distance(i, j); - } - - template - inline typename - boost::unordered::detail::disable_if_forward::type - insert_size(I, I) - { - return 1; - } - - template - inline std::size_t initial_size(I i, I j, - std::size_t num_buckets = - boost::unordered::detail::default_bucket_count) - { - // TODO: Why +1? - return (std::max)( - boost::unordered::detail::insert_size(i, j) + 1, - num_buckets); - } - - //////////////////////////////////////////////////////////////////////////// - // compressed - - template - struct compressed_base : private T - { - compressed_base(T const& x) : T(x) {} - compressed_base(T& x, move_tag) : T(boost::move(x)) {} - - T& get() { return *this; } - T const& get() const { return *this; } - }; - - template - struct uncompressed_base - { - uncompressed_base(T const& x) : value_(x) {} - uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} - - T& get() { return value_; } - T const& get() const { return value_; } - private: - T value_; - }; - - template - struct generate_base - : boost::detail::if_true< - boost::is_empty::value - >:: BOOST_NESTED_TEMPLATE then< - boost::unordered::detail::compressed_base, - boost::unordered::detail::uncompressed_base - > - {}; - - template - struct compressed - : private boost::unordered::detail::generate_base::type, - private boost::unordered::detail::generate_base::type - { - typedef typename generate_base::type base1; - typedef typename generate_base::type base2; - - typedef T1 first_type; - typedef T2 second_type; - - first_type& first() { - return static_cast(this)->get(); - } - - first_type const& first() const { - return static_cast(this)->get(); - } - - second_type& second() { - return static_cast(this)->get(); - } - - second_type const& second() const { - return static_cast(this)->get(); - } - - template - compressed(First const& x1, Second const& x2) - : base1(x1), base2(x2) {} - - compressed(compressed const& x) - : base1(x.first()), base2(x.second()) {} - - compressed(compressed& x, move_tag m) - : base1(x.first(), m), base2(x.second(), m) {} - - void assign(compressed const& x) - { - first() = x.first(); - second() = x.second(); - } - - void move_assign(compressed& x) - { - first() = boost::move(x.first()); - second() = boost::move(x.second()); - } - - void swap(compressed& x) - { - boost::swap(first(), x.first()); - boost::swap(second(), x.second()); - } - - private: - // Prevent assignment just to make use of assign or - // move_assign explicit. - compressed& operator=(compressed const&); - }; -}}} - -#endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 9b180796..0a1fc9f9 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 853b5d73..2759eeee 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include From 2f6b81d8c10a7eb4f043b9fc207e287d0d5c43f0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 19 Aug 2014 16:41:10 +0100 Subject: [PATCH 3/7] Rename iterator typedef to n_iterator. --- include/boost/unordered/detail/table.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 6d71afdb..bb616b6a 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -335,7 +335,7 @@ namespace boost { namespace unordered { namespace iterator_detail { private: #endif typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator iterator; + typedef boost::unordered::iterator_detail::iterator n_iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; @@ -346,7 +346,7 @@ namespace boost { namespace unordered { namespace iterator_detail { l_iterator() BOOST_NOEXCEPT : ptr_() {} - l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT + l_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : ptr_(x.node_), bucket_(b), bucket_count_(c) {} value_type& operator*() const { @@ -394,7 +394,7 @@ namespace boost { namespace unordered { namespace iterator_detail { private: typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator iterator; + typedef boost::unordered::iterator_detail::iterator n_iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; @@ -405,7 +405,7 @@ namespace boost { namespace unordered { namespace iterator_detail { cl_iterator() BOOST_NOEXCEPT : ptr_() {} - cl_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : + cl_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : ptr_(x.node_), bucket_(b), bucket_count_(c) {} cl_iterator(boost::unordered::iterator_detail::l_iterator< From b1232d80611d786a1f3838f816095c393fe2d436 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 22 Oct 2014 21:23:48 +0100 Subject: [PATCH 4/7] Revert some changes so that I can merge to master. Revert "Rename iterator typedef to n_iterator." and "Combine some of the headers." This reverts commits: 2f6b81d8c10a7eb4f043b9fc207e287d0d5c43f0 and e1b39bbbfb7b1a8af988254eb38ea8fd0e30c04e. --- include/boost/unordered/detail/buckets.hpp | 928 ++++++++++++++++ include/boost/unordered/detail/table.hpp | 1159 +------------------- include/boost/unordered/detail/util.hpp | 266 +++++ include/boost/unordered/unordered_map.hpp | 1 + include/boost/unordered/unordered_set.hpp | 1 + 5 files changed, 1199 insertions(+), 1156 deletions(-) create mode 100644 include/boost/unordered/detail/buckets.hpp create mode 100644 include/boost/unordered/detail/util.hpp diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp new file mode 100644 index 00000000..fd038b7b --- /dev/null +++ b/include/boost/unordered/detail/buckets.hpp @@ -0,0 +1,928 @@ + +// 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 +#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; + +}}} + +// 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + typename Node::node_pointer, + 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; + typedef boost::unordered::iterator_detail::iterator iterator; + 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(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT + : ptr_(x.node_), 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + ConstNodePointer, + typename Node::value_type const&> + { + friend struct boost::unordered::iterator_detail::l_iterator + ; + private: + + typedef typename Node::node_pointer node_pointer; + typedef boost::unordered::iterator_detail::iterator iterator; + 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(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : + ptr_(x.node_), 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + typename Node::node_pointer, + 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::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 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(); + } + + 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 boost::iterator< + std::forward_iterator_tag, + typename Node::value_type, + std::ptrdiff_t, + ConstNodePointer, + 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 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(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} + + value_type const& operator*() const { + return node_->value(); + } + + value_type 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) + 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 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_; + 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::func::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::func::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::func::destroy_value_impl(alloc_, + node_->value_ptr()); + } + + if (node_constructed_) { + boost::unordered::detail::func::destroy( + 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); + + new ((void*) boost::addressof(*node_)) node(); + node_->init(node_); + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_); + + if (value_constructed_) + { + boost::unordered::detail::func::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::link_pointer prev = b.get_previous_start(); + nodes_ = static_cast(prev->next_); + prev->next_ = link_pointer(); + b.size_ = 0; + } + } + + ~node_holder(); + + void node_for_assignment() + { + if (!this->node_ && nodes_) { + this->node_ = nodes_; + nodes_ = static_cast(nodes_->next_); + this->node_->init(this->node_); + this->node_->next_ = link_pointer(); + + this->node_constructed_ = true; + this->value_constructed_ = true; + } + } + + template + inline void assign_impl(T const& v) { + if (this->node_ && this->value_constructed_) { + this->node_->value() = v; + } + else { + this->construct_with_value2(v); + } + } + + template + inline void assign_impl(std::pair const& v) { + this->construct_with_value2(v); + } + + template + inline void move_assign_impl(T& v) { + if (this->node_ && this->value_constructed_) { + this->node_->value() = boost::move(v); + } + else { + this->construct_with_value2(boost::move(v)); + } + } + + template + inline void move_assign_impl(std::pair& v) { + this->construct_with_value2(boost::move(v)); + } + + node_pointer copy_of(value_type const& v) + { + node_for_assignment(); + assign_impl(v); + return base::release(); + } + + node_pointer move_copy_of(value_type& v) + { + node_for_assignment(); + move_assign_impl(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::func::destroy_value_impl(this->alloc_, + p->value_ptr()); + boost::unordered::detail::func::destroy(boost::addressof(*p)); + node_allocator_traits::deallocate(this->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 diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index bb616b6a..7b4cc0ec 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2011, 2014 Daniel James +// 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) @@ -12,23 +12,10 @@ #pragma once #endif -#include -#include -#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #if defined(BOOST_MSVC) @@ -50,1146 +37,6 @@ namespace boost { namespace unordered { namespace detail { - static const float minimum_max_load_factor = 1e-3f; - static const std::size_t default_bucket_count = 11; - struct move_tag {}; - struct empty_emplace {}; - - namespace func { - template - inline void ignore_unused_variable_warning(T const&) {} - } - - //////////////////////////////////////////////////////////////////////////// - // iterator SFINAE - - template - struct is_forward : - boost::is_convertible< - typename boost::iterator_traversal::type, - boost::forward_traversal_tag> - {}; - - template - struct enable_if_forward : - boost::enable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; - - template - struct disable_if_forward : - boost::disable_if_c< - boost::unordered::detail::is_forward::value, - ReturnType> - {}; - - //////////////////////////////////////////////////////////////////////////// - // primes - -#define BOOST_UNORDERED_PRIMES \ - (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ - (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ - (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ - (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ - (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ - (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ - (1610612741ul)(3221225473ul)(4294967291ul) - - template struct prime_list_template - { - static std::size_t const value[]; - -#if !defined(SUNPRO_CC) - static std::ptrdiff_t const length; -#else - static std::ptrdiff_t const length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - }; - - template - std::size_t const prime_list_template::value[] = { - BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) - }; - -#if !defined(SUNPRO_CC) - template - std::ptrdiff_t const prime_list_template::length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); -#endif - -#undef BOOST_UNORDERED_PRIMES - - typedef prime_list_template prime_list; - - // no throw - inline std::size_t next_prime(std::size_t num) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::lower_bound(prime_list_begin, prime_list_end, num); - if(bound == prime_list_end) - bound--; - return *bound; - } - - // no throw - inline std::size_t prev_prime(std::size_t num) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::upper_bound(prime_list_begin,prime_list_end, num); - if(bound != prime_list_begin) - bound--; - return *bound; - } - - //////////////////////////////////////////////////////////////////////////// - // insert_size/initial_size - -#if !defined(BOOST_NO_STD_DISTANCE) - - using ::std::distance; - -#else - - template - inline std::size_t distance(ForwardIterator i, ForwardIterator j) { - std::size_t x; - std::distance(i, j, x); - return x; - } - -#endif - - template - inline typename - boost::unordered::detail::enable_if_forward::type - insert_size(I i, I j) - { - return std::distance(i, j); - } - - template - inline typename - boost::unordered::detail::disable_if_forward::type - insert_size(I, I) - { - return 1; - } - - template - inline std::size_t initial_size(I i, I j, - std::size_t num_buckets = - boost::unordered::detail::default_bucket_count) - { - // TODO: Why +1? - return (std::max)( - boost::unordered::detail::insert_size(i, j) + 1, - num_buckets); - } - - //////////////////////////////////////////////////////////////////////////// - // compressed - - template - struct compressed_base : private T - { - compressed_base(T const& x) : T(x) {} - compressed_base(T& x, move_tag) : T(boost::move(x)) {} - - T& get() { return *this; } - T const& get() const { return *this; } - }; - - template - struct uncompressed_base - { - uncompressed_base(T const& x) : value_(x) {} - uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} - - T& get() { return value_; } - T const& get() const { return value_; } - private: - T value_; - }; - - template - struct generate_base - : boost::detail::if_true< - boost::is_empty::value - >:: BOOST_NESTED_TEMPLATE then< - boost::unordered::detail::compressed_base, - boost::unordered::detail::uncompressed_base - > - {}; - - template - struct compressed - : private boost::unordered::detail::generate_base::type, - private boost::unordered::detail::generate_base::type - { - typedef typename generate_base::type base1; - typedef typename generate_base::type base2; - - typedef T1 first_type; - typedef T2 second_type; - - first_type& first() { - return static_cast(this)->get(); - } - - first_type const& first() const { - return static_cast(this)->get(); - } - - second_type& second() { - return static_cast(this)->get(); - } - - second_type const& second() const { - return static_cast(this)->get(); - } - - template - compressed(First const& x1, Second const& x2) - : base1(x1), base2(x2) {} - - compressed(compressed const& x) - : base1(x.first()), base2(x.second()) {} - - compressed(compressed& x, move_tag m) - : base1(x.first(), m), base2(x.second(), m) {} - - void assign(compressed const& x) - { - first() = x.first(); - second() = x.second(); - } - - void move_assign(compressed& x) - { - first() = boost::move(x.first()); - second() = boost::move(x.second()); - } - - void swap(compressed& x) - { - boost::swap(first(), x.first()); - boost::swap(second(), x.second()); - } - - private: - // Prevent assignment just to make use of assign or - // move_assign explicit. - compressed& operator=(compressed const&); - }; -}}} - -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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::node_pointer, - 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; - typedef boost::unordered::iterator_detail::iterator n_iterator; - 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(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT - : ptr_(x.node_), 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - ConstNodePointer, - typename Node::value_type const&> - { - friend struct boost::unordered::iterator_detail::l_iterator - ; - private: - - typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator n_iterator; - 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(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : - ptr_(x.node_), 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - typename Node::node_pointer, - 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::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 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(); - } - - 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 boost::iterator< - std::forward_iterator_tag, - typename Node::value_type, - std::ptrdiff_t, - ConstNodePointer, - 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 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(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} - - value_type const& operator*() const { - return node_->value(); - } - - value_type 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) - 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 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_; - 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::func::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::func::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::func::destroy_value_impl(alloc_, - node_->value_ptr()); - } - - if (node_constructed_) { - boost::unordered::detail::func::destroy( - 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); - - new ((void*) boost::addressof(*node_)) node(); - node_->init(node_); - node_constructed_ = true; - } - else { - BOOST_ASSERT(node_constructed_); - - if (value_constructed_) - { - boost::unordered::detail::func::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::link_pointer prev = b.get_previous_start(); - nodes_ = static_cast(prev->next_); - prev->next_ = link_pointer(); - b.size_ = 0; - } - } - - ~node_holder(); - - void node_for_assignment() - { - if (!this->node_ && nodes_) { - this->node_ = nodes_; - nodes_ = static_cast(nodes_->next_); - this->node_->init(this->node_); - this->node_->next_ = link_pointer(); - - this->node_constructed_ = true; - this->value_constructed_ = true; - } - } - - template - inline void assign_impl(T const& v) { - if (this->node_ && this->value_constructed_) { - this->node_->value() = v; - } - else { - this->construct_with_value2(v); - } - } - - template - inline void assign_impl(std::pair const& v) { - this->construct_with_value2(v); - } - - template - inline void move_assign_impl(T& v) { - if (this->node_ && this->value_constructed_) { - this->node_->value() = boost::move(v); - } - else { - this->construct_with_value2(boost::move(v)); - } - } - - template - inline void move_assign_impl(std::pair& v) { - this->construct_with_value2(boost::move(v)); - } - - node_pointer copy_of(value_type const& v) - { - node_for_assignment(); - assign_impl(v); - return base::release(); - } - - node_pointer move_copy_of(value_type& v) - { - node_for_assignment(); - move_assign_impl(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::func::destroy_value_impl(this->alloc_, - p->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*p)); - node_allocator_traits::deallocate(this->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 - //////////////////////////////////////////////////////////////////////////// // convert double to std::size_t diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp new file mode 100644 index 00000000..3428ed7a --- /dev/null +++ b/include/boost/unordered/detail/util.hpp @@ -0,0 +1,266 @@ + +// 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_UTIL_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace unordered { namespace detail { + + static const float minimum_max_load_factor = 1e-3f; + static const std::size_t default_bucket_count = 11; + struct move_tag {}; + struct empty_emplace {}; + + namespace func { + template + inline void ignore_unused_variable_warning(T const&) {} + } + + //////////////////////////////////////////////////////////////////////////// + // iterator SFINAE + + template + struct is_forward : + boost::is_convertible< + typename boost::iterator_traversal::type, + boost::forward_traversal_tag> + {}; + + template + struct enable_if_forward : + boost::enable_if_c< + boost::unordered::detail::is_forward::value, + ReturnType> + {}; + + template + struct disable_if_forward : + boost::disable_if_c< + boost::unordered::detail::is_forward::value, + ReturnType> + {}; + + //////////////////////////////////////////////////////////////////////////// + // primes + +#define BOOST_UNORDERED_PRIMES \ + (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ + (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ + (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ + (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ + (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ + (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ + (1610612741ul)(3221225473ul)(4294967291ul) + + template struct prime_list_template + { + static std::size_t const value[]; + +#if !defined(SUNPRO_CC) + static std::ptrdiff_t const length; +#else + static std::ptrdiff_t const length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif + }; + + template + std::size_t const prime_list_template::value[] = { + BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) + }; + +#if !defined(SUNPRO_CC) + template + std::ptrdiff_t const prime_list_template::length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif + +#undef BOOST_UNORDERED_PRIMES + + typedef prime_list_template prime_list; + + // no throw + inline std::size_t next_prime(std::size_t num) { + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = prime_list_begin + + prime_list::length; + std::size_t const* bound = + std::lower_bound(prime_list_begin, prime_list_end, num); + if(bound == prime_list_end) + bound--; + return *bound; + } + + // no throw + inline std::size_t prev_prime(std::size_t num) { + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = prime_list_begin + + prime_list::length; + std::size_t const* bound = + std::upper_bound(prime_list_begin,prime_list_end, num); + if(bound != prime_list_begin) + bound--; + return *bound; + } + + //////////////////////////////////////////////////////////////////////////// + // insert_size/initial_size + +#if !defined(BOOST_NO_STD_DISTANCE) + + using ::std::distance; + +#else + + template + inline std::size_t distance(ForwardIterator i, ForwardIterator j) { + std::size_t x; + std::distance(i, j, x); + return x; + } + +#endif + + template + inline typename + boost::unordered::detail::enable_if_forward::type + insert_size(I i, I j) + { + return std::distance(i, j); + } + + template + inline typename + boost::unordered::detail::disable_if_forward::type + insert_size(I, I) + { + return 1; + } + + template + inline std::size_t initial_size(I i, I j, + std::size_t num_buckets = + boost::unordered::detail::default_bucket_count) + { + // TODO: Why +1? + return (std::max)( + boost::unordered::detail::insert_size(i, j) + 1, + num_buckets); + } + + //////////////////////////////////////////////////////////////////////////// + // compressed + + template + struct compressed_base : private T + { + compressed_base(T const& x) : T(x) {} + compressed_base(T& x, move_tag) : T(boost::move(x)) {} + + T& get() { return *this; } + T const& get() const { return *this; } + }; + + template + struct uncompressed_base + { + uncompressed_base(T const& x) : value_(x) {} + uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} + + T& get() { return value_; } + T const& get() const { return value_; } + private: + T value_; + }; + + template + struct generate_base + : boost::detail::if_true< + boost::is_empty::value + >:: BOOST_NESTED_TEMPLATE then< + boost::unordered::detail::compressed_base, + boost::unordered::detail::uncompressed_base + > + {}; + + template + struct compressed + : private boost::unordered::detail::generate_base::type, + private boost::unordered::detail::generate_base::type + { + typedef typename generate_base::type base1; + typedef typename generate_base::type base2; + + typedef T1 first_type; + typedef T2 second_type; + + first_type& first() { + return static_cast(this)->get(); + } + + first_type const& first() const { + return static_cast(this)->get(); + } + + second_type& second() { + return static_cast(this)->get(); + } + + second_type const& second() const { + return static_cast(this)->get(); + } + + template + compressed(First const& x1, Second const& x2) + : base1(x1), base2(x2) {} + + compressed(compressed const& x) + : base1(x.first()), base2(x.second()) {} + + compressed(compressed& x, move_tag m) + : base1(x.first(), m), base2(x.second(), m) {} + + void assign(compressed const& x) + { + first() = x.first(); + second() = x.second(); + } + + void move_assign(compressed& x) + { + first() = boost::move(x.first()); + second() = boost::move(x.second()); + } + + void swap(compressed& x) + { + boost::swap(first(), x.first()); + boost::swap(second(), x.second()); + } + + private: + // Prevent assignment just to make use of assign or + // move_assign explicit. + compressed& operator=(compressed const&); + }; +}}} + +#endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 0a1fc9f9..9b180796 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 2759eeee..853b5d73 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include From 8c5aa5086d77d62ecf80ea10e0c684335435d6e7 Mon Sep 17 00:00:00 2001 From: Zoey Greer Date: Tue, 2 Sep 2014 12:56:06 -0400 Subject: [PATCH 5/7] Initialize data_ in value_base default constructor This means data_ should get initialized in the default constructor for boost::unordered::detail::unique_node (and any other inheritors), as this constructor will be called there. This uninitialized data member was reported by Coverity (CID 49445), which unfortunately does not seem to have any convenient way to publicly, globally address issues. --- include/boost/unordered/detail/table.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 7b4cc0ec..2bb5d450 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -59,6 +59,10 @@ namespace boost { namespace unordered { namespace detail { sizeof(value_type), boost::alignment_of::value>::type data_; + value_base() : + data_() + {} + void* address() { return this; } From 99985bb1b26ea13e9a85f723cfa9369a4c9ee257 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 22 Oct 2014 21:59:37 +0100 Subject: [PATCH 6/7] Fix pointer types in iterators. https://svn.boost.org/trac/boost/ticket/10672 --- include/boost/unordered/detail/buckets.hpp | 8 ++-- test/unordered/compile_tests.hpp | 46 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index fd038b7b..7de4317b 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -60,7 +60,7 @@ namespace boost { namespace unordered { namespace iterator_detail { std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, - typename Node::node_pointer, + typename Node::value_type*, typename Node::value_type&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) @@ -120,7 +120,7 @@ namespace boost { namespace unordered { namespace iterator_detail { std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, - ConstNodePointer, + typename Node::value_type const*, typename Node::value_type const&> { friend struct boost::unordered::iterator_detail::l_iterator @@ -188,7 +188,7 @@ namespace boost { namespace unordered { namespace iterator_detail { std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, - typename Node::node_pointer, + typename Node::value_type*, typename Node::value_type&> { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) @@ -252,7 +252,7 @@ namespace boost { namespace unordered { namespace iterator_detail { std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, - ConstNodePointer, + typename Node::value_type const*, typename Node::value_type const&> { friend struct boost::unordered::iterator_detail::iterator; diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 02ef78aa..b48a6efd 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -180,6 +180,28 @@ void unordered_set_test(X&, Key const&) typedef BOOST_DEDUCED_TYPENAME X::key_type key_type; BOOST_STATIC_ASSERT((boost::is_same::value)); + + // iterator pointer / const_pointer_type + + typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; + typedef BOOST_DEDUCED_TYPENAME X::local_iterator local_iterator; + typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + const_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type local_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + const_local_iterator_pointer; + + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); } template @@ -191,6 +213,30 @@ void unordered_map_test(X& r, Key const& k, T const& v) BOOST_STATIC_ASSERT(( boost::is_same >::value)); + // iterator pointer / const_pointer_type + + typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; + typedef BOOST_DEDUCED_TYPENAME X::local_iterator local_iterator; + typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + const_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type local_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + const_local_iterator_pointer; + + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + + // Calling functions + r.insert(std::pair(k, v)); Key k_lvalue(k); From 7c6f1ef22704cb859e9d1b1dd4bf1ad1465cefe2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 26 Oct 2014 12:17:58 +0000 Subject: [PATCH 7/7] Changelog --- doc/changes.qbk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 8f4bee01..f71da60d 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -252,4 +252,12 @@ C++11 support has resulted in some breaking changes: uses slower ([ticket 9282]). * Only construct elements using allocators, as specified in C++11 standard. +[h2 Boost 1.57.0] + +* Fix the `pointer` typedef in iterators ([ticket 10672]). +* Fix Coverity warning + ([@https://github.com/boostorg/unordered/pull/2 GitHub #2]). +* Rename private `iterator` typedef in some iterator classes, as it + confuses some traits classes. + [endsect]