// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2005-2016 Daniel James // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP #define BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP #include #if defined(BOOST_HAS_PRAGMA_ONCE) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) #include #endif //////////////////////////////////////////////////////////////////////////////// // Configuration // // Unless documented elsewhere these configuration macros should be considered // an implementation detail, I'll try not to break them, but you never know. // 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_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_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_EMPLACE_LIMIT #define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif // BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - Pick which version of // allocator_traits to use. // // 0 = Own partial implementation // 1 = std::allocator_traits // 2 = boost::container::allocator_traits #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) #if !defined(BOOST_NO_CXX11_ALLOCATOR) #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 #elif defined(BOOST_MSVC) #if BOOST_MSVC < 1400 // Use container's allocator_traits for older versions of Visual // C++ as I don't test with them. #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2 #endif #endif #endif #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) #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 #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 struct iterator; template struct c_iterator; template struct l_iterator; template struct cl_iterator; } } } namespace boost { namespace unordered { namespace detail { template struct table; template struct bucket; struct ptr_bucket; template struct node; template struct ptr_node; 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 no_key(T const&) {} }; namespace func { template inline void ignore_unused_variable_warning(T const&) {} } //////////////////////////////////////////////////////////////////////////// // iterator SFINAE template struct is_forward : boost::is_convertible::type, boost::forward_traversal_tag> { }; template struct enable_if_forward : boost::enable_if_c::value, ReturnType> { }; template struct disable_if_forward : boost::disable_if_c::value, ReturnType> { }; //////////////////////////////////////////////////////////////////////////// // primes // clang-format off #define BOOST_UNORDERED_PRIMES \ (17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ (1610612741ul)(3221225473ul)(4294967291ul) // clang-format on template struct prime_list_template { static std::size_t const value[]; #if !BOOST_UNORDERED_SUN_WORKAROUNDS1 static std::ptrdiff_t const length; #else static std::ptrdiff_t const length = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); #endif }; template std::size_t const prime_list_template::value[] = { BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)}; #if !BOOST_UNORDERED_SUN_WORKAROUNDS1 template std::ptrdiff_t const prime_list_template::length = BOOST_PP_SEQ_SIZE( BOOST_UNORDERED_PRIMES); #endif #undef BOOST_UNORDERED_PRIMES typedef prime_list_template prime_list; // no throw inline std::size_t next_prime(std::size_t num) { std::size_t const* const prime_list_begin = prime_list::value; std::size_t const* const prime_list_end = prime_list_begin + prime_list::length; std::size_t const* bound = std::lower_bound(prime_list_begin, prime_list_end, num); if (bound == prime_list_end) bound--; return *bound; } // no throw inline std::size_t prev_prime(std::size_t num) { std::size_t const* const prime_list_begin = prime_list::value; std::size_t const* const prime_list_end = prime_list_begin + prime_list::length; std::size_t const* bound = std::upper_bound(prime_list_begin, prime_list_end, num); if (bound != prime_list_begin) bound--; return *bound; } //////////////////////////////////////////////////////////////////////////// // insert_size/initial_size template inline std::size_t insert_size(I i, I j, typename boost::unordered::detail::enable_if_forward::type = 0) { return static_cast(std::distance(i, j)); } template inline std::size_t insert_size(I, I, typename boost::unordered::detail::disable_if_forward::type = 0) { return 1; } template inline std::size_t initial_size(I i, I j, std::size_t num_buckets = boost::unordered::detail::default_bucket_count) { // TODO: Why +1? return (std::max)( boost::unordered::detail::insert_size(i, j) + 1, num_buckets); } //////////////////////////////////////////////////////////////////////////// // compressed template struct compressed_base : private T { compressed_base(T const& x) : T(x) {} compressed_base(T& x, move_tag) : T(boost::move(x)) {} T& get() { return *this; } T const& get() const { return *this; } }; template struct uncompressed_base { uncompressed_base(T const& x) : value_(x) {} uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {} T& get() { return value_; } T const& get() const { return value_; } private: T value_; }; template struct generate_base : boost::detail::if_true::value>::BOOST_NESTED_TEMPLATE then, boost::unordered::detail::uncompressed_base > { }; template struct compressed : private boost::unordered::detail::generate_base::type, private boost::unordered::detail::generate_base::type { typedef typename generate_base::type base1; typedef typename generate_base::type base2; typedef T1 first_type; typedef T2 second_type; first_type& first() { return static_cast(this)->get(); } first_type const& first() const { return static_cast(this)->get(); } second_type& second() { return static_cast(this)->get(); } second_type const& second() const { return static_cast(this)->get(); } template compressed(First const& x1, Second const& x2) : base1(x1), base2(x2) { } compressed(compressed const& x) : base1(x.first()), base2(x.second()) {} compressed(compressed& x, move_tag m) : base1(x.first(), m), base2(x.second(), m) { } void assign(compressed const& x) { first() = x.first(); second() = x.second(); } void move_assign(compressed& x) { first() = boost::move(x.first()); second() = boost::move(x.second()); } void swap(compressed& x) { boost::swap(first(), x.first()); boost::swap(second(), x.second()); } private: // Prevent assignment just to make use of assign or // move_assign explicit. compressed& operator=(compressed const&); }; //////////////////////////////////////////////////////////////////////////// // pair_traits // // Used to get the types from a pair without instantiating it. template struct pair_traits { typedef typename Pair::first_type first_type; typedef typename Pair::second_type second_type; }; template struct pair_traits > { typedef T1 first_type; typedef T2 second_type; }; #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable : 4512) // assignment operator could not be generated. #pragma warning(disable : 4345) // behavior change: an object of POD type // constructed with an initializer of the form () // will be default-initialized. #endif //////////////////////////////////////////////////////////////////////////// // Bits and pieces for implementing traits template typename boost::add_lvalue_reference::type make(); struct choice9 { typedef char (&type)[9]; }; struct choice8 : choice9 { typedef char (&type)[8]; }; struct choice7 : choice8 { typedef char (&type)[7]; }; struct choice6 : choice7 { typedef char (&type)[6]; }; struct choice5 : choice6 { typedef char (&type)[5]; }; struct choice4 : choice5 { typedef char (&type)[4]; }; struct choice3 : choice4 { typedef char (&type)[3]; }; struct choice2 : choice3 { typedef char (&type)[2]; }; struct choice1 : choice2 { typedef char (&type)[1]; }; choice1 choose(); typedef choice1::type yes_type; typedef choice2::type no_type; struct private_type { private_type const& operator,(int) const; }; template no_type is_private_type(T const&); yes_type is_private_type(private_type const&); struct convert_from_anything { template convert_from_anything(T const&); }; // Get a pointer from a smart pointer, a bit simpler than pointer_traits // as we already know the pointer type that we want. template struct pointer { template static T* get(Ptr const& x) { return static_cast(x.operator->()); } template static T* get(T2* x) { return static_cast(x); } }; //////////////////////////////////////////////////////////////////////////// // emplace_args // // Either forwarding variadic arguments, or storing the arguments in // emplace_args##n #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #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)... #else #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args #define BOOST_UNORDERED_EMPLACE_ARGS Args const& args #define BOOST_UNORDERED_EMPLACE_FORWARD args #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \ BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); #else #define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ typedef typename boost::add_lvalue_reference::type \ BOOST_PP_CAT(Arg, n); \ BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); #endif template struct emplace_args1 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) explicit emplace_args1(Arg0 b0) : a0(b0) {} }; template inline emplace_args1 create_emplace_args(BOOST_FWD_REF(A0) b0) { emplace_args1 e(b0); return e; } template struct emplace_args2 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {} }; template inline emplace_args2 create_emplace_args( BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1) { emplace_args2 e(b0, b1); return e; } template struct emplace_args3 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) BOOST_UNORDERED_EARGS_MEMBER(1, 2, _) emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {} }; template inline emplace_args3 create_emplace_args( BOOST_FWD_REF(A0) b0, BOOST_FWD_REF(A1) b1, BOOST_FWD_REF(A2) b2) { emplace_args3 e(b0, b1, b2); return e; } #define BOOST_UNORDERED_FWD_PARAM(z, n, a) \ BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n) #define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \ boost::forward(BOOST_PP_CAT(a, i)) #define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) #define BOOST_UNORDERED_EARGS(z, n, _) \ template \ struct BOOST_PP_CAT(emplace_args, n) \ { \ BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) BOOST_PP_CAT( \ emplace_args, n)(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, b)) \ : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \ { \ } \ }; \ \ template \ inline BOOST_PP_CAT(emplace_args, n) \ create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b)) \ { \ BOOST_PP_CAT(emplace_args, n) e( \ BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \ 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( 10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EARGS, _) #undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS #undef BOOST_UNORDERED_EARGS_MEMBER #undef BOOST_UNORDERED_EARGS_INIT #endif //////////////////////////////////////////////////////////////////////////////// // // Some utilities for implementing allocator_traits, but useful elsewhere so // they're always defined. //////////////////////////////////////////////////////////////////////////// // Integral_constrant, true_type, false_type // // Uses the standard versions if available. #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) using std::integral_constant; using std::true_type; using std::false_type; #else template struct integral_constant { enum { value = Value }; }; typedef boost::unordered::detail::integral_constant true_type; typedef boost::unordered::detail::integral_constant false_type; #endif //////////////////////////////////////////////////////////////////////////// // Explicitly call a destructor #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable : 4100) // unreferenced formal parameter #endif namespace func { template inline void destroy(T* x) { x->~T(); } } #if defined(BOOST_MSVC) #pragma warning(pop) #endif //////////////////////////////////////////////////////////////////////////// // Expression test mechanism // // When SFINAE expressions are available, define // BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is // supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which // can detect if a class has the specified member, but not that it has the // correct type, this is good enough for a passable impression of // allocator_traits. #if !defined(BOOST_NO_SFINAE_EXPR) template struct expr_test; template struct expr_test : T { }; #define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ template \ static typename boost::unordered::detail::expr_test::type \ test(BOOST_PP_CAT(choice, count)) #define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ template \ static BOOST_PP_CAT(choice, result)::type test( \ BOOST_PP_CAT(choice, count)) #define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \ struct BOOST_PP_CAT(has_, name) \ { \ template static char for_expr_test(U const&); \ BOOST_UNORDERED_CHECK_EXPRESSION( \ 1, 1, boost::unordered::detail::make().name args); \ BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ \ enum \ { \ value = sizeof(test(choose())) == sizeof(choice1::type) \ }; \ } #else template struct identity { typedef T type; }; #define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ \ typedef typename boost::unordered::detail::identity::type \ BOOST_PP_CAT(check, count); \ \ template struct BOOST_PP_CAT(test, count) \ { \ typedef BOOST_PP_CAT(choice, result) type; \ }; \ \ template \ static typename BOOST_PP_CAT(test, count)<&U::name>::type test( \ BOOST_PP_CAT(choice, count)) #define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ template \ static BOOST_PP_CAT(choice, result)::type test( \ BOOST_PP_CAT(choice, count)) #define BOOST_UNORDERED_HAS_MEMBER(name) \ struct BOOST_PP_CAT(has_, name) \ { \ struct impl \ { \ struct base_mixin \ { \ int name; \ }; \ struct base : public T, public base_mixin \ { \ }; \ \ BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, int base_mixin::*); \ BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \ \ enum \ { \ value = sizeof(choice2::type) == sizeof(test(choose())) \ }; \ }; \ \ enum \ { \ value = impl::value \ }; \ } #endif } } } //////////////////////////////////////////////////////////////////////////////// // // Allocator traits // // First our implementation, then later light wrappers around the alternatives #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 #include #include #include namespace boost { namespace unordered { namespace detail { template struct rebind_alloc; #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template