Unordered: Reorganization to use void pointers and other things.

Helps allocators which can't use incomplete pointers, and avoid using
base pointers where that might not be possible.  And some other
reorganization. Storing arguments to emplace in a structure when
variadic template parameters aren't available. Changed some of the odd
design for working with older compilers.

[SVN r74742]
This commit is contained in:
Daniel James
2011-10-05 19:45:14 +00:00
parent c0aaf908c0
commit dac1dc5837
16 changed files with 3110 additions and 2563 deletions

View File

@ -23,6 +23,7 @@
#include <boost/limits.hpp>
#include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/assert.hpp>
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
# include <memory>
@ -454,14 +455,14 @@ namespace boost { namespace unordered { namespace detail {
};
#endif
// allocator_array_constructor
// array_constructor
//
// Allocate and construct an array in an exception safe manner, and
// clean up if an exception is thrown before the container takes charge
// of it.
template <typename Allocator>
struct allocator_array_constructor
struct array_constructor
{
typedef typename allocator_traits<Allocator>::pointer
pointer;
@ -471,14 +472,14 @@ namespace boost { namespace unordered { namespace detail {
pointer constructed_;
std::size_t length_;
allocator_array_constructor(Allocator& a)
array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0)
{
constructed_ = pointer();
ptr_ = pointer();
}
~allocator_array_constructor() {
~array_constructor() {
if (ptr_) {
for(pointer p = ptr_; p != constructed_; ++p)
allocator_traits<Allocator>::destroy(alloc_,
@ -512,9 +513,9 @@ namespace boost { namespace unordered { namespace detail {
return p;
}
private:
allocator_array_constructor(allocator_array_constructor const&);
allocator_array_constructor& operator=(
allocator_array_constructor const&);
array_constructor(array_constructor const&);
array_constructor& operator=(
array_constructor const&);
};
}}}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,548 @@
// Copyright (C) 2011 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org/libs/unordered for documentation
#ifndef BOOST_UNORDERED_EMPLACE_ARGS_HPP
#define BOOST_UNORDERED_EMPLACE_ARGS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/move/move.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_shifted.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/tuple/tuple.hpp>
#include <utility>
#if !defined(BOOST_NO_0X_HDR_TUPLE)
#include <tuple>
#elif defined(BOOST_HAS_TR1_TUPLE)
#include <tr1/tuple>
#endif
#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
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#if 0 && !defined(BOOST_NO_RVALUE_REFERENCES) && \
!defined(BOOST_NO_VARIADIC_TEMPLATES)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
# elif defined(_LIBCPP_VERSION)
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# endif
# elif defined(__STL_CONFIG_H)
# elif defined(__MSL_CPP__)
# elif defined(__IBMCPP__)
# elif defined(MSIPL_COMPILE_H)
# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
// Visual C++. A version check would be a good idea.
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# endif
#endif
namespace boost { namespace unordered { namespace detail {
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
#define BOOST_UNORDERED_EMPLACE_ARGS Args&&... args
#define BOOST_UNORDERED_EMPLACE_FORWARD std::forward<Args>(args)...
#else
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
#define BOOST_UNORDERED_EMPLACE_FORWARD args
#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)>(BOOST_PP_CAT(a,i))
#define BOOST_UNORDERED_EARGS(z, n, _) \
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
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, B, a) \
) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \
{} \
\
}; \
\
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
inline BOOST_PP_CAT(emplace_args, n) < \
BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
> create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
BOOST_PP_CAT(emplace_args, n) < \
BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
> e(BOOST_PP_ENUM_PARAMS_Z(z, n, a)); \
return e; \
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(B, n); \
BOOST_PP_CAT(B, n) BOOST_PP_CAT(a, n);
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)( \
boost::forward<BOOST_PP_CAT(A,n)>(BOOST_PP_CAT(a, n)))
#else
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
BOOST_PP_CAT(B, n); \
BOOST_PP_CAT(B, n) BOOST_PP_CAT(a, n);
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(a, n))
#endif
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
_)
#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
#undef BOOST_UNORDERED_EARGS_MEMBER
#undef BOOST_UNORDERED_EARGS_INIT
#endif
////////////////////////////////////////////////////////////////////////////
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
// e.g. for int
#if !defined(BOOST_NO_RVALUE_REFERENCES)
# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
#else
struct please_ignore_this_overload {
typedef please_ignore_this_overload type;
};
template <typename T>
struct rv_ref_impl {
typedef BOOST_RV_REF(T) type;
};
template <typename T>
struct rv_ref :
boost::detail::if_true<
boost::is_class<T>::value
>::BOOST_NESTED_TEMPLATE then <
rv_ref_impl<T>,
please_ignore_this_overload
>::type
{};
# define BOOST_UNORDERED_RV_REF(T) \
typename ::boost::unordered::detail::rv_ref<T>::type
#endif
////////////////////////////////////////////////////////////////////////////
//
// Value Construction
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
template<typename T> \
void construct_from_tuple(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_) \
template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
void construct_from_tuple(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_) \
); \
}
#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
namespace_::get<n>(x)
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost)
#if !defined(BOOST_NO_0X_HDR_TUPLE)
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std)
#elif defined(BOOST_HAS_TR1_TUPLE)
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::tr1)
#endif
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
#undef BOOST_UNORDERED_GET_TUPLE_ARG
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename A, typename B, typename A0>
struct emulation1 {
static choice1::type check(choice1, std::pair<A, B> const&);
static choice2::type check(choice2, A const&);
static choice3::type check(choice3, ...);
enum { value =
sizeof(check(choose(), make<A0>())) == sizeof(choice2::type) };
};
#endif
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename A, typename B, typename A0>
struct check3_base {
static choice1::type check(choice1,
boost::unordered::piecewise_construct_t);
static choice2::type check(choice2, A const&);
static choice3::type check(choice3, ...);
};
#else
template <typename A, typename B, typename A0>
struct check3_base {
static choice1::type check(choice1,
boost::unordered::piecewise_construct_t);
static choice3::type check(choice3, ...);
};
#endif
template <typename A, typename B, typename A0>
struct piecewise3 {
enum { value =
sizeof(check3_base<A,B,A0>::check(choose(), make<A0>())) ==
sizeof(choice1::type) };
};
template <typename A, typename B, typename A0>
struct emulation3 {
enum { value =
sizeof(check3_base<A,B,A0>::check(choose(), make<A0>())) ==
sizeof(choice2::type) };
};
template <typename A, typename B, typename A0>
struct normal3 {
enum { value =
sizeof(check3_base<A,B,A0>::check(choose(), make<A0>())) ==
sizeof(choice3::type) };
};
template <typename T, typename A0>
struct pair_construct1 {};
template <typename T, typename A0>
struct normal_construct1 { typedef void type; };
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename A, typename B, typename A0>
struct pair_construct1<std::pair<A, B>, A0>
: enable_if<emulation1<A, B, A0>, void> {};
template <typename A, typename B, typename A0>
struct normal_construct1<std::pair<A, B>, A0>
: disable_if<emulation1<A, B, A0>, void> {};
#endif
template <typename T, typename A0>
struct piecewise_construct3 {};
template <typename A, typename B, typename A0>
struct piecewise_construct3<std::pair<A, B>, A0>
: enable_if<piecewise3<A, B, A0>, void> {};
template <typename T, typename A0>
struct pair_construct3 {};
template <typename A, typename B, typename A0>
struct pair_construct3<std::pair<A, B>, A0>
: enable_if<emulation3<A, B, A0>, void> {};
template <typename T, typename A0>
struct normal_construct3 { typedef void type; };
template <typename A, typename B, typename A0>
struct normal_construct3<std::pair<A, B>, A0>
: enable_if<normal3<A, B, A0>, void> {};
template <typename T>
struct pair_construct_n {};
template <typename T>
struct normal_construct_n { typedef void type; };
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename A, typename B>
struct pair_construct_n<std::pair<A, B> > { typedef void type; };
template <typename A, typename B>
struct normal_construct_n<std::pair<A, B> > {};
#endif
template <typename T, typename A0>
inline typename normal_construct1<T, A0>::type
construct_impl2(void* address, BOOST_FWD_REF(A0) a0)
{
new(address) T(
boost::forward<A0>(a0)
);
}
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
////////////////////////////////////////////////////////////////////////////////
// Construct from variadic parameters
template <typename T>
inline void construct_impl(void* address)
{
new(address) T();
}
template <typename T, typename A0>
inline typename normal_construct1<T, A0>::type
construct_impl(void* address, A0&& a0)
{
new(address) T(
boost::forward<A0>(a0)
);
}
template <typename T, typename A0>
inline typename pair_construct1<T, A0>::type
construct_impl(void* address, A0&& a0)
{
new((void*)(&static_cast<T*>(address)->first))
typename T::first_type(
boost::forward<A0>(a0));
new((void*)(&static_cast<T*>(address)->second))
typename T::second_type();
}
template <typename T, typename A0, typename A1>
inline void construct_impl(void* address, A0&& a0, A1&& a1)
{
new(address) T(
boost::forward<A0>(a0),
boost::forward<A1>(a1));
}
template <typename T, typename A0, typename A1, typename A2>
inline typename piecewise_construct3<T, A0>::type
construct_impl(void* address, A0&&, A1&& a1, A2&& a2)
{
construct_from_tuple(
boost::addressof(static_cast<T*>(address)->first), a1);
construct_from_tuple(
boost::addressof(static_cast<T*>(address)->second), a2);
}
template <typename T, typename A0, typename A1, typename A2>
inline typename pair_construct3<T, A0>::type
construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2)
{
new((void*)(&static_cast<T*>(address)->first))
typename T::first_type(
boost::forward<A0>(a0));
new((void*)(&static_cast<T*>(address)->second))
typename T::second_type(
boost::forward<A1>(a1),
boost::forward<A2>(a2));
}
template <typename T, typename A0, typename A1, typename A2>
inline typename normal_construct3<T, A0>::type
construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2)
{
new(address) T(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
boost::forward<A2>(a2));
}
template <typename T, typename A0, typename A1, typename A2, typename A3,
typename... Args>
inline typename normal_construct_n<T>::type
construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2,
A3&& a3, Args&&... args)
{
new(address) T(
std::forward<A0>(a0),
std::forward<A1>(a1),
std::forward<A2>(a2),
std::forward<A3>(a3),
std::forward<Args>(args)...);
}
template <typename T, typename A0, typename A1, typename A2, typename A3,
typename... Args>
inline typename pair_construct_n<T>::type
construct_impl(void* address, A0&& a0, A1&& a1, A2&& a2,
A3&& a3, Args&&... args)
{
new((void*)(&static_cast<T*>(address)->first))
typename T::first_type(
std::forward<A0>(a0));
new((void*)(&static_cast<T*>(address)->second))
typename T::second_type(
std::forward<A1>(a1),
std::forward<A2>(a2),
std::forward<A3>(a3),
std::forward<Args>(args)...);
}
#else
////////////////////////////////////////////////////////////////////////////////
// Construct with emplace_args
template <typename T, typename A0>
inline typename normal_construct1<T, A0>::type
construct_impl(void* address,
::boost::unordered::detail::emplace_args1<A0> const& args)
{
new(address) T(
boost::forward<A0>(args.a0)
);
}
template <typename T, typename A0>
inline typename pair_construct1<T, A0>::type
construct_impl(void* address, A0 const& a0)
{
new((void*)(&static_cast<T*>(address)->first))
typename T::first_type(
boost::forward<A0>(a0));
new((void*)(&static_cast<T*>(address)->second))
typename T::second_type();
}
template <typename T, typename A0>
inline typename pair_construct1<T, A0>::type
construct_impl(void* address,
::boost::unordered::detail::emplace_args1<A0> const& args)
{
new((void*)(&static_cast<T*>(address)->first))
typename T::first_type(
boost::forward<A0>(args.a0));
new((void*)(&static_cast<T*>(address)->second))
typename T::second_type();
}
template <typename T, typename A0, typename A1>
inline void construct_impl(void* address,
::boost::unordered::detail::emplace_args2<A0, A1> const& args)
{
new(address) T(
boost::forward<A0>(args.a0),
boost::forward<A1>(args.a1));
}
template <typename T, typename A0, typename A1, typename A2>
inline typename piecewise_construct3<T, A0>::type
construct_impl(void* address,
::boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
{
construct_from_tuple(
boost::addressof(static_cast<T*>(address)->first), args.a1);
construct_from_tuple(
boost::addressof(static_cast<T*>(address)->second), args.a2);
}
template <typename T, typename A0, typename A1, typename A2>
inline typename pair_construct3<T, A0>::type
construct_impl(void* address,
::boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
{
new((void*)(&static_cast<T*>(address)->first))
typename T::first_type(
boost::forward<A0>(args.a0));
new((void*)(&static_cast<T*>(address)->second))
typename T::second_type(
boost::forward<A1>(args.a1),
boost::forward<A2>(args.a2));
}
template <typename T, typename A0, typename A1, typename A2>
inline typename normal_construct3<T, A0>::type
construct_impl(void* address,
::boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
{
new(address) T(
boost::forward<A0>(args.a0),
boost::forward<A1>(args.a1),
boost::forward<A2>(args.a2));
}
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
template < \
typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
> \
inline typename normal_construct_n<T>::type \
construct_impl(void* address, \
::boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
> const& args) \
{ \
new(address) T( \
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \
args.a)); \
}
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \
template <typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
> \
inline typename pair_construct_n<T>::type \
construct_impl(void* address, \
::boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
> const& args) \
{ \
new((void*)(&static_cast<T*>(address)->first)) \
typename T::first_type( \
boost::forward<A0>(args.a0)); \
new((void*)(&static_cast<T*>(address)->second)) \
typename T::second_type( \
BOOST_PP_ENUM_SHIFTED_##z(num_params, \
BOOST_UNORDERED_CALL_FORWARD, args.a)); \
}
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _)
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
#undef BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL
#endif
}}}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif

View File

@ -7,60 +7,274 @@
#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/emplace_args.hpp>
#include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered { namespace detail {
template <class T>
class equivalent_table : public T::table_base
{
public:
typedef typename T::hasher hasher;
typedef typename T::key_equal key_equal;
typedef typename T::value_allocator value_allocator;
typedef typename T::key_type key_type;
typedef typename T::value_type value_type;
typedef typename T::table_base table_base;
typedef typename T::node_constructor node_constructor;
typedef typename T::node_allocator node_allocator;
template <typename VoidPointer, typename T> struct grouped_node;
template <typename T> struct grouped_ptr_node;
template <typename Types> struct grouped_table_impl;
typedef typename T::node node;
typedef typename T::node_ptr node_ptr;
typedef typename T::bucket_ptr bucket_ptr;
typedef typename T::extractor extractor;
template <typename VoidPointer, typename T>
struct grouped_node :
::boost::unordered::detail::value_base<T>
{
typedef VoidPointer link_pointer;
link_pointer next_;
link_pointer group_prev_;
std::size_t hash_;
grouped_node() :
next_(),
group_prev_(),
hash_(0)
{}
void init(link_pointer self)
{
group_prev_ = self;
}
};
template <typename T>
struct grouped_ptr_node :
::boost::unordered::detail::value_base<T>,
::boost::unordered::detail::ptr_bucket
{
typedef ::boost::unordered::detail::ptr_bucket bucket_base;
typedef ptr_bucket* link_pointer;
link_pointer group_prev_;
std::size_t hash_;
grouped_ptr_node() :
bucket_base(),
group_prev_(0),
hash_(0)
{}
void init(link_pointer self)
{
group_prev_ = self;
}
};
// If the allocator uses raw pointers use grouped_ptr_node
// Otherwise use grouped_node.
template <typename A, typename T, typename VoidPointer, typename NodePtr, typename BucketPtr>
struct pick_grouped_node2
{
typedef ::boost::unordered::detail::grouped_node<VoidPointer, 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 VoidPointer link_pointer;
};
template <typename A, typename T>
struct pick_grouped_node2<A, T, void*,
::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 ::boost::unordered::detail::allocator_traits<
typename ::boost::unordered::detail::rebind_wrap<A,
::boost::unordered::detail::grouped_ptr_node<T> >::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, T,
typename tentative_node_traits::void_pointer,
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;
};
template <typename A, typename H, typename P>
struct multiset
{
typedef multiset<A, H, P> types;
typedef A allocator;
typedef H hasher;
typedef P key_equal;
typedef ::boost::unordered::detail::allocator_traits<A> traits;
typedef typename traits::value_type value_type;
typedef typename traits::void_pointer void_pointer;
typedef value_type key_type;
typedef typename ::boost::unordered::detail::pick_grouped_node<A, value_type>::node node;
typedef typename ::boost::unordered::detail::pick_grouped_node<A, value_type>::bucket bucket;
typedef typename ::boost::unordered::detail::pick_grouped_node<A, value_type>::link_pointer link_pointer;
typedef ::boost::unordered::detail::grouped_table_impl<types> table;
typedef ::boost::unordered::detail::set_extractor<value_type> extractor;
};
template <typename A, typename K, typename H, typename P>
struct multimap
{
typedef multimap<A, K, H, P> types;
typedef A allocator;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef ::boost::unordered::detail::allocator_traits<A> traits;
typedef typename traits::value_type value_type;
typedef typename traits::void_pointer void_pointer;
typedef typename ::boost::unordered::detail::pick_grouped_node<A, value_type>::node node;
typedef typename ::boost::unordered::detail::pick_grouped_node<A, value_type>::bucket bucket;
typedef typename ::boost::unordered::detail::pick_grouped_node<A, value_type>::link_pointer link_pointer;
typedef ::boost::unordered::detail::grouped_table_impl<types> table;
typedef ::boost::unordered::detail::map_extractor<key_type, value_type> extractor;
};
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::buckets buckets;
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::previous_pointer previous_pointer;
typedef typename table::hasher hasher;
typedef typename table::key_equal key_equal;
typedef typename table::key_type key_type;
typedef typename table::node_constructor node_constructor;
typedef typename table::extractor extractor;
// Constructors
equivalent_table(std::size_t n,
hasher const& hf, key_equal const& eq, value_allocator const& a)
: table_base(n, hf, eq, a) {}
equivalent_table(equivalent_table const& x)
: table_base(x,
allocator_traits<node_allocator>::
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())) {}
equivalent_table(equivalent_table const& x,
value_allocator const& a)
: table_base(x, a) {}
equivalent_table(equivalent_table& x, move_tag m)
: table_base(x, m) {}
equivalent_table(equivalent_table& x,
value_allocator const& a, move_tag m)
: table_base(x, a, m) {}
~equivalent_table() {}
grouped_table_impl(grouped_table_impl const& x,
node_allocator const& a)
: table(x, a)
{}
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)
{}
// Accessors
template <class Key, class Pred>
node_pointer find_node_impl(
std::size_t hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = hash % this->bucket_count_;
node_pointer n = this->get_start(bucket_index);
for (;;)
{
if (!n) return n;
std::size_t node_hash = n->hash_;
if (hash == node_hash)
{
if (eq(k, this->get_key(n->value())))
return n;
}
else
{
if (node_hash % this->bucket_count_ != bucket_index)
return node_pointer();
}
n = static_cast<node_pointer>(static_cast<node_pointer>(n->group_prev_)->next_);
}
}
std::size_t count(key_type const& k) const
{
node_pointer n = this->find_node(k);
if (!n) return 0;
std::size_t count = 0;
node_pointer it = n;
do {
it = static_cast<node_pointer>(it->group_prev_);
++count;
} while(it != n);
return count;
}
std::pair<node_pointer, node_pointer>
equal_range(key_type const& k) const
{
node_pointer n = this->find_node(k);
return std::make_pair(n,
n ? static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_) : n);
}
// Equality
bool equals(equivalent_table const& other) const
bool equals(grouped_table_impl const& other) const
{
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;)
for(node_pointer n1 = this->get_start(); n1;)
{
node_ptr n2 = other.find_matching_node(n1);
node_pointer n2 = other.find_matching_node(n1);
if (!n2) return false;
node_ptr end1 = node::next_group(n1);
node_ptr end2 = node::next_group(n2);
node_pointer end1 = static_cast<node_pointer>(static_cast<node_pointer>(n1->group_prev_)->next_);
node_pointer end2 = static_cast<node_pointer>(static_cast<node_pointer>(n2->group_prev_)->next_);
if (!group_equals(n1, end1, n2, end2)) return false;
n1 = end1;
}
@ -70,60 +284,77 @@ namespace boost { namespace unordered { namespace detail {
#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
static bool group_equals(node_ptr n1, node_ptr end1,
node_ptr n2, node_ptr end2)
static bool group_equals(node_pointer n1, node_pointer end1,
node_pointer n2, node_pointer end2)
{
for(;;)
{
if (node::get_value(n1) != node::get_value(n2))
if (n1->value() != n2->value())
break;
n1 = n1->next_;
n2 = n2->next_;
n1 = static_cast<node_pointer>(n1->next_);
n2 = static_cast<node_pointer>(n2->next_);
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
}
for(node_ptr n1a = n1, n2a = n2;;)
for(node_pointer n1a = n1, n2a = n2;;)
{
n1a = n1a->next_;
n2a = n2a->next_;
n1a = static_cast<node_pointer>(n1a->next_);
n2a = static_cast<node_pointer>(n2a->next_);
if (n1a == end1)
{
if (n2a == end2) break;
else return false;
}
if (n2a == end2) return false;
}
node_ptr start = n1;
for(;n1 != end2; n1 = n1->next_)
node_pointer start = n1;
for(;n1 != end2; n1 = static_cast<node_pointer>(n1->next_))
{
value_type const& v = node::get_value(n1);
value_type const& v = n1->value();
if (find(start, n1, v)) continue;
std::size_t matches = count_equal(n2, end2, v);
if (!matches || matches != 1 + count_equal(n1->next_, end1, v))
if (!matches || matches != 1 + count_equal(static_cast<node_pointer>(n1->next_), end1, v))
return false;
}
return true;
}
static bool find(node_pointer n, node_pointer end, value_type const& v)
{
for(;n != end; n = static_cast<node_pointer>(n->next_))
if (n->value() == v)
return true;
return false;
}
static std::size_t count_equal(node_pointer n, node_pointer end, value_type const& v)
{
std::size_t count = 0;
for(;n != end; n = static_cast<node_pointer>(n->next_))
if (n->value() == v) ++count;
return count;
}
#else
static bool group_equals(node_ptr n1, node_ptr end1,
node_ptr n2, node_ptr end2)
static bool group_equals(node_pointer n1, node_pointer end1,
node_pointer n2, node_pointer end2)
{
for(;;)
{
if(!extractor::compare_mapped(
node::get_value(n1), node::get_value(n2)))
n1->value(), n2->value()))
return false;
n1 = n1->next_;
n2 = n2->next_;
n1 = static_cast<node_pointer>(n1->next_);
n2 = static_cast<node_pointer>(n2->next_);
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
@ -132,205 +363,447 @@ namespace boost { namespace unordered { namespace detail {
#endif
static bool find(node_ptr n, node_ptr end, value_type const& v)
// Emplace/Insert
static inline void add_after_node(
node_pointer n,
node_pointer pos)
{
for(;n != end; n = n->next_)
if (node::get_value(n) == v)
return true;
return false;
}
static std::size_t count_equal(node_ptr n, node_ptr end, value_type const& v)
{
std::size_t count = 0;
for(;n != end; n = n->next_)
if (node::get_value(n) == v) ++count;
return count;
n->next_ = static_cast<node_pointer>(pos->group_prev_)->next_;
n->group_prev_ = pos->group_prev_;
static_cast<node_pointer>(pos->group_prev_)->next_ = static_cast<link_pointer>(n);
pos->group_prev_ = static_cast<link_pointer>(n);
}
////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
inline node_ptr add_node(
inline node_pointer add_node(
node_constructor& a,
std::size_t bucket_index,
std::size_t hash,
node_ptr pos)
node_pointer pos)
{
node_ptr n = a.release();
node::set_hash(n, hash);
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
node::add_after_node(n, pos);
node_pointer n = a.release();
n->hash_ = hash;
if(pos) {
this->add_after_node(n, pos);
if (n->next_) {
std::size_t next_bucket =
node::get_hash(n->next_) % this->bucket_count_;
if (next_bucket != bucket_index) {
this->buckets_[next_bucket].next_ = n;
static_cast<node_pointer>(n->next_)->hash_ %
this->bucket_count_;
if (next_bucket != hash % this->bucket_count_) {
this->get_bucket(next_bucket)->next_ = n;
}
}
}
else {
bucket_ptr b = this->get_bucket(bucket_index);
bucket_pointer b = this->get_bucket(hash % this->bucket_count_);
if (!b->next_)
{
bucket_ptr start_node =
this->get_bucket(this->bucket_count_);
previous_pointer start_node = this->get_previous_start();
if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) {
this->buckets_[
node::get_hash(start_node->next_) %
this->bucket_count_].next_ = n;
if (start_node->next_) {
this->get_bucket(
static_cast<node_pointer>(start_node->next_)->hash_ %
this->bucket_count_)->next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = n;
start_node->next_ = static_cast<link_pointer>(n);
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = n;
b->next_->next_ = static_cast<link_pointer>(n);
}
}
++this->size_;
return n;
}
////////////////////////////////////////////////////////////////////////
// Insert methods
node_ptr emplace_impl(node_constructor& a)
node_pointer emplace_impl(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr position = this->find_node(bucket_index, hash, k);
node_pointer position = this->find_node(hash, k);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1)) {
bucket_index = hash % this->bucket_count_;
}
return add_node(a, bucket_index, hash, position);
this->reserve_for_insert(this->size_ + 1);
return this->add_node(a, hash, position);
}
void emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
add_node(a, bucket_index, hash,
this->find_node(bucket_index, hash, k));
this->add_node(a, hash,
this->find_node(hash, k));
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
node_ptr emplace(please_ignore_this_overload const&)
node_pointer emplace(::boost::unordered::detail::emplace_args1<
::boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return this->begin();
}
#endif
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
node_ptr emplace(Args&&... args)
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
node_pointer emplace(BOOST_UNORDERED_EMPLACE_ARGS)
{
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
node_constructor a(this->node_alloc());
a.construct_node();
a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
return emplace_impl(a);
}
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
node_ptr emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
return emplace_impl(a); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
////////////////////////////////////////////////////////////////////////
// Insert range methods
// if hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
void insert_for_range(I i, I j, forward_traversal_tag)
typename ::boost::unordered::detail::enable_if_forward<I, void>::type
insert_range(I i, I j)
{
if(i == j) return;
std::size_t distance = ::boost::unordered::detail::distance(i, j);
if(distance == 1) {
emplace(*i);
node_constructor a(this->node_alloc());
a.construct_node();
a.construct_value2(*i);
emplace_impl(a);
}
else {
// Only require basic exception safety here
this->reserve_for_insert(this->size_ + distance);
node_constructor a(*this);
node_constructor a(this->node_alloc());
for (; i != j; ++i) {
a.construct(*i);
a.construct_node();
a.construct_value2(*i);
emplace_impl_no_rehash(a);
}
}
}
template <class I>
void insert_for_range(I i, I j, ::boost::incrementable_traversal_tag)
typename ::boost::unordered::detail::disable_if_forward<I, void>::type
insert_range(I i, I j)
{
node_constructor a(*this);
node_constructor a(this->node_alloc());
for (; i != j; ++i) {
a.construct(*i);
a.construct_node();
a.construct_value2(*i);
emplace_impl(a);
}
}
// If hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
void insert_range(I i, I j)
////////////////////////////////////////////////////////////////////////////
// Erase
//
// no throw
std::size_t erase_key(key_type const& k)
{
insert_for_range(i, j,
BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal<I>::type());
if(!this->size_) return 0;
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
bucket_pointer bucket = this->get_bucket(bucket_index);
previous_pointer prev = bucket->next_;
if (!prev) return 0;
for (;;)
{
if (!prev->next_) return 0;
std::size_t node_hash = static_cast<node_pointer>(prev->next_)->hash_;
if (node_hash % this->bucket_count_ != bucket_index)
return 0;
if (node_hash == hash &&
this->key_eq()(k, this->get_key(static_cast<node_pointer>(prev->next_)->value())))
break;
prev = static_cast<previous_pointer>(
static_cast<node_pointer>(prev->next_)->group_prev_);
}
node_pointer pos = static_cast<node_pointer>(prev->next_);
link_pointer end1 = static_cast<node_pointer>(pos->group_prev_)->next_;
node_pointer end = static_cast<node_pointer>(end1);
prev->next_ = end1;
this->fix_buckets(bucket, prev, end);
return this->delete_nodes(pos, end);
}
};
node_pointer erase(node_pointer r)
{
BOOST_ASSERT(r);
node_pointer next = static_cast<node_pointer>(r->next_);
template <class H, class P, class A>
struct multiset : public types<
typename allocator_traits<A>::value_type,
typename allocator_traits<A>::value_type,
H, P, A,
set_extractor<typename allocator_traits<A>::value_type>,
false>
{
typedef equivalent_table<multiset<H, P, A> > impl;
typedef table<multiset<H, P, A> > table_base;
};
bucket_pointer bucket = this->get_bucket(
r->hash_ % this->bucket_count_);
previous_pointer prev = unlink_node(*bucket, r);
template <class K, class H, class P, class A>
struct multimap : public types<
K, typename allocator_traits<A>::value_type,
H, P, A,
map_extractor<K, typename allocator_traits<A>::value_type>,
false>
{
typedef equivalent_table<multimap<K, H, P, A> > impl;
typedef table<multimap<K, H, P, A> > table_base;
this->fix_buckets(bucket, prev, next);
this->delete_node(r);
return next;
}
node_pointer erase_range(node_pointer r1, node_pointer r2)
{
if (r1 == r2) return r2;
std::size_t bucket_index = r1->hash_ % this->bucket_count_;
previous_pointer prev = unlink_nodes(
*this->get_bucket(bucket_index), r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
this->delete_nodes(r1, r2);
return r2;
}
static previous_pointer unlink_node(bucket& b, node_pointer n)
{
node_pointer next = static_cast<node_pointer>(n->next_);
previous_pointer prev = static_cast<previous_pointer>(n->group_prev_);
if(prev->next_ != n) {
// The node is at the beginning of a group.
// Find the previous node pointer:
prev = b.next_;
while(prev->next_ != n) {
prev = static_cast<previous_pointer>(static_cast<node_pointer>(prev->next_)->group_prev_);
}
// Remove from group
if (next && next->group_prev_ == static_cast<link_pointer>(n))
{
next->group_prev_ = n->group_prev_;
}
}
else if (next && next->group_prev_ == static_cast<link_pointer>(n))
{
// The deleted node is not at the end of the group, so
// change the link from the next node.
next->group_prev_ = n->group_prev_;
}
else {
// The deleted node is at the end of the group, so the
// first node in the group is pointing to it.
// Find that to change its pointer.
node_pointer x = static_cast<node_pointer>(n->group_prev_);
while(x->group_prev_ != static_cast<link_pointer>(n)) {
x = static_cast<node_pointer>(x->group_prev_);
}
x->group_prev_ = n->group_prev_;
}
prev->next_ = static_cast<link_pointer>(next);
return prev;
}
static previous_pointer unlink_nodes(bucket& b, node_pointer begin, node_pointer end)
{
previous_pointer prev = static_cast<previous_pointer>(begin->group_prev_);
if(prev->next_ != static_cast<link_pointer>(begin)) {
std::cout << "A" << std::endl;
// The node is at the beginning of a group.
// Find the previous node pointer:
prev = b.next_;
while(prev->next_ != static_cast<link_pointer>(begin))
prev = static_cast<previous_pointer>(
static_cast<node_pointer>(prev->next_)->group_prev_);
if (end) split_group(end);
}
else {
std::cout << "B" << std::endl;
node_pointer group1 = split_group(begin);
if (end) {
node_pointer group2 = split_group(end);
if(begin == group2) {
link_pointer end1 = group1->group_prev_;
link_pointer end2 = group2->group_prev_;
group1->group_prev_ = end2;
group2->group_prev_ = end1;
}
}
}
prev->next_ = static_cast<link_pointer>(end);
return prev;
}
// Break a ciruclar list into two, with split as the beginning
// of the second group (if split is at the beginning then don't
// split).
static node_pointer split_group(node_pointer split)
{
// Find first node in group.
node_pointer first = split;
while (static_cast<node_pointer>(first->group_prev_)->next_ == static_cast<link_pointer>(first))
first = static_cast<node_pointer>(first->group_prev_);
if(first == split) return split;
link_pointer last = first->group_prev_;
first->group_prev_ = split->group_prev_;
split->group_prev_ = last;
return first;
}
////////////////////////////////////////////////////////////////////////////
// copy_buckets_to
//
// Basic exception safety. If an exception is thrown this will
// leave dst partially filled and the buckets unset.
static void copy_buckets_to(buckets const& src, buckets& dst)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets();
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
std::size_t hash = n->hash_;
node_pointer group_end =
static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_);
a.construct_node();
a.construct_value2(n->value());
node_pointer first_node = a.release();
node_pointer end = first_node;
first_node->hash_ = hash;
prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_;
for(n = static_cast<node_pointer>(n->next_); n != group_end;
n = static_cast<node_pointer>(n->next_))
{
a.construct_node();
a.construct_value2(n->value());
end = a.release();
end->hash_ = hash;
add_after_node(end, first_node);
++dst.size_;
}
prev = place_in_bucket(dst, prev, end);
}
}
////////////////////////////////////////////////////////////////////////////
// move_buckets_to
//
// Basic exception safety. The source nodes are left in an unusable state
// if an exception throws.
static void move_buckets_to(buckets& src, buckets& dst)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets();
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
std::size_t hash = n->hash_;
node_pointer group_end =
static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_);
a.construct_node();
a.construct_value2(boost::move(n->value()));
node_pointer first_node = a.release();
node_pointer end = first_node;
first_node->hash_ = hash;
prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_;
for(n = static_cast<node_pointer>(n->next_); n != group_end;
n = static_cast<node_pointer>(n->next_))
{
a.construct_node();
a.construct_value2(boost::move(n->value()));
end = a.release();
end->hash_ = hash;
add_after_node(end, first_node);
++dst.size_;
}
prev = place_in_bucket(dst, prev, end);
}
}
// strong otherwise exception safety
void rehash_impl(std::size_t num_buckets)
{
BOOST_ASSERT(this->size_);
buckets dst(this->node_alloc(), num_buckets);
dst.create_buckets();
previous_pointer src_start = this->get_previous_start();
previous_pointer dst_start = dst.get_previous_start();
dst_start->next_ = src_start->next_;
src_start->next_ = link_pointer();
dst.size_ = this->size_;
this->size_ = 0;
previous_pointer prev = dst_start;
while (prev->next_)
prev = place_in_bucket(dst, prev,
static_cast<node_pointer>(
static_cast<node_pointer>(prev->next_)->group_prev_));
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
}
// Iterate through the nodes placing them in the correct buckets.
// pre: prev->next_ is not null.
static previous_pointer place_in_bucket(buckets& dst, previous_pointer prev, node_pointer end)
{
bucket_pointer b = dst.get_bucket(end->hash_ % dst.bucket_count_);
if (!b->next_) {
b->next_ = static_cast<node_pointer>(prev);
return static_cast<previous_pointer>(end);
}
else {
link_pointer next = end->next_;
end->next_ = b->next_->next_;
b->next_->next_ = prev->next_;
prev->next_ = next;
return prev;
}
}
};
}}}

File diff suppressed because it is too large Load Diff

View File

@ -7,66 +7,277 @@
#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/emplace_args.hpp>
#include <boost/unordered/detail/extract_key.hpp>
#include <boost/throw_exception.hpp>
#include <stdexcept>
namespace boost { namespace unordered { namespace detail {
template <class T>
class unique_table : public T::table_base
{
public:
typedef typename T::hasher hasher;
typedef typename T::key_equal key_equal;
typedef typename T::value_allocator value_allocator;
typedef typename T::key_type key_type;
typedef typename T::value_type value_type;
typedef typename T::table_base table_base;
typedef typename T::node_constructor node_constructor;
typedef typename T::node_allocator node_allocator;
template <typename VoidPointer, typename T> struct node;
template <typename T> struct ptr_node;
template <typename Types> struct table_impl;
typedef typename T::node node;
typedef typename T::node_ptr node_ptr;
typedef typename T::bucket_ptr bucket_ptr;
typedef typename T::extractor extractor;
typedef std::pair<node_ptr, bool> emplace_return;
template <typename VoidPointer, typename T>
struct node :
::boost::unordered::detail::value_base<T>
{
typedef VoidPointer link_pointer;
link_pointer next_;
std::size_t hash_;
node() :
next_(),
hash_(0)
{}
void init(link_pointer)
{
}
};
template <typename T>
struct ptr_node :
::boost::unordered::detail::value_base<T>,
::boost::unordered::detail::ptr_bucket
{
typedef ::boost::unordered::detail::ptr_bucket bucket_base;
typedef ptr_bucket* link_pointer;
std::size_t hash_;
ptr_node() :
bucket_base(),
hash_(0)
{}
void init(link_pointer)
{
}
};
// If the allocator uses raw pointers use ptr_node
// Otherwise use node.
template <typename A, typename T, typename VoidPointer, typename NodePtr, typename BucketPtr>
struct pick_node2
{
typedef ::boost::unordered::detail::node<VoidPointer, 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 VoidPointer link_pointer;
};
template <typename A, typename T>
struct pick_node2<A, T, void*,
::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 ::boost::unordered::detail::allocator_traits<
typename ::boost::unordered::detail::rebind_wrap<A,
::boost::unordered::detail::ptr_node<T> >::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, T,
typename tentative_node_traits::void_pointer,
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;
};
template <typename A, typename H, typename P>
struct set
{
typedef set<A, H, P> types;
typedef A allocator;
typedef H hasher;
typedef P key_equal;
typedef ::boost::unordered::detail::allocator_traits<A> traits;
typedef typename traits::value_type value_type;
typedef typename traits::void_pointer void_pointer;
typedef value_type key_type;
typedef typename ::boost::unordered::detail::pick_node<A, value_type>::node node;
typedef typename ::boost::unordered::detail::pick_node<A, value_type>::bucket bucket;
typedef typename ::boost::unordered::detail::pick_node<A, value_type>::link_pointer link_pointer;
typedef ::boost::unordered::detail::table_impl<types> table;
typedef ::boost::unordered::detail::set_extractor<value_type> extractor;
};
template <typename A, typename K, typename H, typename P>
struct map
{
typedef map<A, K, H, P> types;
typedef A allocator;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef ::boost::unordered::detail::allocator_traits<A> traits;
typedef typename traits::value_type value_type;
typedef typename traits::void_pointer void_pointer;
typedef typename ::boost::unordered::detail::pick_node<A, value_type>::node node;
typedef typename ::boost::unordered::detail::pick_node<A, value_type>::bucket bucket;
typedef typename ::boost::unordered::detail::pick_node<A, value_type>::link_pointer link_pointer;
typedef ::boost::unordered::detail::table_impl<types> table;
typedef ::boost::unordered::detail::map_extractor<key_type, value_type> extractor;
};
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::bucket bucket;
typedef typename table::buckets buckets;
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::previous_pointer previous_pointer;
typedef typename table::hasher hasher;
typedef typename table::key_equal key_equal;
typedef typename table::key_type key_type;
typedef typename table::node_constructor node_constructor;
typedef typename table::extractor extractor;
typedef std::pair<node_pointer, bool> emplace_return;
// Constructors
unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
value_allocator const& a)
: table_base(n, hf, eq, a) {}
unique_table(unique_table const& x)
: table_base(x,
allocator_traits<node_allocator>::
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())) {}
unique_table(unique_table const& x, value_allocator const& a)
: table_base(x, a) {}
unique_table(unique_table& x, move_tag m)
: table_base(x, m) {}
unique_table(unique_table& x, value_allocator const& a,
move_tag m)
: table_base(x, a, m) {}
~unique_table() {}
table_impl(table_impl const& x,
node_allocator const& a)
: table(x, a)
{}
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)
{}
// Accessors
template <class Key, class Pred>
node_pointer find_node_impl(
std::size_t hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = hash % this->bucket_count_;
node_pointer n = this->get_start(bucket_index);
for (;;)
{
if (!n) return n;
std::size_t node_hash = n->hash_;
if (hash == node_hash)
{
if (eq(k, this->get_key(n->value())))
return n;
}
else
{
if (node_hash % this->bucket_count_ != bucket_index)
return node_pointer();
}
n = static_cast<node_pointer>(n->next_);
}
}
std::size_t count(key_type const& k) const
{
return this->find_node(k) ? 1 : 0;
}
value_type& at(key_type const& k) const
{
if (this->size_) {
node_pointer it = this->find_node(k);
if (it) return it->value();
}
::boost::throw_exception(
std::out_of_range("Unable to find key in unordered_map."));
}
std::pair<node_pointer, node_pointer>
equal_range(key_type const& k) const
{
node_pointer n = this->find_node(k);
return std::make_pair(n,
n ? static_cast<node_pointer>(n->next_) : n);
}
// equals
bool equals(unique_table const& other) const
bool equals(table_impl const& other) const
{
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
for(node_ptr n1 = this->get_bucket(this->bucket_count_)->next_;
n1; n1 = n1->next_)
for(node_pointer n1 = this->get_start(); n1;
n1 = static_cast<node_pointer>(n1->next_))
{
node_ptr n2 = other.find_matching_node(n1);
node_pointer n2 = other.find_matching_node(n1);
#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
if(!n2 || node::get_value(n1) != node::get_value(n2))
if(!n2 || n1->value() != n2->value())
return false;
#else
if(!n2 || !extractor::compare_mapped(
node::get_value(n1), node::get_value(n2)))
n1->value(), n2->value()))
return false;
#endif
}
@ -74,247 +285,147 @@ namespace boost { namespace unordered { namespace detail {
return true;
}
////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
// Emplace/Insert
node_ptr add_node(
inline node_pointer add_node(
node_constructor& a,
std::size_t bucket_index,
std::size_t hash)
std::size_t hash)
{
bucket_ptr b = this->get_bucket(bucket_index);
node_ptr n = a.release();
node::set_hash(n, hash);
node_pointer n = a.release();
n->hash_ = hash;
bucket_pointer b = this->get_bucket(hash % this->bucket_count_);
if (!b->next_)
{
bucket_ptr start_node = this->get_bucket(this->bucket_count_);
previous_pointer start_node = this->get_previous_start();
if (start_node->next_) {
this->buckets_[
node::get_hash(start_node->next_) % this->bucket_count_
].next_ = n;
this->get_bucket(
static_cast<node_pointer>(start_node->next_)->hash_ %
this->bucket_count_)->next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = n;
start_node->next_ = static_cast<link_pointer>(n);
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = n;
b->next_->next_ = static_cast<link_pointer>(n);
}
++this->size_;
return n;
}
////////////////////////////////////////////////////////////////////////////
// Insert methods
// if hash function throws, basic exception safety
// strong otherwise
value_type& operator[](key_type const& k)
{
typedef typename value_type::second_type mapped_type;
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
node_pointer pos = this->find_node(hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
return node::get_value(pos);
}
if (pos) return pos->value();
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct_pair(k, (mapped_type*) 0);
node_constructor a(this->node_alloc());
a.construct_node();
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
a.construct_value(boost::unordered::piecewise_construct,
boost::make_tuple(k), boost::make_tuple());
#else
a.construct_value(
boost::unordered::detail::create_emplace_args(
boost::unordered::piecewise_construct,
boost::make_tuple(k),
boost::make_tuple()));
#endif
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return node::get_value(add_node(a, bucket_index, hash));
this->reserve_for_insert(this->size_ + 1);
return add_node(a, hash)->value();
}
emplace_return emplace_impl_with_node(node_constructor& a)
{
// No side effects in this initial code
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(pos, false);
}
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return emplace_return(add_node(a, bucket_index, hash), true);
}
emplace_return insert(value_type const& v)
{
key_type const& k = extractor::extract(v);
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(pos, false);
}
// Isn't in table, add to bucket.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(v);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return emplace_return(add_node(a, bucket_index, hash), true);
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
emplace_return emplace(please_ignore_this_overload const&)
emplace_return emplace(::boost::unordered::detail::emplace_args1<
::boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return emplace_return(this->begin(), false);
}
#endif
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template<class... Args>
emplace_return emplace(Args&&... args)
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
{
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
return emplace_impl(
extractor::extract(std::forward<Args>(args)...),
std::forward<Args>(args)...);
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
}
template<class... Args>
emplace_return emplace_impl(key_type const& k, Args&&... args)
#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <typename A0>
emplace_return emplace(
boost::unordered::detail::emplace_args1<A0> const& args)
{
return emplace_impl(extractor::extract(args.a0), args);
}
#endif
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
{
// No side effects in this initial code
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
node_pointer pos = this->find_node(hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(pos, false);
}
// Doesn't already exist, add to bucket.
// Side effects only in this block.
if (pos) return emplace_return(pos, false);
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
node_constructor a(this->node_alloc());
a.construct_node();
a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return emplace_return(add_node(a, bucket_index, hash), true);
this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(a, hash), true);
}
template<class... Args>
emplace_return emplace_impl(no_key, Args&&... args)
emplace_return emplace_impl_with_node(node_constructor& a)
{
// Construct the node regardless - in order to get the key.
// It will be discarded if it isn't used
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
node_pointer pos = this->find_node(hash, k);
if (pos) return emplace_return(pos, false);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(a, hash), true);
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{
// Don't have a key, so construct the node first in order
// to be able to lookup the position.
node_constructor a(this->node_alloc());
a.construct_node();
a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
return emplace_impl_with_node(a);
}
#else
template <class Arg0>
emplace_return emplace(BOOST_FWD_REF(Arg0) arg0)
{
return emplace_impl(
extractor::extract(boost::forward<Arg0>(arg0)),
boost::forward<Arg0>(arg0));
}
#define BOOST_UNORDERED_INSERT1_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
}
#define BOOST_UNORDERED_INSERT2_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace_impl(key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
std::size_t hash = this->hash_function()(k); \
std::size_t bucket_index = hash % this->bucket_count_; \
node_ptr pos = this->find_node(bucket_index, hash, k); \
\
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
return emplace_return(pos, false); \
} else { \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
\
if(this->reserve_for_insert(this->size_ + 1)) \
bucket_index = hash % this->bucket_count_; \
\
return emplace_return( \
add_node(a, bucket_index, hash), \
true); \
} \
} \
\
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace_impl(no_key, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_impl_with_node(a); \
}
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT1_IMPL, _)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT2_IMPL, _)
#undef BOOST_UNORDERED_INSERT1_IMPL
#undef BOOST_UNORDERED_INSERT2_IMPL
#endif
////////////////////////////////////////////////////////////////////////
// Insert range methods
@ -330,14 +441,14 @@ namespace boost { namespace unordered { namespace detail {
}
template <class InputIt>
void insert_range_impl(key_type const&, InputIt i, InputIt j)
void insert_range_impl(key_type const& k, InputIt i, InputIt j)
{
node_constructor a(*this);
node_constructor a(this->node_alloc());
// Special case for empty buckets so that we can use
// max_load_ (which isn't valid when buckets_ is null).
if (!this->buckets_) {
insert_range_empty(a, extractor::extract(*i), i, j);
insert_range_empty(a, k, i, j);
if (++i == j) return;
}
@ -358,9 +469,11 @@ namespace boost { namespace unordered { namespace detail {
InputIt i, InputIt j)
{
std::size_t hash = this->hash_function()(k);
a.construct(*i);
this->reserve_for_insert(this->size_ + insert_size(i, j));
add_node(a, hash % this->bucket_count_, hash);
a.construct_node();
a.construct_value2(*i);
this->reserve_for_insert(this->size_ +
::boost::unordered::detail::insert_size(i, j));
this->add_node(a, hash);
}
template <class InputIt>
@ -369,63 +482,216 @@ namespace boost { namespace unordered { namespace detail {
{
// No side effects in this initial code
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
node_pointer pos = this->find_node(hash, k);
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
if (!pos) {
a.construct_node();
a.construct_value2(*i);
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
a.construct(*i);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->size_ + 1 >= this->max_load_) {
this->reserve_for_insert(this->size_ + insert_size(i, j));
bucket_index = hash % this->bucket_count_;
}
if(this->size_ + 1 >= this->max_load_)
this->reserve_for_insert(this->size_ +
::boost::unordered::detail::insert_size(i, j));
// Nothing after this point can throw.
add_node(a, bucket_index, hash);
this->add_node(a, hash);
}
}
template <class InputIt>
void insert_range_impl(no_key, InputIt i, InputIt j)
{
node_constructor a(*this);
node_constructor a(this->node_alloc());
do {
// No side effects in this initial code
a.construct(*i);
a.construct_node();
a.construct_value2(*i);
emplace_impl_with_node(a);
} while(++i != j);
}
};
template <class H, class P, class A>
struct set : public types<
typename allocator_traits<A>::value_type,
typename allocator_traits<A>::value_type,
H, P, A,
set_extractor<typename allocator_traits<A>::value_type>,
true>
{
typedef ::boost::unordered::detail::unique_table<set<H, P, A> > impl;
typedef ::boost::unordered::detail::table<set<H, P, A> > table_base;
};
////////////////////////////////////////////////////////////////////////////
// Erase
//
// no throw
template <class K, class H, class P, class A>
struct map : public types<
K, typename allocator_traits<A>::value_type,
H, P, A,
map_extractor<K, typename allocator_traits<A>::value_type>,
true>
{
typedef ::boost::unordered::detail::unique_table<map<K, H, P, A> > impl;
typedef ::boost::unordered::detail::table<map<K, H, P, A> > table_base;
std::size_t erase_key(key_type const& k)
{
if(!this->size_) return 0;
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
bucket_pointer bucket = this->get_bucket(bucket_index);
previous_pointer prev = bucket->next_;
if (!prev) return 0;
for (;;)
{
if (!prev->next_) return 0;
std::size_t node_hash = static_cast<node_pointer>(prev->next_)->hash_;
if (node_hash % this->bucket_count_ != bucket_index)
return 0;
if (node_hash == hash &&
this->key_eq()(k, this->get_key(static_cast<node_pointer>(prev->next_)->value())))
break;
prev = static_cast<previous_pointer>(prev->next_);
}
node_pointer pos = static_cast<node_pointer>(prev->next_);
node_pointer end = static_cast<node_pointer>(pos->next_);
prev->next_ = pos->next_;
this->fix_buckets(bucket, prev, end);
return this->delete_nodes(pos, end);
}
node_pointer erase(node_pointer r)
{
BOOST_ASSERT(r);
node_pointer next = static_cast<node_pointer>(r->next_);
bucket_pointer bucket = this->get_bucket(
r->hash_ % this->bucket_count_);
previous_pointer prev = unlink_node(*bucket, r);
this->fix_buckets(bucket, prev, next);
this->delete_node(r);
return next;
}
node_pointer erase_range(node_pointer r1, node_pointer r2)
{
if (r1 == r2) return r2;
std::size_t bucket_index = r1->hash_ % this->bucket_count_;
previous_pointer prev = unlink_nodes(
*this->get_bucket(bucket_index), r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
this->delete_nodes(r1, r2);
return r2;
}
static previous_pointer unlink_node(bucket& b, node_pointer n)
{
return unlink_nodes(b, n, static_cast<node_pointer>(n->next_));
}
static previous_pointer unlink_nodes(bucket& b, node_pointer begin, node_pointer end)
{
previous_pointer prev = b.next_;
link_pointer begin_void = static_cast<link_pointer>(begin);
while(prev->next_ != begin_void) prev = static_cast<previous_pointer>(prev->next_);
prev->next_ = static_cast<link_pointer>(end);
return prev;
}
////////////////////////////////////////////////////////////////////////////
// copy_buckets_to
//
// Basic exception safety. If an exception is thrown this will
// leave dst partially filled and the buckets unset.
static void copy_buckets_to(buckets const& src, buckets& dst)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets();
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
a.construct_node();
a.construct_value2(n->value());
node_pointer node = a.release();
node->hash_ = n->hash_;
prev->next_ = static_cast<link_pointer>(node);
++dst.size_;
n = static_cast<node_pointer>(n->next_);
prev = place_in_bucket(dst, prev);
}
}
////////////////////////////////////////////////////////////////////////////
// move_buckets_to
//
// Basic exception safety. The source nodes are left in an unusable state
// if an exception throws.
static void move_buckets_to(buckets& src, buckets& dst)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets();
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
a.construct_node();
a.construct_value2(boost::move(n->value()));
node_pointer node = a.release();
node->hash_ = n->hash_;
prev->next_ = static_cast<link_pointer>(node);
++dst.size_;
n = static_cast<node_pointer>(n->next_);
prev = place_in_bucket(dst, prev);
}
}
// strong otherwise exception safety
void rehash_impl(std::size_t num_buckets)
{
BOOST_ASSERT(this->size_);
buckets dst(this->node_alloc(), num_buckets);
dst.create_buckets();
previous_pointer src_start = this->get_previous_start();
previous_pointer dst_start = dst.get_previous_start();
dst_start->next_ = src_start->next_;
src_start->next_ = link_pointer();
dst.size_ = this->size_;
this->size_ = 0;
previous_pointer prev = dst.get_previous_start();
while (prev->next_)
prev = place_in_bucket(dst, prev);
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
}
// Iterate through the nodes placing them in the correct buckets.
// pre: prev->next_ is not null.
static previous_pointer place_in_bucket(buckets& dst, previous_pointer prev)
{
node_pointer n = static_cast<node_pointer>(prev->next_);
bucket_pointer b = dst.get_bucket(n->hash_ % dst.bucket_count_);
if (!b->next_) {
b->next_ = prev;
return static_cast<previous_pointer>(n);
}
else {
prev->next_ = n->next_;
n->next_ = b->next_->next_;
b->next_->next_ = static_cast<link_pointer>(n);
return prev;
}
}
};
}}}

View File

@ -7,156 +7,50 @@
#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <utility>
#include <boost/limits.hpp>
#include <boost/config.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/assert.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_empty.hpp>
#if defined(BOOST_NO_RVALUE_REFERENCES)
#include <boost/type_traits/is_class.hpp>
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/throw_exception.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/move/move.hpp>
#include <boost/swap.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/tuple/tuple.hpp>
#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
#include <tuple>
#endif
#include <boost/unordered/detail/allocator_helpers.hpp>
// Template parameters:
//
// H = Hash Function
// P = Predicate
// A = Value Allocator
// G = Bucket group policy, 'grouped' or 'ungrouped'
// E = Key Extractor
#if !defined(BOOST_NO_RVALUE_REFERENCES) && \
!defined(BOOST_NO_VARIADIC_TEMPLATES)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
# elif defined(_LIBCPP_VERSION)
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# endif
# elif defined(__STL_CONFIG_H)
# elif defined(__MSL_CPP__)
# elif defined(__IBMCPP__)
# elif defined(MSIPL_COMPILE_H)
# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
// Visual C++. A version check would be a good idea.
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# endif
#endif
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#endif
#if defined(__SUNPRO_CC)
#define BOOST_UNORDERED_USE_RV_REF 0
#else
#define BOOST_UNORDERED_USE_RV_REF 1
#endif
#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_FUNCTION_PARAMS2, _)
#define BOOST_UNORDERED_FUNCTION_PARAMS2(z, i, _) \
BOOST_FWD_REF(Arg##i) arg##i
#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_PARAMS2, _)
#define BOOST_UNORDERED_CALL_PARAMS2(z, i, _) \
boost::forward<Arg##i>(arg##i)
#endif
#include <boost/swap.hpp>
namespace boost { namespace unordered { namespace detail {
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_bucket_count = 11;
struct move_tag {};
struct empty_emplace {};
template <class T> class unique_table;
template <class T> class equivalent_table;
template <class Alloc, bool Unique> class node_constructor;
template <class ValueType>
struct set_extractor;
template <class Key, class ValueType>
struct map_extractor;
struct no_key;
////////////////////////////////////////////////////////////////////////////
// iterator SFINAE
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
#else
struct please_ignore_this_overload {
typedef please_ignore_this_overload type;
};
template <typename T>
struct rv_ref_impl {
typedef BOOST_RV_REF(T) type;
};
template <typename T>
struct rv_ref :
boost::detail::if_true<
boost::is_class<T>::value
>::BOOST_NESTED_TEMPLATE then <
rv_ref_impl<T>,
please_ignore_this_overload
>::type
template <typename I>
struct is_forward :
::boost::is_convertible<
typename ::boost::iterator_traversal<I>::type,
::boost::forward_traversal_tag>
{};
#define BOOST_UNORDERED_RV_REF(T) \
typename ::boost::unordered::detail::rv_ref<T>::type
template <typename I, typename ReturnType>
struct enable_if_forward :
::boost::enable_if_c<
::boost::unordered::detail::is_forward<I>::value,
ReturnType>
{};
#endif
////////////////////////////////////////////////////////////////////////////
// convert double to std::size_t
inline std::size_t double_to_size_t(double f)
{
return f >= static_cast<double>(
(std::numeric_limits<std::size_t>::max)()) ?
(std::numeric_limits<std::size_t>::max)() :
static_cast<std::size_t>(f);
}
template <typename I, typename ReturnType>
struct disable_if_forward :
::boost::disable_if_c<
::boost::unordered::detail::is_forward<I>::value,
ReturnType>
{};
////////////////////////////////////////////////////////////////////////////
// primes
@ -225,45 +119,48 @@ namespace boost { namespace unordered { namespace detail {
// insert_size/initial_size
#if !defined(BOOST_NO_STD_DISTANCE)
using ::std::distance;
#else
template <class ForwardIterator>
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
std::size_t x;
std::distance(i, j, x);
return x;
}
#endif
template <class I>
inline std::size_t insert_size(I i, I j, ::boost::forward_traversal_tag)
inline typename
::boost::unordered::detail::enable_if_forward<I, std::size_t>::type
insert_size(I i, I j)
{
return std::distance(i, j);
}
template <class I>
inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag)
inline typename
::boost::unordered::detail::disable_if_forward<I, std::size_t>::type
insert_size(I, I)
{
return 1;
}
template <class I>
inline std::size_t insert_size(I i, I j)
{
return insert_size(i, j,
typename ::boost::iterator_traversal<I>::type());
}
template <class I>
inline std::size_t initial_size(I i, I j,
std::size_t num_buckets = ::boost::unordered::detail::default_bucket_count)
{
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
// TODO: Why +1?
return (std::max)(
::boost::unordered::detail::insert_size(i, j) + 1,
num_buckets);
}
////////////////////////////////////////////////////////////////////////////
// compressed_pair
// compressed
template <typename T, int Index>
struct compressed_base : private T
@ -298,7 +195,7 @@ namespace boost { namespace unordered { namespace detail {
{};
template <typename T1, typename T2>
struct compressed_pair
struct compressed
: private generate_base<T1, 1>::type,
private generate_base<T2, 2>::type
{
@ -325,28 +222,28 @@ namespace boost { namespace unordered { namespace detail {
}
template <typename First, typename Second>
compressed_pair(First const& x1, Second const& x2)
compressed(First const& x1, Second const& x2)
: base1(x1), base2(x2) {}
compressed_pair(compressed_pair const& x)
compressed(compressed const& x)
: base1(x.first()), base2(x.second()) {}
compressed_pair(compressed_pair& x, move_tag m)
compressed(compressed& x, move_tag m)
: base1(x.first(), m), base2(x.second(), m) {}
void assign(compressed_pair const& x)
void assign(compressed const& x)
{
first() = x.first();
second() = x.second();
}
void move_assign(compressed_pair& x)
void move_assign(compressed& x)
{
first() = boost::move(x.first());
second() = boost::move(x.second());
}
void swap(compressed_pair& x)
void swap(compressed& x)
{
boost::swap(first(), x.first());
boost::swap(second(), x.second());
@ -355,7 +252,7 @@ namespace boost { namespace unordered { namespace detail {
private:
// Prevent assignment just to make use of assign or
// move_assign explicit.
compressed_pair& operator=(compressed_pair const&);
compressed& operator=(compressed const&);
};
}}}

View File

@ -14,10 +14,12 @@
#endif
#include <boost/unordered/unordered_map_fwd.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#include <boost/unordered/detail/util.hpp>
#include <boost/functional/hash.hpp>
#include <boost/move/move.hpp>
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#include <initializer_list>
@ -40,7 +42,9 @@ namespace unordered
class unordered_map
{
BOOST_COPYABLE_AND_MOVABLE(unordered_map)
public:
typedef K key_type;
typedef std::pair<const K, T> value_type;
typedef T mapped_type;
@ -48,20 +52,18 @@ namespace unordered
typedef P key_equal;
typedef A allocator_type;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
typedef typename ::boost::unordered::detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef ::boost::unordered::detail::allocator_traits<value_allocator> allocator_traits;
typedef ::boost::unordered::detail::map<K, H, P,
value_allocator> types;
typedef typename types::impl table;
typedef ::boost::unordered::detail::allocator_traits<value_allocator>
allocator_traits;
typedef typename types::node_ptr node_ptr;
typedef ::boost::unordered::detail::map<value_allocator, K, H, P>
types;
typedef typename types::table table;
public:
@ -74,24 +76,18 @@ namespace unordered
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef ::boost::unordered::iterator_detail::cl_iterator<
value_allocator, true> const_local_iterator;
typedef ::boost::unordered::iterator_detail::l_iterator<
value_allocator, true> local_iterator;
typedef ::boost::unordered::iterator_detail::c_iterator<
value_allocator, true> const_iterator;
typedef ::boost::unordered::iterator_detail::iterator<
value_allocator, true> iterator;
typedef typename table::cl_iterator const_local_iterator;
typedef typename table::l_iterator local_iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::iterator iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
table table_;
public:
// construct/destroy/copy
// constructors
explicit unordered_map(
size_type = ::boost::unordered::detail::default_bucket_count,
@ -101,17 +97,15 @@ namespace unordered
explicit unordered_map(allocator_type const&);
unordered_map(unordered_map const&, allocator_type const&);
template <class InputIt>
unordered_map(InputIt f, InputIt l);
unordered_map(InputIt, InputIt);
template <class InputIt>
unordered_map(
InputIt, InputIt,
size_type,
const hasher& = hasher(),
const key_equal& = key_equal());
const key_equal& = key_equal());
template <class InputIt>
unordered_map(
@ -120,23 +114,12 @@ namespace unordered
const hasher&,
const key_equal&,
const allocator_type&);
~unordered_map();
unordered_map& operator=(
BOOST_COPY_ASSIGN_REF(unordered_map) x)
{
table_.assign(x.table_);
return *this;
}
// copy/move constructors
unordered_map(unordered_map const&);
unordered_map& operator=(BOOST_RV_REF(unordered_map) x)
{
table_.move_assign(x.table_);
return *this;
}
unordered_map(unordered_map const&, allocator_type const&);
unordered_map(BOOST_RV_REF(unordered_map) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
@ -154,7 +137,27 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
#endif
// Destructor
~unordered_map();
// Assign
unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x)
{
table_.assign(x.table_);
return *this;
}
unordered_map& operator=(BOOST_RV_REF(unordered_map) x)
{
table_.move_assign(x.table_);
return *this;
}
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_map& operator=(std::initializer_list<value_type>);
#endif
@ -209,54 +212,98 @@ namespace unordered
return const_iterator();
}
// modifiers
// emplace
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
std::pair<iterator, bool> emplace(Args&&...);
std::pair<iterator, bool> emplace(Args&&... args)
{
return table_.emplace(std::forward<Args>(args)...);
}
template <class... Args>
iterator emplace_hint(const_iterator, Args&&...);
iterator emplace_hint(const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...).first);
}
#else
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
std::pair<iterator, bool> emplace(
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
iterator emplace_hint(const_iterator,
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
#endif
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
std::pair<iterator, bool> emplace( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
)); \
} \
\
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return iterator(table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
)).first); \
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
); \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
);
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
std::pair<iterator, bool> emplace(
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type())
{
return this->emplace(boost::move(v));
}
iterator emplace_hint(const_iterator hint,
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
)
{
return this->emplace_hint(hint, boost::move(v));
}
#endif
std::pair<iterator, bool> insert(value_type const&);
std::pair<iterator, bool> insert(BOOST_RV_REF(value_type));
iterator insert(const_iterator, value_type const&);
iterator insert(const_iterator, BOOST_RV_REF(value_type));
#endif
std::pair<iterator, bool> insert(value_type const& x)
{
return this->emplace(x);
}
std::pair<iterator, bool> insert(BOOST_RV_REF(value_type) x)
{
return this->emplace(boost::move(x));
}
iterator insert(const_iterator hint, value_type const& x)
{
return this->emplace_hint(hint, x);
}
iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x)
{
return this->emplace_hint(hint, boost::move(x));
}
template <class InputIt> void insert(InputIt, InputIt);
@ -320,7 +367,7 @@ namespace unordered
return table_.max_bucket_count();
}
size_type bucket_size(size_type n) const;
size_type bucket_size(size_type) const;
size_type bucket(const key_type& k) const
{
@ -329,14 +376,16 @@ namespace unordered
local_iterator begin(size_type n)
{
return local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
local_iterator();
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
local_iterator end(size_type)
@ -351,8 +400,9 @@ namespace unordered
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
const_local_iterator cend(size_type) const
@ -369,7 +419,7 @@ namespace unordered
float load_factor() const;
void max_load_factor(float);
void rehash(size_type n);
void rehash(size_type);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<K,T,H,P,A>(
@ -383,6 +433,7 @@ namespace unordered
class unordered_multimap
{
BOOST_COPYABLE_AND_MOVABLE(unordered_multimap)
public:
typedef K key_type;
@ -392,21 +443,18 @@ namespace unordered
typedef P key_equal;
typedef A allocator_type;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
typedef typename ::boost::unordered::detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef ::boost::unordered::detail::allocator_traits<value_allocator>
allocator_traits;
typedef ::boost::unordered::detail::multimap<K, H, P,
value_allocator> types;
typedef typename types::impl table;
typedef typename types::node_ptr node_ptr;
typedef ::boost::unordered::detail::multimap<value_allocator, K, H, P>
types;
typedef typename types::table table;
public:
@ -419,24 +467,18 @@ namespace unordered
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef ::boost::unordered::iterator_detail::cl_iterator<
value_allocator, false> const_local_iterator;
typedef ::boost::unordered::iterator_detail::l_iterator<
value_allocator, false> local_iterator;
typedef ::boost::unordered::iterator_detail::c_iterator<
value_allocator, false> const_iterator;
typedef ::boost::unordered::iterator_detail::iterator<
value_allocator, false> iterator;
typedef typename table::cl_iterator const_local_iterator;
typedef typename table::l_iterator local_iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::iterator iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
table table_;
public:
// construct/destroy/copy
// constructors
explicit unordered_multimap(
size_type = ::boost::unordered::detail::default_bucket_count,
@ -446,8 +488,6 @@ namespace unordered
explicit unordered_multimap(allocator_type const&);
unordered_multimap(unordered_multimap const&, allocator_type const&);
template <class InputIt>
unordered_multimap(InputIt, InputIt);
@ -466,22 +506,11 @@ namespace unordered
const key_equal&,
const allocator_type&);
~unordered_multimap();
unordered_multimap& operator=(
BOOST_COPY_ASSIGN_REF(unordered_multimap) x)
{
table_.assign(x.table_);
return *this;
}
// copy/move constructors
unordered_multimap(unordered_multimap const&);
unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x)
{
table_.move_assign(x.table_);
return *this;
}
unordered_multimap(unordered_multimap const&, allocator_type const&);
unordered_multimap(BOOST_RV_REF(unordered_multimap) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
@ -499,7 +528,27 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
#endif
// Destructor
~unordered_multimap();
// Assign
unordered_multimap& operator=(BOOST_COPY_ASSIGN_REF(unordered_multimap) x)
{
table_.assign(x.table_);
return *this;
}
unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x)
{
table_.move_assign(x.table_);
return *this;
}
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_multimap& operator=(std::initializer_list<value_type>);
#endif
@ -554,54 +603,98 @@ namespace unordered
return const_iterator();
}
// modifiers
// emplace
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
iterator emplace(Args&&...);
iterator emplace(Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
template <class... Args>
iterator emplace_hint(const_iterator, Args&&...);
iterator emplace_hint(const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
#else
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
iterator emplace(
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
iterator emplace_hint(const_iterator,
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
#endif
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return iterator(table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
))); \
} \
\
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return iterator(table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
))); \
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
); \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
);
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
iterator emplace(
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type())
{
return iterator(this->emplace(boost::move(v)));
}
iterator emplace_hint(const_iterator hint,
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
)
{
return iterator(this->emplace_hint(hint, boost::move(v)));
}
#endif
iterator insert(value_type const&);
iterator insert(BOOST_RV_REF(value_type));
iterator insert(const_iterator, value_type const&);
iterator insert(const_iterator, BOOST_RV_REF(value_type));
#endif
iterator insert(value_type const& x)
{
return this->emplace(x);
}
iterator insert(BOOST_RV_REF(value_type) x)
{
return this->emplace(boost::move(x));
}
iterator insert(const_iterator hint, value_type const& x)
{
return this->emplace_hint(hint, x);
}
iterator insert(const_iterator hint, BOOST_RV_REF(value_type) x)
{
return this->emplace_hint(hint, boost::move(x));
}
template <class InputIt> void insert(InputIt, InputIt);
@ -612,8 +705,8 @@ namespace unordered
iterator erase(const_iterator);
size_type erase(const key_type&);
iterator erase(const_iterator, const_iterator);
void quick_erase(const_iterator position) { erase(position); }
void erase_return_void(const_iterator position) { erase(position); }
void quick_erase(const_iterator it) { erase(it); }
void erase_return_void(const_iterator it) { erase(it); }
void clear();
void swap(unordered_multimap&);
@ -670,14 +763,16 @@ namespace unordered
local_iterator begin(size_type n)
{
return local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
local_iterator();
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
local_iterator end(size_type)
@ -692,8 +787,9 @@ namespace unordered
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
const_local_iterator cend(size_type) const
@ -714,9 +810,9 @@ namespace unordered
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<K,T,H,P,A>(
unordered_multimap const&, unordered_multimap const&);
unordered_multimap const&, unordered_multimap const&);
friend bool operator!=<K,T,H,P,A>(
unordered_multimap const&, unordered_multimap const&);
unordered_multimap const&, unordered_multimap const&);
#endif
}; // class template unordered_multimap
@ -783,7 +879,8 @@ namespace unordered
unordered_map<K,T,H,P,A>::~unordered_map() {}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(unordered_map const& other)
unordered_map<K,T,H,P,A>::unordered_map(
unordered_map const& other)
: table_(other.table_)
{
}
@ -834,109 +931,6 @@ namespace unordered
// modifiers
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class K, class T, class H, class P, class A>
template <class... Args>
std::pair<typename unordered_map<K,T,H,P,A>::iterator, bool>
unordered_map<K,T,H,P,A>::emplace(Args&&... args)
{
return table_.emplace(std::forward<Args>(args)...);
}
template <class K, class T, class H, class P, class A>
template <class... Args>
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::emplace_hint(const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...).first);
}
#else
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
template <class K, class T, class H, class P, class A>
std::pair<typename unordered_map<K,T,H,P,A>::iterator, bool>
unordered_map<K,T,H,P,A>::emplace(
boost::unordered::detail::empty_emplace,
value_type v
)
{
return table_.emplace(boost::move(v));
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::emplace_hint(const_iterator,
boost::unordered::detail::empty_emplace,
value_type v
)
{
return iterator(table_.emplace(boost::move(v)).first);
}
#endif
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template <class K, class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<typename unordered_map<K,T,H,P,A>::iterator, bool> \
unordered_map<K,T,H,P,A>::emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <class K, class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
typename unordered_map<K,T,H,P,A>::iterator \
unordered_map<K,T,H,P,A>::emplace_hint( \
const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif
template <class K, class T, class H, class P, class A>
std::pair<typename unordered_map<K,T,H,P,A>::iterator, bool>
unordered_map<K,T,H,P,A>::insert(value_type const& obj)
{
return table_.emplace(obj);
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::insert(const_iterator,
value_type const& obj)
{
return iterator(table_.emplace(obj).first);
}
template <class K, class T, class H, class P, class A>
std::pair<typename unordered_map<K,T,H,P,A>::iterator, bool>
unordered_map<K,T,H,P,A>::insert(BOOST_RV_REF(value_type) obj)
{
return table_.emplace(boost::move(obj));
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::insert(const_iterator,
BOOST_RV_REF(value_type) obj)
{
return iterator(table_.emplace(boost::move(obj)).first);
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
void unordered_map<K,T,H,P,A>::insert(InputIt first, InputIt last)
@ -1230,6 +1224,7 @@ namespace unordered
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
std::initializer_list<value_type> list, size_type n,
@ -1250,6 +1245,7 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
return *this;
}
#endif
// size and capacity
@ -1262,112 +1258,6 @@ namespace unordered
// modifiers
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class K, class T, class H, class P, class A>
template <class... Args>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::emplace(Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
template <class K, class T, class H, class P, class A>
template <class... Args>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::emplace_hint(
const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
#else
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::emplace(
boost::unordered::detail::empty_emplace,
value_type v
)
{
return iterator(table_.emplace(boost::move(v)));
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::emplace_hint(const_iterator,
boost::unordered::detail::empty_emplace,
value_type v
)
{
return iterator(table_.emplace(boost::move(v)));
}
#endif
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template <class K, class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
typename unordered_multimap<K,T,H,P,A>::iterator \
unordered_multimap<K,T,H,P,A>::emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return iterator(table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n))); \
} \
\
template <class K, class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
typename unordered_multimap<K,T,H,P,A>::iterator \
unordered_multimap<K,T,H,P,A>::emplace_hint( \
const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return iterator(table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n))); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::insert(value_type const& obj)
{
return iterator(table_.emplace(obj));
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::insert(
const_iterator, value_type const& obj)
{
return iterator(table_.emplace(obj));
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::insert(BOOST_RV_REF(value_type) obj)
{
return iterator(table_.emplace(boost::move(obj)));
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::insert(
const_iterator, BOOST_RV_REF(value_type) obj)
{
return iterator(table_.emplace(boost::move(obj)));
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
void unordered_multimap<K,T,H,P,A>::insert(InputIt first, InputIt last)

View File

@ -14,10 +14,12 @@
#endif
#include <boost/unordered/unordered_set_fwd.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#include <boost/unordered/detail/util.hpp>
#include <boost/functional/hash.hpp>
#include <boost/move/move.hpp>
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#include <initializer_list>
@ -48,21 +50,18 @@ namespace unordered
typedef P key_equal;
typedef A allocator_type;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
typedef typename ::boost::unordered::detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef ::boost::unordered::detail::allocator_traits<value_allocator>
allocator_traits;
typedef ::boost::unordered::detail::set<H, P,
value_allocator> types;
typedef typename types::impl table;
typedef typename types::node_ptr node_ptr;
typedef ::boost::unordered::detail::set<value_allocator, H, P>
types;
typedef typename types::table table;
public:
@ -75,22 +74,18 @@ namespace unordered
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef ::boost::unordered::iterator_detail::cl_iterator<
value_allocator, true> const_local_iterator;
typedef ::boost::unordered::iterator_detail::c_iterator<
value_allocator, true> const_iterator;
typedef const_local_iterator local_iterator;
typedef const_iterator iterator;
typedef typename table::cl_iterator const_local_iterator;
typedef typename table::cl_iterator local_iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::c_iterator iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
table table_;
public:
// construct/destroy/copy
// constructors
explicit unordered_set(
size_type = ::boost::unordered::detail::default_bucket_count,
@ -100,17 +95,15 @@ namespace unordered
explicit unordered_set(allocator_type const&);
unordered_set(unordered_set const&, allocator_type const&);
template <class InputIt>
unordered_set(InputIt f, InputIt l);
unordered_set(InputIt, InputIt);
template <class InputIt>
unordered_set(
InputIt, InputIt,
size_type,
const hasher& = hasher(),
const key_equal& = key_equal());
const key_equal& = key_equal());
template <class InputIt>
unordered_set(
@ -119,23 +112,12 @@ namespace unordered
const hasher&,
const key_equal&,
const allocator_type&);
~unordered_set();
unordered_set& operator=(
BOOST_COPY_ASSIGN_REF(unordered_set) x)
{
table_.assign(x.table_);
return *this;
}
// copy/move constructors
unordered_set(unordered_set const&);
unordered_set& operator=(BOOST_RV_REF(unordered_set) x)
{
table_.move_assign(x.table_);
return *this;
}
unordered_set(unordered_set const&, allocator_type const&);
unordered_set(BOOST_RV_REF(unordered_set) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
@ -153,7 +135,27 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
#endif
// Destructor
~unordered_set();
// Assign
unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x)
{
table_.assign(x.table_);
return *this;
}
unordered_set& operator=(BOOST_RV_REF(unordered_set) x)
{
table_.move_assign(x.table_);
return *this;
}
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_set& operator=(std::initializer_list<value_type>);
#endif
@ -208,52 +210,99 @@ namespace unordered
return const_iterator();
}
// modifiers
// emplace
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
std::pair<iterator, bool> emplace(Args&&...);
std::pair<iterator, bool> emplace(Args&&... args)
{
return table_.emplace(std::forward<Args>(args)...);
}
template <class... Args>
iterator emplace_hint(const_iterator, Args&&...);
iterator emplace_hint(const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...).first);
}
#else
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
std::pair<iterator, bool> emplace( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
)); \
} \
\
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return iterator(table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
)).first); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
std::pair<iterator, bool> emplace(
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
iterator emplace_hint(const_iterator,
value_type v = value_type())
{
return this->emplace(boost::move(v));
}
iterator emplace_hint(const_iterator hint,
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
); \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
);
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
)
{
return iterator(this->emplace_hint(hint, boost::move(v)));
}
#endif
std::pair<iterator, bool> insert(value_type const&);
std::pair<iterator, bool> insert(BOOST_UNORDERED_RV_REF(value_type));
iterator insert(const_iterator, value_type const&);
iterator insert(const_iterator, BOOST_UNORDERED_RV_REF(value_type));
#endif
std::pair<iterator, bool> insert(value_type const& x)
{
return this->emplace(x);
}
std::pair<iterator, bool> insert(BOOST_UNORDERED_RV_REF(value_type) x)
{
return this->emplace(boost::move(x));
}
iterator insert(const_iterator hint, value_type const& x)
{
return this->emplace_hint(hint, x);
}
iterator insert(const_iterator hint, BOOST_UNORDERED_RV_REF(value_type) x)
{
return this->emplace_hint(hint, boost::move(x));
}
template <class InputIt> void insert(InputIt, InputIt);
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
@ -286,6 +335,7 @@ namespace unordered
CompatiblePredicate const&) const;
size_type count(const key_type&) const;
std::pair<const_iterator, const_iterator>
equal_range(const key_type&) const;
@ -301,7 +351,7 @@ namespace unordered
return table_.max_bucket_count();
}
size_type bucket_size(size_type n) const;
size_type bucket_size(size_type) const;
size_type bucket(const key_type& k) const
{
@ -310,14 +360,16 @@ namespace unordered
local_iterator begin(size_type n)
{
return local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
local_iterator();
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
local_iterator end(size_type)
@ -332,8 +384,9 @@ namespace unordered
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
const_local_iterator cend(size_type) const
@ -350,7 +403,7 @@ namespace unordered
float load_factor() const;
void max_load_factor(float);
void rehash(size_type n);
void rehash(size_type);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<T,H,P,A>(
@ -372,21 +425,18 @@ namespace unordered
typedef P key_equal;
typedef A allocator_type;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
typedef typename ::boost::unordered::detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef ::boost::unordered::detail::allocator_traits<value_allocator>
allocator_traits;
typedef ::boost::unordered::detail::multiset<H, P,
value_allocator> types;
typedef typename types::impl table;
typedef typename types::node_ptr node_ptr;
typedef ::boost::unordered::detail::multiset<value_allocator, H, P>
types;
typedef typename types::table table;
public:
@ -399,22 +449,18 @@ namespace unordered
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef ::boost::unordered::iterator_detail::cl_iterator<
value_allocator, false> const_local_iterator;
typedef ::boost::unordered::iterator_detail::c_iterator<
value_allocator, false> const_iterator;
typedef const_local_iterator local_iterator;
typedef const_iterator iterator;
typedef typename table::cl_iterator const_local_iterator;
typedef typename table::cl_iterator local_iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::c_iterator iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
table table_;
public:
// construct/destroy/copy
// constructors
explicit unordered_multiset(
size_type = ::boost::unordered::detail::default_bucket_count,
@ -424,8 +470,6 @@ namespace unordered
explicit unordered_multiset(allocator_type const&);
unordered_multiset(unordered_multiset const&, allocator_type const&);
template <class InputIt>
unordered_multiset(InputIt, InputIt);
@ -444,22 +488,11 @@ namespace unordered
const key_equal&,
const allocator_type&);
~unordered_multiset();
unordered_multiset& operator=(
BOOST_COPY_ASSIGN_REF(unordered_multiset) x)
{
table_.assign(x.table_);
return *this;
}
// copy/move constructors
unordered_multiset(unordered_multiset const&);
unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x)
{
table_.move_assign(x.table_);
return *this;
}
unordered_multiset(unordered_multiset const&, allocator_type const&);
unordered_multiset(BOOST_RV_REF(unordered_multiset) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
@ -477,7 +510,27 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
#endif
// Destructor
~unordered_multiset();
// Assign
unordered_multiset& operator=(BOOST_COPY_ASSIGN_REF(unordered_multiset) x)
{
table_.assign(x.table_);
return *this;
}
unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x)
{
table_.move_assign(x.table_);
return *this;
}
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_multiset& operator=(std::initializer_list<value_type>);
#endif
@ -532,55 +585,100 @@ namespace unordered
return const_iterator();
}
// modifiers
// emplace
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
iterator emplace(Args&&...);
iterator emplace(Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
template <class... Args>
iterator emplace_hint(const_iterator, Args&&...);
iterator emplace_hint(const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
#else
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return iterator(table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
))); \
} \
\
template < \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return iterator(table_.emplace( \
::boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
))); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
iterator emplace(
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
iterator emplace_hint(const_iterator,
value_type v = value_type())
{
return this->emplace(boost::move(v));
}
iterator emplace_hint(const_iterator hint,
boost::unordered::detail::empty_emplace
= boost::unordered::detail::empty_emplace(),
value_type v = value_type()
);
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
); \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
);
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
)
{
return this->emplace_hint(hint, boost::move(v));
}
#endif
iterator insert(value_type const&);
iterator insert(BOOST_UNORDERED_RV_REF(value_type));
iterator insert(const_iterator, value_type const&);
iterator insert(const_iterator, BOOST_UNORDERED_RV_REF(value_type));
#endif
template <class InputIt>
void insert(InputIt, InputIt);
iterator insert(value_type const& x)
{
return this->emplace(x);
}
iterator insert(BOOST_UNORDERED_RV_REF(value_type) x)
{
return this->emplace(boost::move(x));
}
iterator insert(const_iterator hint, value_type const& x)
{
return this->emplace_hint(hint, x);
}
iterator insert(const_iterator hint, BOOST_UNORDERED_RV_REF(value_type) x)
{
return this->emplace_hint(hint, boost::move(x));
}
template <class InputIt> void insert(InputIt, InputIt);
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
void insert(std::initializer_list<value_type>);
@ -589,8 +687,8 @@ namespace unordered
iterator erase(const_iterator);
size_type erase(const key_type&);
iterator erase(const_iterator, const_iterator);
void quick_erase(const_iterator position) { erase(position); }
void erase_return_void(const_iterator position) { erase(position); }
void quick_erase(const_iterator it) { erase(it); }
void erase_return_void(const_iterator it) { erase(it); }
void clear();
void swap(unordered_multiset&);
@ -612,6 +710,7 @@ namespace unordered
CompatiblePredicate const&) const;
size_type count(const key_type&) const;
std::pair<const_iterator, const_iterator>
equal_range(const key_type&) const;
@ -636,14 +735,16 @@ namespace unordered
local_iterator begin(size_type n)
{
return local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
local_iterator();
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
local_iterator end(size_type)
@ -658,8 +759,9 @@ namespace unordered
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(
table_.bucket_begin(n), n, table_.bucket_count_);
return table_.size_ ? const_local_iterator(
table_.get_start(n), n, table_.bucket_count_) :
const_local_iterator();
}
const_local_iterator cend(size_type) const
@ -749,7 +851,8 @@ namespace unordered
unordered_set<T,H,P,A>::~unordered_set() {}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(unordered_set const& other)
unordered_set<T,H,P,A>::unordered_set(
unordered_set const& other)
: table_(other.table_)
{
}
@ -800,107 +903,6 @@ namespace unordered
// modifiers
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class T, class H, class P, class A>
template <class... Args>
std::pair<typename unordered_set<T,H,P,A>::iterator, bool>
unordered_set<T,H,P,A>::emplace(Args&&... args)
{
return table_.emplace(std::forward<Args>(args)...);
}
template <class T, class H, class P, class A>
template <class... Args>
typename unordered_set<T,H,P,A>::iterator
unordered_set<T,H,P,A>::emplace_hint(const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...).first);
}
#else
template <class T, class H, class P, class A>
std::pair<typename unordered_set<T,H,P,A>::iterator, bool>
unordered_set<T,H,P,A>::emplace(
boost::unordered::detail::empty_emplace,
value_type v
)
{
return table_.emplace(boost::move(v));
}
template <class T, class H, class P, class A>
typename unordered_set<T,H,P,A>::iterator
unordered_set<T,H,P,A>::emplace_hint(const_iterator,
boost::unordered::detail::empty_emplace,
value_type v
)
{
return iterator(table_.emplace(boost::move(v)).first);
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template <class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<typename unordered_set<T,H,P,A>::iterator, bool> \
unordered_set<T,H,P,A>::emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
typename unordered_set<T,H,P,A>::iterator \
unordered_set<T,H,P,A>::emplace_hint( \
const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif
template <class T, class H, class P, class A>
std::pair<typename unordered_set<T,H,P,A>::iterator, bool>
unordered_set<T,H,P,A>::insert(value_type const& obj)
{
return table_.emplace(obj);
}
template <class T, class H, class P, class A>
typename unordered_set<T,H,P,A>::iterator
unordered_set<T,H,P,A>::insert(const_iterator,
value_type const& obj)
{
return iterator(table_.emplace(obj).first);
}
template <class T, class H, class P, class A>
std::pair<typename unordered_set<T,H,P,A>::iterator, bool>
unordered_set<T,H,P,A>::insert(BOOST_UNORDERED_RV_REF(value_type) obj)
{
return table_.emplace(boost::move(obj));
}
template <class T, class H, class P, class A>
typename unordered_set<T,H,P,A>::iterator
unordered_set<T,H,P,A>::insert(const_iterator,
BOOST_UNORDERED_RV_REF(value_type) obj)
{
return iterator(table_.emplace(boost::move(obj)).first);
}
template <class T, class H, class P, class A>
template <class InputIt>
void unordered_set<T,H,P,A>::insert(InputIt first, InputIt last)
@ -910,7 +912,8 @@ namespace unordered
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
template <class T, class H, class P, class A>
void unordered_set<T,H,P,A>::insert(std::initializer_list<value_type> list)
void unordered_set<T,H,P,A>::insert(
std::initializer_list<value_type> list)
{
table_.insert_range(list.begin(), list.end());
}
@ -932,7 +935,8 @@ namespace unordered
template <class T, class H, class P, class A>
typename unordered_set<T,H,P,A>::iterator
unordered_set<T,H,P,A>::erase(const_iterator first, const_iterator last)
unordered_set<T,H,P,A>::erase(
const_iterator first, const_iterator last)
{
return iterator(table_.erase_range(first.node_, last.node_));
}
@ -1143,6 +1147,7 @@ namespace unordered
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
std::initializer_list<value_type> list, size_type n,
@ -1163,6 +1168,7 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
return *this;
}
#endif
// size and capacity
@ -1175,110 +1181,6 @@ namespace unordered
// modifiers
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class T, class H, class P, class A>
template <class... Args>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::emplace(Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
template <class T, class H, class P, class A>
template <class... Args>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::emplace_hint(
const_iterator, Args&&... args)
{
return iterator(table_.emplace(std::forward<Args>(args)...));
}
#else
template <class T, class H, class P, class A>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::emplace(
boost::unordered::detail::empty_emplace,
value_type v
)
{
return iterator(table_.emplace(boost::move(v)));
}
template <class T, class H, class P, class A>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::emplace_hint(const_iterator,
boost::unordered::detail::empty_emplace,
value_type v
)
{
return iterator(table_.emplace(boost::move(v)));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template <class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
typename unordered_multiset<T,H,P,A>::iterator \
unordered_multiset<T,H,P,A>::emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return iterator(table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n))); \
} \
\
template <class T, class H, class P, class A> \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
typename unordered_multiset<T,H,P,A>::iterator \
unordered_multiset<T,H,P,A>::emplace_hint( \
const_iterator, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return iterator(table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n))); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif
template <class T, class H, class P, class A>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::insert(value_type const& obj)
{
return iterator(table_.emplace(obj));
}
template <class T, class H, class P, class A>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::insert(const_iterator,
value_type const& obj)
{
return iterator(table_.emplace(obj));
}
template <class T, class H, class P, class A>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::insert(BOOST_UNORDERED_RV_REF(value_type) obj)
{
return iterator(table_.emplace(boost::move(obj)));
}
template <class T, class H, class P, class A>
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::insert(const_iterator,
BOOST_UNORDERED_RV_REF(value_type) obj)
{
return iterator(table_.emplace(boost::move(obj)));
}
template <class T, class H, class P, class A>
template <class InputIt>
void unordered_multiset<T,H,P,A>::insert(InputIt first, InputIt last)
@ -1439,7 +1341,6 @@ namespace unordered
#endif
m1.swap(m2);
}
} // namespace unordered
} // namespace boost

View File

@ -202,17 +202,67 @@ namespace minimal
template <class T> class ptr;
template <class T> class const_ptr;
struct void_ptr
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename T>
friend class ptr;
private:
#endif
void* ptr_;
public:
void_ptr() : ptr_(0) {}
template <typename T>
explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
};
class void_const_ptr
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename T>
friend class const_ptr;
private:
#endif
void* ptr_;
public:
void_const_ptr() : ptr_(0) {}
template <typename T>
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_) {}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
};
template <class T>
class ptr
{
friend class allocator<T>;
friend class const_ptr<T>;
friend struct void_ptr;
T* ptr_;
ptr(T* x) : ptr_(x) {}
public:
ptr() : ptr_(0) {}
explicit ptr(void_ptr const& x) : ptr_((T*) x.ptr_) {}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
@ -234,13 +284,6 @@ namespace minimal
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
bool operator==(const_ptr<T> const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr<T> const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr<T> const& x) const { return ptr_ < x.ptr_; }
bool operator>(const_ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr<T> const& x) const { return ptr_ >= x.ptr_; }
private:
// TODO:
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
@ -250,6 +293,7 @@ namespace minimal
class const_ptr
{
friend class allocator<T>;
friend struct const_void_ptr;
T const* ptr_;
@ -257,6 +301,7 @@ namespace minimal
public:
const_ptr() : ptr_(0) {}
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*) x.ptr_) {}
T const& operator*() const { return *ptr_; }
T const* operator->() const { return ptr_; }
@ -270,13 +315,6 @@ namespace minimal
bool operator!() const { return !ptr_; }
operator bool() const { return !!ptr_; }
bool operator==(ptr<T> const& x) const { return ptr_ == x.ptr_; }
bool operator!=(ptr<T> const& x) const { return ptr_ != x.ptr_; }
bool operator<(ptr<T> const& x) const { return ptr_ < x.ptr_; }
bool operator>(ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr<T> const& x) const { return ptr_ >= x.ptr_; }
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
@ -294,6 +332,8 @@ namespace minimal
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef void_ptr void_pointer;
typedef void_const_ptr void_const_pointer;
typedef ptr<T> pointer;
typedef const_ptr<T> const_pointer;
typedef T& reference;

View File

@ -57,9 +57,12 @@ void assign_tests1(T*,
T y;
y.max_load_factor(x.max_load_factor() / 20);
float mlf = x.max_load_factor();
y = x;
tracker.compare(x);
tracker.compare(y);
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
BOOST_TEST(x.max_load_factor() == mlf);
BOOST_TEST(y.max_load_factor() == mlf);
}
}

View File

@ -128,7 +128,7 @@ UNORDERED_AUTO_TEST(test1)
std::equal_to<int> equal_to;
int value = 0;
std::cout<<"Test unordered_set.\n";
std::cout<<"Test unordered_set." << std::endl;
boost::unordered_set<int> set;
@ -145,7 +145,7 @@ UNORDERED_AUTO_TEST(test1)
unordered_set_test(set2, value);
unordered_copyable_test(set2, value, value, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
std::cout<<"Test unordered_multiset." << std::endl;
boost::unordered_multiset<int> multiset;

View File

@ -413,6 +413,7 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
X a6(i, j, 10, hf);

View File

@ -15,8 +15,6 @@
#include "../helpers/input_iterator.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
namespace constructor_tests {
test::seed_t seed(356730);

View File

@ -5,6 +5,7 @@
#include "../helpers/prefix.hpp"
#include <utility>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>

View File

@ -245,9 +245,11 @@ namespace unnecessary_copy_tests
x.emplace();
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
COPY_COUNT(1); MOVE_COUNT(0);
#else
#elif !defined(BOOST_NO_RVALUE_REFERENCES)
// source_cost doesn't make much sense here, but it seems to fit.
COPY_COUNT(1); MOVE_COUNT(source_cost);
#else
COPY_COUNT(1); MOVE_COUNT(1 + source_cost);
#endif
#endif
@ -357,7 +359,6 @@ namespace unnecessary_copy_tests
(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \
(defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \
(!defined(__GNUC__) && !defined(BOOST_MSVC))
count_copies part;
reset();
std::pair<count_copies const&, count_copies const&> a_ref(part, part);