/usr/include/boost/unordered/detail
Edit: /usr/include/boost/unordered/detail/implementation.hpp (163989B)
// 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
#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
// BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES)
#if BOOST_COMP_CLANG && __cplusplus >= 201703
#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 1
#endif
#endif
#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES)
#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 0
#endif
namespace boost {
namespace unordered {
namespace iterator_detail {
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_base_of::iterator_category>
{
};
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
namespace boost {
namespace unordered {
namespace detail {
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)
{
return (std::max)(
boost::unordered::detail::insert_size(i, j), num_buckets);
}
//////////////////////////////////////////////////////////////////////////
// compressed
template struct compressed_base : private T
{
compressed_base(T const& x) : T(x) {}
compressed_base(T& x, move_tag) : T(boost::move(x)) {}
T& get() { return *this; }
T const& get() const { return *this; }
};
template struct uncompressed_base
{
uncompressed_base(T const& x) : value_(x) {}
uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
T& get() { return value_; }
T const& get() const { return value_; }
private:
T value_;
};
template
struct generate_base
: boost::detail::if_true<
boost::is_empty::value>::BOOST_NESTED_TEMPLATE
then,
boost::unordered::detail::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&);
};
}
}
}
////////////////////////////////////////////////////////////////////////////
// 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
#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; \
}
namespace boost {
namespace unordered {
namespace detail {
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;
}
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.
namespace boost {
namespace unordered {
namespace detail {
////////////////////////////////////////////////////////////////////////////
// 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
//////////////////////////////////////////////////////////////////////////
// value_base
//
// Space used to store values.
template struct value_base
{
typedef ValueType value_type;
typename boost::aligned_storage::value>::type data_;
value_base() : data_() {}
void* address() { return this; }
value_type& value() { return *(ValueType*)this; }
value_type const& value() const { return *(ValueType const*)this; }
value_type* value_ptr() { return (ValueType*)this; }
value_type const* value_ptr() const { return (ValueType const*)this; }
private:
value_base& operator=(value_base const&);
};
//////////////////////////////////////////////////////////////////////////
// optional
// TODO: Use std::optional when available.
template class optional
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(optional)
boost::unordered::detail::value_base value_;
bool has_value_;
void destroy()
{
if (has_value_) {
boost::unordered::detail::func::destroy(value_.value_ptr());
has_value_ = false;
}
}
void move(optional& x)
{
BOOST_ASSERT(!has_value_ && x.has_value_);
new (value_.value_ptr()) T(boost::move(x.value_.value()));
boost::unordered::detail::func::destroy(x.value_.value_ptr());
has_value_ = true;
x.has_value_ = false;
}
public:
optional() BOOST_NOEXCEPT : has_value_(false) {}
optional(BOOST_RV_REF(optional) x) : has_value_(false)
{
if (x.has_value_) {
move(x);
}
}
explicit optional(T const& x) : has_value_(true)
{
new (value_.value_ptr()) T(x);
}
optional& operator=(BOOST_RV_REF(optional) x)
{
destroy();
if (x.has_value_) {
move(x);
}
return *this;
}
~optional() { destroy(); }
bool has_value() const { return has_value_; }
T& operator*() { return value_.value(); }
T const& operator*() const { return value_.value(); }
T* operator->() { return value_.value_ptr(); }
T const* operator->() const { return value_.value_ptr(); }
bool operator==(optional const& x)
{
return has_value_ ? x.has_value_ && value_.value() == x.value_.value()
: !x.has_value_;
}
bool operator!=(optional const& x) { return !((*this) == x); }
void swap(optional& x)
{
if (has_value_ != x.has_value_) {
if (has_value_) {
x.move(*this);
} else {
move(x);
}
} else if (has_value_) {
boost::swap(value_.value(), x.value_.value());
}
}
friend void swap(optional& x, optional& y) { x.swap(y); }
};
}
}
}
////////////////////////////////////////////////////////////////////////////
// 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)
namespace boost {
namespace unordered {
namespace detail {
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
namespace boost {
namespace unordered {
namespace detail {
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
////////////////////////////////////////////////////////////////////////////
// TRAITS TYPE DETECTION MECHANISM
//
// Used to implement traits that use a type if present, or a
// default otherwise.
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
template struct default_type_##tname \
{ \
\
template \
static choice1::type test(choice1, typename X::tname* = 0); \
\
template static choice2::type test(choice2, void* = 0); \
\
struct DefaultWrap \
{ \
typedef Default tname; \
}; \
\
enum \
{ \
value = (1 == sizeof(test(choose()))) \
}; \
\
typedef typename boost::detail::if_true::BOOST_NESTED_TEMPLATE \
then::type::tname type; \
}
#else
namespace boost {
namespace unordered {
namespace detail {
template struct sfinae : T2
{
};
}
}
}
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
template struct default_type_##tname \
{ \
\
template \
static typename boost::unordered::detail::sfinae::type test(choice1); \
\
template static choice2::type test(choice2); \
\
struct DefaultWrap \
{ \
typedef Default tname; \
}; \
\
enum \
{ \
value = (1 == sizeof(test(choose()))) \
}; \
\
typedef typename boost::detail::if_true::BOOST_NESTED_TEMPLATE \
then::type::tname type; \
}
#endif
#define BOOST_UNORDERED_DEFAULT_TYPE(T, tname, arg) \
typename default_type_##tname::type
////////////////////////////////////////////////////////////////////////////////
//
// 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 class Alloc, typename U,
typename T, typename... Args>
struct rebind_alloc, T>
{
typedef Alloc type;
};
#else
template class Alloc, typename U, typename T>
struct rebind_alloc, T>
{
typedef Alloc type;
};
template class Alloc, typename U,
typename T, typename A0>
struct rebind_alloc, T>
{
typedef Alloc type;
};
template class Alloc, typename U,
typename T, typename A0, typename A1>
struct rebind_alloc, T>
{
typedef Alloc type;
};
#endif
template struct rebind_wrap
{
template
static choice1::type test(
choice1, typename X::BOOST_NESTED_TEMPLATE rebind::other* = 0);
template static choice2::type test(choice2, void* = 0);
enum
{
value = (1 == sizeof(test(choose())))
};
struct fallback
{
template struct rebind
{
typedef typename rebind_alloc::type other;
};
};
typedef
typename boost::detail::if_true::BOOST_NESTED_TEMPLATE then<
Alloc, fallback>::type::BOOST_NESTED_TEMPLATE rebind::other type;
};
}
}
}
namespace boost {
namespace unordered {
namespace detail {
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
propagate_on_container_copy_assignment);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
propagate_on_container_move_assignment);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(is_always_equal);
#if !defined(BOOST_NO_SFINAE_EXPR)
template
BOOST_UNORDERED_HAS_FUNCTION(
select_on_container_copy_construction, U const, (), 0);
template
BOOST_UNORDERED_HAS_FUNCTION(max_size, U const, (), 0);
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template
BOOST_UNORDERED_HAS_FUNCTION(construct, U,
(boost::unordered::detail::make(),
boost::unordered::detail::make()...),
2);
#else
template
BOOST_UNORDERED_HAS_FUNCTION(construct, U,
(boost::unordered::detail::make(),
boost::unordered::detail::make()),
2);
#endif
template
BOOST_UNORDERED_HAS_FUNCTION(
destroy, U, (boost::unordered::detail::make()), 1);
#else
template
BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction);
template BOOST_UNORDERED_HAS_MEMBER(max_size);
template
BOOST_UNORDERED_HAS_MEMBER(construct);
template
BOOST_UNORDERED_HAS_MEMBER(destroy);
#endif
}
}
}
namespace boost {
namespace unordered {
namespace detail {
namespace func {
template
inline Alloc call_select_on_container_copy_construction(
const Alloc& rhs,
typename boost::enable_if_c<
boost::unordered::detail::has_select_on_container_copy_construction<
Alloc>::value,
void*>::type = 0)
{
return rhs.select_on_container_copy_construction();
}
template
inline Alloc call_select_on_container_copy_construction(
const Alloc& rhs,
typename boost::disable_if_c<
boost::unordered::detail::has_select_on_container_copy_construction<
Alloc>::value,
void*>::type = 0)
{
return rhs;
}
template
inline SizeType call_max_size(const Alloc& a,
typename boost::enable_if_c<
boost::unordered::detail::has_max_size::value, void*>::type =
0)
{
return a.max_size();
}
template
inline SizeType call_max_size(const Alloc&,
typename boost::disable_if_c<
boost::unordered::detail::has_max_size::value, void*>::type =
0)
{
return (std::numeric_limits::max)();
}
} // namespace func.
}
}
}
namespace boost {
namespace unordered {
namespace detail {
template struct allocator_traits
{
typedef Alloc allocator_type;
typedef typename Alloc::value_type value_type;
typedef BOOST_UNORDERED_DEFAULT_TYPE(
Alloc, pointer, value_type*) pointer;
template
struct pointer_to_other : boost::pointer_to_other
{
};
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
typename pointer_to_other::type) const_pointer;
// typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
// typename pointer_to_other::type)
// void_pointer;
//
// typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
// typename pointer_to_other::type)
// const_void_pointer;
typedef BOOST_UNORDERED_DEFAULT_TYPE(
Alloc, difference_type, std::ptrdiff_t) difference_type;
typedef BOOST_UNORDERED_DEFAULT_TYPE(
Alloc, size_type, std::size_t) size_type;
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
template
using rebind_alloc = typename rebind_wrap::type;
template
using rebind_traits =
boost::unordered::detail::allocator_traits >;
#endif
static pointer allocate(Alloc& a, size_type n) { return a.allocate(n); }
// I never use this, so I'll just comment it out for now.
//
// static pointer allocate(Alloc& a, size_type n,
// const_void_pointer hint)
// { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); }
static void deallocate(Alloc& a, pointer p, size_type n)
{
a.deallocate(p, n);
}
public:
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
template
static
typename boost::enable_if_c::value>::type
construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x)
{
a.construct(p, boost::forward(x)...);
}
template
static
typename boost::disable_if_c::value>::type
construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x)
{
new (static_cast(p)) T(boost::forward(x)...);
}
template
static typename boost::enable_if_c<
boost::unordered::detail::has_destroy::value>::type
destroy(Alloc& a, T* p)
{
a.destroy(p);
}
template
static typename boost::disable_if_c<
boost::unordered::detail::has_destroy::value>::type
destroy(Alloc&, T* p)
{
boost::unordered::detail::func::destroy(p);
}
#elif !defined(BOOST_NO_SFINAE_EXPR)
template
static typename boost::enable_if_c<
boost::unordered::detail::has_construct::value>::type
construct(Alloc& a, T* p, T const& x)
{
a.construct(p, x);
}
template
static typename boost::disable_if_c<
boost::unordered::detail::has_construct::value>::type
construct(Alloc&, T* p, T const& x)
{
new (static_cast(p)) T(x);
}
template
static typename boost::enable_if_c<
boost::unordered::detail::has_destroy::value>::type
destroy(Alloc& a, T* p)
{
a.destroy(p);
}
template
static typename boost::disable_if_c<
boost::unordered::detail::has_destroy::value>::type
destroy(Alloc&, T* p)
{
boost::unordered::detail::func::destroy(p);
}
#else
// If we don't have SFINAE expressions, only call construct for the
// copy constructor for the allocator's value_type - as that's
// the only construct method that old fashioned allocators support.
template
static void construct(Alloc& a, T* p, T const& x,
typename boost::enable_if_c<
boost::unordered::detail::has_construct::value &&
boost::is_same::value,
void*>::type = 0)
{
a.construct(p, x);
}
template
static void construct(Alloc&, T* p, T const& x,
typename boost::disable_if_c<
boost::unordered::detail::has_construct::value &&
boost::is_same::value,
void*>::type = 0)
{
new (static_cast(p)) T(x);
}
template
static void destroy(Alloc& a, T* p,
typename boost::enable_if_c<
boost::unordered::detail::has_destroy::value &&
boost::is_same::value,
void*>::type = 0)
{
a.destroy(p);
}
template
static void destroy(Alloc&, T* p,
typename boost::disable_if_c<
boost::unordered::detail::has_destroy::value &&
boost::is_same::value,
void*>::type = 0)
{
boost::unordered::detail::func::destroy(p);
}
#endif
static size_type max_size(const Alloc& a)
{
return boost::unordered::detail::func::call_max_size(a);
}
// Allocator propagation on construction
static Alloc select_on_container_copy_construction(Alloc const& rhs)
{
return boost::unordered::detail::func::
call_select_on_container_copy_construction(rhs);
}
// Allocator propagation on assignment and swap.
// Return true if lhs is modified.
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc,
propagate_on_container_copy_assignment,
false_type) propagate_on_container_copy_assignment;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc,
propagate_on_container_move_assignment,
false_type) propagate_on_container_move_assignment;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, propagate_on_container_swap,
false_type) propagate_on_container_swap;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, is_always_equal,
typename boost::is_empty::type) is_always_equal;
};
}
}
}
#undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT
#undef BOOST_UNORDERED_DEFAULT_TYPE
////////////////////////////////////////////////////////////////////////////////
//
// std::allocator_traits
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
#include
namespace boost {
namespace unordered {
namespace detail {
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(is_always_equal);
template
struct allocator_traits : std::allocator_traits
{
// As is_always_equal was introduced in C++17, std::allocator_traits
// doesn't always have it. So use it when available, implement it
// ourselves when not. Would be simpler not to bother with
// std::allocator_traits, but I feel like I should try to use
// it where possible.
typedef BOOST_UNORDERED_DEFAULT_TYPE(std::allocator_traits,
is_always_equal,
BOOST_UNORDERED_DEFAULT_TYPE(Alloc, is_always_equal,
typename boost::is_empty::type)) is_always_equal;
};
template struct rebind_wrap
{
typedef typename std::allocator_traits::template rebind_alloc
type;
};
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
// boost::container::allocator_traits
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
#include