forked from boostorg/unordered
Merge branch 'feature/better-construction' into develop
This commit is contained in:
@ -2,7 +2,13 @@
|
||||
/ 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) ]
|
||||
|
||||
[section:compliance C++11 Compliance]
|
||||
[section:compliance Standard Compliance]
|
||||
|
||||
The intent of Boost.Unordered is to implement a close (but inperfect)
|
||||
implementation of the C++17 standard, that will work with C++98 upwards.
|
||||
The wide compatibility does mean some comprimises have to be made.
|
||||
With a compiler and library that fully support C++11, the differences should
|
||||
be minor.
|
||||
|
||||
[section:move Move emulation]
|
||||
|
||||
@ -51,23 +57,32 @@ Due to imperfect move emulation, some assignments might check
|
||||
`propagate_on_container_copy_assignment` on some compilers and
|
||||
`propagate_on_container_move_assignment` on others.
|
||||
|
||||
The use of the allocator's construct and destruct methods might be a bit
|
||||
surprising.
|
||||
Nodes are constructed and destructed using the allocator, but the elements
|
||||
are stored in aligned space within the node and constructed and destructed
|
||||
by calling the constructor and destructor directly.
|
||||
[endsect]
|
||||
|
||||
In C++11 the allocator's construct function has the signature:
|
||||
[section:construction Construction/Destruction using allocators]
|
||||
|
||||
template <class U, class... Args>
|
||||
void construct(U* p, Args&&... args);
|
||||
The following support is required for full use of C++11 style
|
||||
construction/destruction:
|
||||
|
||||
which supports calling `construct` for the contained object, but
|
||||
most existing allocators don't support this. If member function detection
|
||||
was good enough then with old allocators it would fall back to calling
|
||||
the element's constructor directly but in general, detection isn't good
|
||||
enough to do this which is why Boost.Unordered just calls the constructor
|
||||
directly every time. In most cases this will work okay.
|
||||
* Variadic templates.
|
||||
* Piecewise construction of `std::pair`.
|
||||
* Either `std::allocator_traits` or expression SFINAE.
|
||||
|
||||
This is detected using Boost.Config. The macro
|
||||
`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0
|
||||
otherwise.
|
||||
|
||||
When this is the case `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` will always be used, apart from when piecewise
|
||||
constructing a `std::pair` using `boost::tuple` (see [link
|
||||
unordered.compliance.pairs below]), but that should be easily avoided.
|
||||
|
||||
When support is not available `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` are never called.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pointer_traits Pointer Traits]
|
||||
|
||||
`pointer_traits` aren't used. Instead, pointer types are obtained from
|
||||
rebound allocators, this can cause problems if the allocator can't be
|
||||
@ -77,6 +92,7 @@ is used to obtain a const pointer.
|
||||
|
||||
[endsect]
|
||||
|
||||
[#unordered.compliance.pairs]
|
||||
[section:pairs Pairs]
|
||||
|
||||
Since the containers use `std::pair` they're limited to the version
|
||||
|
@ -104,6 +104,25 @@
|
||||
#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
|
||||
#endif
|
||||
|
||||
// BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
//
|
||||
// Use C++11 construction, requires variadic arguments, good construct support
|
||||
// in allocator_traits and piecewise construction of std::pair
|
||||
// Otherwise allocators aren't used for construction/destruction
|
||||
|
||||
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \
|
||||
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && !defined(BOOST_NO_SFINAE_EXPR)
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
|
||||
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION)
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
|
||||
#endif
|
||||
|
||||
//
|
||||
// Other configuration macros
|
||||
//
|
||||
@ -466,17 +485,6 @@ struct convert_from_anything
|
||||
template <typename T> convert_from_anything(T const&);
|
||||
};
|
||||
|
||||
namespace func {
|
||||
// This is a bit nasty, when constructing the individual members
|
||||
// of a std::pair, need to cast away 'const'. For modern compilers,
|
||||
// should be able to use std::piecewise_construct instead.
|
||||
template <typename T> T* const_cast_pointer(T* x) { return x; }
|
||||
template <typename T> T* const_cast_pointer(T const* x)
|
||||
{
|
||||
return const_cast<T*>(x);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// emplace_args
|
||||
//
|
||||
@ -765,13 +773,6 @@ template <typename T> struct identity
|
||||
#include <boost/pointer_to_other.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
!defined(BOOST_NO_SFINAE_EXPR)
|
||||
#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
|
||||
#else
|
||||
#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
@ -1040,7 +1041,7 @@ template <typename Alloc> struct allocator_traits
|
||||
}
|
||||
|
||||
public:
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static typename boost::enable_if_c<
|
||||
@ -1195,8 +1196,6 @@ template <typename Alloc> struct allocator_traits
|
||||
|
||||
#include <memory>
|
||||
|
||||
#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
@ -1222,8 +1221,6 @@ template <typename Alloc, typename T> struct rebind_wrap
|
||||
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
|
||||
#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
@ -1258,73 +1255,68 @@ namespace detail {
|
||||
namespace func {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// call_construct
|
||||
// construct_value
|
||||
//
|
||||
// Only use allocator_traits::construct, allocator_traits::destroy when full
|
||||
// C++11 support is available.
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \
|
||||
Traits::construct(alloc, address)
|
||||
#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
|
||||
Traits::construct(alloc, address, a0)
|
||||
#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) Traits::destroy(alloc, x)
|
||||
|
||||
template <typename Alloc, typename T, typename... Args>
|
||||
inline void call_construct(
|
||||
Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(
|
||||
alloc, address, boost::forward<Args>(args)...);
|
||||
}
|
||||
#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Alloc, typename T>
|
||||
inline void call_destroy(Alloc& alloc, T* x)
|
||||
{
|
||||
boost::unordered::detail::allocator_traits<Alloc>::destroy(alloc, x);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Alloc, typename T, typename... Args>
|
||||
inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(Args)... args)
|
||||
template <typename T, typename... Args>
|
||||
inline void construct_value(T* address, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)address) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x)
|
||||
{
|
||||
boost::unordered::detail::func::destroy(x);
|
||||
}
|
||||
|
||||
#endif
|
||||
#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \
|
||||
boost::unordered::detail::func::construct_value(address)
|
||||
#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
|
||||
boost::unordered::detail::func::construct_value(address, a0)
|
||||
#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \
|
||||
boost::unordered::detail::func::destroy(x)
|
||||
|
||||
#else
|
||||
template <typename Alloc, typename T>
|
||||
inline void call_construct(Alloc&, T* address)
|
||||
|
||||
template <typename T> inline void construct_value(T* address)
|
||||
{
|
||||
new ((void*)address) T();
|
||||
}
|
||||
|
||||
template <typename Alloc, typename T, typename A0>
|
||||
inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(A0) a0)
|
||||
template <typename T, typename A0>
|
||||
inline void construct_value(T* address, BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
new ((void*)address) T(boost::forward<A0>(a0));
|
||||
}
|
||||
|
||||
template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x)
|
||||
{
|
||||
boost::unordered::detail::func::destroy(x);
|
||||
}
|
||||
#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \
|
||||
boost::unordered::detail::func::construct_value(address)
|
||||
#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \
|
||||
boost::unordered::detail::func::construct_value(address, a0)
|
||||
#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \
|
||||
boost::unordered::detail::func::destroy(x)
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Construct from tuple
|
||||
//
|
||||
// Used for piecewise construction.
|
||||
// Used to emulate piecewise construction.
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
|
||||
template <typename Alloc, typename T> \
|
||||
void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \
|
||||
void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \
|
||||
{ \
|
||||
boost::unordered::detail::func::call_construct(alloc, ptr); \
|
||||
new ((void*)ptr) T(); \
|
||||
} \
|
||||
\
|
||||
BOOST_PP_REPEAT_FROM_TO( \
|
||||
@ -1333,10 +1325,10 @@ template <typename Alloc, typename T> inline void call_destroy(Alloc&, T* x)
|
||||
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
|
||||
template <typename Alloc, typename T, \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
|
||||
void construct_from_tuple(Alloc& alloc, T* ptr, \
|
||||
void construct_from_tuple(Alloc&, T* ptr, \
|
||||
namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
|
||||
{ \
|
||||
boost::unordered::detail::func::call_construct(alloc, ptr, \
|
||||
new ((void*)ptr) T( \
|
||||
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \
|
||||
}
|
||||
|
||||
@ -1400,7 +1392,8 @@ template <int N> struct length
|
||||
|
||||
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
|
||||
|
||||
#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && !defined(__SUNPRO_CC) && \
|
||||
!defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::)
|
||||
#endif
|
||||
|
||||
@ -1436,25 +1429,76 @@ template <typename A0> struct use_piecewise
|
||||
};
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Construct from variadic parameters
|
||||
|
||||
// For the standard pair constructor.
|
||||
|
||||
template <typename Alloc, typename T, typename... Args>
|
||||
inline void construct_from_args(
|
||||
Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
boost::unordered::detail::func::call_construct(
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(
|
||||
alloc, address, boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Special case for piece_construct
|
||||
//
|
||||
// TODO: When possible, it might be better to use std::pair's
|
||||
// constructor for std::piece_construct with std::tuple.
|
||||
// For backwards compatibility, implement a special case for
|
||||
// piecewise_construct with boost::tuple
|
||||
|
||||
template <typename A0> struct detect_boost_tuple
|
||||
{
|
||||
template <typename... T0>
|
||||
static choice1::type test(choice1, boost::tuple<T0...> const&);
|
||||
|
||||
static choice2::type test(choice2, ...);
|
||||
|
||||
enum
|
||||
{
|
||||
value = sizeof(choice1::type) ==
|
||||
sizeof(test(choose(), boost::unordered::detail::make<A0>()))
|
||||
};
|
||||
};
|
||||
|
||||
// Special case for piecewise_construct
|
||||
|
||||
template <typename Alloc, typename A, typename B, typename A0, typename A1,
|
||||
typename A2>
|
||||
inline typename boost::enable_if_c<use_piecewise<A0>::value &&
|
||||
detect_boost_tuple<A1>::value &&
|
||||
detect_boost_tuple<A2>::value,
|
||||
void>::type
|
||||
construct_from_args(Alloc& alloc, std::pair<A, B>* address, BOOST_FWD_REF(A0),
|
||||
BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_tuple(
|
||||
alloc, boost::addressof(address->first), boost::forward<A1>(a1));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_tuple(
|
||||
alloc, boost::addressof(address->second), boost::forward<A2>(a2));
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::unordered::detail::func::destroy(
|
||||
boost::addressof(address->first));
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Construct from variadic parameters
|
||||
|
||||
template <typename Alloc, typename T, typename... Args>
|
||||
inline void construct_from_args(
|
||||
Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)address) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Special case for piecewise_construct
|
||||
|
||||
template <typename Alloc, typename A, typename B, typename A0, typename A1,
|
||||
typename A2>
|
||||
@ -1463,21 +1507,16 @@ inline typename enable_if<use_piecewise<A0>, void>::type construct_from_args(
|
||||
BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_tuple(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(address->first)),
|
||||
boost::forward<A1>(a1));
|
||||
alloc, boost::addressof(address->first), boost::forward<A1>(a1));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_tuple(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(address->second)),
|
||||
boost::forward<A2>(a2));
|
||||
alloc, boost::addressof(address->second), boost::forward<A2>(a2));
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(address->first)));
|
||||
boost::unordered::detail::func::destroy(
|
||||
boost::addressof(address->first));
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -1532,7 +1571,7 @@ BOOST_PP_REPEAT_FROM_TO(
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
||||
|
||||
// Construct with piece_construct
|
||||
// Construct with piecewise_construct
|
||||
|
||||
template <typename Alloc, typename A, typename B, typename A0, typename A1,
|
||||
typename A2>
|
||||
@ -1541,21 +1580,16 @@ inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address,
|
||||
typename enable_if<use_piecewise<A0>, void*>::type = 0)
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_tuple(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(address->first)),
|
||||
args.a1);
|
||||
alloc, boost::addressof(address->first), args.a1);
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_tuple(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(address->second)),
|
||||
args.a2);
|
||||
alloc, boost::addressof(address->second), args.a2);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(address->first)));
|
||||
boost::unordered::detail::func::destroy(
|
||||
boost::addressof(address->first));
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -1611,8 +1645,8 @@ template <typename NodeAlloc> struct node_constructor
|
||||
BOOST_ASSERT(!node_);
|
||||
node_ = p;
|
||||
node_constructed_ = true;
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc_, node_->value_ptr());
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, alloc_, node_->value_ptr());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1624,7 +1658,8 @@ template <typename Alloc> node_constructor<Alloc>::~node_constructor()
|
||||
{
|
||||
if (node_) {
|
||||
if (node_constructed_) {
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*node_));
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, alloc_, boost::addressof(*node_));
|
||||
}
|
||||
|
||||
node_allocator_traits::deallocate(alloc_, node_, 1);
|
||||
@ -1638,7 +1673,8 @@ template <typename Alloc> void node_constructor<Alloc>::create_node()
|
||||
|
||||
node_ = node_allocator_traits::allocate(alloc_, 1);
|
||||
|
||||
new ((void*)boost::addressof(*node_)) node();
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT0(
|
||||
node_allocator_traits, alloc_, boost::addressof(*node_));
|
||||
node_->init(node_);
|
||||
node_constructed_ = true;
|
||||
}
|
||||
@ -1668,9 +1704,10 @@ template <typename NodeAlloc> struct node_tmp
|
||||
template <typename Alloc> node_tmp<Alloc>::~node_tmp()
|
||||
{
|
||||
if (node_) {
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc_, node_->value_ptr());
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*node_));
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, alloc_, node_->value_ptr());
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, alloc_, boost::addressof(*node_));
|
||||
node_allocator_traits::deallocate(alloc_, node_, 1);
|
||||
}
|
||||
}
|
||||
@ -1703,34 +1740,72 @@ construct_node(Alloc& alloc, BOOST_FWD_REF(U) x)
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::func::call_construct(
|
||||
alloc, a.node_->value_ptr(), boost::forward<U>(x));
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT1(
|
||||
boost::unordered::detail::allocator_traits<Alloc>, alloc,
|
||||
a.node_->value_ptr(), boost::forward<U>(x));
|
||||
return a.release();
|
||||
}
|
||||
|
||||
// TODO: When possible, it might be better to use std::pair's
|
||||
// constructor for std::piece_construct with std::tuple.
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
|
||||
template <typename Alloc, typename Key>
|
||||
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
|
||||
construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::func::call_construct(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->first)),
|
||||
boost::forward<Key>(k));
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
|
||||
a.node_->value_ptr(), std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)), std::forward_as_tuple());
|
||||
return a.release();
|
||||
}
|
||||
|
||||
template <typename Alloc, typename Key, typename Mapped>
|
||||
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
|
||||
construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
|
||||
a.node_->value_ptr(), std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Mapped>(m)));
|
||||
return a.release();
|
||||
}
|
||||
|
||||
template <typename Alloc, typename Key, typename... Args>
|
||||
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
|
||||
construct_node_pair_from_args(
|
||||
Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(alloc,
|
||||
a.node_->value_ptr(), std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...));
|
||||
return a.release();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Alloc, typename Key>
|
||||
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
|
||||
construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::func::construct_value(
|
||||
boost::addressof(a.node_->value_ptr()->first), boost::forward<Key>(k));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::unordered::detail::func::call_construct(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->second)));
|
||||
boost::unordered::detail::func::construct_value(
|
||||
boost::addressof(a.node_->value_ptr()->second));
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->first)));
|
||||
boost::unordered::detail::func::destroy(
|
||||
boost::addressof(a.node_->value_ptr()->first));
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -1743,22 +1818,18 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::func::call_construct(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->first)),
|
||||
boost::forward<Key>(k));
|
||||
boost::unordered::detail::func::construct_value(
|
||||
boost::addressof(a.node_->value_ptr()->first), boost::forward<Key>(k));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::unordered::detail::func::call_construct(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->second)),
|
||||
boost::unordered::detail::func::construct_value(
|
||||
boost::addressof(a.node_->value_ptr()->second),
|
||||
boost::forward<Mapped>(m));
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->first)));
|
||||
boost::unordered::detail::func::destroy(
|
||||
boost::addressof(a.node_->value_ptr()->first));
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -1772,27 +1843,25 @@ construct_node_pair_from_args(
|
||||
{
|
||||
node_constructor<Alloc> a(alloc);
|
||||
a.create_node();
|
||||
boost::unordered::detail::func::call_construct(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->first)),
|
||||
boost::forward<Key>(k));
|
||||
boost::unordered::detail::func::construct_value(
|
||||
boost::addressof(a.node_->value_ptr()->first), boost::forward<Key>(k));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::unordered::detail::func::construct_from_args(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->second)),
|
||||
boost::unordered::detail::func::construct_from_args(alloc,
|
||||
boost::addressof(a.node_->value_ptr()->second),
|
||||
BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
alloc, boost::unordered::detail::func::const_cast_pointer(
|
||||
boost::addressof(a.node_->value_ptr()->first)));
|
||||
boost::unordered::detail::func::destroy(
|
||||
boost::addressof(a.node_->value_ptr()->first));
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return a.release();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2113,7 +2182,7 @@ template <typename NodeAlloc> struct node_holder
|
||||
} else {
|
||||
constructor_.create_node();
|
||||
}
|
||||
boost::unordered::detail::func::call_construct(
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits,
|
||||
constructor_.alloc_, constructor_.node_->value_ptr(), v);
|
||||
return constructor_.release();
|
||||
}
|
||||
@ -2125,8 +2194,9 @@ template <typename NodeAlloc> struct node_holder
|
||||
} else {
|
||||
constructor_.create_node();
|
||||
}
|
||||
boost::unordered::detail::func::call_construct(constructor_.alloc_,
|
||||
constructor_.node_->value_ptr(), boost::move(v));
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits,
|
||||
constructor_.alloc_, constructor_.node_->value_ptr(),
|
||||
boost::move(v));
|
||||
return constructor_.release();
|
||||
}
|
||||
|
||||
@ -2139,9 +2209,10 @@ template <typename Alloc> node_holder<Alloc>::~node_holder()
|
||||
node_pointer p = nodes_;
|
||||
nodes_ = static_cast<node_pointer>(p->next_);
|
||||
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
constructor_.alloc_, p->value_ptr());
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*p));
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, constructor_.alloc_, p->value_ptr());
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, constructor_.alloc_, boost::addressof(*p));
|
||||
node_allocator_traits::deallocate(constructor_.alloc_, p, 1);
|
||||
}
|
||||
}
|
||||
@ -2156,6 +2227,7 @@ template <typename NodePointer> struct bucket
|
||||
link_pointer next_;
|
||||
|
||||
bucket() : next_() {}
|
||||
bucket(link_pointer n) : next_(n) {}
|
||||
|
||||
link_pointer first_from_start() { return next_; }
|
||||
|
||||
@ -2171,6 +2243,7 @@ struct ptr_bucket
|
||||
link_pointer next_;
|
||||
|
||||
ptr_bucket() : next_(0) {}
|
||||
ptr_bucket(link_pointer n) : next_(n) {}
|
||||
|
||||
link_pointer first_from_start() { return this; }
|
||||
|
||||
@ -2826,30 +2899,40 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||
BOOST_TRY
|
||||
{
|
||||
bucket_pointer end =
|
||||
new_buckets + static_cast<std::ptrdiff_t>(length);
|
||||
new_buckets + static_cast<std::ptrdiff_t>(new_count);
|
||||
for (; constructed != end; ++constructed) {
|
||||
new ((void*)boost::addressof(*constructed)) bucket();
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT0(bucket_allocator_traits,
|
||||
bucket_alloc(), boost::addressof(*constructed));
|
||||
}
|
||||
|
||||
if (buckets_) {
|
||||
// Copy the nodes to the new buckets, including the dummy
|
||||
// node if there is one.
|
||||
(new_buckets + static_cast<std::ptrdiff_t>(new_count))->next_ =
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT1(bucket_allocator_traits,
|
||||
bucket_alloc(), boost::addressof(*constructed),
|
||||
(buckets_ + static_cast<std::ptrdiff_t>(bucket_count_))
|
||||
->next_;
|
||||
->next_);
|
||||
++constructed;
|
||||
destroy_buckets();
|
||||
} else if (bucket::extra_node) {
|
||||
node_constructor a(node_alloc());
|
||||
a.create_node();
|
||||
|
||||
(new_buckets + static_cast<std::ptrdiff_t>(new_count))->next_ =
|
||||
a.release();
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT1(bucket_allocator_traits,
|
||||
bucket_alloc(), boost::addressof(*constructed),
|
||||
a.release());
|
||||
++constructed;
|
||||
} else {
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT0(bucket_allocator_traits,
|
||||
bucket_alloc(), boost::addressof(*constructed));
|
||||
++constructed;
|
||||
}
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
for (bucket_pointer p = new_buckets; p != constructed; ++p) {
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*p));
|
||||
BOOST_UNORDERED_CALL_DESTROY(bucket_allocator_traits,
|
||||
bucket_alloc(), boost::addressof(*p));
|
||||
}
|
||||
|
||||
bucket_allocator_traits::deallocate(
|
||||
@ -2927,9 +3010,10 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||
node_pointer n = static_cast<node_pointer>(prev->next_);
|
||||
prev->next_ = n->next_;
|
||||
|
||||
boost::unordered::detail::func::call_destroy(
|
||||
node_alloc(), n->value_ptr());
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*n));
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, node_alloc(), n->value_ptr());
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, node_alloc(), boost::addressof(*n));
|
||||
node_allocator_traits::deallocate(node_alloc(), n, 1);
|
||||
--size_;
|
||||
}
|
||||
@ -2957,7 +3041,8 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||
if (bucket::extra_node) {
|
||||
node_pointer n =
|
||||
static_cast<node_pointer>(get_bucket(bucket_count_)->next_);
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*n));
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
node_allocator_traits, node_alloc(), boost::addressof(*n));
|
||||
node_allocator_traits::deallocate(node_alloc(), n, 1);
|
||||
}
|
||||
|
||||
@ -2984,7 +3069,8 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||
{
|
||||
bucket_pointer end = get_bucket(bucket_count_ + 1);
|
||||
for (bucket_pointer it = buckets_; it != end; ++it) {
|
||||
boost::unordered::detail::func::destroy(boost::addressof(*it));
|
||||
BOOST_UNORDERED_CALL_DESTROY(
|
||||
bucket_allocator_traits, bucket_alloc(), boost::addressof(*it));
|
||||
}
|
||||
|
||||
bucket_allocator_traits::deallocate(
|
||||
@ -4129,8 +4215,8 @@ struct table_unique : boost::unordered::detail::table<Types>
|
||||
if (!a.node_) {
|
||||
a.create_node();
|
||||
}
|
||||
boost::unordered::detail::func::call_construct(
|
||||
a.alloc_, a.node_->value_ptr(), *i);
|
||||
BOOST_UNORDERED_CALL_CONSTRUCT1(
|
||||
node_allocator_traits, a.alloc_, a.node_->value_ptr(), *i);
|
||||
node_tmp b(a.release(), a.alloc_);
|
||||
|
||||
const_key_type& k = this->get_key(b.node_);
|
||||
|
@ -15,6 +15,7 @@ project unordered-test/unordered
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>clang:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>msvc:<cxxflags>"/wd4494"
|
||||
<toolset>gcc:<c++-template-depth>500
|
||||
;
|
||||
|
||||
#alias framework : /boost/test//boost_unit_test_framework ;
|
||||
|
@ -60,12 +60,16 @@ struct memory_tracker
|
||||
unsigned int count_allocators;
|
||||
unsigned int count_allocations;
|
||||
unsigned int count_constructions;
|
||||
bool tracking_constructions;
|
||||
|
||||
memory_tracker()
|
||||
: count_allocators(0), count_allocations(0), count_constructions(0)
|
||||
: count_allocators(0), count_allocations(0), count_constructions(0),
|
||||
tracking_constructions(true)
|
||||
{
|
||||
}
|
||||
|
||||
~memory_tracker() { BOOST_TEST(count_allocators == 0); }
|
||||
|
||||
void allocator_ref()
|
||||
{
|
||||
if (count_allocators == 0) {
|
||||
@ -131,14 +135,18 @@ struct memory_tracker
|
||||
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
{
|
||||
++count_constructions;
|
||||
if (tracking_constructions) {
|
||||
++count_constructions;
|
||||
}
|
||||
}
|
||||
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
{
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if (count_constructions > 0)
|
||||
--count_constructions;
|
||||
if (tracking_constructions) {
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if (count_constructions > 0)
|
||||
--count_constructions;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -153,6 +161,29 @@ namespace {
|
||||
test::detail::memory_tracker tracker;
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
struct disable_construction_tracking
|
||||
{
|
||||
bool old_value;
|
||||
|
||||
disable_construction_tracking()
|
||||
: old_value(detail::tracker.tracking_constructions)
|
||||
{
|
||||
test::detail::tracker.tracking_constructions = false;
|
||||
}
|
||||
|
||||
~disable_construction_tracking()
|
||||
{
|
||||
test::detail::tracker.tracking_constructions = old_value;
|
||||
}
|
||||
|
||||
private:
|
||||
disable_construction_tracking(disable_construction_tracking const&);
|
||||
disable_construction_tracking& operator=(
|
||||
disable_construction_tracking const&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -391,21 +391,37 @@ template <class T> class allocator1
|
||||
::operator delete((void*)p);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t)
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
template <typename U, typename... Args> void construct(U* p, Args&&... args)
|
||||
{
|
||||
// Don't count constructions here as it isn't always called.
|
||||
// detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new (p) T(t);
|
||||
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
|
||||
new (p) U(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void destroy(T* p)
|
||||
template <typename U> void destroy(U* p)
|
||||
{
|
||||
// detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
|
||||
p->~U();
|
||||
|
||||
// Work around MSVC buggy unused parameter warning.
|
||||
ignore_variable(&p);
|
||||
}
|
||||
#else
|
||||
private:
|
||||
// I'm going to claim in the documentation that construct/destroy
|
||||
// is never used when C++11 support isn't available, so might as
|
||||
// well check that in the text.
|
||||
// TODO: Or maybe just disallow them for values?
|
||||
template <typename U> void construct(U* p);
|
||||
template <typename U, typename A0> void construct(U* p, A0 const&);
|
||||
template <typename U, typename A0, typename A1>
|
||||
void construct(U* p, A0 const&, A1 const&);
|
||||
template <typename U, typename A0, typename A1, typename A2>
|
||||
void construct(U* p, A0 const&, A1 const&, A2 const&);
|
||||
template <typename U> void destroy(U* p);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }
|
||||
|
||||
|
@ -1030,21 +1030,43 @@ struct overloaded_constructor
|
||||
|
||||
UNORDERED_AUTO_TEST(map_emplace_test)
|
||||
{
|
||||
boost::unordered_map<int, overloaded_constructor> x;
|
||||
{
|
||||
boost::unordered_map<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
|
||||
x.emplace();
|
||||
BOOST_TEST(
|
||||
x.find(0) != x.end() && x.find(0)->second == overloaded_constructor());
|
||||
x.emplace();
|
||||
BOOST_TEST(x.find(0) != x.end() &&
|
||||
x.find(0)->second == overloaded_constructor());
|
||||
#endif
|
||||
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(
|
||||
x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3));
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(x.find(2) != x.end() &&
|
||||
x.find(2)->second == overloaded_constructor(3));
|
||||
|
||||
x.try_emplace(5);
|
||||
BOOST_TEST(
|
||||
x.find(5) != x.end() && x.find(5)->second == overloaded_constructor());
|
||||
x.try_emplace(5);
|
||||
BOOST_TEST(x.find(5) != x.end() &&
|
||||
x.find(5)->second == overloaded_constructor());
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
|
||||
x.emplace();
|
||||
BOOST_TEST(x.find(0) != x.end() &&
|
||||
x.find(0)->second == overloaded_constructor());
|
||||
#endif
|
||||
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(x.find(2) != x.end() &&
|
||||
x.find(2)->second == overloaded_constructor(3));
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(set_emplace_test)
|
||||
@ -1098,48 +1120,92 @@ struct convertible_to_piecewise
|
||||
|
||||
UNORDERED_AUTO_TEST(map_emplace_test2)
|
||||
{
|
||||
boost::unordered_map<overloaded_constructor, overloaded_constructor> x;
|
||||
// Emulating piecewise construction with boost::tuple bypasses the
|
||||
// allocator's construct method, but still uses test destroy method.
|
||||
test::detail::disable_construction_tracking _scoped;
|
||||
|
||||
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(),
|
||||
boost::make_tuple());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second == overloaded_constructor());
|
||||
{
|
||||
boost::unordered_map<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
x.emplace(
|
||||
convertible_to_piecewise(), boost::make_tuple(1), boost::make_tuple());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second == overloaded_constructor());
|
||||
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(),
|
||||
boost::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3),
|
||||
boost::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
x.emplace(convertible_to_piecewise(), boost::make_tuple(1),
|
||||
boost::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3),
|
||||
boost::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
|
||||
x.clear();
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
|
||||
x.try_emplace(overloaded_constructor());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second == overloaded_constructor());
|
||||
x.clear();
|
||||
|
||||
x.try_emplace(1);
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second == overloaded_constructor());
|
||||
x.try_emplace(overloaded_constructor());
|
||||
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6);
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
x.try_emplace(1);
|
||||
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6);
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap<overloaded_constructor,
|
||||
overloaded_constructor, boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(),
|
||||
boost::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(convertible_to_piecewise(), boost::make_tuple(1),
|
||||
boost::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3),
|
||||
boost::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(set_emplace_test2)
|
||||
@ -1158,9 +1224,115 @@ UNORDERED_AUTO_TEST(set_emplace_test2)
|
||||
boost::make_tuple(2, 3));
|
||||
check =
|
||||
std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));
|
||||
;
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
}
|
||||
|
||||
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
|
||||
|
||||
UNORDERED_AUTO_TEST(map_std_emplace_test2)
|
||||
{
|
||||
{
|
||||
boost::unordered_map<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
x.emplace(
|
||||
std::piecewise_construct, std::make_tuple(), std::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(
|
||||
convertible_to_piecewise(), std::make_tuple(1), std::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(piecewise_rvalue(), std::make_tuple(2, 3),
|
||||
std::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(d, std::make_tuple(9, 3, 1), std::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
|
||||
x.clear();
|
||||
|
||||
x.try_emplace(overloaded_constructor());
|
||||
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.try_emplace(1);
|
||||
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6);
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
}
|
||||
{
|
||||
boost::unordered_multimap<overloaded_constructor,
|
||||
overloaded_constructor, boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
x.emplace(
|
||||
std::piecewise_construct, std::make_tuple(), std::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(
|
||||
convertible_to_piecewise(), std::make_tuple(1), std::make_tuple());
|
||||
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second ==
|
||||
overloaded_constructor());
|
||||
|
||||
x.emplace(piecewise_rvalue(), std::make_tuple(2, 3),
|
||||
std::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(d, std::make_tuple(9, 3, 1), std::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(set_std_emplace_test2)
|
||||
{
|
||||
boost::unordered_set<
|
||||
std::pair<overloaded_constructor, overloaded_constructor> >
|
||||
x;
|
||||
std::pair<overloaded_constructor, overloaded_constructor> check;
|
||||
|
||||
x.emplace(std::piecewise_construct, std::make_tuple(), std::make_tuple());
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
|
||||
x.clear();
|
||||
x.emplace(
|
||||
std::piecewise_construct, std::make_tuple(1), std::make_tuple(2, 3));
|
||||
check =
|
||||
std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
Reference in New Issue
Block a user