summaryrefslogtreecommitdiff
path: root/boost/unordered/detail/implementation.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/unordered/detail/implementation.hpp')
-rw-r--r--boost/unordered/detail/implementation.hpp742
1 files changed, 441 insertions, 301 deletions
diff --git a/boost/unordered/detail/implementation.hpp b/boost/unordered/detail/implementation.hpp
index d25026fe07..9dffde159d 100644
--- a/boost/unordered/detail/implementation.hpp
+++ b/boost/unordered/detail/implementation.hpp
@@ -13,12 +13,11 @@
#endif
#include <boost/assert.hpp>
-#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/core/no_exceptions_support.hpp>
+#include <boost/core/pointer_traits.hpp>
#include <boost/detail/select_type.hpp>
-#include <boost/iterator/iterator_categories.hpp>
#include <boost/limits.hpp>
#include <boost/move/move.hpp>
-#include <boost/predef.h>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
@@ -33,11 +32,13 @@
#include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
+#include <boost/type_traits/integral_constant.hpp>
+#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/is_class.hpp>
-#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
+#include <boost/type_traits/is_nothrow_swappable.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/unordered/detail/fwd.hpp>
@@ -195,6 +196,18 @@
#endif
#endif
+// BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
+
+#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES)
+#if BOOST_COMP_CLANG && __cplusplus >= 201703
+#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 1
+#endif
+#endif
+
+#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES)
+#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 0
+#endif
+
namespace boost {
namespace unordered {
namespace iterator_detail {
@@ -244,9 +257,8 @@ namespace boost {
// iterator SFINAE
template <typename I>
- struct is_forward
- : boost::is_convertible<typename boost::iterator_traversal<I>::type,
- boost::forward_traversal_tag>
+ struct is_forward : boost::is_base_of<std::forward_iterator_tag,
+ typename std::iterator_traits<I>::iterator_category>
{
};
@@ -541,21 +553,6 @@ namespace boost {
{
template <typename T> convert_from_anything(T const&);
};
-
- // Get a pointer from a smart pointer, a bit simpler than pointer_traits
- // as we already know the pointer type that we want.
- template <typename T> struct pointer
- {
- template <typename Ptr> static T* get(Ptr const& x)
- {
- return static_cast<T*>(x.operator->());
- }
-
- template <typename T2> static T* get(T2* x)
- {
- return static_cast<T*>(x);
- }
- };
}
}
}
@@ -741,6 +738,118 @@ namespace boost {
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
+
+ //////////////////////////////////////////////////////////////////////////
+ // value_base
+ //
+ // Space used to store values.
+
+ template <typename ValueType> struct value_base
+ {
+ typedef ValueType value_type;
+
+ typename boost::aligned_storage<sizeof(value_type),
+ boost::alignment_of<value_type>::value>::type data_;
+
+ value_base() : data_() {}
+
+ void* address() { return this; }
+
+ value_type& value() { return *(ValueType*)this; }
+
+ value_type const& value() const { return *(ValueType const*)this; }
+
+ value_type* value_ptr() { return (ValueType*)this; }
+
+ value_type const* value_ptr() const { return (ValueType const*)this; }
+
+ private:
+ value_base& operator=(value_base const&);
+ };
+
+ //////////////////////////////////////////////////////////////////////////
+ // optional
+ // TODO: Use std::optional when available.
+
+ template <typename T> class optional
+ {
+ BOOST_MOVABLE_BUT_NOT_COPYABLE(optional)
+
+ boost::unordered::detail::value_base<T> value_;
+ bool has_value_;
+
+ void destroy()
+ {
+ if (has_value_) {
+ boost::unordered::detail::func::destroy(value_.value_ptr());
+ has_value_ = false;
+ }
+ }
+
+ void move(optional<T>& x)
+ {
+ BOOST_ASSERT(!has_value_ && x.has_value_);
+ new (value_.value_ptr()) T(boost::move(x.value_.value()));
+ boost::unordered::detail::func::destroy(x.value_.value_ptr());
+ has_value_ = true;
+ x.has_value_ = false;
+ }
+
+ public:
+ optional() BOOST_NOEXCEPT : has_value_(false) {}
+
+ optional(BOOST_RV_REF(optional<T>) x) : has_value_(false)
+ {
+ if (x.has_value_) {
+ move(x);
+ }
+ }
+
+ explicit optional(T const& x) : has_value_(true)
+ {
+ new (value_.value_ptr()) T(x);
+ }
+
+ optional& operator=(BOOST_RV_REF(optional<T>) x)
+ {
+ destroy();
+ if (x.has_value_) {
+ move(x);
+ }
+ return *this;
+ }
+
+ ~optional() { destroy(); }
+
+ bool has_value() const { return has_value_; }
+ T& operator*() { return value_.value(); }
+ T const& operator*() const { return value_.value(); }
+ T* operator->() { return value_.value_ptr(); }
+ T const* operator->() const { return value_.value_ptr(); }
+
+ bool operator==(optional<T> const& x)
+ {
+ return has_value_ ? x.has_value_ && value_.value() == x.value_.value()
+ : !x.has_value_;
+ }
+
+ bool operator!=(optional<T> const& x) { return !((*this) == x); }
+
+ void swap(optional<T>& x)
+ {
+ if (has_value_ != x.has_value_) {
+ if (has_value_) {
+ x.move(*this);
+ } else {
+ move(x);
+ }
+ } else if (has_value_) {
+ boost::swap(value_.value(), x.value_.value());
+ }
+ }
+
+ friend void swap(optional<T>& x, optional<T>& y) { x.swap(y); }
+ };
}
}
}
@@ -855,6 +964,78 @@ namespace boost {
#endif
+////////////////////////////////////////////////////////////////////////////
+// TRAITS TYPE DETECTION MECHANISM
+//
+// Used to implement traits that use a type if present, or a
+// default otherwise.
+
+#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
+
+#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
+ template <typename Tp, typename Default> struct default_type_##tname \
+ { \
+ \
+ template <typename X> \
+ static choice1::type test(choice1, typename X::tname* = 0); \
+ \
+ template <typename X> static choice2::type test(choice2, void* = 0); \
+ \
+ struct DefaultWrap \
+ { \
+ typedef Default tname; \
+ }; \
+ \
+ enum \
+ { \
+ value = (1 == sizeof(test<Tp>(choose()))) \
+ }; \
+ \
+ typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \
+ then<Tp, DefaultWrap>::type::tname type; \
+ }
+
+#else
+
+namespace boost {
+ namespace unordered {
+ namespace detail {
+ template <typename T, typename T2> struct sfinae : T2
+ {
+ };
+ }
+ }
+}
+
+#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
+ template <typename Tp, typename Default> struct default_type_##tname \
+ { \
+ \
+ template <typename X> \
+ static typename boost::unordered::detail::sfinae<typename X::tname, \
+ choice1>::type test(choice1); \
+ \
+ template <typename X> static choice2::type test(choice2); \
+ \
+ struct DefaultWrap \
+ { \
+ typedef Default tname; \
+ }; \
+ \
+ enum \
+ { \
+ value = (1 == sizeof(test<Tp>(choose()))) \
+ }; \
+ \
+ typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \
+ then<Tp, DefaultWrap>::type::tname type; \
+ }
+
+#endif
+
+#define BOOST_UNORDERED_DEFAULT_TYPE(T, tname, arg) \
+ typename default_type_##tname<T, arg>::type
+
////////////////////////////////////////////////////////////////////////////////
//
// Allocator traits
@@ -934,72 +1115,6 @@ namespace boost {
}
}
-#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
-
-#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
- template <typename Tp, typename Default> struct default_type_##tname \
- { \
- \
- template <typename X> \
- static choice1::type test(choice1, typename X::tname* = 0); \
- \
- template <typename X> static choice2::type test(choice2, void* = 0); \
- \
- struct DefaultWrap \
- { \
- typedef Default tname; \
- }; \
- \
- enum \
- { \
- value = (1 == sizeof(test<Tp>(choose()))) \
- }; \
- \
- typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \
- then<Tp, DefaultWrap>::type::tname type; \
- }
-
-#else
-
-namespace boost {
- namespace unordered {
- namespace detail {
- template <typename T, typename T2> struct sfinae : T2
- {
- };
- }
- }
-}
-
-#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
- template <typename Tp, typename Default> struct default_type_##tname \
- { \
- \
- template <typename X> \
- static typename boost::unordered::detail::sfinae<typename X::tname, \
- choice1>::type test(choice1); \
- \
- template <typename X> static choice2::type test(choice2); \
- \
- struct DefaultWrap \
- { \
- typedef Default tname; \
- }; \
- \
- enum \
- { \
- value = (1 == sizeof(test<Tp>(choose()))) \
- }; \
- \
- typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE \
- then<Tp, DefaultWrap>::type::tname type; \
- }
-
-#endif
-
-#define BOOST_UNORDERED_DEFAULT_TYPE(T, tname, arg) \
- typename default_type_##tname<T, arg>::type
-
namespace boost {
namespace unordered {
namespace detail {
@@ -1014,6 +1129,7 @@ namespace boost {
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
propagate_on_container_move_assignment);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
+ BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(is_always_equal);
#if !defined(BOOST_NO_SFINAE_EXPR)
@@ -1310,6 +1426,9 @@ namespace boost {
false_type) propagate_on_container_move_assignment;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, propagate_on_container_swap,
false_type) propagate_on_container_swap;
+
+ typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, is_always_equal,
+ typename boost::is_empty<Alloc>::type) is_always_equal;
};
}
}
@@ -1330,9 +1449,20 @@ namespace boost {
namespace unordered {
namespace detail {
+ BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(is_always_equal);
+
template <typename Alloc>
struct allocator_traits : std::allocator_traits<Alloc>
{
+ // As is_always_equal was introduced in C++17, std::allocator_traits
+ // doesn't always have it. So use it when available, implement it
+ // ourselves when not. Would be simpler not to bother with
+ // std::allocator_traits, but I feel like I should try to use
+ // it where possible.
+ typedef BOOST_UNORDERED_DEFAULT_TYPE(std::allocator_traits<Alloc>,
+ is_always_equal,
+ BOOST_UNORDERED_DEFAULT_TYPE(Alloc, is_always_equal,
+ typename boost::is_empty<Alloc>::type)) is_always_equal;
};
template <typename Alloc, typename T> struct rebind_wrap
@@ -1844,7 +1974,7 @@ namespace boost {
template <typename Alloc> node_constructor<Alloc>::~node_constructor()
{
if (node_) {
- boost::unordered::detail::func::destroy(pointer<node>::get(node_));
+ boost::unordered::detail::func::destroy(boost::to_address(node_));
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
@@ -1853,7 +1983,7 @@ namespace boost {
{
BOOST_ASSERT(!node_);
node_ = node_allocator_traits::allocate(alloc_, 1);
- new (pointer<void>::get(node_)) node();
+ new ((void*)boost::to_address(node_)) node();
}
template <typename NodeAlloc> struct node_tmp
@@ -1884,7 +2014,7 @@ namespace boost {
if (node_) {
BOOST_UNORDERED_CALL_DESTROY(
node_allocator_traits, alloc_, node_->value_ptr());
- boost::unordered::detail::func::destroy(pointer<node>::get(node_));
+ boost::unordered::detail::func::destroy(boost::to_address(node_));
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
@@ -2088,11 +2218,7 @@ namespace boost {
//
// all no throw
- template <typename Node>
- struct l_iterator
- : public std::iterator<std::forward_iterator_tag,
- typename Node::value_type, std::ptrdiff_t,
- typename Node::value_type*, typename Node::value_type&>
+ template <typename Node> struct l_iterator
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename Node2>
@@ -2106,7 +2232,12 @@ namespace boost {
std::size_t bucket_count_;
public:
+ typedef typename Node::value_type element_type;
typedef typename Node::value_type value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::forward_iterator_tag iterator_category;
l_iterator() BOOST_NOEXCEPT : ptr_() {}
@@ -2147,11 +2278,7 @@ namespace boost {
}
};
- template <typename Node>
- struct cl_iterator
- : public std::iterator<std::forward_iterator_tag,
- typename Node::value_type, std::ptrdiff_t,
- typename Node::value_type const*, typename Node::value_type const&>
+ template <typename Node> struct cl_iterator
{
friend struct boost::unordered::iterator_detail::l_iterator<Node>;
@@ -2162,7 +2289,12 @@ namespace boost {
std::size_t bucket_count_;
public:
+ typedef typename Node::value_type const element_type;
typedef typename Node::value_type value_type;
+ typedef value_type const* pointer;
+ typedef value_type const& reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::forward_iterator_tag iterator_category;
cl_iterator() BOOST_NOEXCEPT : ptr_() {}
@@ -2213,11 +2345,7 @@ namespace boost {
}
};
- template <typename Node>
- struct iterator
- : public std::iterator<std::forward_iterator_tag,
- typename Node::value_type, std::ptrdiff_t,
- typename Node::value_type*, typename Node::value_type&>
+ template <typename Node> struct iterator
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename>
@@ -2230,7 +2358,12 @@ namespace boost {
node_pointer node_;
public:
+ typedef typename Node::value_type element_type;
typedef typename Node::value_type value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::forward_iterator_tag iterator_category;
iterator() BOOST_NOEXCEPT : node_() {}
@@ -2267,11 +2400,7 @@ namespace boost {
}
};
- template <typename Node>
- struct c_iterator
- : public std::iterator<std::forward_iterator_tag,
- typename Node::value_type, std::ptrdiff_t,
- typename Node::value_type const*, typename Node::value_type const&>
+ template <typename Node> struct c_iterator
{
friend struct boost::unordered::iterator_detail::iterator<Node>;
@@ -2285,7 +2414,12 @@ namespace boost {
node_pointer node_;
public:
+ typedef typename Node::value_type const element_type;
typedef typename Node::value_type value_type;
+ typedef value_type const* pointer;
+ typedef value_type const& reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::forward_iterator_tag iterator_category;
c_iterator() BOOST_NOEXCEPT : node_() {}
@@ -2412,7 +2546,7 @@ namespace boost {
BOOST_UNORDERED_CALL_DESTROY(
node_allocator_traits, constructor_.alloc_, p->value_ptr());
- boost::unordered::detail::func::destroy(pointer<node>::get(p));
+ boost::unordered::detail::func::destroy(boost::to_address(p));
node_allocator_traits::deallocate(constructor_.alloc_, p, 1);
}
}
@@ -2590,20 +2724,13 @@ namespace boost {
//////////////////////////////////////////////////////////////////////////
// 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 H, class P, bool NoThrowMoveAssign>
- class set_hash_functions;
+ //
+ // This double buffers the storage for the hash function and key equality
+ // predicate in order to have exception safe copy/swap. To do so,
+ // use 'construct_spare' to construct in the spare space, and then when
+ // ready to use 'switch_functions' to switch to the new functions.
+ // If an exception is thrown between these two calls, use
+ // 'cleanup_spare_functions' to destroy the unused constructed functions.
template <class H, class P> class functions
{
@@ -2614,10 +2741,11 @@ namespace boost {
static const bool nothrow_move_constructible =
boost::is_nothrow_move_constructible<H>::value &&
boost::is_nothrow_move_constructible<P>::value;
+ static const bool nothrow_swappable =
+ boost::is_nothrow_swappable<H>::value &&
+ boost::is_nothrow_swappable<P>::value;
private:
- friend class boost::unordered::detail::set_hash_functions<H, P,
- nothrow_move_assignable>;
functions& operator=(functions const&);
typedef compressed<H, P> function_pair;
@@ -2625,134 +2753,101 @@ namespace boost {
typedef typename boost::aligned_storage<sizeof(function_pair),
boost::alignment_of<function_pair>::value>::type aligned_function;
- bool current_; // The currently active functions.
+ unsigned char current_; // 0/1 - Currently active functions
+ // +2 - Both constructed
aligned_function funcs_[2];
- function_pair const& current() const
- {
- return *static_cast<function_pair const*>(
- static_cast<void const*>(funcs_[current_].address()));
- }
-
- function_pair& current()
+ public:
+ functions(H const& hf, P const& eq) : current_(0)
{
- return *static_cast<function_pair*>(
- static_cast<void*>(funcs_[current_].address()));
+ construct_functions(current_, hf, eq);
}
- void construct(bool which, H const& hf, P const& eq)
+ functions(functions const& bf) : current_(0)
{
- new ((void*)&funcs_[which]) function_pair(hf, eq);
+ construct_functions(current_, bf.current_functions());
}
- void construct(bool which, function_pair const& f,
- boost::unordered::detail::false_type =
- boost::unordered::detail::false_type())
+ functions(functions& bf, boost::unordered::detail::move_tag)
+ : current_(0)
{
- new ((void*)&funcs_[which]) function_pair(f);
+ construct_functions(current_, bf.current_functions(),
+ boost::unordered::detail::integral_constant<bool,
+ nothrow_move_constructible>());
}
- void construct(
- bool which, function_pair& f, boost::unordered::detail::true_type)
+ ~functions()
{
- new ((void*)&funcs_[which])
- function_pair(f, boost::unordered::detail::move_tag());
+ BOOST_ASSERT(!(current_ & 2));
+ destroy_functions(current_);
}
- void destroy(bool which)
- {
- boost::unordered::detail::func::destroy(
- (function_pair*)(&funcs_[which]));
- }
+ H const& hash_function() const { return current_functions().first(); }
- public:
- typedef boost::unordered::detail::set_hash_functions<H, P,
- nothrow_move_assignable>
- set_hash_functions;
+ P const& key_eq() const { return current_functions().second(); }
- functions(H const& hf, P const& eq) : current_(false)
+ function_pair const& current_functions() const
{
- construct(current_, hf, eq);
+ return *static_cast<function_pair const*>(
+ static_cast<void const*>(funcs_[current_ & 1].address()));
}
- functions(functions const& bf) : current_(false)
+ function_pair& current_functions()
{
- construct(current_, bf.current());
+ return *static_cast<function_pair*>(
+ static_cast<void*>(funcs_[current_ & 1].address()));
}
- functions(functions& bf, boost::unordered::detail::move_tag)
- : current_(false)
+ void construct_spare_functions(function_pair const& f)
{
- construct(current_, bf.current(),
- boost::unordered::detail::integral_constant<bool,
- nothrow_move_constructible>());
+ BOOST_ASSERT(!(current_ & 2));
+ construct_functions(current_ ^ 1, f);
+ current_ |= 2;
}
- ~functions() { this->destroy(current_); }
-
- H const& hash_function() const { return current().first(); }
-
- P const& key_eq() const { return current().second(); }
- };
-
- template <class H, class P> class set_hash_functions<H, P, false>
- {
- set_hash_functions(set_hash_functions const&);
- set_hash_functions& operator=(set_hash_functions const&);
-
- typedef functions<H, P> 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_)
+ void cleanup_spare_functions()
{
- f.construct(tmp_functions_, h, p);
+ if (current_ & 2) {
+ current_ = static_cast<unsigned char>(current_ & 1);
+ destroy_functions(current_ ^ 1);
+ }
}
- set_hash_functions(functions_type& f, functions_type const& other)
- : functions_(f), tmp_functions_(!f.current_)
+ void switch_functions()
{
- f.construct(tmp_functions_, other.current());
+ BOOST_ASSERT(current_ & 2);
+ destroy_functions(static_cast<unsigned char>(current_ & 1));
+ current_ ^= 3;
}
- ~set_hash_functions() { functions_.destroy(tmp_functions_); }
-
- void commit()
+ private:
+ void construct_functions(unsigned char which, H const& hf, P const& eq)
{
- functions_.current_ = tmp_functions_;
- tmp_functions_ = !tmp_functions_;
+ BOOST_ASSERT(!(which & 2));
+ new ((void*)&funcs_[which]) function_pair(hf, eq);
}
- };
-
- template <class H, class P> class set_hash_functions<H, P, true>
- {
- set_hash_functions(set_hash_functions const&);
- set_hash_functions& operator=(set_hash_functions const&);
-
- typedef functions<H, P> 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)
+ void construct_functions(unsigned char which, function_pair const& f,
+ boost::unordered::detail::false_type =
+ boost::unordered::detail::false_type())
{
+ BOOST_ASSERT(!(which & 2));
+ new ((void*)&funcs_[which]) function_pair(f);
}
- set_hash_functions(functions_type& f, functions_type const& other)
- : functions_(f), hash_(other.hash_function()), pred_(other.key_eq())
+ void construct_functions(unsigned char which, function_pair& f,
+ boost::unordered::detail::true_type)
{
+ BOOST_ASSERT(!(which & 2));
+ new ((void*)&funcs_[which])
+ function_pair(f, boost::unordered::detail::move_tag());
}
- void commit()
+ void destroy_functions(unsigned char which)
{
- functions_.current().first() = boost::move(hash_);
- functions_.current().second() = boost::move(pred_);
+ BOOST_ASSERT(!(which & 2));
+ boost::unordered::detail::func::destroy(
+ (function_pair*)(&funcs_[which]));
}
};
@@ -2801,31 +2896,6 @@ namespace boost {
: static_cast<std::size_t>(f);
}
- // The space used to store values in a node.
-
- template <typename ValueType> struct value_base
- {
- typedef ValueType value_type;
-
- typename boost::aligned_storage<sizeof(value_type),
- boost::alignment_of<value_type>::value>::type data_;
-
- value_base() : data_() {}
-
- void* address() { return this; }
-
- value_type& value() { return *(ValueType*)this; }
-
- value_type const& value() const { return *(ValueType const*)this; }
-
- value_type* value_ptr() { return (ValueType*)this; }
-
- value_type const* value_ptr() const { return (ValueType const*)this; }
-
- private:
- value_base& operator=(value_base const&);
- };
-
template <typename Types>
struct table : boost::unordered::detail::functions<typename Types::hasher,
typename Types::key_equal>
@@ -2853,7 +2923,6 @@ namespace boost {
typedef boost::unordered::detail::functions<typename Types::hasher,
typename Types::key_equal>
functions;
- typedef typename functions::set_hash_functions set_hash_functions;
typedef typename Types::value_allocator value_allocator;
typedef typename boost::unordered::detail::rebind_wrap<value_allocator,
@@ -2951,7 +3020,7 @@ namespace boost {
bucket_allocator_traits::max_size(bucket_alloc()) - 1);
}
- bucket_pointer get_bucket(std::size_t bucket_index) const
+ bucket_pointer get_bucket_pointer(std::size_t bucket_index) const
{
BOOST_ASSERT(buckets_);
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
@@ -2959,12 +3028,12 @@ namespace boost {
link_pointer get_previous_start() const
{
- return get_bucket(bucket_count_)->first_from_start();
+ return get_bucket_pointer(bucket_count_)->first_from_start();
}
link_pointer get_previous_start(std::size_t bucket_index) const
{
- return get_bucket(bucket_index)->next_;
+ return get_bucket_pointer(bucket_index)->next_;
}
node_pointer begin() const
@@ -3093,7 +3162,7 @@ namespace boost {
// Clear the bucket pointers.
void clear_buckets()
{
- bucket_pointer end = get_bucket(bucket_count_);
+ bucket_pointer end = get_bucket_pointer(bucket_count_);
for (bucket_pointer it = buckets_; it != end; ++it) {
it->next_ = node_pointer();
}
@@ -3137,9 +3206,9 @@ namespace boost {
bucket_pointer end =
buckets_ + static_cast<std::ptrdiff_t>(new_count);
for (bucket_pointer i = buckets_; i != end; ++i) {
- new (pointer<void>::get(i)) bucket();
+ new ((void*)boost::to_address(i)) bucket();
}
- new (pointer<void>::get(end)) bucket(dummy_node);
+ new ((void*)boost::to_address(end)) bucket(dummy_node);
}
////////////////////////////////////////////////////////////////////////
@@ -3160,14 +3229,24 @@ namespace boost {
allocators_.swap(other.allocators_);
}
- // Only swaps the allocators if propagate_on_container_swap
- void swap(table& x)
+ // Not nothrow swappable
+ void swap(table& x, false_type)
{
- set_hash_functions op1(*this, x);
- set_hash_functions op2(x, *this);
+ if (this == &x) {
+ return;
+ }
+
+ this->construct_spare_functions(x.current_functions());
+ BOOST_TRY { x.construct_spare_functions(this->current_functions()); }
+ BOOST_CATCH(...)
+ {
+ this->cleanup_spare_functions();
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ this->switch_functions();
+ x.switch_functions();
- // I think swap can throw if Propagate::value,
- // since the allocators' swap can throw. Not sure though.
swap_allocators(
x, boost::unordered::detail::integral_constant<bool,
allocator_traits<
@@ -3178,8 +3257,34 @@ namespace boost {
boost::swap(size_, x.size_);
std::swap(mlf_, x.mlf_);
std::swap(max_load_, x.max_load_);
- op1.commit();
- op2.commit();
+ }
+
+ // Nothrow swappable
+ void swap(table& x, true_type)
+ {
+ swap_allocators(
+ x, boost::unordered::detail::integral_constant<bool,
+ allocator_traits<
+ node_allocator>::propagate_on_container_swap::value>());
+
+ boost::swap(buckets_, x.buckets_);
+ boost::swap(bucket_count_, x.bucket_count_);
+ boost::swap(size_, x.size_);
+ std::swap(mlf_, x.mlf_);
+ std::swap(max_load_, x.max_load_);
+ this->current_functions().swap(x.current_functions());
+ }
+
+ // Only swaps the allocators if propagate_on_container_swap.
+ // If not propagate_on_container_swap and allocators aren't
+ // equal, behaviour is undefined.
+ void swap(table& x)
+ {
+ BOOST_ASSERT(allocator_traits<
+ node_allocator>::propagate_on_container_swap::value ||
+ node_alloc() == x.node_alloc());
+ swap(x, boost::unordered::detail::integral_constant<bool,
+ functions::nothrow_swappable>());
}
// Only call with nodes allocated with the currect allocator, or
@@ -3207,9 +3312,9 @@ namespace boost {
link_pointer prev = this->get_previous_start();
std::size_t last_bucket = this->bucket_count_;
for (node_pointer n = src.begin(); n; n = next_node(n)) {
- std::size_t bucket = n->get_bucket();
- if (bucket != last_bucket) {
- this->get_bucket(bucket)->next_ = prev;
+ std::size_t n_bucket = n->get_bucket();
+ if (n_bucket != last_bucket) {
+ this->get_bucket_pointer(n_bucket)->next_ = prev;
}
node_pointer n2 = boost::unordered::detail::func::construct_node(
this->node_alloc(), boost::move(n->value()));
@@ -3217,7 +3322,7 @@ namespace boost {
prev->next_ = n2;
++size_;
prev = n2;
- last_bucket = bucket;
+ last_bucket = n_bucket;
}
}
}
@@ -3231,19 +3336,19 @@ namespace boost {
{
BOOST_UNORDERED_CALL_DESTROY(
node_allocator_traits, node_alloc(), n->value_ptr());
- boost::unordered::detail::func::destroy(pointer<node>::get(n));
+ boost::unordered::detail::func::destroy(boost::to_address(n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
}
void delete_buckets()
{
if (buckets_) {
- node_pointer n =
- static_cast<node_pointer>(get_bucket(bucket_count_)->next_);
+ node_pointer n = static_cast<node_pointer>(
+ get_bucket_pointer(bucket_count_)->next_);
if (bucket::extra_node) {
node_pointer next = next_node(n);
- boost::unordered::detail::func::destroy(pointer<node>::get(n));
+ boost::unordered::detail::func::destroy(boost::to_address(n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
n = next;
}
@@ -3263,9 +3368,9 @@ namespace boost {
void destroy_buckets()
{
- bucket_pointer end = get_bucket(bucket_count_ + 1);
+ bucket_pointer end = get_bucket_pointer(bucket_count_ + 1);
for (bucket_pointer it = buckets_; it != end; ++it) {
- boost::unordered::detail::func::destroy(pointer<bucket>::get(it));
+ boost::unordered::detail::func::destroy(boost::to_address(it));
}
bucket_allocator_traits::deallocate(
@@ -3293,11 +3398,11 @@ namespace boost {
}
// Update the bucket containing next.
- get_bucket(bucket_index2)->next_ = prev;
+ get_bucket_pointer(bucket_index2)->next_ = prev;
}
// Check if this bucket is now empty.
- bucket_pointer this_bucket = get_bucket(bucket_index);
+ bucket_pointer this_bucket = get_bucket_pointer(bucket_index);
if (this_bucket->next_ == prev) {
this_bucket->next_ = link_pointer();
}
@@ -3328,18 +3433,25 @@ namespace boost {
void assign(table const& x, UniqueType is_unique, false_type)
{
// Strong exception safety.
- set_hash_functions new_func_this(*this, x);
- mlf_ = x.mlf_;
- recalculate_max_load();
+ this->construct_spare_functions(x.current_functions());
+ BOOST_TRY
+ {
+ mlf_ = x.mlf_;
+ recalculate_max_load();
- if (x.size_ > max_load_) {
- create_buckets(min_buckets_for_size(x.size_));
- } else if (size_) {
- clear_buckets();
+ if (x.size_ > max_load_) {
+ create_buckets(min_buckets_for_size(x.size_));
+ } else if (size_) {
+ clear_buckets();
+ }
}
-
- new_func_this.commit();
-
+ BOOST_CATCH(...)
+ {
+ this->cleanup_spare_functions();
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ this->switch_functions();
assign_buckets(x, is_unique);
}
@@ -3350,7 +3462,8 @@ namespace boost {
allocators_.assign(x.allocators_);
assign(x, is_unique, false_type());
} else {
- set_hash_functions new_func_this(*this, x);
+ this->construct_spare_functions(x.current_functions());
+ this->switch_functions();
// Delete everything with current allocators before assigning
// the new ones.
@@ -3358,7 +3471,6 @@ namespace boost {
allocators_.assign(x.allocators_);
// Copy over other data, all no throw.
- new_func_this.commit();
mlf_ = x.mlf_;
bucket_count_ = min_buckets_for_size(x.size_);
@@ -3380,30 +3492,52 @@ namespace boost {
}
}
+ // Propagate allocator
template <typename UniqueType>
void move_assign(table& x, UniqueType, true_type)
{
+ if (!functions::nothrow_move_assignable) {
+ this->construct_spare_functions(x.current_functions());
+ this->switch_functions();
+ } else {
+ this->current_functions().move_assign(x.current_functions());
+ }
delete_buckets();
- set_hash_functions new_func_this(*this, x);
allocators_.move_assign(x.allocators_);
- // No throw from here.
mlf_ = x.mlf_;
move_buckets_from(x);
- new_func_this.commit();
}
+ // Don't propagate allocator
template <typename UniqueType>
void move_assign(table& x, UniqueType is_unique, false_type)
{
if (node_alloc() == x.node_alloc()) {
- delete_buckets();
- set_hash_functions new_func_this(*this, x);
- // No throw from here.
- mlf_ = x.mlf_;
- move_buckets_from(x);
- new_func_this.commit();
+ move_assign_equal_alloc(x);
} else {
- set_hash_functions new_func_this(*this, x);
+ move_assign_realloc(x, is_unique);
+ }
+ }
+
+ void move_assign_equal_alloc(table& x)
+ {
+ if (!functions::nothrow_move_assignable) {
+ this->construct_spare_functions(x.current_functions());
+ this->switch_functions();
+ } else {
+ this->current_functions().move_assign(x.current_functions());
+ }
+ delete_buckets();
+ mlf_ = x.mlf_;
+ move_buckets_from(x);
+ }
+
+ template <typename UniqueType>
+ void move_assign_realloc(table& x, UniqueType is_unique)
+ {
+ this->construct_spare_functions(x.current_functions());
+ BOOST_TRY
+ {
mlf_ = x.mlf_;
recalculate_max_load();
@@ -3412,11 +3546,15 @@ namespace boost {
} else if (size_) {
clear_buckets();
}
-
- new_func_this.commit();
-
- move_assign_buckets(x, is_unique);
}
+ BOOST_CATCH(...)
+ {
+ this->cleanup_spare_functions();
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ this->switch_functions();
+ move_assign_buckets(x, is_unique);
}
// Accessors
@@ -3547,7 +3685,7 @@ namespace boost {
node_pointer n, std::size_t key_hash)
{
std::size_t bucket_index = this->hash_to_bucket(key_hash);
- bucket_pointer b = this->get_bucket(bucket_index);
+ bucket_pointer b = this->get_bucket_pointer(bucket_index);
n->bucket_info_ = bucket_index;
n->set_first_in_group();
@@ -3556,7 +3694,8 @@ namespace boost {
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
- this->get_bucket(node_bucket(next_node(start_node)))->next_ = n;
+ this->get_bucket_pointer(node_bucket(next_node(start_node)))
+ ->next_ = n;
}
b->next_ = start_node;
@@ -4068,18 +4207,19 @@ namespace boost {
if (n->next_) {
std::size_t next_bucket = this->node_bucket(next_node(n));
if (next_bucket != bucket_index) {
- this->get_bucket(next_bucket)->next_ = n;
+ this->get_bucket_pointer(next_bucket)->next_ = n;
}
}
} else {
n->set_first_in_group();
- bucket_pointer b = this->get_bucket(bucket_index);
+ bucket_pointer b = this->get_bucket_pointer(bucket_index);
if (!b->next_) {
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
- this->get_bucket(this->node_bucket(next_node(start_node)))
+ this
+ ->get_bucket_pointer(this->node_bucket(next_node(start_node)))
->next_ = n;
}
@@ -4105,7 +4245,7 @@ namespace boost {
if (n->next_) {
std::size_t next_bucket = this->node_bucket(next_node(n));
if (next_bucket != this->node_bucket(n)) {
- this->get_bucket(next_bucket)->next_ = n;
+ this->get_bucket_pointer(next_bucket)->next_ = n;
}
}
++this->size_;
@@ -4374,7 +4514,7 @@ namespace boost {
template <typename Types> inline void table<Types>::clear_impl()
{
if (size_) {
- bucket_pointer end = get_bucket(bucket_count_);
+ bucket_pointer end = get_bucket_pointer(bucket_count_);
for (bucket_pointer it = buckets_; it != end; ++it) {
it->next_ = node_pointer();
}
@@ -4462,7 +4602,7 @@ namespace boost {
}
// n is now the last node in the group
- bucket_pointer b = this->get_bucket(bucket_index);
+ bucket_pointer b = this->get_bucket_pointer(bucket_index);
if (!b->next_) {
b->next_ = prev;
prev = n;