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.hpp2945
1 files changed, 1305 insertions, 1640 deletions
diff --git a/boost/unordered/detail/implementation.hpp b/boost/unordered/detail/implementation.hpp
index c293ae2f50..5750a4c67f 100644
--- a/boost/unordered/detail/implementation.hpp
+++ b/boost/unordered/detail/implementation.hpp
@@ -1,4 +1,3 @@
-
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2016 Daniel James
//
@@ -19,6 +18,8 @@
#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>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
@@ -47,10 +48,6 @@
#include <stdexcept>
#include <utility>
-#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
-#include <tuple>
-#endif
-
#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
#include <type_traits>
#endif
@@ -61,24 +58,25 @@
// Unless documented elsewhere these configuration macros should be considered
// an implementation detail, I'll try not to break them, but you never know.
-// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in emplace
-// (not including things like hints). Don't set it to a lower value, as that
-// might break something.
+// Use Sun C++ workarounds
+// I'm not sure which versions of the compiler require these workarounds, so
+// I'm just using them of everything older than the current test compilers
+// (as of May 2017).
-#if !defined BOOST_UNORDERED_EMPLACE_LIMIT
-#define BOOST_UNORDERED_EMPLACE_LIMIT 11
+#if !defined(BOOST_UNORDERED_SUN_WORKAROUNDS1)
+#if BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 20, 0)
+#define BOOST_UNORDERED_SUN_WORKAROUNDS1 1
+#else
+#define BOOST_UNORDERED_SUN_WORKAROUNDS1 0
+#endif
#endif
-// BOOST_UNORDERED_INTEROPERABLE_NODES - Use the same node type for
-// containers with unique and equivalent keys.
-//
-// 0 = Use different nodes
-// 1 = Use ungrouped nodes everywhere
-//
-// Might add an extra value to use grouped nodes everywhere later.
+// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in
+// emplace (not including things like hints). Don't set it to a lower value, as
+// that might break something.
-#if !defined(BOOST_UNORDERED_INTEROPERABLE_NODES)
-#define BOOST_UNORDERED_INTEROPERABLE_NODES 0
+#if !defined BOOST_UNORDERED_EMPLACE_LIMIT
+#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#endif
// BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - Pick which version of
@@ -104,13 +102,106 @@
#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
#endif
+// BOOST_UNORDERED_TUPLE_ARGS
+//
+// Maximum number of std::tuple members to support, or 0 if std::tuple
+// isn't avaiable. More are supported when full C++11 is used.
+
+// Already defined, so do nothing
+#if defined(BOOST_UNORDERED_TUPLE_ARGS)
+
+// Assume if we have C++11 tuple it's properly variadic,
+// and just use a max number of 10 arguments.
+#elif !defined(BOOST_NO_CXX11_HDR_TUPLE)
+#define BOOST_UNORDERED_TUPLE_ARGS 10
+
+// Visual C++ has a decent enough tuple for piecewise construction,
+// so use that if available, using _VARIADIC_MAX for the maximum
+// number of parameters. Note that this comes after the check
+// for a full C++11 tuple.
+#elif defined(BOOST_MSVC)
+#if !BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
+#define BOOST_UNORDERED_TUPLE_ARGS 0
+#elif defined(_VARIADIC_MAX)
+#define BOOST_UNORDERED_TUPLE_ARGS _VARIADIC_MAX
+#else
+#define BOOST_UNORDERED_TUPLE_ARGS 5
+#endif
+
+// Assume that we don't have std::tuple
+#else
+#define BOOST_UNORDERED_TUPLE_ARGS 0
+#endif
+
+#if BOOST_UNORDERED_TUPLE_ARGS
+#include <tuple>
+#endif
+
+// BOOST_UNORDERED_CXX11_CONSTRUCTION
+//
+// Use C++11 construction, requires variadic arguments, good construct support
+// in allocator_traits and piecewise construction of std::pair
+// Otherwise allocators aren't used for construction/destruction
+
+#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \
+ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && BOOST_UNORDERED_TUPLE_ARGS
+#if BOOST_COMP_SUNPRO && BOOST_LIB_STD_GNU
+// Sun C++ std::pair piecewise construction doesn't seem to be exception safe.
+// (At least for Sun C++ 12.5 using libstdc++).
+#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
+#elif BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 7, 0)
+// Piecewise construction in GCC 4.6 doesn't work for uncopyable types.
+#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
+#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && \
+ !defined(BOOST_NO_SFINAE_EXPR)
+#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
+#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
+#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
+#endif
+#endif
+
+#if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION)
+#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
+#endif
+
+// BOOST_UNORDERED_SUPPRESS_DEPRECATED
+//
+// Define to stop deprecation attributes
+
+#if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED)
+#define BOOST_UNORDERED_DEPRECATED(msg)
+#endif
+
+// BOOST_UNORDERED_DEPRECATED
+//
+// Wrapper around various depreaction attributes.
+
+#if defined(__has_cpp_attribute) && \
+ (!defined(__cplusplus) || __cplusplus >= 201402)
+#if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED)
+#define BOOST_UNORDERED_DEPRECATED(msg) [[deprecated(msg)]]
+#endif
+#endif
+
+#if !defined(BOOST_UNORDERED_DEPRECATED)
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define BOOST_UNORDERED_DEPRECATED(msg) __attribute__((deprecated))
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+#define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated(msg))
+#elif defined(_MSC_VER) && _MSC_VER >= 1310
+#define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated)
+#else
+#define BOOST_UNORDERED_DEPRECATED(msg)
+#endif
+#endif
+
namespace boost {
namespace unordered {
namespace iterator_detail {
template <typename Node> struct iterator;
template <typename Node> struct c_iterator;
-template <typename Node, typename Policy> struct l_iterator;
-template <typename Node, typename Policy> struct cl_iterator;
+template <typename Node> struct l_iterator;
+template <typename Node> struct cl_iterator;
}
}
}
@@ -122,28 +213,27 @@ namespace detail {
template <typename Types> struct table;
template <typename NodePointer> struct bucket;
struct ptr_bucket;
-template <typename Types> struct table_impl;
-template <typename Types> struct grouped_table_impl;
-template <typename A, typename T> struct unique_node;
+template <typename A, typename T> struct node;
template <typename T> struct ptr_node;
-template <typename Types> struct table_impl;
-
-template <typename A, typename T> struct grouped_node;
-template <typename T> struct grouped_ptr_node;
-template <typename Types> struct grouped_table_impl;
-template <typename N> struct node_algo;
-template <typename N> struct grouped_node_algo;
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_bucket_count = 11;
+
struct move_tag
{
};
+
struct empty_emplace
{
};
+struct no_key
+{
+ no_key() {}
+ template <class T> no_key(T const&) {}
+};
+
namespace func {
template <class T> inline void ignore_unused_variable_warning(T const&) {}
}
@@ -190,7 +280,7 @@ template <class T> struct prime_list_template
{
static std::size_t const value[];
-#if !defined(SUNPRO_CC)
+#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
static std::ptrdiff_t const length;
#else
static std::ptrdiff_t const length =
@@ -202,7 +292,7 @@ template <class T>
std::size_t const prime_list_template<T>::value[] = {
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)};
-#if !defined(SUNPRO_CC)
+#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
template <class T>
std::ptrdiff_t const prime_list_template<T>::length = BOOST_PP_SEQ_SIZE(
BOOST_UNORDERED_PRIMES);
@@ -439,16 +529,17 @@ struct convert_from_anything
template <typename T> convert_from_anything(T const&);
};
-namespace func {
-// This is a bit nasty, when constructing the individual members
-// of a std::pair, need to cast away 'const'. For modern compilers,
-// should be able to use std::piecewise_construct instead.
-template <typename T> T* const_cast_pointer(T* x) { return x; }
-template <typename T> T* const_cast_pointer(T const* x)
+// 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
{
- return const_cast<T*>(x);
-}
-}
+ 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); }
+};
////////////////////////////////////////////////////////////////////////////
// emplace_args
@@ -458,20 +549,12 @@ template <typename T> T* const_cast_pointer(T const* x)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
-#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0
-#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1
-#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2
-
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
#else
-#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args
-#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
-#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
-
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
#define BOOST_UNORDERED_EMPLACE_FORWARD args
@@ -491,7 +574,8 @@ template <typename T> T* const_cast_pointer(T const* x)
#endif
-template <typename A0> struct emplace_args1
+template <typename A0>
+struct emplace_args1
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
@@ -568,8 +652,14 @@ inline emplace_args3<A0, A1, A2> create_emplace_args(
return e; \
}
+BOOST_UNORDERED_EARGS(1, 4, _)
+BOOST_UNORDERED_EARGS(1, 5, _)
+BOOST_UNORDERED_EARGS(1, 6, _)
+BOOST_UNORDERED_EARGS(1, 7, _)
+BOOST_UNORDERED_EARGS(1, 8, _)
+BOOST_UNORDERED_EARGS(1, 9, _)
BOOST_PP_REPEAT_FROM_TO(
- 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, _)
+ 10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EARGS, _)
#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
#undef BOOST_UNORDERED_EARGS_MEMBER
@@ -738,13 +828,6 @@ template <typename T> struct identity
#include <boost/pointer_to_other.hpp>
#include <boost/utility/enable_if.hpp>
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
- !defined(BOOST_NO_SFINAE_EXPR)
-#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
-#else
-#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
-#endif
-
namespace boost {
namespace unordered {
namespace detail {
@@ -1013,7 +1096,7 @@ template <typename Alloc> struct allocator_traits
}
public:
-#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
+#if BOOST_UNORDERED_CXX11_CONSTRUCTION
template <typename T, typename... Args>
static typename boost::enable_if_c<
@@ -1168,8 +1251,6 @@ template <typename Alloc> struct allocator_traits
#include <memory>
-#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
-
namespace boost {
namespace unordered {
namespace detail {
@@ -1195,8 +1276,6 @@ template <typename Alloc, typename T> struct rebind_wrap
#include <boost/container/allocator_traits.hpp>
-#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
-
namespace boost {
namespace unordered {
namespace detail {
@@ -1231,157 +1310,160 @@ namespace detail {
namespace func {
////////////////////////////////////////////////////////////////////////////
-// call_construct
+// construct_value
+//
+// Only use allocator_traits::construct, allocator_traits::destroy when full
+// C++11 support is available.
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+#if BOOST_UNORDERED_CXX11_CONSTRUCTION
-#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
+#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
+ Traits::construct(alloc, address, a0)
+#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) Traits::destroy(alloc, x)
-template <typename Alloc, typename T, typename... Args>
-inline void call_construct(
- Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args)
-{
- boost::unordered::detail::allocator_traits<Alloc>::construct(
- alloc, address, boost::forward<Args>(args)...);
-}
-
-template <typename Alloc, typename T>
-inline void call_destroy(Alloc& alloc, T* x)
-{
- boost::unordered::detail::allocator_traits<Alloc>::destroy(alloc, x);
-}
-
-#else
+#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
-template <typename Alloc, typename T, typename... Args>
-inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(Args)... args)
+template <typename T, typename... Args>
+inline void construct_value(T* address, BOOST_FWD_REF(Args)... args)
{
new ((void*)address) T(boost::forward<Args>(args)...);
}
-template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x)
-{
- boost::unordered::detail::func::destroy(x);
-}
-
-#endif
+#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
+ boost::unordered::detail::func::construct_value(address, a0)
+#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \
+ boost::unordered::detail::func::destroy(x)
#else
-template <typename Alloc, typename T>
-inline void call_construct(Alloc&, T* address)
+
+template <typename T> inline void construct_value(T* address)
{
new ((void*)address) T();
}
-template <typename Alloc, typename T, typename A0>
-inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(A0) a0)
+template <typename T, typename A0>
+inline void construct_value(T* address, BOOST_FWD_REF(A0) a0)
{
new ((void*)address) T(boost::forward<A0>(a0));
}
-template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x)
-{
- boost::unordered::detail::func::destroy(x);
-}
+#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
+ boost::unordered::detail::func::construct_value(address, a0)
+#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \
+ boost::unordered::detail::func::destroy(x)
#endif
////////////////////////////////////////////////////////////////////////////
// Construct from tuple
//
-// Used for piecewise construction.
-
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
-
-#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
- template <typename Alloc, typename T> \
- void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \
- { \
- boost::unordered::detail::func::call_construct(alloc, ptr); \
- } \
- \
- BOOST_PP_REPEAT_FROM_TO( \
- 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
+// Used to emulate piecewise construction.
-#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
+#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \
template <typename Alloc, typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
- void construct_from_tuple(Alloc& alloc, T* ptr, \
- namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
+ void construct_from_tuple(Alloc&, T* ptr, \
+ namespace_::tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
{ \
- boost::unordered::detail::func::call_construct(alloc, ptr, \
+ new ((void*)ptr) T( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \
}
-#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get<n>(x)
+#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get<n>(x)
-#elif !defined(__SUNPRO_CC)
+// construct_from_tuple for boost::tuple
+// The workaround for old Sun compilers comes later in the file.
-#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
- template <typename Alloc, typename T> \
- void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \
- { \
- new ((void*)ptr) T(); \
- } \
- \
- BOOST_PP_REPEAT_FROM_TO( \
- 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
+#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
-#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
- template <typename Alloc, typename T, \
- BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
- void construct_from_tuple(Alloc&, T* ptr, \
- namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
- { \
- new ((void*)ptr) T( \
- BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \
- }
+template <typename Alloc, typename T>
+void construct_from_tuple(Alloc&, T* ptr, boost::tuple<>)
+{
+ new ((void*)ptr) T();
+}
-#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get<n>(x)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 6, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 7, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost)
-#else
+#endif
+
+// construct_from_tuple for std::tuple
+
+#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && BOOST_UNORDERED_TUPLE_ARGS
+
+template <typename Alloc, typename T>
+void construct_from_tuple(Alloc&, T* ptr, std::tuple<>)
+{
+ new ((void*)ptr) T();
+}
+
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, std)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, std)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, std)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, std)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, std)
+
+#if BOOST_UNORDERED_TUPLE_ARGS >= 6
+BOOST_PP_REPEAT_FROM_TO(6, BOOST_PP_INC(BOOST_UNORDERED_TUPLE_ARGS),
+ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE, std)
+#endif
+
+#endif
+
+#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
+#undef BOOST_UNORDERED_GET_TUPLE_ARG
+
+// construct_from_tuple for boost::tuple on old versions of sunpro.
+//
+// Old versions of Sun C++ had problems with template overloads of
+// boost::tuple, so to fix it I added a distinct type for each length to
+// the overloads. That means there's no possible ambiguity between the
+// different overloads, so that the compiler doesn't get confused
+
+#if BOOST_UNORDERED_SUN_WORKAROUNDS1
template <int N> struct length
{
};
-#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
- template <typename Alloc, typename T> \
- void construct_from_tuple_impl(boost::unordered::detail::func::length<0>, \
- Alloc&, T* ptr, namespace_ tuple<>) \
- { \
- new ((void*)ptr) T(); \
- } \
- \
- BOOST_PP_REPEAT_FROM_TO( \
- 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
-
-#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
+#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \
template <typename Alloc, typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
void construct_from_tuple_impl(boost::unordered::detail::func::length<n>, \
Alloc&, T* ptr, \
- namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
+ namespace_::tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
{ \
new ((void*)ptr) T( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \
}
-#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get<n>(x)
-
-#endif
-
-BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
-
-#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
-BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::)
-#endif
+#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get<n>(x)
-#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
-#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
-#undef BOOST_UNORDERED_GET_TUPLE_ARG
+template <typename Alloc, typename T>
+void construct_from_tuple_impl(
+ boost::unordered::detail::func::length<0>, Alloc&, T* ptr, boost::tuple<>)
+{
+ new ((void*)ptr) T();
+}
-#if defined(__SUNPRO_CC)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 6, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 7, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost)
+BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost)
template <typename Alloc, typename T, typename Tuple>
void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x)
@@ -1391,6 +1473,9 @@ void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x)
alloc, ptr, x);
}
+#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
+#undef BOOST_UNORDERED_GET_TUPLE_ARG
+
#endif
////////////////////////////////////////////////////////////////////////////
@@ -1409,25 +1494,77 @@ template <typename A0> struct use_piecewise
};
};
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+#if BOOST_UNORDERED_CXX11_CONSTRUCTION
////////////////////////////////////////////////////////////////////////////
// Construct from variadic parameters
-// For the standard pair constructor.
-
template <typename Alloc, typename T, typename... Args>
inline void construct_from_args(
Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args)
{
- boost::unordered::detail::func::call_construct(
+ boost::unordered::detail::allocator_traits<Alloc>::construct(
alloc, address, boost::forward<Args>(args)...);
}
-// Special case for piece_construct
-//
-// TODO: When possible, it might be better to use std::pair's
-// constructor for std::piece_construct with std::tuple.
+// For backwards compatibility, implement a special case for
+// piecewise_construct with boost::tuple
+
+template <typename A0> struct detect_boost_tuple
+{
+ template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+ static choice1::type test(
+ choice1, boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> const&);
+
+ static choice2::type test(choice2, ...);
+
+ enum
+ {
+ value = sizeof(choice1::type) ==
+ sizeof(test(choose(), boost::unordered::detail::make<A0>()))
+ };
+};
+
+// Special case for piecewise_construct
+
+template <typename Alloc, typename A, typename B, typename A0, typename A1,
+ typename A2>
+inline typename boost::enable_if_c<use_piecewise<A0>::value &&
+ detect_boost_tuple<A1>::value &&
+ detect_boost_tuple<A2>::value,
+ void>::type
+construct_from_args(Alloc& alloc, std::pair<A, B>* address, BOOST_FWD_REF(A0),
+ BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
+{
+ boost::unordered::detail::func::construct_from_tuple(
+ alloc, boost::addressof(address->first), boost::forward<A1>(a1));
+ BOOST_TRY
+ {
+ boost::unordered::detail::func::construct_from_tuple(
+ alloc, boost::addressof(address->second), boost::forward<A2>(a2));
+ }
+ BOOST_CATCH(...)
+ {
+ boost::unordered::detail::func::destroy(
+ boost::addressof(address->first));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+}
+
+#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+////////////////////////////////////////////////////////////////////////////
+// Construct from variadic parameters
+
+template <typename Alloc, typename T, typename... Args>
+inline void construct_from_args(Alloc&, T* address, BOOST_FWD_REF(Args)... args)
+{
+ new ((void*)address) T(boost::forward<Args>(args)...);
+}
+
+// Special case for piecewise_construct
template <typename Alloc, typename A, typename B, typename A0, typename A1,
typename A2>
@@ -1436,22 +1573,17 @@ inline typename enable_if<use_piecewise<A0>, void>::type construct_from_args(
BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
{
boost::unordered::detail::func::construct_from_tuple(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(address->first)),
- boost::forward<A1>(a1));
+ alloc, boost::addressof(address->first), boost::forward<A1>(a1));
BOOST_TRY
{
boost::unordered::detail::func::construct_from_tuple(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(address->second)),
- boost::forward<A2>(a2));
+ alloc, boost::addressof(address->second), boost::forward<A2>(a2));
}
BOOST_CATCH(...)
{
- boost::unordered::detail::func::call_destroy(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(address->first)));
- BOOST_RETHROW;
+ boost::unordered::detail::func::destroy(
+ boost::addressof(address->first));
+ BOOST_RETHROW
}
BOOST_CATCH_END
}
@@ -1500,12 +1632,18 @@ inline void construct_from_args(
num_params, BOOST_UNORDERED_CALL_FORWARD, args.a)); \
}
-BOOST_PP_REPEAT_FROM_TO(
- 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_CONSTRUCT_IMPL, _)
+BOOST_UNORDERED_CONSTRUCT_IMPL(1, 4, _)
+BOOST_UNORDERED_CONSTRUCT_IMPL(1, 5, _)
+BOOST_UNORDERED_CONSTRUCT_IMPL(1, 6, _)
+BOOST_UNORDERED_CONSTRUCT_IMPL(1, 7, _)
+BOOST_UNORDERED_CONSTRUCT_IMPL(1, 8, _)
+BOOST_UNORDERED_CONSTRUCT_IMPL(1, 9, _)
+BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT),
+ BOOST_UNORDERED_CONSTRUCT_IMPL, _)
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
-// Construct with piece_construct
+// Construct with piecewise_construct
template <typename Alloc, typename A, typename B, typename A0, typename A1,
typename A2>
@@ -1514,22 +1652,17 @@ inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address,
typename enable_if<use_piecewise<A0>, void*>::type = 0)
{
boost::unordered::detail::func::construct_from_tuple(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(address->first)),
- args.a1);
+ alloc, boost::addressof(address->first), args.a1);
BOOST_TRY
{
boost::unordered::detail::func::construct_from_tuple(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(address->second)),
- args.a2);
+ alloc, boost::addressof(address->second), args.a2);
}
BOOST_CATCH(...)
{
- boost::unordered::detail::func::call_destroy(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(address->first)));
- BOOST_RETHROW;
+ boost::unordered::detail::func::destroy(
+ boost::addressof(address->first));
+ BOOST_RETHROW
}
BOOST_CATCH_END
}
@@ -1559,12 +1692,8 @@ template <typename NodeAlloc> struct node_constructor
node_allocator& alloc_;
node_pointer node_;
- bool node_constructed_;
- node_constructor(node_allocator& n)
- : alloc_(n), node_(), node_constructed_(false)
- {
- }
+ node_constructor(node_allocator& n) : alloc_(n), node_() {}
~node_constructor();
@@ -1573,7 +1702,7 @@ template <typename NodeAlloc> struct node_constructor
// no throw
node_pointer release()
{
- BOOST_ASSERT(node_ && node_constructed_);
+ BOOST_ASSERT(node_);
node_pointer p = node_;
node_ = node_pointer();
return p;
@@ -1583,9 +1712,8 @@ template <typename NodeAlloc> struct node_constructor
{
BOOST_ASSERT(!node_);
node_ = p;
- node_constructed_ = true;
- boost::unordered::detail::func::call_destroy(
- alloc_, node_->value_ptr());
+ BOOST_UNORDERED_CALL_DESTROY(
+ node_allocator_traits, alloc_, node_->value_ptr());
}
private:
@@ -1596,10 +1724,7 @@ template <typename NodeAlloc> struct node_constructor
template <typename Alloc> node_constructor<Alloc>::~node_constructor()
{
if (node_) {
- if (node_constructed_) {
- boost::unordered::detail::func::destroy(boost::addressof(*node_));
- }
-
+ boost::unordered::detail::func::destroy(pointer<node>::get(node_));
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
@@ -1607,13 +1732,8 @@ template <typename Alloc> node_constructor<Alloc>::~node_constructor()
template <typename Alloc> void node_constructor<Alloc>::create_node()
{
BOOST_ASSERT(!node_);
- node_constructed_ = false;
-
node_ = node_allocator_traits::allocate(alloc_, 1);
-
- new ((void*)boost::addressof(*node_)) node();
- node_->init(node_);
- node_constructed_ = true;
+ new (pointer<void>::get(node_)) node();
}
template <typename NodeAlloc> struct node_tmp
@@ -1621,6 +1741,7 @@ template <typename NodeAlloc> struct node_tmp
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
typedef typename node_allocator_traits::pointer node_pointer;
+ typedef typename node_allocator_traits::value_type node;
NodeAlloc& alloc_;
node_pointer node_;
@@ -1641,9 +1762,9 @@ template <typename NodeAlloc> struct node_tmp
template <typename Alloc> node_tmp<Alloc>::~node_tmp()
{
if (node_) {
- boost::unordered::detail::func::call_destroy(
- alloc_, node_->value_ptr());
- boost::unordered::detail::func::destroy(boost::addressof(*node_));
+ BOOST_UNORDERED_CALL_DESTROY(
+ node_allocator_traits, alloc_, node_->value_ptr());
+ boost::unordered::detail::func::destroy(pointer<node>::get(node_));
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
@@ -1676,35 +1797,84 @@ construct_node(Alloc& alloc, BOOST_FWD_REF(U) x)
{
node_constructor<Alloc> a(alloc);
a.create_node();
- boost::unordered::detail::func::call_construct(
- alloc, a.node_->value_ptr(), boost::forward<U>(x));
+ BOOST_UNORDERED_CALL_CONSTRUCT1(
+ boost::unordered::detail::allocator_traits<Alloc>, alloc,
+ a.node_->value_ptr(), boost::forward<U>(x));
+ return a.release();
+}
+
+#if BOOST_UNORDERED_CXX11_CONSTRUCTION
+
+template <typename Alloc, typename Key>
+inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
+construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
+{
+ node_constructor<Alloc> a(alloc);
+ a.create_node();
+ boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
+ a.node_->value_ptr(), std::piecewise_construct,
+ std::forward_as_tuple(boost::forward<Key>(k)), std::forward_as_tuple());
+ return a.release();
+}
+
+template <typename Alloc, typename Key, typename Mapped>
+inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
+construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
+{
+ node_constructor<Alloc> a(alloc);
+ a.create_node();
+ boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
+ a.node_->value_ptr(), std::piecewise_construct,
+ std::forward_as_tuple(boost::forward<Key>(k)),
+ std::forward_as_tuple(boost::forward<Mapped>(m)));
+ return a.release();
+}
+
+template <typename Alloc, typename Key, typename... Args>
+inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
+construct_node_pair_from_args(
+ Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Args)... args)
+{
+ node_constructor<Alloc> a(alloc);
+ a.create_node();
+#if !(BOOST_COMP_CLANG && BOOST_COMP_CLANG < BOOST_VERSION_NUMBER(3, 8, 0) && \
+ defined(BOOST_LIBSTDCXX11))
+ boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
+ a.node_->value_ptr(), std::piecewise_construct,
+ std::forward_as_tuple(boost::forward<Key>(k)),
+ std::forward_as_tuple(boost::forward<Args>(args)...));
+#else
+ // It doesn't seem to be possible to construct a tuple with 3 variadic
+ // rvalue reference members when using older versions of clang with
+ // libstdc++, so just use std::make_tuple instead of std::forward_as_tuple.
+ boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
+ a.node_->value_ptr(), std::piecewise_construct,
+ std::forward_as_tuple(boost::forward<Key>(k)),
+ std::make_tuple(boost::forward<Args>(args)...));
+#endif
return a.release();
}
-// TODO: When possible, it might be better to use std::pair's
-// constructor for std::piece_construct with std::tuple.
+#else
+
template <typename Alloc, typename Key>
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
{
node_constructor<Alloc> a(alloc);
a.create_node();
- boost::unordered::detail::func::call_construct(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->first)),
- boost::forward<Key>(k));
+ boost::unordered::detail::func::construct_value(
+ boost::addressof(a.node_->value_ptr()->first), boost::forward<Key>(k));
BOOST_TRY
{
- boost::unordered::detail::func::call_construct(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->second)));
+ boost::unordered::detail::func::construct_value(
+ boost::addressof(a.node_->value_ptr()->second));
}
BOOST_CATCH(...)
{
- boost::unordered::detail::func::call_destroy(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->first)));
- BOOST_RETHROW;
+ boost::unordered::detail::func::destroy(
+ boost::addressof(a.node_->value_ptr()->first));
+ BOOST_RETHROW
}
BOOST_CATCH_END
return a.release();
@@ -1716,23 +1886,19 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
{
node_constructor<Alloc> a(alloc);
a.create_node();
- boost::unordered::detail::func::call_construct(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->first)),
- boost::forward<Key>(k));
+ boost::unordered::detail::func::construct_value(
+ boost::addressof(a.node_->value_ptr()->first), boost::forward<Key>(k));
BOOST_TRY
{
- boost::unordered::detail::func::call_construct(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->second)),
+ boost::unordered::detail::func::construct_value(
+ boost::addressof(a.node_->value_ptr()->second),
boost::forward<Mapped>(m));
}
BOOST_CATCH(...)
{
- boost::unordered::detail::func::call_destroy(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->first)));
- BOOST_RETHROW;
+ boost::unordered::detail::func::destroy(
+ boost::addressof(a.node_->value_ptr()->first));
+ BOOST_RETHROW
}
BOOST_CATCH_END
return a.release();
@@ -1745,27 +1911,25 @@ construct_node_pair_from_args(
{
node_constructor<Alloc> a(alloc);
a.create_node();
- boost::unordered::detail::func::call_construct(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->first)),
- boost::forward<Key>(k));
+ boost::unordered::detail::func::construct_value(
+ boost::addressof(a.node_->value_ptr()->first), boost::forward<Key>(k));
BOOST_TRY
{
- boost::unordered::detail::func::construct_from_args(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->second)),
+ boost::unordered::detail::func::construct_from_args(alloc,
+ boost::addressof(a.node_->value_ptr()->second),
BOOST_UNORDERED_EMPLACE_FORWARD);
}
BOOST_CATCH(...)
{
- boost::unordered::detail::func::call_destroy(
- alloc, boost::unordered::detail::func::const_cast_pointer(
- boost::addressof(a.node_->value_ptr()->first)));
- BOOST_RETHROW;
+ boost::unordered::detail::func::destroy(
+ boost::addressof(a.node_->value_ptr()->first));
+ BOOST_RETHROW
}
BOOST_CATCH_END
return a.release();
}
+
+#endif
}
}
}
@@ -1788,13 +1952,13 @@ namespace iterator_detail {
//
// all no throw
-template <typename Node, typename Policy>
+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&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
- template <typename Node2, typename Policy2>
+ template <typename Node2>
friend struct boost::unordered::iterator_detail::cl_iterator;
private:
@@ -1823,7 +1987,7 @@ struct l_iterator : public std::iterator<std::forward_iterator_tag,
l_iterator& operator++()
{
ptr_ = static_cast<node_pointer>(ptr_->next_);
- if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_)
+ if (ptr_ && ptr_->get_bucket() != bucket_)
ptr_ = node_pointer();
return *this;
}
@@ -1846,13 +2010,13 @@ struct l_iterator : public std::iterator<std::forward_iterator_tag,
}
};
-template <typename Node, typename Policy>
+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&>
{
- friend struct boost::unordered::iterator_detail::l_iterator<Node, Policy>;
+ friend struct boost::unordered::iterator_detail::l_iterator<Node>;
private:
typedef typename Node::node_pointer node_pointer;
@@ -1872,8 +2036,7 @@ struct cl_iterator
{
}
- cl_iterator(
- boost::unordered::iterator_detail::l_iterator<Node, Policy> const& x)
+ cl_iterator(boost::unordered::iterator_detail::l_iterator<Node> const& x)
BOOST_NOEXCEPT : ptr_(x.ptr_),
bucket_(x.bucket_),
bucket_count_(x.bucket_count_)
@@ -1887,7 +2050,7 @@ struct cl_iterator
cl_iterator& operator++()
{
ptr_ = static_cast<node_pointer>(ptr_->next_);
- if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_)
+ if (ptr_ && ptr_->get_bucket() != bucket_)
ptr_ = node_pointer();
return *this;
}
@@ -1921,9 +2084,6 @@ struct iterator : public std::iterator<std::forward_iterator_tag,
template <typename>
friend struct boost::unordered::iterator_detail::c_iterator;
template <typename> friend struct boost::unordered::detail::table;
- template <typename> friend struct boost::unordered::detail::table_impl;
- template <typename>
- friend struct boost::unordered::detail::grouped_table_impl;
private:
#endif
@@ -1978,9 +2138,6 @@ struct c_iterator
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename> friend struct boost::unordered::detail::table;
- template <typename> friend struct boost::unordered::detail::table_impl;
- template <typename>
- friend struct boost::unordered::detail::grouped_table_impl;
private:
#endif
@@ -2076,7 +2233,6 @@ template <typename NodeAlloc> struct node_holder
{
node_pointer n = nodes_;
nodes_ = static_cast<node_pointer>(nodes_->next_);
- n->init(n);
n->next_ = link_pointer();
return n;
}
@@ -2088,7 +2244,7 @@ template <typename NodeAlloc> struct node_holder
} else {
constructor_.create_node();
}
- boost::unordered::detail::func::call_construct(
+ BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits,
constructor_.alloc_, constructor_.node_->value_ptr(), v);
return constructor_.release();
}
@@ -2100,8 +2256,9 @@ template <typename NodeAlloc> struct node_holder
} else {
constructor_.create_node();
}
- boost::unordered::detail::func::call_construct(constructor_.alloc_,
- constructor_.node_->value_ptr(), boost::move(v));
+ BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits,
+ constructor_.alloc_, constructor_.node_->value_ptr(),
+ boost::move(v));
return constructor_.release();
}
@@ -2114,9 +2271,9 @@ template <typename Alloc> node_holder<Alloc>::~node_holder()
node_pointer p = nodes_;
nodes_ = static_cast<node_pointer>(p->next_);
- boost::unordered::detail::func::call_destroy(
- constructor_.alloc_, p->value_ptr());
- boost::unordered::detail::func::destroy(boost::addressof(*p));
+ BOOST_UNORDERED_CALL_DESTROY(
+ node_allocator_traits, constructor_.alloc_, p->value_ptr());
+ boost::unordered::detail::func::destroy(pointer<node>::get(p));
node_allocator_traits::deallocate(constructor_.alloc_, p, 1);
}
}
@@ -2131,6 +2288,7 @@ template <typename NodePointer> struct bucket
link_pointer next_;
bucket() : next_() {}
+ bucket(link_pointer n) : next_(n) {}
link_pointer first_from_start() { return next_; }
@@ -2146,6 +2304,7 @@ struct ptr_bucket
link_pointer next_;
ptr_bucket() : next_(0) {}
+ ptr_bucket(link_pointer n) : next_(n) {}
link_pointer first_from_start() { return this; }
@@ -2332,13 +2491,13 @@ template <class H, class P> class functions
function_pair const& current() const
{
return *static_cast<function_pair const*>(
- static_cast<void const*>(&funcs_[current_]));
+ static_cast<void const*>(funcs_[current_].address()));
}
function_pair& current()
{
return *static_cast<function_pair*>(
- static_cast<void*>(&funcs_[current_]));
+ static_cast<void*>(funcs_[current_].address()));
}
void construct(bool which, H const& hf, P const& eq)
@@ -2549,7 +2708,6 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
typedef typename Types::c_iterator c_iterator;
typedef typename Types::l_iterator l_iterator;
typedef typename Types::cl_iterator cl_iterator;
- typedef typename Types::node_algo node_algo;
typedef boost::unordered::detail::functions<typename Types::hasher,
typename Types::key_equal>
@@ -2572,6 +2730,8 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
node_constructor;
typedef boost::unordered::detail::node_tmp<node_allocator> node_tmp;
+ typedef std::pair<iterator, bool> emplace_return;
+
////////////////////////////////////////////////////////////////////////
// Members
@@ -2586,6 +2746,45 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
////////////////////////////////////////////////////////////////////////
// Data access
+ static node_pointer get_node(c_iterator it) { return it.node_; }
+
+ static node_pointer next_node(link_pointer n)
+ {
+ return static_cast<node_pointer>(n->next_);
+ }
+
+ static node_pointer next_for_find(link_pointer n)
+ {
+ node_pointer n2 = static_cast<node_pointer>(n);
+ do {
+ n2 = next_node(n2);
+ } while (n2 && !n2->is_first_in_group());
+ return n2;
+ }
+
+ node_pointer next_group(node_pointer n) const
+ {
+ node_pointer n1 = n;
+ do {
+ n1 = next_node(n1);
+ } while (n1 && !n1->is_first_in_group());
+ return n1;
+ }
+
+ std::size_t group_count(node_pointer n) const
+ {
+ std::size_t x = 0;
+ node_pointer it = n;
+ do {
+ ++x;
+ it = next_node(it);
+ } while (it && !it->is_first_in_group());
+
+ return x;
+ }
+
+ std::size_t node_bucket(node_pointer n) const { return n->get_bucket(); }
+
bucket_allocator const& bucket_alloc() const { return allocators_.first(); }
node_allocator const& node_alloc() const { return allocators_.second(); }
@@ -2619,8 +2818,7 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
node_pointer begin() const
{
- return size_ ? node_algo::next_node(get_previous_start())
- : node_pointer();
+ return size_ ? next_node(get_previous_start()) : node_pointer();
}
node_pointer begin(std::size_t bucket_index) const
@@ -2628,7 +2826,7 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
if (!size_)
return node_pointer();
link_pointer prev = get_previous_start(bucket_index);
- return prev ? node_algo::next_node(prev) : node_pointer();
+ return prev ? next_node(prev) : node_pointer();
}
std::size_t hash_to_bucket(std::size_t hash_value) const
@@ -2636,12 +2834,6 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
return policy::to_bucket(bucket_count_, hash_value);
}
- float load_factor() const
- {
- BOOST_ASSERT(bucket_count_ != 0);
- return static_cast<float>(size_) / static_cast<float>(bucket_count_);
- }
-
std::size_t bucket_size(std::size_t index) const
{
node_pointer n = begin(index);
@@ -2649,9 +2841,9 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
return 0;
std::size_t count = 0;
- while (n && hash_to_bucket(n->hash_) == index) {
+ while (n && node_bucket(n) == index) {
++count;
- n = node_algo::next_node(n);
+ n = next_node(n);
}
return count;
@@ -2660,17 +2852,6 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
////////////////////////////////////////////////////////////////////////
// Load methods
- std::size_t max_size() const
- {
- using namespace std;
-
- // size < mlf_ * count
- return boost::unordered::detail::double_to_size(
- ceil(static_cast<double>(mlf_) *
- static_cast<double>(max_bucket_count()))) -
- 1;
- }
-
void recalculate_max_load()
{
using namespace std;
@@ -2742,79 +2923,68 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
table(
table& x, node_allocator const& a, boost::unordered::detail::move_tag m)
: functions(x, m), allocators_(a, a), bucket_count_(x.bucket_count_),
- size_(0), mlf_(x.mlf_), max_load_(x.max_load_), buckets_()
+ size_(0), mlf_(x.mlf_), max_load_(0), buckets_()
{
}
////////////////////////////////////////////////////////////////////////
- // Initialisation.
-
- void init(table const& x)
- {
- if (x.size_) {
- static_cast<table_impl*>(this)->copy_buckets(x);
- }
- }
-
- void move_init(table& x)
+ // Clear buckets and Create buckets
+ //
+ // IMPORTANT: If the container already contains any elements, the
+ // buckets will not contain any links to them. This will
+ // need to be dealt with, for example by:
+ // - deleting them
+ // - putting them in a 'node_holder' for future use
+ // (as in assignment)
+ // - placing them in buckets (see rehash_impl)
+
+ // Clear the bucket pointers.
+ void clear_buckets()
{
- if (node_alloc() == x.node_alloc()) {
- move_buckets_from(x);
- } else if (x.size_) {
- // TODO: Could pick new bucket size?
- static_cast<table_impl*>(this)->move_buckets(x);
+ bucket_pointer end = get_bucket(bucket_count_);
+ for (bucket_pointer it = buckets_; it != end; ++it) {
+ it->next_ = node_pointer();
}
}
- ////////////////////////////////////////////////////////////////////////
- // Create buckets
-
+ // Create container buckets. If the container already contains any buckets
+ // the linked list will be transferred to the new buckets, but none
+ // of the bucket pointers will be set. See above note.
+ //
+ // Strong exception safety.
void create_buckets(std::size_t new_count)
{
- std::size_t length = new_count + 1;
- bucket_pointer new_buckets =
- bucket_allocator_traits::allocate(bucket_alloc(), length);
- bucket_pointer constructed = new_buckets;
-
- BOOST_TRY
- {
- bucket_pointer end =
- new_buckets + static_cast<std::ptrdiff_t>(length);
- for (; constructed != end; ++constructed) {
- new ((void*)boost::addressof(*constructed)) bucket();
- }
-
- if (buckets_) {
- // Copy the nodes to the new buckets, including the dummy
- // node if there is one.
- (new_buckets + static_cast<std::ptrdiff_t>(new_count))->next_ =
- (buckets_ + static_cast<std::ptrdiff_t>(bucket_count_))
- ->next_;
- destroy_buckets();
- } else if (bucket::extra_node) {
- node_constructor a(node_alloc());
- a.create_node();
-
- (new_buckets + static_cast<std::ptrdiff_t>(new_count))->next_ =
- a.release();
- }
- }
- BOOST_CATCH(...)
- {
- for (bucket_pointer p = new_buckets; p != constructed; ++p) {
- boost::unordered::detail::func::destroy(boost::addressof(*p));
- }
+ link_pointer dummy_node;
- bucket_allocator_traits::deallocate(
- bucket_alloc(), new_buckets, length);
-
- BOOST_RETHROW;
+ // Construct the new buckets and dummy node, and destroy the old buckets
+ if (buckets_) {
+ dummy_node =
+ (buckets_ + static_cast<std::ptrdiff_t>(bucket_count_))->next_;
+ bucket_pointer new_buckets = bucket_allocator_traits::allocate(
+ bucket_alloc(), new_count + 1);
+ destroy_buckets();
+ buckets_ = new_buckets;
+ } else if (bucket::extra_node) {
+ node_constructor a(node_alloc());
+ a.create_node();
+ buckets_ = bucket_allocator_traits::allocate(
+ bucket_alloc(), new_count + 1);
+ dummy_node = a.release();
+ } else {
+ dummy_node = link_pointer();
+ buckets_ = bucket_allocator_traits::allocate(
+ bucket_alloc(), new_count + 1);
}
- BOOST_CATCH_END
+ // nothrow from here...
bucket_count_ = new_count;
- buckets_ = new_buckets;
recalculate_max_load();
+
+ 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 (pointer<void>::get(end)) bucket(dummy_node);
}
////////////////////////////////////////////////////////////////////////
@@ -2865,6 +3035,7 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
buckets_ = other.buckets_;
bucket_count_ = other.bucket_count_;
size_ = other.size_;
+ max_load_ = other.max_load_;
other.buckets_ = bucket_pointer();
other.size_ = 0;
other.max_load_ = 0;
@@ -2875,69 +3046,37 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
~table() { delete_buckets(); }
- void delete_node(link_pointer prev)
+ void destroy_node(node_pointer n)
{
- node_pointer n = static_cast<node_pointer>(prev->next_);
- prev->next_ = n->next_;
-
- boost::unordered::detail::func::call_destroy(
- node_alloc(), n->value_ptr());
- boost::unordered::detail::func::destroy(boost::addressof(*n));
+ BOOST_UNORDERED_CALL_DESTROY(
+ node_allocator_traits, node_alloc(), n->value_ptr());
+ boost::unordered::detail::func::destroy(pointer<node>::get(n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
- --size_;
- }
-
- std::size_t delete_nodes(link_pointer prev, link_pointer end)
- {
- BOOST_ASSERT(prev->next_ != end);
-
- std::size_t count = 0;
-
- do {
- delete_node(prev);
- ++count;
- } while (prev->next_ != end);
-
- return count;
}
void delete_buckets()
{
if (buckets_) {
- if (size_)
- delete_nodes(get_previous_start(), link_pointer());
+ node_pointer n =
+ static_cast<node_pointer>(get_bucket(bucket_count_)->next_);
if (bucket::extra_node) {
- node_pointer n =
- static_cast<node_pointer>(get_bucket(bucket_count_)->next_);
- boost::unordered::detail::func::destroy(boost::addressof(*n));
+ node_pointer next = next_node(n);
+ boost::unordered::detail::func::destroy(pointer<node>::get(n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
+ n = next;
+ }
+
+ while (n) {
+ node_pointer next = next_node(n);
+ destroy_node(n);
+ n = next;
}
destroy_buckets();
buckets_ = bucket_pointer();
max_load_ = 0;
- }
-
- BOOST_ASSERT(!size_);
- }
-
- void clear()
- {
- if (!size_)
- return;
-
- delete_nodes(get_previous_start(), link_pointer());
- clear_buckets();
-
- BOOST_ASSERT(!size_);
- }
-
- void clear_buckets()
- {
- bucket_pointer end = get_bucket(bucket_count_);
- for (bucket_pointer it = buckets_; it != end; ++it) {
- it->next_ = node_pointer();
+ size_ = 0;
}
}
@@ -2945,7 +3084,7 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
{
bucket_pointer end = get_bucket(bucket_count_ + 1);
for (bucket_pointer it = buckets_; it != end; ++it) {
- boost::unordered::detail::func::destroy(boost::addressof(*it));
+ boost::unordered::detail::func::destroy(pointer<bucket>::get(it));
}
bucket_allocator_traits::deallocate(
@@ -2953,74 +3092,81 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
}
////////////////////////////////////////////////////////////////////////
- // Fix buckets after delete
+ // Fix buckets after delete/extract
//
+ // (prev,next) should mark an open range of nodes in a single bucket which
+ // have either been unlinked, or are about to be.
- std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev)
+ std::size_t fix_bucket(
+ std::size_t bucket_index, link_pointer prev, node_pointer next)
{
- link_pointer end = prev->next_;
std::size_t bucket_index2 = bucket_index;
- if (end) {
- bucket_index2 =
- hash_to_bucket(static_cast<node_pointer>(end)->hash_);
+ if (next) {
+ bucket_index2 = node_bucket(next);
- // If begin and end are in the same bucket, then
- // there's nothing to do.
- if (bucket_index == bucket_index2)
+ // If next is in the same bucket, then there's nothing to do.
+ if (bucket_index == bucket_index2) {
return bucket_index2;
+ }
- // Update the bucket containing end.
+ // Update the bucket containing next.
get_bucket(bucket_index2)->next_ = prev;
}
// Check if this bucket is now empty.
bucket_pointer this_bucket = get_bucket(bucket_index);
- if (this_bucket->next_ == prev)
+ if (this_bucket->next_ == prev) {
this_bucket->next_ = link_pointer();
+ }
return bucket_index2;
}
////////////////////////////////////////////////////////////////////////
+ // Clear
+
+ void clear_impl();
+
+ ////////////////////////////////////////////////////////////////////////
// Assignment
- void assign(table const& x)
+ template <typename UniqueType>
+ void assign(table const& x, UniqueType is_unique)
{
- if (this != boost::addressof(x)) {
- assign(x, boost::unordered::detail::integral_constant<bool,
- allocator_traits<node_allocator>::
- propagate_on_container_copy_assignment::value>());
+ if (this != &x) {
+ assign(x, is_unique,
+ boost::unordered::detail::integral_constant<bool,
+ allocator_traits<node_allocator>::
+ propagate_on_container_copy_assignment::value>());
}
}
- void assign(table const& x, false_type)
+ template <typename UniqueType>
+ 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();
- if (!size_ && !x.size_) {
- new_func_this.commit();
- return;
- }
-
if (x.size_ >= max_load_) {
create_buckets(min_buckets_for_size(x.size_));
- } else {
+ } else if (size_) {
clear_buckets();
}
new_func_this.commit();
- static_cast<table_impl*>(this)->assign_buckets(x);
+
+ assign_buckets(x, is_unique);
}
- void assign(table const& x, true_type)
+ template <typename UniqueType>
+ void assign(table const& x, UniqueType is_unique, true_type)
{
if (node_alloc() == x.node_alloc()) {
allocators_.assign(x.allocators_);
- assign(x, false_type());
+ assign(x, is_unique, false_type());
} else {
set_hash_functions new_func_this(*this, x);
@@ -3033,45 +3179,46 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
new_func_this.commit();
mlf_ = x.mlf_;
bucket_count_ = min_buckets_for_size(x.size_);
- max_load_ = 0;
// Finally copy the elements.
if (x.size_) {
- static_cast<table_impl*>(this)->copy_buckets(x);
+ copy_buckets(x, is_unique);
}
}
}
- void move_assign(table& x)
+ template <typename UniqueType>
+ void move_assign(table& x, UniqueType is_unique)
{
- if (this != boost::addressof(x)) {
+ if (this != &x) {
move_assign(
- x, boost::unordered::detail::integral_constant<bool,
- allocator_traits<node_allocator>::
- propagate_on_container_move_assignment::value>());
+ x, is_unique,
+ boost::unordered::detail::integral_constant<bool,
+ allocator_traits<node_allocator>::
+ propagate_on_container_move_assignment::value>());
}
}
- void move_assign(table& x, true_type)
+ template <typename UniqueType>
+ void move_assign(table& x, UniqueType, true_type)
{
delete_buckets();
set_hash_functions new_func_this(*this, x);
allocators_.move_assign(x.allocators_);
// No throw from here.
mlf_ = x.mlf_;
- max_load_ = x.max_load_;
move_buckets_from(x);
new_func_this.commit();
}
- void move_assign(table& x, false_type)
+ 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_;
- max_load_ = x.max_load_;
move_buckets_from(x);
new_func_this.commit();
} else {
@@ -3079,27 +3226,23 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
mlf_ = x.mlf_;
recalculate_max_load();
- if (!size_ && !x.size_) {
- new_func_this.commit();
- return;
- }
-
if (x.size_ >= max_load_) {
create_buckets(min_buckets_for_size(x.size_));
- } else {
+ } else if (size_) {
clear_buckets();
}
new_func_this.commit();
- static_cast<table_impl*>(this)->move_assign_buckets(x);
+
+ move_assign_buckets(x, is_unique);
}
}
// Accessors
- const_key_type& get_key(value_type const& x) const
+ const_key_type& get_key(node_pointer n) const
{
- return extractor::extract(x);
+ return extractor::extract(n->value());
}
std::size_t hash(const_key_type& k) const
@@ -3109,13 +3252,6 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
// Find Node
- template <typename Key, typename Hash, typename Pred>
- node_pointer generic_find_node(
- Key const& k, Hash const& hf, Pred const& eq) const
- {
- return this->find_node_impl(policy::apply_hash(hf, k), k, eq);
- }
-
node_pointer find_node(std::size_t key_hash, const_key_type& k) const
{
return this->find_node_impl(key_hash, k, this->key_eq());
@@ -3137,22 +3273,18 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
if (!n)
return n;
- std::size_t node_hash = n->hash_;
- if (key_hash == node_hash) {
- if (eq(k, this->get_key(n->value())))
- return n;
- } else {
- if (this->hash_to_bucket(node_hash) != bucket_index)
- return node_pointer();
+ if (eq(k, this->get_key(n))) {
+ return n;
+ } else if (this->node_bucket(n) != bucket_index) {
+ return node_pointer();
}
- n = node_algo::next_for_find(n);
+ n = next_for_find(n);
}
}
// Find the node before the key, so that it can be erased.
- link_pointer find_previous_node(
- const_key_type& k, std::size_t key_hash, std::size_t bucket_index)
+ link_pointer find_previous_node(const_key_type& k, std::size_t bucket_index)
{
link_pointer prev = this->get_previous_start(bucket_index);
if (!prev) {
@@ -3160,19 +3292,17 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
}
for (;;) {
- if (!prev->next_) {
+ node_pointer n = next_node(prev);
+ if (!n) {
return link_pointer();
+ } else if (n->is_first_in_group()) {
+ if (node_bucket(n) != bucket_index) {
+ return link_pointer();
+ } else if (this->key_eq()(k, this->get_key(n))) {
+ return prev;
+ }
}
- std::size_t node_hash = node_algo::next_node(prev)->hash_;
- if (this->hash_to_bucket(node_hash) != bucket_index) {
- return link_pointer();
- }
- if (node_hash == key_hash &&
- this->key_eq()(
- k, this->get_key(node_algo::next_node(prev)->value()))) {
- return prev;
- }
- prev = node_algo::next_for_erase(prev);
+ prev = n;
}
}
@@ -3185,13 +3315,18 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
}
std::size_t key_hash = this->hash(k);
std::size_t bucket_index = this->hash_to_bucket(key_hash);
- link_pointer prev = this->find_previous_node(k, key_hash, bucket_index);
+ link_pointer prev = this->find_previous_node(k, bucket_index);
if (!prev) {
return node_pointer();
}
- node_pointer n = node_algo::extract_first_node(prev);
+ node_pointer n = next_node(prev);
+ node_pointer n2 = next_node(n);
+ if (n2) {
+ n2->set_first_in_group();
+ }
+ prev->next_ = n2;
--this->size_;
- this->fix_bucket(bucket_index, prev);
+ this->fix_bucket(bucket_index, prev, n2);
n->next_ = link_pointer();
return n;
@@ -3203,502 +3338,19 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
void rehash(std::size_t);
void reserve(std::size_t);
void rehash_impl(std::size_t);
-};
-
-////////////////////////////////////////////////////////////////////////////
-// Reserve & Rehash
-
-// basic exception safety
-template <typename Types>
-inline void table<Types>::reserve_for_insert(std::size_t size)
-{
- if (!buckets_) {
- create_buckets((std::max)(bucket_count_, min_buckets_for_size(size)));
- } else if (size > max_load_) {
- std::size_t num_buckets =
- min_buckets_for_size((std::max)(size, size_ + (size_ >> 1)));
-
- if (num_buckets != bucket_count_)
- this->rehash_impl(num_buckets);
- }
-}
-
-// if hash function throws, basic exception safety
-// strong otherwise.
-
-template <typename Types>
-inline void table<Types>::rehash(std::size_t min_buckets)
-{
- using namespace std;
-
- if (!size_) {
- delete_buckets();
- bucket_count_ = policy::new_bucket_count(min_buckets);
- } else {
- min_buckets = policy::new_bucket_count((std::max)(min_buckets,
- boost::unordered::detail::double_to_size(
- floor(static_cast<double>(size_) / static_cast<double>(mlf_))) +
- 1));
-
- if (min_buckets != bucket_count_)
- this->rehash_impl(min_buckets);
- }
-}
-
-template <typename Types>
-inline void table<Types>::reserve(std::size_t num_elements)
-{
- rehash(static_cast<std::size_t>(
- std::ceil(static_cast<double>(num_elements) / mlf_)));
-}
-
-template <typename Types>
-inline void table<Types>::rehash_impl(std::size_t num_buckets)
-{
- BOOST_ASSERT(this->buckets_);
-
- this->create_buckets(num_buckets);
- link_pointer prev = this->get_previous_start();
- while (prev->next_) {
- node_pointer group_last = node_algo::last_for_rehash(prev);
- bucket_pointer b =
- this->get_bucket(this->hash_to_bucket(group_last->hash_));
- if (!b->next_) {
- b->next_ = prev;
- prev = group_last;
- } else {
- link_pointer next = group_last->next_;
- group_last->next_ = b->next_->next_;
- b->next_->next_ = prev->next_;
- prev->next_ = next;
- }
- }
-}
-
-#if defined(BOOST_MSVC)
-#pragma warning(pop)
-#endif
-
-////////////////////////////////////////////////////////////////////////
-// key extractors
-//
-// no throw
-//
-// 'extract_key' is called with the emplace parameters to return a
-// key if available or 'no_key' is one isn't and will need to be
-// constructed. This could be done by overloading the emplace implementation
-// for the different cases, but that's a bit tricky on compilers without
-// variadic templates.
-
-struct no_key
-{
- no_key() {}
- template <class T> no_key(T const&) {}
-};
-
-template <typename Key, typename T> struct is_key
-{
- template <typename T2> static choice1::type test(T2 const&);
- static choice2::type test(Key const&);
-
- enum
- {
- value = sizeof(test(boost::unordered::detail::make<T>())) ==
- sizeof(choice2::type)
- };
-
- typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE
- then<Key const&, no_key>::type type;
-};
-
-template <class ValueType> struct set_extractor
-{
- typedef ValueType value_type;
- typedef ValueType key_type;
-
- static key_type const& extract(value_type const& v) { return v; }
-
- static no_key extract() { return no_key(); }
-
- template <class Arg> static no_key extract(Arg const&) { return no_key(); }
-
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- template <class Arg1, class Arg2, class... Args>
- static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
- {
- return no_key();
- }
-#else
- template <class Arg1, class Arg2>
- static no_key extract(Arg1 const&, Arg2 const&)
- {
- return no_key();
- }
-#endif
-};
-
-template <class ValueType> struct map_extractor
-{
- typedef ValueType value_type;
- typedef typename boost::remove_const<typename boost::unordered::detail::
- pair_traits<ValueType>::first_type>::type key_type;
-
- static key_type const& extract(value_type const& v) { return v.first; }
-
- template <class Second>
- static key_type const& extract(std::pair<key_type, Second> const& v)
- {
- return v.first;
- }
-
- template <class Second>
- static key_type const& extract(std::pair<key_type const, Second> const& v)
- {
- return v.first;
- }
-
- template <class Arg1>
- static key_type const& extract(key_type const& k, Arg1 const&)
- {
- return k;
- }
-
- static no_key extract() { return no_key(); }
-
- template <class Arg> static no_key extract(Arg const&) { return no_key(); }
-
- template <class Arg1, class Arg2>
- static no_key extract(Arg1 const&, Arg2 const&)
- {
- return no_key();
- }
-
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- template <class Arg1, class Arg2, class Arg3, class... Args>
- static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, Args const&...)
- {
- return no_key();
- }
-#endif
-
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
-
-#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
- template <typename T2> \
- static no_key extract(boost::unordered::piecewise_construct_t, \
- namespace_ tuple<> const&, T2 const&) \
- { \
- return no_key(); \
- } \
- \
- template <typename T, typename T2> \
- static typename is_key<key_type, T>::type extract( \
- boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k, \
- T2 const&) \
- { \
- return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \
- }
-
-#else
-
-#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
- static no_key extract( \
- boost::unordered::piecewise_construct_t, namespace_ tuple<> const&) \
- { \
- return no_key(); \
- } \
- \
- template <typename T> \
- static typename is_key<key_type, T>::type extract( \
- boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k) \
- { \
- return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \
- }
-
-#endif
-
- BOOST_UNORDERED_KEY_FROM_TUPLE(boost::)
-
-#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
- BOOST_UNORDERED_KEY_FROM_TUPLE(std::)
-#endif
-};
-
-////////////////////////////////////////////////////////////////////////
-// Unique nodes
-
-template <typename A, typename T>
-struct unique_node : boost::unordered::detail::value_base<T>
-{
- typedef typename ::boost::unordered::detail::rebind_wrap<A,
- unique_node<A, T> >::type allocator;
- typedef typename ::boost::unordered::detail::allocator_traits<
- allocator>::pointer node_pointer;
- typedef node_pointer link_pointer;
- typedef typename ::boost::unordered::detail::rebind_wrap<A,
- bucket<node_pointer> >::type bucket_allocator;
- typedef typename ::boost::unordered::detail::allocator_traits<
- bucket_allocator>::pointer bucket_pointer;
-
- link_pointer next_;
- std::size_t hash_;
-
- unique_node() : next_(), hash_(0) {}
-
- void init(node_pointer) {}
-
- private:
- unique_node& operator=(unique_node const&);
-};
-
-template <typename T> struct ptr_node : boost::unordered::detail::ptr_bucket
-{
- typedef T value_type;
- typedef boost::unordered::detail::ptr_bucket bucket_base;
- typedef ptr_node<T>* node_pointer;
- typedef ptr_bucket* link_pointer;
- typedef ptr_bucket* bucket_pointer;
-
- std::size_t hash_;
- boost::unordered::detail::value_base<T> value_base_;
-
- ptr_node() : bucket_base(), hash_(0) {}
-
- void init(node_pointer) {}
-
- void* address() { return value_base_.address(); }
- value_type& value() { return value_base_.value(); }
- value_type* value_ptr() { return value_base_.value_ptr(); }
-
- private:
- ptr_node& operator=(ptr_node const&);
-};
-
-template <typename N> struct node_algo
-{
- typedef typename N::node_pointer node_pointer;
- typedef typename N::link_pointer link_pointer;
- typedef typename N::bucket_pointer bucket_pointer;
-
- static node_pointer next_node(link_pointer n)
- {
- return static_cast<node_pointer>(n->next_);
- }
-
- static node_pointer next_for_find(node_pointer n)
- {
- return static_cast<node_pointer>(n->next_);
- }
-
- static link_pointer next_for_erase(link_pointer prev)
- {
- return prev->next_;
- }
-
- // Group together all nodes with equal hash value, this may
- // include nodes with different keys, but that's okay because
- // they will end up in the same bucket.
- static node_pointer last_for_rehash(link_pointer prev)
- {
- node_pointer n = next_node(prev);
- std::size_t hash = n->hash_;
- for (;;) {
- node_pointer next = next_node(n);
- if (!next || next->hash_ != hash) {
- return n;
- }
- n = next;
- }
- }
-
- template <typename Table>
- static node_pointer next_group(node_pointer n, Table const* t)
- {
- node_pointer n1 = n;
- do {
- n1 = next_node(n1);
- } while (
- n1 && t->key_eq()(t->get_key(n->value()), t->get_key(n1->value())));
- return n1;
- }
-
- template <typename Table>
- static std::size_t count(node_pointer n, Table const* t)
- {
- std::size_t x = 0;
- node_pointer it = n;
- do {
- ++x;
- it = next_node(it);
- } while (
- it && t->key_eq()(t->get_key(n->value()), t->get_key(it->value())));
-
- return x;
- }
-
- // Add node 'n' after 'pos'.
- // This results in a different order to the grouped implementation.
- static inline void add_to_node_group(node_pointer n, node_pointer pos)
- {
- n->next_ = pos->next_;
- pos->next_ = n;
- }
-
- static inline node_pointer extract_first_node(link_pointer prev)
- {
- node_pointer n = next_node(prev);
- prev->next_ = n->next_;
- return n;
- }
-
- static link_pointer split_groups(node_pointer, node_pointer)
- {
- return link_pointer();
- }
-};
-
-// If the allocator uses raw pointers use ptr_node
-// Otherwise use node.
-
-template <typename A, typename T, typename NodePtr, typename BucketPtr>
-struct pick_node2
-{
- typedef boost::unordered::detail::unique_node<A, T> node;
-
- typedef typename boost::unordered::detail::allocator_traits<
- typename boost::unordered::detail::rebind_wrap<A, node>::type>::pointer
- node_pointer;
-
- typedef boost::unordered::detail::bucket<node_pointer> bucket;
- typedef node_pointer link_pointer;
-};
-
-template <typename A, typename T>
-struct pick_node2<A, T, boost::unordered::detail::ptr_node<T>*,
- boost::unordered::detail::ptr_bucket*>
-{
- typedef boost::unordered::detail::ptr_node<T> node;
- typedef boost::unordered::detail::ptr_bucket bucket;
- typedef bucket* link_pointer;
-};
-
-template <typename A, typename T> struct pick_node
-{
- typedef typename boost::remove_const<T>::type nonconst;
-
- typedef boost::unordered::detail::allocator_traits<
- typename boost::unordered::detail::rebind_wrap<A,
- boost::unordered::detail::ptr_node<nonconst> >::type>
- tentative_node_traits;
-
- typedef boost::unordered::detail::allocator_traits<
- typename boost::unordered::detail::rebind_wrap<A,
- boost::unordered::detail::ptr_bucket>::type>
- tentative_bucket_traits;
-
- typedef pick_node2<A, nonconst, typename tentative_node_traits::pointer,
- typename tentative_bucket_traits::pointer>
- pick;
-
- typedef typename pick::node node;
- typedef typename pick::bucket bucket;
- typedef typename pick::link_pointer link_pointer;
- typedef boost::unordered::detail::node_algo<node> node_algo;
-};
-
-template <typename Types>
-struct table_impl : boost::unordered::detail::table<Types>
-{
- typedef boost::unordered::detail::table<Types> table;
- typedef typename table::value_type value_type;
- typedef typename table::node node;
- typedef typename table::bucket bucket;
- typedef typename table::policy policy;
- typedef typename table::node_pointer node_pointer;
- typedef typename table::node_allocator node_allocator;
- typedef typename table::node_allocator_traits node_allocator_traits;
- typedef typename table::bucket_pointer bucket_pointer;
- typedef typename table::link_pointer link_pointer;
- typedef typename table::hasher hasher;
- typedef typename table::key_equal key_equal;
- typedef typename table::const_key_type const_key_type;
- typedef typename table::node_constructor node_constructor;
- typedef typename table::node_tmp node_tmp;
- typedef typename table::extractor extractor;
- typedef typename table::iterator iterator;
- typedef typename table::c_iterator c_iterator;
- typedef typename table::node_algo node_algo;
-
- typedef std::pair<iterator, bool> emplace_return;
-
- // Constructors
-
- table_impl(std::size_t n, hasher const& hf, key_equal const& eq,
- node_allocator const& a)
- : table(n, hf, eq, a)
- {
- }
-
- table_impl(table_impl const& x)
- : table(x, node_allocator_traits::select_on_container_copy_construction(
- x.node_alloc()))
- {
- this->init(x);
- }
-
- table_impl(table_impl const& x, node_allocator const& a) : table(x, a)
- {
- this->init(x);
- }
-
- table_impl(table_impl& x, boost::unordered::detail::move_tag m)
- : table(x, m)
- {
- }
-
- table_impl(table_impl& x, node_allocator const& a,
- boost::unordered::detail::move_tag m)
- : table(x, a, m)
- {
- this->move_init(x);
- }
-
- // Accessors
- std::size_t count(const_key_type& k) const
- {
- return this->find_node(k) ? 1 : 0;
- }
-
- value_type& at(const_key_type& k) const
- {
- if (this->size_) {
- node_pointer n = this->find_node(k);
- if (n)
- return n->value();
- }
-
- boost::throw_exception(
- std::out_of_range("Unable to find key in unordered_map."));
- }
-
- std::pair<iterator, iterator> equal_range(const_key_type& k) const
- {
- node_pointer n = this->find_node(k);
- return std::make_pair(
- iterator(n), iterator(n ? node_algo::next_node(n) : n));
- }
+ ////////////////////////////////////////////////////////////////////////
+ // Unique keys
// equals
- bool equals(table_impl const& other) const
+ bool equals_unique(table const& other) const
{
if (this->size_ != other.size_)
return false;
- for (node_pointer n1 = this->begin(); n1;
- n1 = node_algo::next_node(n1)) {
- node_pointer n2 = other.find_node(other.get_key(n1->value()));
+ for (node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) {
+ node_pointer n2 = other.find_node(other.get_key(n1));
if (!n2 || n1->value() != n2->value())
return false;
@@ -3709,19 +3361,20 @@ struct table_impl : boost::unordered::detail::table<Types>
// Emplace/Insert
- inline node_pointer add_node(node_pointer n, std::size_t key_hash)
+ inline node_pointer add_node_unique(node_pointer n, std::size_t key_hash)
{
- n->hash_ = 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(this->hash_to_bucket(key_hash));
+ // TODO: Do this need to set_first_in_group ?
+ n->bucket_info_ = bucket_index;
+ // n->set_first_in_group();
if (!b->next_) {
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
- this->get_bucket(this->hash_to_bucket(
- node_algo::next_node(start_node)->hash_))
- ->next_ = n;
+ this->get_bucket(node_bucket(next_node(start_node)))->next_ = n;
}
b->next_ = start_node;
@@ -3736,102 +3389,28 @@ struct table_impl : boost::unordered::detail::table<Types>
return n;
}
- inline node_pointer resize_and_add_node(
+ inline node_pointer resize_and_add_node_unique(
node_pointer n, std::size_t key_hash)
{
node_tmp b(n, this->node_alloc());
this->reserve_for_insert(this->size_ + 1);
- return this->add_node(b.release(), key_hash);
- }
-
-#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
-#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- emplace_return emplace(boost::unordered::detail::emplace_args1<
- boost::unordered::detail::please_ignore_this_overload> const&)
- {
- BOOST_ASSERT(false);
- return emplace_return(iterator(), false);
- }
-
- iterator emplace_hint(
- c_iterator,
- boost::unordered::detail::emplace_args1<
- boost::unordered::detail::please_ignore_this_overload> const&)
- {
- BOOST_ASSERT(false);
- return iterator();
- }
-#else
- emplace_return emplace(
- boost::unordered::detail::please_ignore_this_overload const&)
- {
- BOOST_ASSERT(false);
- return emplace_return(iterator(), false);
- }
-
- iterator emplace_hint(c_iterator,
- boost::unordered::detail::please_ignore_this_overload const&)
- {
- BOOST_ASSERT(false);
- return iterator();
- }
-#endif
-#endif
-
- template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
- {
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- return emplace_impl(extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
- BOOST_UNORDERED_EMPLACE_FORWARD);
-#else
- return emplace_impl(extractor::extract(args.a0, args.a1),
- BOOST_UNORDERED_EMPLACE_FORWARD);
-#endif
+ return this->add_node_unique(b.release(), key_hash);
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS)
- {
-#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- return emplace_hint_impl(hint,
- extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
- BOOST_UNORDERED_EMPLACE_FORWARD);
-#else
- return emplace_hint_impl(hint, extractor::extract(args.a0, args.a1),
- BOOST_UNORDERED_EMPLACE_FORWARD);
-#endif
- }
-
-#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- template <typename A0>
- emplace_return emplace(
- boost::unordered::detail::emplace_args1<A0> const& args)
- {
- return emplace_impl(extractor::extract(args.a0), args);
- }
-
- template <typename A0>
- iterator emplace_hint(c_iterator hint,
- boost::unordered::detail::emplace_args1<A0> const& args)
- {
- return emplace_hint_impl(hint, extractor::extract(args.a0), args);
- }
-#endif
-
- template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- iterator emplace_hint_impl(
+ iterator emplace_hint_unique(
c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS)
{
- if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
return iterator(hint.node_);
} else {
- return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
+ return emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
}
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- emplace_return emplace_impl(const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS)
+ emplace_return emplace_unique(
+ const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS)
{
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
@@ -3839,7 +3418,7 @@ struct table_impl : boost::unordered::detail::table<Types>
return emplace_return(iterator(pos), false);
} else {
return emplace_return(
- iterator(this->resize_and_add_node(
+ iterator(this->resize_and_add_node_unique(
boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
key_hash)),
@@ -3848,14 +3427,14 @@ struct table_impl : boost::unordered::detail::table<Types>
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- iterator emplace_hint_impl(
+ iterator emplace_hint_unique(
c_iterator hint, no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{
node_tmp b(boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
this->node_alloc());
- const_key_type& k = this->get_key(b.node_->value());
- if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ const_key_type& k = this->get_key(b.node_);
+ if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
return iterator(hint.node_);
}
std::size_t key_hash = this->hash(k);
@@ -3863,30 +3442,31 @@ struct table_impl : boost::unordered::detail::table<Types>
if (pos) {
return iterator(pos);
} else {
- return iterator(this->resize_and_add_node(b.release(), key_hash));
+ return iterator(
+ this->resize_and_add_node_unique(b.release(), key_hash));
}
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
+ emplace_return emplace_unique(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{
node_tmp b(boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
this->node_alloc());
- const_key_type& k = this->get_key(b.node_->value());
+ const_key_type& k = this->get_key(b.node_);
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
if (pos) {
return emplace_return(iterator(pos), false);
} else {
- return emplace_return(
- iterator(this->resize_and_add_node(b.release(), key_hash)),
+ return emplace_return(iterator(this->resize_and_add_node_unique(
+ b.release(), key_hash)),
true);
}
}
template <typename Key>
- emplace_return try_emplace_impl(BOOST_FWD_REF(Key) k)
+ emplace_return try_emplace_unique(BOOST_FWD_REF(Key) k)
{
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
@@ -3894,7 +3474,7 @@ struct table_impl : boost::unordered::detail::table<Types>
return emplace_return(iterator(pos), false);
} else {
return emplace_return(
- iterator(this->resize_and_add_node(
+ iterator(this->resize_and_add_node_unique(
boost::unordered::detail::func::construct_node_pair(
this->node_alloc(), boost::forward<Key>(k)),
key_hash)),
@@ -3903,17 +3483,17 @@ struct table_impl : boost::unordered::detail::table<Types>
}
template <typename Key>
- iterator try_emplace_hint_impl(c_iterator hint, BOOST_FWD_REF(Key) k)
+ iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k)
{
if (hint.node_ && this->key_eq()(hint->first, k)) {
return iterator(hint.node_);
} else {
- return try_emplace_impl(k).first;
+ return try_emplace_unique(k).first;
}
}
template <typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE>
- emplace_return try_emplace_impl(
+ emplace_return try_emplace_unique(
BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS)
{
std::size_t key_hash = this->hash(k);
@@ -3922,7 +3502,7 @@ struct table_impl : boost::unordered::detail::table<Types>
return emplace_return(iterator(pos), false);
} else {
return emplace_return(
- iterator(this->resize_and_add_node(
+ iterator(this->resize_and_add_node_unique(
boost::unordered::detail::func::
construct_node_pair_from_args(this->node_alloc(),
boost::forward<Key>(k),
@@ -3933,18 +3513,18 @@ struct table_impl : boost::unordered::detail::table<Types>
}
template <typename Key, BOOST_UNORDERED_EMPLACE_TEMPLATE>
- iterator try_emplace_hint_impl(
+ iterator try_emplace_hint_unique(
c_iterator hint, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS)
{
if (hint.node_ && this->key_eq()(hint->first, k)) {
return iterator(hint.node_);
} else {
- return try_emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
+ return try_emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
}
}
template <typename Key, typename M>
- emplace_return insert_or_assign_impl(
+ emplace_return insert_or_assign_unique(
BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj)
{
std::size_t key_hash = this->hash(k);
@@ -3955,7 +3535,7 @@ struct table_impl : boost::unordered::detail::table<Types>
return emplace_return(iterator(pos), false);
} else {
return emplace_return(
- iterator(this->resize_and_add_node(
+ iterator(this->resize_and_add_node_unique(
boost::unordered::detail::func::construct_node_pair(
this->node_alloc(), boost::forward<Key>(k),
boost::forward<M>(obj)),
@@ -3965,10 +3545,10 @@ struct table_impl : boost::unordered::detail::table<Types>
}
template <typename NodeType, typename InsertReturnType>
- void move_insert_node_type(NodeType& np, InsertReturnType& result)
+ void move_insert_node_type_unique(NodeType& np, InsertReturnType& result)
{
if (np) {
- const_key_type& k = this->get_key(np.ptr_->value());
+ const_key_type& k = this->get_key(np.ptr_);
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
@@ -3977,7 +3557,8 @@ struct table_impl : boost::unordered::detail::table<Types>
result.position = iterator(pos);
} else {
this->reserve_for_insert(this->size_ + 1);
- result.position = iterator(this->add_node(np.ptr_, key_hash));
+ result.position =
+ iterator(this->add_node_unique(np.ptr_, key_hash));
result.inserted = true;
np.ptr_ = node_pointer();
}
@@ -3985,27 +3566,28 @@ struct table_impl : boost::unordered::detail::table<Types>
}
template <typename NodeType>
- iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np)
+ iterator move_insert_node_type_with_hint_unique(
+ c_iterator hint, NodeType& np)
{
if (!np) {
return iterator();
}
- const_key_type& k = this->get_key(np.ptr_->value());
- if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ const_key_type& k = this->get_key(np.ptr_);
+ if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
return iterator(hint.node_);
}
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
if (!pos) {
this->reserve_for_insert(this->size_ + 1);
- pos = this->add_node(np.ptr_, key_hash);
+ pos = this->add_node_unique(np.ptr_, key_hash);
np.ptr_ = node_pointer();
}
return iterator(pos);
}
template <typename Types2>
- void merge_impl(boost::unordered::detail::table<Types2>& other)
+ void merge_unique(boost::unordered::detail::table<Types2>& other)
{
typedef boost::unordered::detail::table<Types2> other_table;
BOOST_STATIC_ASSERT(
@@ -4016,8 +3598,8 @@ struct table_impl : boost::unordered::detail::table<Types>
link_pointer prev = other.get_previous_start();
while (prev->next_) {
- node_pointer n = other_table::node_algo::next_node(prev);
- const_key_type& k = this->get_key(n->value());
+ node_pointer n = other_table::next_node(prev);
+ const_key_type& k = this->get_key(n);
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
@@ -4025,12 +3607,14 @@ struct table_impl : boost::unordered::detail::table<Types>
prev = n;
} else {
this->reserve_for_insert(this->size_ + 1);
- other_table::node_algo::split_groups(
- n, other_table::node_algo::next_node(n));
- prev->next_ = n->next_;
+ node_pointer n2 = next_node(n);
+ prev->next_ = n2;
+ if (n2 && n->is_first_in_group()) {
+ n2->set_first_in_group();
+ }
--other.size_;
- other.fix_bucket(other.hash_to_bucket(n->hash_), prev);
- this->add_node(n, key_hash);
+ other.fix_bucket(other.node_bucket(n), prev, n2);
+ this->add_node_unique(n, key_hash);
}
}
}
@@ -4042,32 +3626,21 @@ struct table_impl : boost::unordered::detail::table<Types>
// if hash function throws, or inserting > 1 element, basic exception
// safety strong otherwise
- template <class InputIt> void insert_range(InputIt i, InputIt j)
- {
- if (i != j)
- return insert_range_impl(extractor::extract(*i), i, j);
- }
-
template <class InputIt>
- void insert_range_impl(const_key_type& k, InputIt i, InputIt j)
+ void insert_range_unique(const_key_type& k, InputIt i, InputIt j)
{
- insert_range_impl2(k, i, j);
+ insert_range_unique2(k, i, j);
while (++i != j) {
// Note: can't use get_key as '*i' might not be value_type - it
// could be a pair with first_types as key_type without const or
// a different second_type.
- //
- // TODO: Might be worth storing the value_type instead of the
- // key here. Could be more efficient if '*i' is expensive. Could
- // be less efficient if copying the full value_type is
- // expensive.
- insert_range_impl2(extractor::extract(*i), i, j);
+ insert_range_unique2(extractor::extract(*i), i, j);
}
}
template <class InputIt>
- void insert_range_impl2(const_key_type& k, InputIt i, InputIt j)
+ void insert_range_unique2(const_key_type& k, InputIt i, InputIt j)
{
// No side effects in this initial code
std::size_t key_hash = this->hash(k);
@@ -4080,12 +3653,12 @@ struct table_impl : boost::unordered::detail::table<Types>
if (this->size_ + 1 > this->max_load_)
this->reserve_for_insert(
this->size_ + boost::unordered::detail::insert_size(i, j));
- this->add_node(b.release(), key_hash);
+ this->add_node_unique(b.release(), key_hash);
}
}
template <class InputIt>
- void insert_range_impl(no_key, InputIt i, InputIt j)
+ void insert_range_unique(no_key, InputIt i, InputIt j)
{
node_constructor a(this->node_alloc());
@@ -4093,11 +3666,11 @@ struct table_impl : boost::unordered::detail::table<Types>
if (!a.node_) {
a.create_node();
}
- boost::unordered::detail::func::call_construct(
- a.alloc_, a.node_->value_ptr(), *i);
+ BOOST_UNORDERED_CALL_CONSTRUCT1(
+ node_allocator_traits, a.alloc_, a.node_->value_ptr(), *i);
node_tmp b(a.release(), a.alloc_);
- const_key_type& k = this->get_key(b.node_->value());
+ const_key_type& k = this->get_key(b.node_);
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
@@ -4107,7 +3680,7 @@ struct table_impl : boost::unordered::detail::table<Types>
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
- this->add_node(b.release(), key_hash);
+ this->add_node_unique(b.release(), key_hash);
}
} while (++i != j);
}
@@ -4115,19 +3688,19 @@ struct table_impl : boost::unordered::detail::table<Types>
////////////////////////////////////////////////////////////////////////
// Extract
- inline node_pointer extract_by_iterator(c_iterator i)
+ inline node_pointer extract_by_iterator_unique(c_iterator i)
{
node_pointer n = i.node_;
BOOST_ASSERT(n);
- std::size_t key_hash = n->hash_;
- std::size_t bucket_index = this->hash_to_bucket(key_hash);
+ std::size_t bucket_index = this->node_bucket(n);
link_pointer prev = this->get_previous_start(bucket_index);
while (prev->next_ != n) {
prev = prev->next_;
}
- prev->next_ = n->next_;
+ node_pointer n2 = next_node(n);
+ prev->next_ = n2;
--this->size_;
- this->fix_bucket(bucket_index, prev);
+ this->fix_bucket(bucket_index, prev, n2);
n->next_ = link_pointer();
return n;
}
@@ -4137,40 +3710,27 @@ struct table_impl : boost::unordered::detail::table<Types>
//
// no throw
- std::size_t erase_key(const_key_type& k)
+ std::size_t erase_key_unique(const_key_type& k)
{
if (!this->size_)
return 0;
std::size_t key_hash = this->hash(k);
std::size_t bucket_index = this->hash_to_bucket(key_hash);
- link_pointer prev = this->find_previous_node(k, key_hash, bucket_index);
+ link_pointer prev = this->find_previous_node(k, bucket_index);
if (!prev)
return 0;
- link_pointer end = node_algo::next_node(prev)->next_;
- this->delete_nodes(prev, end);
- this->fix_bucket(bucket_index, prev);
+ node_pointer n = next_node(prev);
+ node_pointer n2 = next_node(n);
+ prev->next_ = n2;
+ --size_;
+ this->fix_bucket(bucket_index, prev, n2);
+ this->destroy_node(n);
return 1;
}
- iterator erase(c_iterator r)
+ void erase_nodes_unique(node_pointer i, node_pointer j)
{
- BOOST_ASSERT(r.node_);
- node_pointer next = node_algo::next_node(r.node_);
- erase_nodes(r.node_, next);
- return iterator(next);
- }
-
- iterator erase_range(c_iterator r1, c_iterator r2)
- {
- if (r1 == r2)
- return iterator(r2.node_);
- erase_nodes(r1.node_, r2.node_);
- return iterator(r2.node_);
- }
-
- void erase_nodes(node_pointer i, node_pointer j)
- {
- std::size_t bucket_index = this->hash_to_bucket(i->hash_);
+ std::size_t bucket_index = this->node_bucket(i);
// Find the node before i.
link_pointer prev = this->get_previous_start(bucket_index);
@@ -4178,343 +3738,81 @@ struct table_impl : boost::unordered::detail::table<Types>
prev = prev->next_;
// Delete the nodes.
+ prev->next_ = j;
do {
- this->delete_node(prev);
- bucket_index = this->fix_bucket(bucket_index, prev);
- } while (prev->next_ != j);
+ node_pointer next = next_node(i);
+ destroy_node(i);
+ --size_;
+ bucket_index = this->fix_bucket(bucket_index, prev, next);
+ i = next;
+ } while (i != j);
}
////////////////////////////////////////////////////////////////////////
- // fill_buckets
+ // fill_buckets_unique
- void copy_buckets(table const& src)
+ void copy_buckets(table const& src, true_type)
{
this->create_buckets(this->bucket_count_);
- for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) {
- this->add_node(boost::unordered::detail::func::construct_node(
- this->node_alloc(), n->value()),
- n->hash_);
+ for (node_pointer n = src.begin(); n; n = next_node(n)) {
+ std::size_t key_hash = this->hash(this->get_key(n));
+ this->add_node_unique(
+ boost::unordered::detail::func::construct_node(
+ this->node_alloc(), n->value()),
+ key_hash);
}
}
+ // TODO: Should be move_buckets_uniq
void move_buckets(table const& src)
{
this->create_buckets(this->bucket_count_);
- for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) {
- this->add_node(boost::unordered::detail::func::construct_node(
- this->node_alloc(), boost::move(n->value())),
- n->hash_);
+ for (node_pointer n = src.begin(); n; n = next_node(n)) {
+ std::size_t key_hash = this->hash(this->get_key(n));
+ this->add_node_unique(
+ boost::unordered::detail::func::construct_node(
+ this->node_alloc(), boost::move(n->value())),
+ key_hash);
}
}
- void assign_buckets(table const& src)
+ void assign_buckets(table const& src, true_type)
{
node_holder<node_allocator> holder(*this);
- for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) {
- this->add_node(holder.copy_of(n->value()), n->hash_);
+ for (node_pointer n = src.begin(); n; n = next_node(n)) {
+ std::size_t key_hash = this->hash(this->get_key(n));
+ this->add_node_unique(holder.copy_of(n->value()), key_hash);
}
}
- void move_assign_buckets(table& src)
+ void move_assign_buckets(table& src, true_type)
{
node_holder<node_allocator> holder(*this);
- for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) {
- this->add_node(holder.move_copy_of(n->value()), n->hash_);
- }
- }
-};
-
-////////////////////////////////////////////////////////////////////////
-// Grouped nodes
-
-template <typename A, typename T>
-struct grouped_node : boost::unordered::detail::value_base<T>
-{
- typedef typename ::boost::unordered::detail::rebind_wrap<A,
- grouped_node<A, T> >::type allocator;
- typedef typename ::boost::unordered::detail::allocator_traits<
- allocator>::pointer node_pointer;
- typedef node_pointer link_pointer;
- typedef typename ::boost::unordered::detail::rebind_wrap<A,
- bucket<node_pointer> >::type bucket_allocator;
- typedef typename ::boost::unordered::detail::allocator_traits<
- bucket_allocator>::pointer bucket_pointer;
-
- link_pointer next_;
- node_pointer group_prev_;
- std::size_t hash_;
-
- grouped_node() : next_(), group_prev_(), hash_(0) {}
-
- void init(node_pointer self) { group_prev_ = self; }
-
- private:
- grouped_node& operator=(grouped_node const&);
-};
-
-template <typename T>
-struct grouped_ptr_node : boost::unordered::detail::ptr_bucket
-{
- typedef T value_type;
- typedef boost::unordered::detail::ptr_bucket bucket_base;
- typedef grouped_ptr_node<T>* node_pointer;
- typedef ptr_bucket* link_pointer;
- typedef ptr_bucket* bucket_pointer;
-
- node_pointer group_prev_;
- std::size_t hash_;
- boost::unordered::detail::value_base<T> value_base_;
-
- grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {}
-
- void init(node_pointer self) { group_prev_ = self; }
-
- void* address() { return value_base_.address(); }
- value_type& value() { return value_base_.value(); }
- value_type* value_ptr() { return value_base_.value_ptr(); }
-
- private:
- grouped_ptr_node& operator=(grouped_ptr_node const&);
-};
-
-template <typename N> struct grouped_node_algo
-{
- typedef typename N::node_pointer node_pointer;
- typedef typename N::link_pointer link_pointer;
- typedef typename N::bucket_pointer bucket_pointer;
-
- static node_pointer next_node(link_pointer n)
- {
- return static_cast<node_pointer>(n->next_);
- }
-
- static node_pointer next_for_find(node_pointer n)
- {
- return static_cast<node_pointer>(n->group_prev_->next_);
- }
-
- static link_pointer next_for_erase(link_pointer prev)
- {
- return static_cast<node_pointer>(prev->next_)->group_prev_;
- }
-
- static node_pointer last_for_rehash(link_pointer prev)
- {
- return static_cast<node_pointer>(prev->next_)->group_prev_;
- }
-
- // The 'void*' arguments are pointers to the table, which we
- // will ignore, but without groups they could be used to
- // access the various functions for dealing with values and keys.
- static node_pointer next_group(node_pointer n, void const*)
- {
- return static_cast<node_pointer>(n->group_prev_->next_);
- }
-
- static std::size_t count(node_pointer n, void const*)
- {
- std::size_t x = 0;
- node_pointer it = n;
- do {
- it = it->group_prev_;
- ++x;
- } while (it != n);
-
- return x;
- }
-
- // Adds node 'n' to the group containing 'pos'.
- // If 'pos' is the first node in group, add to the end of the group,
- // otherwise add before 'pos'. Other versions will probably behave
- // differently.
- static inline void add_to_node_group(node_pointer n, node_pointer pos)
- {
- n->next_ = pos->group_prev_->next_;
- n->group_prev_ = pos->group_prev_;
- pos->group_prev_->next_ = n;
- pos->group_prev_ = n;
- }
-
- static inline node_pointer extract_first_node(link_pointer prev)
- {
- node_pointer n = next_node(prev);
- if (n->group_prev_ != n) {
- node_pointer next = next_node(n);
- next->group_prev_ = n->group_prev_;
- n->group_prev_ = n;
+ for (node_pointer n = src.begin(); n; n = next_node(n)) {
+ std::size_t key_hash = this->hash(this->get_key(n));
+ this->add_node_unique(holder.move_copy_of(n->value()), key_hash);
}
- prev->next_ = n->next_;
- return n;
- }
-
- // Split the groups containing 'i' and 'j' so that they can
- // be safely erased/extracted.
- static link_pointer split_groups(node_pointer i, node_pointer j)
- {
- node_pointer prev = i->group_prev_;
- if (prev->next_ != i)
- prev = node_pointer();
-
- if (j) {
- node_pointer first = j;
- while (first != i && first->group_prev_->next_ == first) {
- first = first->group_prev_;
- }
-
- boost::swap(first->group_prev_, j->group_prev_);
- if (first == i)
- return prev;
- }
-
- if (prev) {
- node_pointer first = prev;
- while (first->group_prev_->next_ == first) {
- first = first->group_prev_;
- }
- boost::swap(first->group_prev_, i->group_prev_);
- }
-
- return prev;
- }
-};
-
-// If the allocator uses raw pointers use grouped_ptr_node
-// Otherwise use grouped_node.
-
-template <typename A, typename T, typename NodePtr, typename BucketPtr>
-struct pick_grouped_node2
-{
- typedef boost::unordered::detail::grouped_node<A, T> node;
-
- typedef typename boost::unordered::detail::allocator_traits<
- typename boost::unordered::detail::rebind_wrap<A, node>::type>::pointer
- node_pointer;
-
- typedef boost::unordered::detail::bucket<node_pointer> bucket;
- typedef node_pointer link_pointer;
-};
-
-template <typename A, typename T>
-struct pick_grouped_node2<A, T, boost::unordered::detail::grouped_ptr_node<T>*,
- boost::unordered::detail::ptr_bucket*>
-{
- typedef boost::unordered::detail::grouped_ptr_node<T> node;
- typedef boost::unordered::detail::ptr_bucket bucket;
- typedef bucket* link_pointer;
-};
-
-template <typename A, typename T> struct pick_grouped_node
-{
- typedef typename boost::remove_const<T>::type nonconst;
-
- typedef boost::unordered::detail::allocator_traits<
- typename boost::unordered::detail::rebind_wrap<A,
- boost::unordered::detail::grouped_ptr_node<nonconst> >::type>
- tentative_node_traits;
-
- typedef boost::unordered::detail::allocator_traits<
- typename boost::unordered::detail::rebind_wrap<A,
- boost::unordered::detail::ptr_bucket>::type>
- tentative_bucket_traits;
-
- typedef pick_grouped_node2<A, nonconst,
- typename tentative_node_traits::pointer,
- typename tentative_bucket_traits::pointer>
- pick;
-
- typedef typename pick::node node;
- typedef typename pick::bucket bucket;
- typedef typename pick::link_pointer link_pointer;
- typedef boost::unordered::detail::grouped_node_algo<node> node_algo;
-};
-
-template <typename Types>
-struct grouped_table_impl : boost::unordered::detail::table<Types>
-{
- typedef boost::unordered::detail::table<Types> table;
- typedef typename table::value_type value_type;
- typedef typename table::bucket bucket;
- typedef typename table::policy policy;
- typedef typename table::node_pointer node_pointer;
- typedef typename table::node_allocator node_allocator;
- typedef typename table::node_allocator_traits node_allocator_traits;
- typedef typename table::bucket_pointer bucket_pointer;
- typedef typename table::link_pointer link_pointer;
- typedef typename table::hasher hasher;
- typedef typename table::key_equal key_equal;
- typedef typename table::const_key_type const_key_type;
- typedef typename table::node_constructor node_constructor;
- typedef typename table::node_tmp node_tmp;
- typedef typename table::extractor extractor;
- typedef typename table::iterator iterator;
- typedef typename table::c_iterator c_iterator;
- typedef typename table::node_algo node_algo;
-
- // Constructors
-
- grouped_table_impl(std::size_t n, hasher const& hf, key_equal const& eq,
- node_allocator const& a)
- : table(n, hf, eq, a)
- {
- }
-
- grouped_table_impl(grouped_table_impl const& x)
- : table(x, node_allocator_traits::select_on_container_copy_construction(
- x.node_alloc()))
- {
- this->init(x);
- }
-
- grouped_table_impl(grouped_table_impl const& x, node_allocator const& a)
- : table(x, a)
- {
- this->init(x);
- }
-
- grouped_table_impl(
- grouped_table_impl& x, boost::unordered::detail::move_tag m)
- : table(x, m)
- {
- }
-
- grouped_table_impl(grouped_table_impl& x, node_allocator const& a,
- boost::unordered::detail::move_tag m)
- : table(x, a, m)
- {
- this->move_init(x);
}
- // Accessors
-
- std::size_t count(const_key_type& k) const
- {
- node_pointer n = this->find_node(k);
- return n ? node_algo::count(n, this) : 0;
- }
-
- std::pair<iterator, iterator> equal_range(const_key_type& k) const
- {
- node_pointer n = this->find_node(k);
- return std::make_pair(
- iterator(n), iterator(n ? node_algo::next_group(n, this) : n));
- }
+ ////////////////////////////////////////////////////////////////////////
+ // Equivalent keys
// Equality
- bool equals(grouped_table_impl const& other) const
+ bool equals_equiv(table const& other) const
{
if (this->size_ != other.size_)
return false;
for (node_pointer n1 = this->begin(); n1;) {
- node_pointer n2 = other.find_node(other.get_key(n1->value()));
+ node_pointer n2 = other.find_node(other.get_key(n1));
if (!n2)
return false;
- node_pointer end1 = node_algo::next_group(n1, this);
- node_pointer end2 = node_algo::next_group(n2, this);
- if (!group_equals(n1, end1, n2, end2))
+ node_pointer end1 = next_group(n1);
+ node_pointer end2 = next_group(n2);
+ if (!group_equals_equiv(n1, end1, n2, end2))
return false;
n1 = end1;
}
@@ -4522,15 +3820,15 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
return true;
}
- static bool group_equals(
+ static bool group_equals_equiv(
node_pointer n1, node_pointer end1, node_pointer n2, node_pointer end2)
{
for (;;) {
if (n1->value() != n2->value())
break;
- n1 = node_algo::next_node(n1);
- n2 = node_algo::next_node(n2);
+ n1 = next_node(n1);
+ n2 = next_node(n2);
if (n1 == end1)
return n2 == end2;
@@ -4539,8 +3837,8 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
}
for (node_pointer n1a = n1, n2a = n2;;) {
- n1a = node_algo::next_node(n1a);
- n2a = node_algo::next_node(n2a);
+ n1a = next_node(n1a);
+ n2a = next_node(n2a);
if (n1a == end1) {
if (n2a == end2)
@@ -4554,14 +3852,13 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
}
node_pointer start = n1;
- for (; n1 != end1; n1 = node_algo::next_node(n1)) {
+ for (; n1 != end1; n1 = next_node(n1)) {
value_type const& v = n1->value();
- if (!find(start, n1, v)) {
- std::size_t matches = count_equal(n2, end2, v);
+ if (!find_equiv(start, n1, v)) {
+ std::size_t matches = count_equal_equiv(n2, end2, v);
if (!matches)
return false;
- if (matches !=
- 1 + count_equal(node_algo::next_node(n1), end1, v))
+ if (matches != 1 + count_equal_equiv(next_node(n1), end1, v))
return false;
}
}
@@ -4569,19 +3866,20 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
return true;
}
- static bool find(node_pointer n, node_pointer end, value_type const& v)
+ static bool find_equiv(
+ node_pointer n, node_pointer end, value_type const& v)
{
- for (; n != end; n = node_algo::next_node(n))
+ for (; n != end; n = next_node(n))
if (n->value() == v)
return true;
return false;
}
- static std::size_t count_equal(
+ static std::size_t count_equal_equiv(
node_pointer n, node_pointer end, value_type const& v)
{
std::size_t count = 0;
- for (; n != end; n = node_algo::next_node(n))
+ for (; n != end; n = next_node(n))
if (n->value() == v)
++count;
return count;
@@ -4589,29 +3887,31 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
// Emplace/Insert
- inline node_pointer add_node(
+ inline node_pointer add_node_equiv(
node_pointer n, std::size_t key_hash, node_pointer pos)
{
- n->hash_ = key_hash;
+ std::size_t bucket_index = this->hash_to_bucket(key_hash);
+ n->bucket_info_ = bucket_index;
+
if (pos) {
- node_algo::add_to_node_group(n, pos);
+ n->reset_first_in_group();
+ n->next_ = pos->next_;
+ pos->next_ = n;
if (n->next_) {
- std::size_t next_bucket =
- this->hash_to_bucket(node_algo::next_node(n)->hash_);
- if (next_bucket != this->hash_to_bucket(key_hash)) {
+ std::size_t next_bucket = this->node_bucket(next_node(n));
+ if (next_bucket != bucket_index) {
this->get_bucket(next_bucket)->next_ = n;
}
}
} else {
- bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
+ // n->set_first_in_group();
+ bucket_pointer b = this->get_bucket(bucket_index);
if (!b->next_) {
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
- this->get_bucket(
- this->hash_to_bucket(
- node_algo::next_node(start_node)->hash_))
+ this->get_bucket(this->node_bucket(next_node(start_node)))
->next_ = n;
}
@@ -4627,14 +3927,15 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
return n;
}
- inline node_pointer add_using_hint(node_pointer n, node_pointer hint)
+ inline node_pointer add_using_hint_equiv(node_pointer n, node_pointer hint)
{
- n->hash_ = hint->hash_;
- node_algo::add_to_node_group(n, hint);
- if (n->next_ != hint && n->next_) {
- std::size_t next_bucket =
- this->hash_to_bucket(node_algo::next_node(n)->hash_);
- if (next_bucket != this->hash_to_bucket(n->hash_)) {
+ n->bucket_info_ = hint->bucket_info_;
+ n->reset_first_in_group();
+ n->next_ = hint->next_;
+ hint->next_ = n;
+ 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;
}
}
@@ -4642,100 +3943,53 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
return n;
}
-#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
-#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
- iterator emplace(boost::unordered::detail::emplace_args1<
- boost::unordered::detail::please_ignore_this_overload> const&)
- {
- BOOST_ASSERT(false);
- return iterator();
- }
-
- iterator emplace_hint(
- c_iterator,
- boost::unordered::detail::emplace_args1<
- boost::unordered::detail::please_ignore_this_overload> const&)
- {
- BOOST_ASSERT(false);
- return iterator();
- }
-#else
- iterator emplace(
- boost::unordered::detail::please_ignore_this_overload const&)
- {
- BOOST_ASSERT(false);
- return iterator();
- }
-
- iterator emplace_hint(c_iterator,
- boost::unordered::detail::please_ignore_this_overload const&)
- {
- BOOST_ASSERT(false);
- return iterator();
- }
-#endif
-#endif
-
- template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
- {
- return iterator(emplace_impl(
- boost::unordered::detail::func::construct_node_from_args(
- this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD)));
- }
-
- template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS)
- {
- return iterator(emplace_hint_impl(
- hint, boost::unordered::detail::func::construct_node_from_args(
- this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD)));
- }
-
- iterator emplace_impl(node_pointer n)
+ iterator emplace_equiv(node_pointer n)
{
node_tmp a(n, this->node_alloc());
- const_key_type& k = this->get_key(a.node_->value());
+ const_key_type& k = this->get_key(a.node_);
std::size_t key_hash = this->hash(k);
node_pointer position = this->find_node(key_hash, k);
this->reserve_for_insert(this->size_ + 1);
- return iterator(this->add_node(a.release(), key_hash, position));
+ return iterator(this->add_node_equiv(a.release(), key_hash, position));
}
- iterator emplace_hint_impl(c_iterator hint, node_pointer n)
+ iterator emplace_hint_equiv(c_iterator hint, node_pointer n)
{
node_tmp a(n, this->node_alloc());
- const_key_type& k = this->get_key(a.node_->value());
- if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ const_key_type& k = this->get_key(a.node_);
+ if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
this->reserve_for_insert(this->size_ + 1);
- return iterator(this->add_using_hint(a.release(), hint.node_));
+ return iterator(
+ this->add_using_hint_equiv(a.release(), hint.node_));
} else {
std::size_t key_hash = this->hash(k);
node_pointer position = this->find_node(key_hash, k);
this->reserve_for_insert(this->size_ + 1);
- return iterator(this->add_node(a.release(), key_hash, position));
+ return iterator(
+ this->add_node_equiv(a.release(), key_hash, position));
}
}
- void emplace_impl_no_rehash(node_pointer n)
+ void emplace_no_rehash_equiv(node_pointer n)
{
node_tmp a(n, this->node_alloc());
- const_key_type& k = this->get_key(a.node_->value());
+ const_key_type& k = this->get_key(a.node_);
std::size_t key_hash = this->hash(k);
node_pointer position = this->find_node(key_hash, k);
- this->add_node(a.release(), key_hash, position);
+ this->add_node_equiv(a.release(), key_hash, position);
}
- template <typename NodeType> iterator move_insert_node_type(NodeType& np)
+ template <typename NodeType>
+ iterator move_insert_node_type_equiv(NodeType& np)
{
iterator result;
if (np) {
- const_key_type& k = this->get_key(np.ptr_->value());
+ const_key_type& k = this->get_key(np.ptr_);
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
this->reserve_for_insert(this->size_ + 1);
- result = iterator(this->add_node(np.ptr_, key_hash, pos));
+ result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos));
np.ptr_ = node_pointer();
}
@@ -4743,21 +3997,23 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
}
template <typename NodeType>
- iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np)
+ iterator move_insert_node_type_with_hint_equiv(
+ c_iterator hint, NodeType& np)
{
iterator result;
if (np) {
- const_key_type& k = this->get_key(np.ptr_->value());
+ const_key_type& k = this->get_key(np.ptr_);
- if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) {
this->reserve_for_insert(this->size_ + 1);
- result = iterator(this->add_using_hint(np.ptr_, hint.node_));
+ result =
+ iterator(this->add_using_hint_equiv(np.ptr_, hint.node_));
} else {
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
this->reserve_for_insert(this->size_ + 1);
- result = iterator(this->add_node(np.ptr_, key_hash, pos));
+ result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos));
}
np.ptr_ = node_pointer();
}
@@ -4771,7 +4027,7 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
// if hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
- void insert_range(I i, I j,
+ void insert_range_equiv(I i, I j,
typename boost::unordered::detail::enable_if_forward<I, void*>::type =
0)
{
@@ -4780,14 +4036,14 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
std::size_t distance = static_cast<std::size_t>(std::distance(i, j));
if (distance == 1) {
- emplace_impl(boost::unordered::detail::func::construct_node(
+ emplace_equiv(boost::unordered::detail::func::construct_node(
this->node_alloc(), *i));
} else {
// Only require basic exception safety here
this->reserve_for_insert(this->size_ + distance);
for (; i != j; ++i) {
- emplace_impl_no_rehash(
+ emplace_no_rehash_equiv(
boost::unordered::detail::func::construct_node(
this->node_alloc(), *i));
}
@@ -4795,12 +4051,12 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
}
template <class I>
- void insert_range(I i, I j,
+ void insert_range_equiv(I i, I j,
typename boost::unordered::detail::disable_if_forward<I, void*>::type =
0)
{
for (; i != j; ++i) {
- emplace_impl(boost::unordered::detail::func::construct_node(
+ emplace_equiv(boost::unordered::detail::func::construct_node(
this->node_alloc(), *i));
}
}
@@ -4808,30 +4064,24 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
////////////////////////////////////////////////////////////////////////
// Extract
- inline node_pointer extract_by_iterator(c_iterator n)
+ inline node_pointer extract_by_iterator_equiv(c_iterator n)
{
node_pointer i = n.node_;
BOOST_ASSERT(i);
- node_pointer j(node_algo::next_node(i));
- std::size_t bucket_index = this->hash_to_bucket(i->hash_);
- // Split the groups containing 'i' and 'j'.
- // And get the pointer to the node before i while
- // we're at it.
- link_pointer prev = node_algo::split_groups(i, j);
-
- // If we don't have a 'prev' it means that i is at the
- // beginning of a block, so search through the blocks in the
- // same bucket.
- if (!prev) {
- prev = this->get_previous_start(bucket_index);
- while (prev->next_ != i) {
- prev = node_algo::next_for_erase(prev);
- }
+ node_pointer j(next_node(i));
+ std::size_t bucket_index = this->node_bucket(i);
+
+ link_pointer prev = this->get_previous_start(bucket_index);
+ while (prev->next_ != i) {
+ prev = next_node(prev);
}
- prev->next_ = i->next_;
+ prev->next_ = j;
+ if (j && i->is_first_in_group()) {
+ j->set_first_in_group();
+ }
--this->size_;
- this->fix_bucket(bucket_index, prev);
+ this->fix_bucket(bucket_index, prev, j);
i->next_ = link_pointer();
return i;
@@ -4842,66 +4092,55 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
//
// no throw
- std::size_t erase_key(const_key_type& k)
+ std::size_t erase_key_equiv(const_key_type& k)
{
if (!this->size_)
return 0;
std::size_t key_hash = this->hash(k);
std::size_t bucket_index = this->hash_to_bucket(key_hash);
- link_pointer prev = this->find_previous_node(k, key_hash, bucket_index);
+ link_pointer prev = this->find_previous_node(k, bucket_index);
if (!prev)
return 0;
- node_pointer first_node = node_algo::next_node(prev);
- link_pointer end = node_algo::next_group(first_node, this);
-
- std::size_t deleted_count = this->delete_nodes(prev, end);
- this->fix_bucket(bucket_index, prev);
+ std::size_t deleted_count = 0;
+ node_pointer n = next_node(prev);
+ do {
+ node_pointer n2 = next_node(n);
+ destroy_node(n);
+ ++deleted_count;
+ n = n2;
+ } while (n && !n->is_first_in_group());
+ size_ -= deleted_count;
+ prev->next_ = n;
+ this->fix_bucket(bucket_index, prev, n);
return deleted_count;
}
- iterator erase(c_iterator r)
+ link_pointer erase_nodes_equiv(node_pointer i, node_pointer j)
{
- BOOST_ASSERT(r.node_);
- node_pointer next = node_algo::next_node(r.node_);
- erase_nodes(r.node_, next);
- return iterator(next);
- }
+ std::size_t bucket_index = this->node_bucket(i);
- iterator erase_range(c_iterator r1, c_iterator r2)
- {
- if (r1 == r2)
- return iterator(r2.node_);
- erase_nodes(r1.node_, r2.node_);
- return iterator(r2.node_);
- }
-
- link_pointer erase_nodes(node_pointer i, node_pointer j)
- {
- std::size_t bucket_index = this->hash_to_bucket(i->hash_);
-
- // Split the groups containing 'i' and 'j'.
- // And get the pointer to the node before i while
- // we're at it.
- link_pointer prev = node_algo::split_groups(i, j);
-
- // If we don't have a 'prev' it means that i is at the
- // beginning of a block, so search through the blocks in the
- // same bucket.
- if (!prev) {
- prev = this->get_previous_start(bucket_index);
- while (prev->next_ != i) {
- prev = node_algo::next_for_erase(prev);
- }
+ link_pointer prev = this->get_previous_start(bucket_index);
+ while (prev->next_ != i) {
+ prev = next_node(prev);
}
// Delete the nodes.
// Is it inefficient to call fix_bucket for every node?
+ bool includes_first = false;
+ prev->next_ = j;
do {
- this->delete_node(prev);
- bucket_index = this->fix_bucket(bucket_index, prev);
- } while (prev->next_ != j);
+ includes_first = includes_first || i->is_first_in_group();
+ node_pointer next = next_node(i);
+ destroy_node(i);
+ --size_;
+ bucket_index = this->fix_bucket(bucket_index, prev, next);
+ i = next;
+ } while (i != j);
+ if (j && includes_first) {
+ j->set_first_in_group();
+ }
return prev;
}
@@ -4909,78 +4148,504 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
////////////////////////////////////////////////////////////////////////
// fill_buckets
- void copy_buckets(table const& src)
+ void copy_buckets(table const& src, false_type)
{
this->create_buckets(this->bucket_count_);
for (node_pointer n = src.begin(); n;) {
- std::size_t key_hash = n->hash_;
- node_pointer group_end(node_algo::next_group(n, this));
- node_pointer pos =
- this->add_node(boost::unordered::detail::func::construct_node(
- this->node_alloc(), n->value()),
- key_hash, node_pointer());
- for (n = node_algo::next_node(n); n != group_end;
- n = node_algo::next_node(n)) {
- this->add_node(boost::unordered::detail::func::construct_node(
- this->node_alloc(), n->value()),
+ std::size_t key_hash = this->hash(this->get_key(n));
+ node_pointer group_end(next_group(n));
+ node_pointer pos = this->add_node_equiv(
+ boost::unordered::detail::func::construct_node(
+ this->node_alloc(), n->value()),
+ key_hash, node_pointer());
+ for (n = next_node(n); n != group_end; n = next_node(n)) {
+ this->add_node_equiv(
+ boost::unordered::detail::func::construct_node(
+ this->node_alloc(), n->value()),
key_hash, pos);
}
}
}
- void move_buckets(table const& src)
+ void move_buckets_equiv(table const& src)
{
this->create_buckets(this->bucket_count_);
for (node_pointer n = src.begin(); n;) {
- std::size_t key_hash = n->hash_;
- node_pointer group_end(node_algo::next_group(n, this));
- node_pointer pos =
- this->add_node(boost::unordered::detail::func::construct_node(
- this->node_alloc(), boost::move(n->value())),
- key_hash, node_pointer());
- for (n = node_algo::next_node(n); n != group_end;
- n = node_algo::next_node(n)) {
- this->add_node(boost::unordered::detail::func::construct_node(
- this->node_alloc(), boost::move(n->value())),
+ std::size_t key_hash = this->hash(this->get_key(n));
+ node_pointer group_end(next_group(n));
+ node_pointer pos = this->add_node_equiv(
+ boost::unordered::detail::func::construct_node(
+ this->node_alloc(), boost::move(n->value())),
+ key_hash, node_pointer());
+ for (n = next_node(n); n != group_end; n = next_node(n)) {
+ this->add_node_equiv(
+ boost::unordered::detail::func::construct_node(
+ this->node_alloc(), boost::move(n->value())),
key_hash, pos);
}
}
}
- void assign_buckets(table const& src)
+ void assign_buckets(table const& src, false_type)
{
node_holder<node_allocator> holder(*this);
for (node_pointer n = src.begin(); n;) {
- std::size_t key_hash = n->hash_;
- node_pointer group_end(node_algo::next_group(n, this));
- node_pointer pos = this->add_node(
+ std::size_t key_hash = this->hash(this->get_key(n));
+ node_pointer group_end(next_group(n));
+ node_pointer pos = this->add_node_equiv(
holder.copy_of(n->value()), key_hash, node_pointer());
- for (n = node_algo::next_node(n); n != group_end;
- n = node_algo::next_node(n)) {
- this->add_node(holder.copy_of(n->value()), key_hash, pos);
+ for (n = next_node(n); n != group_end; n = next_node(n)) {
+ this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos);
}
}
}
- void move_assign_buckets(table& src)
+ void move_assign_buckets(table& src, false_type)
{
node_holder<node_allocator> holder(*this);
for (node_pointer n = src.begin(); n;) {
- std::size_t key_hash = n->hash_;
- node_pointer group_end(node_algo::next_group(n, this));
- node_pointer pos = this->add_node(
+ std::size_t key_hash = this->hash(this->get_key(n));
+ node_pointer group_end(next_group(n));
+ node_pointer pos = this->add_node_equiv(
holder.move_copy_of(n->value()), key_hash, node_pointer());
- for (n = node_algo::next_node(n); n != group_end;
- n = node_algo::next_node(n)) {
- this->add_node(holder.move_copy_of(n->value()), key_hash, pos);
+ for (n = next_node(n); n != group_end; n = next_node(n)) {
+ this->add_node_equiv(
+ holder.move_copy_of(n->value()), key_hash, pos);
+ }
+ }
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////
+// Clear
+
+template <typename Types> inline void table<Types>::clear_impl()
+{
+ if (size_) {
+ bucket_pointer end = get_bucket(bucket_count_);
+ for (bucket_pointer it = buckets_; it != end; ++it) {
+ it->next_ = node_pointer();
+ }
+
+ link_pointer prev = end->first_from_start();
+ node_pointer n = next_node(prev);
+ prev->next_ = node_pointer();
+ size_ = 0;
+
+ while (n) {
+ node_pointer next = next_node(n);
+ destroy_node(n);
+ n = next;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Reserve & Rehash
+
+// basic exception safety
+template <typename Types>
+inline void table<Types>::reserve_for_insert(std::size_t size)
+{
+ if (!buckets_) {
+ create_buckets((std::max)(bucket_count_, min_buckets_for_size(size)));
+ } else if (size > max_load_) {
+ std::size_t num_buckets =
+ min_buckets_for_size((std::max)(size, size_ + (size_ >> 1)));
+
+ if (num_buckets != bucket_count_)
+ this->rehash_impl(num_buckets);
+ }
+}
+
+// if hash function throws, basic exception safety
+// strong otherwise.
+
+template <typename Types>
+inline void table<Types>::rehash(std::size_t min_buckets)
+{
+ using namespace std;
+
+ if (!size_) {
+ delete_buckets();
+ bucket_count_ = policy::new_bucket_count(min_buckets);
+ } else {
+ min_buckets = policy::new_bucket_count((std::max)(min_buckets,
+ boost::unordered::detail::double_to_size(
+ floor(static_cast<double>(size_) / static_cast<double>(mlf_))) +
+ 1));
+
+ if (min_buckets != bucket_count_)
+ this->rehash_impl(min_buckets);
+ }
+}
+
+template <typename Types>
+inline void table<Types>::rehash_impl(std::size_t num_buckets)
+{
+ BOOST_ASSERT(this->buckets_);
+
+ this->create_buckets(num_buckets);
+ link_pointer prev = this->get_previous_start();
+ BOOST_TRY
+ {
+ while (prev->next_) {
+ node_pointer n = next_node(prev);
+ std::size_t key_hash = this->hash(this->get_key(n));
+ std::size_t bucket_index = this->hash_to_bucket(key_hash);
+
+ n->bucket_info_ = bucket_index;
+ n->set_first_in_group();
+
+ // Iterator through the rest of the group of equal nodes,
+ // setting the bucket.
+ for (;;) {
+ node_pointer next = next_node(n);
+ if (!next || next->is_first_in_group()) {
+ break;
+ }
+ n = next;
+ n->bucket_info_ = bucket_index;
+ n->reset_first_in_group();
+ }
+
+ // n is now the last node in the group
+ bucket_pointer b = this->get_bucket(bucket_index);
+ if (!b->next_) {
+ b->next_ = prev;
+ prev = n;
+ } else {
+ link_pointer next = n->next_;
+ n->next_ = b->next_->next_;
+ b->next_->next_ = prev->next_;
+ prev->next_ = next;
}
}
}
+ BOOST_CATCH(...)
+ {
+ node_pointer n = next_node(prev);
+ prev->next_ = node_pointer();
+ while (n) {
+ node_pointer next = next_node(n);
+ destroy_node(n);
+ --size_;
+ n = next;
+ }
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+}
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// key extractors
+//
+// no throw
+//
+// 'extract_key' is called with the emplace parameters to return a
+// key if available or 'no_key' is one isn't and will need to be
+// constructed. This could be done by overloading the emplace implementation
+// for the different cases, but that's a bit tricky on compilers without
+// variadic templates.
+
+template <typename Key, typename T> struct is_key
+{
+ template <typename T2> static choice1::type test(T2 const&);
+ static choice2::type test(Key const&);
+
+ enum
+ {
+ value = sizeof(test(boost::unordered::detail::make<T>())) ==
+ sizeof(choice2::type)
+ };
+
+ typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE
+ then<Key const&, no_key>::type type;
+};
+
+template <class ValueType> struct set_extractor
+{
+ typedef ValueType value_type;
+ typedef ValueType key_type;
+
+ static key_type const& extract(value_type const& v) { return v; }
+
+ static key_type const& extract(BOOST_UNORDERED_RV_REF(value_type) v)
+ {
+ return v;
+ }
+
+ static no_key extract() { return no_key(); }
+
+ template <class Arg> static no_key extract(Arg const&) { return no_key(); }
+
+#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+ template <class Arg1, class Arg2, class... Args>
+ static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
+ {
+ return no_key();
+ }
+#else
+ template <class Arg1, class Arg2>
+ static no_key extract(Arg1 const&, Arg2 const&)
+ {
+ return no_key();
+ }
+#endif
+};
+
+template <class ValueType> struct map_extractor
+{
+ typedef ValueType value_type;
+ typedef typename boost::remove_const<typename boost::unordered::detail::
+ pair_traits<ValueType>::first_type>::type key_type;
+
+ static key_type const& extract(value_type const& v) { return v.first; }
+
+ template <class Second>
+ static key_type const& extract(std::pair<key_type, Second> const& v)
+ {
+ return v.first;
+ }
+
+ template <class Second>
+ static key_type const& extract(std::pair<key_type const, Second> const& v)
+ {
+ return v.first;
+ }
+
+#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template <class Second>
+ static key_type const& extract(
+ boost::rv<std::pair<key_type, Second> > const& v)
+ {
+ return v.first;
+ }
+
+ template <class Second>
+ static key_type const& extract(
+ boost::rv<std::pair<key_type const, Second> > const& v)
+ {
+ return v.first;
+ }
+#endif
+
+ template <class Arg1>
+ static key_type const& extract(key_type const& k, Arg1 const&)
+ {
+ return k;
+ }
+
+ static no_key extract() { return no_key(); }
+
+ template <class Arg> static no_key extract(Arg const&) { return no_key(); }
+
+ template <class Arg1, class Arg2>
+ static no_key extract(Arg1 const&, Arg2 const&)
+ {
+ return no_key();
+ }
+
+#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+ template <class Arg1, class Arg2, class Arg3, class... Args>
+ static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, Args const&...)
+ {
+ return no_key();
+ }
+#endif
+
+#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
+ template <typename T2> \
+ static no_key extract(boost::unordered::piecewise_construct_t, \
+ namespace_ tuple<> const&, T2 const&) \
+ { \
+ return no_key(); \
+ } \
+ \
+ template <typename T, typename T2> \
+ static typename is_key<key_type, T>::type extract( \
+ boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k, \
+ T2 const&) \
+ { \
+ return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \
+ }
+
+#else
+
+#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
+ static no_key extract( \
+ boost::unordered::piecewise_construct_t, namespace_ tuple<> const&) \
+ { \
+ return no_key(); \
+ } \
+ \
+ template <typename T> \
+ static typename is_key<key_type, T>::type extract( \
+ boost::unordered::piecewise_construct_t, namespace_ tuple<T> const& k) \
+ { \
+ return typename is_key<key_type, T>::type(namespace_ get<0>(k)); \
+ }
+
+#endif
+
+ BOOST_UNORDERED_KEY_FROM_TUPLE(boost::)
+
+#if BOOST_UNORDERED_TUPLE_ARGS
+ BOOST_UNORDERED_KEY_FROM_TUPLE(std::)
+#endif
+
+#undef BOOST_UNORDERED_KEY_FROM_TUPLE
+};
+
+////////////////////////////////////////////////////////////////////////
+// Unique nodes
+
+template <typename A, typename T>
+struct node : boost::unordered::detail::value_base<T>
+{
+ typedef typename ::boost::unordered::detail::rebind_wrap<A,
+ node<A, T> >::type allocator;
+ typedef typename ::boost::unordered::detail::allocator_traits<
+ allocator>::pointer node_pointer;
+ typedef node_pointer link_pointer;
+ typedef typename ::boost::unordered::detail::rebind_wrap<A,
+ bucket<node_pointer> >::type bucket_allocator;
+ typedef typename ::boost::unordered::detail::allocator_traits<
+ bucket_allocator>::pointer bucket_pointer;
+
+ link_pointer next_;
+ std::size_t bucket_info_;
+
+ node() : next_(), bucket_info_(0) {}
+
+ std::size_t get_bucket() const
+ {
+ return bucket_info_ & ((std::size_t)-1 >> 1);
+ }
+
+ std::size_t is_first_in_group() const
+ {
+ return !(bucket_info_ & ~((std::size_t)-1 >> 1));
+ }
+
+ void set_first_in_group()
+ {
+ bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1);
+ }
+
+ void reset_first_in_group()
+ {
+ bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1);
+ }
+
+ private:
+ node& operator=(node const&);
+};
+
+template <typename T> struct ptr_node : boost::unordered::detail::ptr_bucket
+{
+ typedef T value_type;
+ typedef boost::unordered::detail::ptr_bucket bucket_base;
+ typedef ptr_node<T>* node_pointer;
+ typedef ptr_bucket* link_pointer;
+ typedef ptr_bucket* bucket_pointer;
+
+ std::size_t bucket_info_;
+ boost::unordered::detail::value_base<T> value_base_;
+
+ ptr_node() : bucket_base(), bucket_info_(0) {}
+
+ void* address() { return value_base_.address(); }
+ value_type& value() { return value_base_.value(); }
+ value_type* value_ptr() { return value_base_.value_ptr(); }
+
+ std::size_t get_bucket() const
+ {
+ return bucket_info_ & ((std::size_t)-1 >> 1);
+ }
+
+ std::size_t is_first_in_group() const
+ {
+ return !(bucket_info_ & ~((std::size_t)-1 >> 1));
+ }
+
+ void set_first_in_group()
+ {
+ bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1);
+ }
+
+ void reset_first_in_group()
+ {
+ bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1);
+ }
+
+ private:
+ ptr_node& operator=(ptr_node const&);
+};
+
+// If the allocator uses raw pointers use ptr_node
+// Otherwise use node.
+
+template <typename A, typename T, typename NodePtr, typename BucketPtr>
+struct pick_node2
+{
+ typedef boost::unordered::detail::node<A, T> node;
+
+ typedef typename boost::unordered::detail::allocator_traits<
+ typename boost::unordered::detail::rebind_wrap<A, node>::type>::pointer
+ node_pointer;
+
+ typedef boost::unordered::detail::bucket<node_pointer> bucket;
+ typedef node_pointer link_pointer;
+};
+
+template <typename A, typename T>
+struct pick_node2<A, T, boost::unordered::detail::ptr_node<T>*,
+ boost::unordered::detail::ptr_bucket*>
+{
+ typedef boost::unordered::detail::ptr_node<T> node;
+ typedef boost::unordered::detail::ptr_bucket bucket;
+ typedef bucket* link_pointer;
+};
+
+template <typename A, typename T> struct pick_node
+{
+ typedef typename boost::remove_const<T>::type nonconst;
+
+ typedef boost::unordered::detail::allocator_traits<
+ typename boost::unordered::detail::rebind_wrap<A,
+ boost::unordered::detail::ptr_node<nonconst> >::type>
+ tentative_node_traits;
+
+ typedef boost::unordered::detail::allocator_traits<
+ typename boost::unordered::detail::rebind_wrap<A,
+ boost::unordered::detail::ptr_bucket>::type>
+ tentative_bucket_traits;
+
+ typedef pick_node2<A, nonconst, typename tentative_node_traits::pointer,
+ typename tentative_bucket_traits::pointer>
+ pick;
+
+ typedef typename pick::node node;
+ typedef typename pick::bucket bucket;
+ typedef typename pick::link_pointer link_pointer;
};
}
}
}
+#undef BOOST_UNORDERED_EMPLACE_TEMPLATE
+#undef BOOST_UNORDERED_EMPLACE_ARGS
+#undef BOOST_UNORDERED_EMPLACE_FORWARD
+#undef BOOST_UNORDERED_CALL_CONSTRUCT1
+#undef BOOST_UNORDERED_CALL_DESTROY
+
#endif