Compare commits

...

11 Commits

Author SHA1 Message Date
bea92e8842 Merge unordered and hash from trunk.
- Only use Visual C++ pragma with appropriate compilers.
- Working link for Thomas Wang's hash function.
- Updated unordered rationale.
- Fix `unnecessary_copy_tests` for Visual C++ 12.
- Some extra insert tests.


[SVN r86728]
2013-11-16 20:36:27 +00:00
6ca8d5e0d9 Merge Visual C++ 12 fix for Unordered.
[SVN r86551]
2013-11-03 19:20:09 +00:00
9b9a1d21a6 Merge release notes + float hash fix. Ref #8822.
[SVN r86210]
2013-10-08 21:26:30 +00:00
a7c0ddb5b3 Merge unordered to release. Fixes #8851, #8874
Avoid some warnings, and move detail functions into a sub-namespace to avoid
exposing them via. ADL.


[SVN r85388]
2013-08-18 09:44:14 +00:00
c88126e1d2 Merge unordered from trunk.
Add `BOOST_NOEXPECT` to:

- Move constructors (when appropriate)
- Destructors
- Iterators

Also, fix some misleading documentation about the containers' move support.


[SVN r85048]
2013-07-15 21:32:45 +00:00
0c7c7cc6ad Merge some change log entries to release.
[SVN r84497]
2013-05-25 15:53:49 +00:00
bd10a8b5aa Merge initial unordered use of noexcept + friends.
Still more to come, hopefully in time for the release.


[SVN r84304]
2013-05-16 22:15:42 +00:00
0221f1a9bd Unordered: Merge assign fix.
[SVN r82651]
2013-01-27 23:10:29 +00:00
34b69e67ee Unordered: Merge test tweaks + inspect fixes from trunk.
[SVN r81922]
2012-12-13 22:39:44 +00:00
654fed166a Unordered: Remove and update various deprecated things.
[SVN r81727]
2012-12-05 22:06:57 +00:00
981f1e2acb Unordered: Merge code clean up.
[SVN r81358]
2012-11-15 13:43:37 +00:00
33 changed files with 937 additions and 1177 deletions

View File

@ -220,4 +220,24 @@ C++11 support has resulted in some breaking changes:
for C++11 allocators.
* Simplified the implementation a bit. Hopefully more robust.
[h2 Boost 1.53.0]
* Remove support for the old pre-standard variadic pair constructors, and
equality implementation. Both have been deprecated since Boost 1.48.
* Remove use of deprecated config macros.
* More internal implementation changes, including a much simpler
implementation of `erase`.
[h2 Boost 1.54.0]
* Mark methods specified in standard as `noexpect`. More to come in the next
release.
* If the hash function and equality predicate are known to both have nothrow
move assignment or construction then use them.
[h2 Boost 1.55.0]
* Avoid some warnings ([ticket 8851], [ticket 8874]).
* Avoid exposing some detail functions via. ADL on the iterators.
[endsect]

View File

@ -8,11 +8,12 @@
Support for move semantics is implemented using Boost.Move. If rvalue
references are available it will use them, but if not it uses a close,
but imperfect emulation. On such compilers you'll need to use Boost.Move
to take advantage of using movable container elements, also note that:
but imperfect emulation. On such compilers:
* Non-copyable objects can be stored in the containers, but without support
for rvalue references the container will not be movable.
* Non-copyable objects can be stored in the containers.
They can be constructed in place using `emplace`, or if they support
Boost.Move, moved into place.
* The containers themselves are not movable.
* Argument forwarding is not perfect.
[endsect]

View File

@ -3,7 +3,7 @@
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[def __wang__
[@http://www.concentric.net/~Ttwang/tech/inthash.htm
[@http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm
Thomas Wang's article on integer hash functions]]
[section:rationale Implementation Rationale]
@ -85,7 +85,8 @@ of 2.
Using a prime number of buckets, and choosing a bucket by using the modulus
of the hash function's result will usually give a good result. The downside
is that the required modulus operation is fairly expensive.
is that the required modulus operation is fairly expensive. This is what the
containers do in most cases.
Using a power of 2 allows for much quicker selection of the bucket
to use, but at the expense of loosing the upper bits of the hash value.
@ -95,12 +96,16 @@ functions this can't be relied on.
To avoid this a transformation could be applied to the hash function, for an
example see __wang__. Unfortunately, a transformation like Wang's requires
knowledge of the number of bits in the hash value, so it isn't portable enough.
This leaves more expensive methods, such as Knuth's Multiplicative Method
(mentioned in Wang's article). These don't tend to work as well as taking the
modulus of a prime, and the extra computation required might negate
efficiency advantage of power of 2 hash tables.
knowledge of the number of bits in the hash value, so it isn't portable enough
to use as a default. It can applicable in certain cases so the containers
have a policy based implementation that can use this alternative technique.
So, this implementation uses a prime number for the hash table size.
Currently this is only done on 64 bit architecures, where prime number
modulus can be expensive. Although this varies depending on the architecture,
so I probably should revisit it.
I'm also thinking of introducing a mechanism whereby a hash function can
indicate that it's safe to be used directly with power of 2 buckets, in
which case a faster plain power of 2 implementation can be used.
[endsect]

View File

@ -449,10 +449,6 @@ EOL;
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="emplace_hint">
@ -499,10 +495,6 @@ EOL;
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="insert">
@ -1114,9 +1106,7 @@ EOL;
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -1157,9 +1147,7 @@ EOL;
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>

View File

@ -383,10 +383,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="emplace_hint">
@ -426,10 +422,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="insert">
@ -970,9 +962,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -1005,9 +995,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -1429,10 +1417,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="emplace_hint">
@ -1472,10 +1456,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="insert">
@ -2014,9 +1994,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -2049,9 +2027,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -2488,10 +2464,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="emplace_hint">
@ -2531,10 +2503,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="insert">
@ -3108,9 +3076,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -3145,9 +3111,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -3581,10 +3545,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="emplace_hint">
@ -3624,10 +3584,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>Since existing <code>std::pair</code> implementations don't support
<code>std::piecewise_construct</code> this emulates it,
but using <code>boost::unordered::piecewise_construct</code>.</para>
<para>In version of Boost before 1.48 this emulated the variadic pair
constructor from older C++0x drafts. For backwards compatability
this can be enabled by defining the macro
<code>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT</code>.</para>
</notes>
</method>
<method name="insert">
@ -4168,9 +4124,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>
@ -4205,9 +4159,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</description>
<notes>
<para>The behavior of this function was changed to match
the C++11 standard in Boost 1.48. If you wish to use
the old behaviour, define the macro
<code>BOOST_UNORDERED_DEPRECATED_EQUALITY</code>.</para>
the C++11 standard in Boost 1.48.</para>
<para>Behavior is undefined if the two containers don't have
equivalent equality predicates.</para>
</notes>

View File

@ -85,7 +85,7 @@ namespace boost { namespace unordered { namespace detail {
// Either forwarding variadic arguments, or storing the arguments in
// emplace_args##n
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
@ -136,7 +136,7 @@ namespace boost { namespace unordered { namespace detail {
#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
#if defined(BOOST_NO_RVALUE_REFERENCES)
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
@ -234,9 +234,11 @@ namespace boost { namespace unordered { namespace detail {
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
template <class T>
inline void destroy(T* x) {
x->~T();
namespace func {
template <class T>
inline void destroy(T* x) {
x->~T();
}
}
#if defined(BOOST_MSVC)
@ -257,13 +259,12 @@ namespace boost { namespace unordered { namespace detail {
template <typename T, unsigned int> struct expr_test;
template <typename T> struct expr_test<T, sizeof(char)> : T {};
template <typename U> static char for_expr_test(U const&);
# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \
template <typename U> \
static typename boost::unordered::detail::expr_test< \
BOOST_PP_CAT(choice, result), \
sizeof(boost::unordered::detail::for_expr_test(( \
sizeof(for_expr_test(( \
(expression), \
0)))>::type test( \
BOOST_PP_CAT(choice, count))
@ -276,6 +277,7 @@ namespace boost { namespace unordered { namespace detail {
# define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \
struct BOOST_PP_CAT(has_, name) \
{ \
template <typename U> static char for_expr_test(U const&); \
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \
boost::unordered::detail::make< thing >().name args); \
BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \
@ -342,7 +344,7 @@ namespace boost { namespace unordered { namespace detail {
# include <boost/type_traits/is_same.hpp>
# endif
# if !defined(BOOST_NO_VARIADIC_TEMPLATES) && \
# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
!defined(BOOST_NO_SFINAE_EXPR)
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
# else
@ -432,7 +434,7 @@ namespace boost { namespace unordered { namespace detail {
max_size, U const, (), 0
);
# if !defined(BOOST_NO_VARIADIC_TEMPLATES)
# if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename T, typename ValueType, typename... Args>
BOOST_UNORDERED_HAS_FUNCTION(
@ -473,6 +475,9 @@ namespace boost { namespace unordered { namespace detail {
# endif
namespace func
{
template <typename Alloc>
inline Alloc call_select_on_container_copy_construction(const Alloc& rhs,
typename boost::enable_if_c<
@ -510,6 +515,8 @@ namespace boost { namespace unordered { namespace detail {
return (std::numeric_limits<SizeType>::max)();
}
} // namespace func.
template <typename Alloc>
struct allocator_traits
{
@ -589,7 +596,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
destroy(Alloc&, T* p)
{
boost::unordered::detail::destroy(p);
boost::unordered::detail::func::destroy(p);
}
# elif !defined(BOOST_NO_SFINAE_EXPR)
@ -623,7 +630,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
destroy(Alloc&, T* p)
{
boost::unordered::detail::destroy(p);
boost::unordered::detail::func::destroy(p);
}
# else
@ -669,21 +676,22 @@ namespace boost { namespace unordered { namespace detail {
boost::is_same<T, value_type>::value,
void*>::type = 0)
{
boost::unordered::detail::destroy(p);
boost::unordered::detail::func::destroy(p);
}
# endif
static size_type max_size(const Alloc& a)
{
return boost::unordered::detail::call_max_size<size_type>(a);
return boost::unordered::detail::func::
call_max_size<size_type>(a);
}
// Allocator propagation on construction
static Alloc select_on_container_copy_construction(Alloc const& rhs)
{
return boost::unordered::detail::
return boost::unordered::detail::func::
call_select_on_container_copy_construction(rhs);
}
@ -758,12 +766,12 @@ namespace boost { namespace unordered { namespace detail {
#endif
namespace boost { namespace unordered { namespace detail {
namespace boost { namespace unordered { namespace detail { namespace func {
////////////////////////////////////////////////////////////////////////////
// call_construct
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
@ -792,7 +800,7 @@ namespace boost { namespace unordered { namespace detail {
template <typename Alloc, typename T>
inline void destroy_value_impl(Alloc&, T* x) {
boost::unordered::detail::destroy(x);
boost::unordered::detail::func::destroy(x);
}
@ -802,7 +810,7 @@ namespace boost { namespace unordered { namespace detail {
template <typename Alloc, typename T>
inline void destroy_value_impl(Alloc&, T* x) {
boost::unordered::detail::destroy(x);
boost::unordered::detail::func::destroy(x);
}
#endif
@ -812,13 +820,13 @@ namespace boost { namespace unordered { namespace detail {
//
// Used for piecewise construction.
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
template<typename Alloc, typename T> \
void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \
{ \
boost::unordered::detail::call_construct(alloc, ptr); \
boost::unordered::detail::func::call_construct(alloc, ptr); \
} \
\
BOOST_PP_REPEAT_FROM_TO(1, n, \
@ -830,7 +838,7 @@ namespace boost { namespace unordered { namespace detail {
void construct_from_tuple(Alloc& alloc, T* ptr, \
namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
{ \
boost::unordered::detail::call_construct(alloc, ptr, \
boost::unordered::detail::func::call_construct(alloc, ptr, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \
); \
}
@ -921,146 +929,58 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
#endif
////////////////////////////////////////////////////////////////////////////
// SFINAE traits for construction.
// Trait to check for piecewise construction.
// Decide which construction method to use for a three argument
// call. Note that this is difficult to do using overloads because
// the arguments are packed into 'emplace_args3'.
//
// The decision is made on the first argument.
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename A, typename B, typename A0>
struct emulation1 {
static choice1::type test(choice1, std::pair<A, B> const&);
static choice2::type test(choice2, A const&);
static choice3::type test(choice3, convert_from_anything const&);
enum { value =
sizeof(test(choose(), boost::unordered::detail::make<A0>())) ==
sizeof(choice2::type) };
};
#endif
template <typename A, typename B, typename A0>
struct check3_base {
template <typename A0>
struct use_piecewise {
static choice1::type test(choice1,
boost::unordered::piecewise_construct_t);
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
static choice2::type test(choice2, A const&);
#endif
static choice2::type test(choice2, ...);
static choice3::type test(choice3, ...);
enum { value =
enum { value = sizeof(choice1::type) ==
sizeof(test(choose(), boost::unordered::detail::make<A0>())) };
};
template <typename A, typename B, typename A0>
struct piecewise3 {
enum { value = check3_base<A,B,A0>::value == sizeof(choice1::type) };
};
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename A, typename B, typename A0>
struct emulation3 {
enum { value = check3_base<A,B,A0>::value == sizeof(choice2::type) };
};
#endif
// TODO: Full construct?
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
////////////////////////////////////////////////////////////////////////////
// Construct from variadic parameters
// For the standard pair constructor.
template <typename Alloc, typename T, typename... Args>
inline void construct_value_impl(Alloc& alloc, T* address,
BOOST_FWD_REF(Args)... args)
{
boost::unordered::detail::call_construct(alloc,
boost::unordered::detail::func::call_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.
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2>
inline typename enable_if<piecewise3<A, B, A0>, void>::type
inline typename enable_if<use_piecewise<A0>, void>::type
construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
{
boost::unordered::detail::construct_from_tuple(alloc,
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->first), boost::forward<A1>(a1));
boost::unordered::detail::construct_from_tuple(alloc,
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->second), boost::forward<A2>(a2));
}
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
template <typename Alloc, typename A, typename B, typename A0>
inline typename enable_if<emulation1<A, B, A0>, void>::type
construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
BOOST_FWD_REF(A0) a0)
{
boost::unordered::detail::call_construct(alloc,
boost::addressof(address->first),boost::forward<A0>(a0));
boost::unordered::detail::call_construct(alloc,
boost::addressof(address->second));
}
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2>
inline typename enable_if<emulation3<A, B, A0>, void>::type
construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
{
boost::unordered::detail::call_construct(alloc,
boost::addressof(address->first),boost::forward<A0>(a0));
boost::unordered::detail::call_construct(alloc,
boost::addressof(address->second),
boost::forward<A1>(a1),
boost::forward<A2>(a2));
}
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2, typename A3,
typename... Args>
inline void construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2,
BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(Args)... args)
{
boost::unordered::detail::call_construct(alloc,
boost::addressof(address->first),boost::forward<A0>(a0));
boost::unordered::detail::call_construct(alloc,
boost::addressof(address->second),
boost::forward<A1>(a1),
boost::forward<A2>(a2),
boost::forward<A3>(a3),
boost::forward<Args>(args)...);
}
#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
#else // BOOST_NO_VARIADIC_TEMPLATES
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
////////////////////////////////////////////////////////////////////////////////
// Construct from emplace_args
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
template < \
typename Alloc, typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
> \
inline void construct_value_impl(Alloc&, T* address, \
boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
> const& args) \
{ \
new((void*) address) T( \
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \
args.a)); \
}
// Explicitly write out first three overloads for the sake of sane
// error messages.
template <typename Alloc, typename T, typename A0>
inline void construct_value_impl(Alloc&, T* address,
@ -1090,82 +1010,45 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
);
}
// Use a macro for the rest.
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
template < \
typename Alloc, typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
> \
inline void construct_value_impl(Alloc&, T* address, \
boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
> const& args) \
{ \
new((void*) 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, _)
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
// Construct with piece_construct
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2>
inline void construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
boost::unordered::detail::emplace_args3<A0, A1, A2> const& args,
typename enable_if<piecewise3<A, B, A0>, void*>::type = 0)
typename enable_if<use_piecewise<A0>, void*>::type = 0)
{
boost::unordered::detail::construct_from_tuple(alloc,
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->first), args.a1);
boost::unordered::detail::construct_from_tuple(alloc,
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->second), args.a2);
}
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
template <typename Alloc, typename A, typename B, typename A0>
inline void construct_value_impl(Alloc&, std::pair<A, B>* address,
boost::unordered::detail::emplace_args1<A0> const& args,
typename enable_if<emulation1<A, B, A0>, void*>::type = 0)
{
new((void*) boost::addressof(address->first)) A(
boost::forward<A0>(args.a0));
new((void*) boost::addressof(address->second)) B();
}
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2>
inline void construct_value_impl(Alloc&, std::pair<A, B>* address,
boost::unordered::detail::emplace_args3<A0, A1, A2> const& args,
typename enable_if<emulation3<A, B, A0>, void*>::type = 0)
{
new((void*) boost::addressof(address->first)) A(
boost::forward<A0>(args.a0));
new((void*) boost::addressof(address->second)) B(
boost::forward<A1>(args.a1),
boost::forward<A2>(args.a2));
}
#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \
template <typename Alloc, typename A, typename B, \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
> \
inline void construct_value_impl(Alloc&, std::pair<A, B>* address, \
boost::unordered::detail::BOOST_PP_CAT(emplace_args, num_params) < \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
> const& args) \
{ \
new((void*) boost::addressof(address->first)) A( \
boost::forward<A0>(args.a0)); \
new((void*) boost::addressof(address->second)) B( \
BOOST_PP_ENUM_##z(BOOST_PP_DEC(num_params), \
BOOST_UNORDERED_CALL_FORWARD2, args.a)); \
}
#define BOOST_UNORDERED_CALL_FORWARD2(z, i, a) \
BOOST_UNORDERED_CALL_FORWARD(z, BOOST_PP_INC(i), a)
BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(1, 2, _)
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _)
#undef BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL
#undef BOOST_UNORDERED_CALL_FORWARD2
#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
#endif // BOOST_NO_VARIADIC_TEMPLATES
}}}
////////////////////////////////////////////////////////////////////////////////
//
// Some helper functions for allocating & constructing
}}}}
namespace boost { namespace unordered { namespace detail {

View File

@ -15,6 +15,8 @@
#include <boost/unordered/detail/allocate.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
#include <boost/swap.hpp>
#include <boost/assert.hpp>
#include <boost/limits.hpp>
@ -30,6 +32,10 @@ namespace boost { namespace unordered { namespace detail {
}}}
// The 'iterator_detail' namespace was a misguided attempt at avoiding ADL
// in the detail namespace. It didn't work because the template parameters
// were in detail. I'm not changing it at the moment to be safe. I might
// do in the future if I change the iterator types.
namespace boost { namespace unordered { namespace iterator_detail {
////////////////////////////////////////////////////////////////////////////
@ -37,49 +43,50 @@ namespace boost { namespace unordered { namespace iterator_detail {
//
// all no throw
template <typename NodePointer, typename Value> struct iterator;
template <typename ConstNodePointer, typename NodePointer,
typename Value> struct c_iterator;
template <typename NodePointer, typename Value, typename Policy>
struct l_iterator;
template <typename ConstNodePointer, typename NodePointer,
typename Value, typename Policy> struct cl_iterator;
template <typename Node> struct iterator;
template <typename Node, typename ConstNodePointer> struct c_iterator;
template <typename Node, typename Policy> struct l_iterator;
template <typename Node, typename ConstNodePointer, typename Policy>
struct cl_iterator;
// Local Iterators
//
// all no throw
template <typename NodePointer, typename Value, typename Policy>
template <typename Node, typename Policy>
struct l_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
NodePointer, Value&>
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
typename Node::node_pointer,
typename Node::value_type&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename ConstNodePointer, typename NodePointer2,
typename Value2, typename Policy2>
template <typename Node2, typename ConstNodePointer, typename Policy2>
friend struct boost::unordered::iterator_detail::cl_iterator;
private:
#endif
typedef NodePointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<NodePointer, Value>
iterator;
typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> iterator;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
public:
l_iterator() : ptr_() {}
typedef typename Node::value_type value_type;
l_iterator(iterator x, std::size_t b, std::size_t c)
l_iterator() BOOST_NOEXCEPT : ptr_() {}
l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT
: ptr_(x.node_), bucket_(b), bucket_count_(c) {}
Value& operator*() const {
value_type& operator*() const {
return ptr_->value();
}
Value* operator->() const {
value_type* operator->() const {
return ptr_->value_ptr();
}
@ -97,51 +104,53 @@ namespace boost { namespace unordered { namespace iterator_detail {
return tmp;
}
bool operator==(l_iterator x) const {
bool operator==(l_iterator x) const BOOST_NOEXCEPT {
return ptr_ == x.ptr_;
}
bool operator!=(l_iterator x) const {
bool operator!=(l_iterator x) const BOOST_NOEXCEPT {
return ptr_ != x.ptr_;
}
};
template <typename ConstNodePointer, typename NodePointer, typename Value,
typename Policy>
template <typename Node, typename ConstNodePointer, typename Policy>
struct cl_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
ConstNodePointer, Value const&>
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
ConstNodePointer,
typename Node::value_type const&>
{
friend struct boost::unordered::iterator_detail::l_iterator
<NodePointer, Value, Policy>;
<Node, Policy>;
private:
typedef NodePointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<NodePointer, Value>
iterator;
typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> iterator;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
public:
cl_iterator() : ptr_() {}
typedef typename Node::value_type value_type;
cl_iterator(iterator x, std::size_t b, std::size_t c) :
cl_iterator() BOOST_NOEXCEPT : ptr_() {}
cl_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT :
ptr_(x.node_), bucket_(b), bucket_count_(c) {}
cl_iterator(boost::unordered::iterator_detail::l_iterator<
NodePointer, Value, Policy> const& x) :
Node, Policy> const& x) BOOST_NOEXCEPT :
ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
{}
Value const&
operator*() const {
value_type const& operator*() const {
return ptr_->value();
}
Value const* operator->() const {
value_type const* operator->() const {
return ptr_->value_ptr();
}
@ -159,27 +168,34 @@ namespace boost { namespace unordered { namespace iterator_detail {
return tmp;
}
friend bool operator==(cl_iterator const& x, cl_iterator const& y) {
friend bool operator==(cl_iterator const& x, cl_iterator const& y)
BOOST_NOEXCEPT
{
return x.ptr_ == y.ptr_;
}
friend bool operator!=(cl_iterator const& x, cl_iterator const& y) {
friend bool operator!=(cl_iterator const& x, cl_iterator const& y)
BOOST_NOEXCEPT
{
return x.ptr_ != y.ptr_;
}
};
template <typename NodePointer, typename Value>
template <typename Node>
struct iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
NodePointer, Value&>
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
typename Node::node_pointer,
typename Node::value_type&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename, typename, typename>
template <typename, typename>
friend struct boost::unordered::iterator_detail::c_iterator;
template <typename, typename, typename>
template <typename, typename>
friend struct boost::unordered::iterator_detail::l_iterator;
template <typename, typename, typename, typename>
template <typename, typename, typename>
friend struct boost::unordered::iterator_detail::cl_iterator;
template <typename>
friend struct boost::unordered::detail::table;
@ -189,20 +205,23 @@ namespace boost { namespace unordered { namespace iterator_detail {
friend struct boost::unordered::detail::grouped_table_impl;
private:
#endif
typedef NodePointer node_pointer;
typedef typename Node::node_pointer node_pointer;
node_pointer node_;
public:
iterator() : node_() {}
typedef typename Node::value_type value_type;
explicit iterator(node_pointer const& x) : node_(x) {}
iterator() BOOST_NOEXCEPT : node_() {}
Value& operator*() const {
explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
node_(static_cast<node_pointer>(x)) {}
value_type& operator*() const {
return node_->value();
}
Value* operator->() const {
value_type* operator->() const {
return &node_->value();
}
@ -217,23 +236,25 @@ namespace boost { namespace unordered { namespace iterator_detail {
return tmp;
}
bool operator==(iterator const& x) const {
bool operator==(iterator const& x) const BOOST_NOEXCEPT {
return node_ == x.node_;
}
bool operator!=(iterator const& x) const {
bool operator!=(iterator const& x) const BOOST_NOEXCEPT {
return node_ != x.node_;
}
};
template <typename ConstNodePointer, typename NodePointer, typename Value>
template <typename Node, typename ConstNodePointer>
struct c_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
ConstNodePointer, Value const&>
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
ConstNodePointer,
typename Node::value_type const&>
{
friend struct boost::unordered::iterator_detail::iterator<
NodePointer, Value>;
friend struct boost::unordered::iterator_detail::iterator<Node>;
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename>
@ -245,26 +266,26 @@ namespace boost { namespace unordered { namespace iterator_detail {
private:
#endif
typedef NodePointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<NodePointer, Value>
iterator;
typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> iterator;
node_pointer node_;
public:
c_iterator() : node_() {}
typedef typename Node::value_type value_type;
explicit c_iterator(node_pointer const& x) : node_(x) {}
c_iterator() BOOST_NOEXCEPT : node_() {}
c_iterator(boost::unordered::iterator_detail::iterator<
NodePointer, Value> const& x) : node_(x.node_) {}
explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
node_(static_cast<node_pointer>(x)) {}
Value const& operator*() const {
c_iterator(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {}
value_type const& operator*() const {
return node_->value();
}
Value const* operator->() const {
value_type const* operator->() const {
return &node_->value();
}
@ -279,11 +300,15 @@ namespace boost { namespace unordered { namespace iterator_detail {
return tmp;
}
friend bool operator==(c_iterator const& x, c_iterator const& y) {
friend bool operator==(c_iterator const& x, c_iterator const& y)
BOOST_NOEXCEPT
{
return x.node_ == y.node_;
}
friend bool operator!=(c_iterator const& x, c_iterator const& y) {
friend bool operator!=(c_iterator const& x, c_iterator const& y)
BOOST_NOEXCEPT
{
return x.node_ != y.node_;
}
};
@ -310,9 +335,6 @@ namespace boost { namespace unordered { namespace detail {
protected:
node_allocator& alloc_;
private:
node_pointer node_;
bool node_constructed_;
bool value_constructed_;
@ -335,7 +357,7 @@ namespace boost { namespace unordered { namespace detail {
void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS)
{
construct();
boost::unordered::detail::construct_value_impl(
boost::unordered::detail::func::construct_value_impl(
alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
value_constructed_ = true;
}
@ -344,7 +366,7 @@ namespace boost { namespace unordered { namespace detail {
void construct_with_value2(BOOST_FWD_REF(A0) a0)
{
construct();
boost::unordered::detail::construct_value_impl(
boost::unordered::detail::func::construct_value_impl(
alloc_, node_->value_ptr(),
BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward<A0>(a0)));
value_constructed_ = true;
@ -374,7 +396,7 @@ namespace boost { namespace unordered { namespace detail {
{
if (node_) {
if (value_constructed_) {
boost::unordered::detail::destroy_value_impl(alloc_,
boost::unordered::detail::func::destroy_value_impl(alloc_,
node_->value_ptr());
}
@ -398,7 +420,7 @@ namespace boost { namespace unordered { namespace detail {
node_allocator_traits::construct(alloc_,
boost::addressof(*node_), node());
node_->init(static_cast<typename node::link_pointer>(node_));
node_->init(node_);
node_constructed_ = true;
}
else {
@ -406,7 +428,7 @@ namespace boost { namespace unordered { namespace detail {
if (value_constructed_)
{
boost::unordered::detail::destroy_value_impl(alloc_,
boost::unordered::detail::func::destroy_value_impl(alloc_,
node_->value_ptr());
value_constructed_ = false;
}
@ -432,8 +454,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename node_allocator_traits::pointer node_pointer;
typedef typename node::value_type value_type;
typedef typename node::link_pointer link_pointer;
typedef boost::unordered::iterator_detail::
iterator<node_pointer, value_type> iterator;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
node_pointer nodes_;
@ -445,7 +466,7 @@ namespace boost { namespace unordered { namespace detail {
nodes_()
{
if (b.size_) {
typename Table::previous_pointer prev = b.get_previous_start();
typename Table::link_pointer prev = b.get_previous_start();
nodes_ = static_cast<node_pointer>(prev->next_);
prev->next_ = link_pointer();
b.size_ = 0;
@ -454,60 +475,61 @@ namespace boost { namespace unordered { namespace detail {
~node_holder();
void node_for_assignment()
{
if (!this->node_ && nodes_) {
this->node_ = nodes_;
nodes_ = static_cast<node_pointer>(nodes_->next_);
this->node_->init(this->node_);
this->node_->next_ = link_pointer();
this->node_constructed_ = true;
this->value_constructed_ = true;
}
}
template <typename T>
inline void assign_impl(T const& v) {
nodes_->value() = v;
if (this->node_ && this->value_constructed_) {
this->node_->value() = v;
}
else {
this->construct_with_value2(v);
}
}
template <typename T1, typename T2>
inline void assign_impl(std::pair<T1 const, T2> const& v) {
const_cast<T1&>(nodes_->value().first) = v.first;
nodes_->value().second = v.second;
this->construct_with_value2(v);
}
template <typename T>
inline void move_assign_impl(T& v) {
nodes_->value() = boost::move(v);
if (this->node_ && this->value_constructed_) {
this->node_->value() = boost::move(v);
}
else {
this->construct_with_value2(boost::move(v));
}
}
template <typename T1, typename T2>
inline void move_assign_impl(std::pair<T1 const, T2>& v) {
// TODO: Move key as well?
const_cast<T1&>(nodes_->value().first) =
boost::move(const_cast<T1&>(v.first));
nodes_->value().second = boost::move(v.second);
this->construct_with_value2(boost::move(v));
}
node_pointer copy_of(value_type const& v)
{
if (nodes_) {
assign_impl(v);
node_pointer p = nodes_;
nodes_ = static_cast<node_pointer>(p->next_);
p->init(static_cast<typename node::link_pointer>(p));
p->next_ = link_pointer();
return p;
}
else {
this->construct_with_value2(v);
return base::release();
}
node_for_assignment();
assign_impl(v);
return base::release();
}
node_pointer move_copy_of(value_type& v)
{
if (nodes_) {
move_assign_impl(v);
node_pointer p = nodes_;
nodes_ = static_cast<node_pointer>(p->next_);
p->init(static_cast<typename node::link_pointer>(p));
p->next_ = link_pointer();
return p;
}
else {
this->construct_with_value2(boost::move(v));
return base::release();
}
node_for_assignment();
move_assign_impl(v);
return base::release();
}
iterator begin() const
@ -523,7 +545,7 @@ namespace boost { namespace unordered { namespace detail {
node_pointer p = nodes_;
nodes_ = static_cast<node_pointer>(p->next_);
boost::unordered::detail::destroy_value_impl(this->alloc_,
boost::unordered::detail::func::destroy_value_impl(this->alloc_,
p->value_ptr());
node_allocator_traits::destroy(this->alloc_, boost::addressof(*p));
node_allocator_traits::deallocate(this->alloc_, p, 1);
@ -537,12 +559,12 @@ namespace boost { namespace unordered { namespace detail {
template <typename NodePointer>
struct bucket
{
typedef NodePointer previous_pointer;
previous_pointer next_;
typedef NodePointer link_pointer;
link_pointer next_;
bucket() : next_() {}
previous_pointer first_from_start()
link_pointer first_from_start()
{
return next_;
}
@ -552,12 +574,12 @@ namespace boost { namespace unordered { namespace detail {
struct ptr_bucket
{
typedef ptr_bucket* previous_pointer;
previous_pointer next_;
typedef ptr_bucket* link_pointer;
link_pointer next_;
ptr_bucket() : next_(0) {}
previous_pointer first_from_start()
link_pointer first_from_start()
{
return this;
}
@ -568,8 +590,6 @@ namespace boost { namespace unordered { namespace detail {
///////////////////////////////////////////////////////////////////
//
// Hash Policy
//
// Don't really want table to derive from this, but will for now.
template <typename SizeT>
struct prime_policy
@ -664,12 +684,23 @@ namespace boost { namespace unordered { namespace detail {
// atomically assigns the new function objects in a strongly
// exception safe manner.
template <class H, class P> class set_hash_functions;
template <class H, class P, bool NoThrowMoveAssign>
class set_hash_functions;
template <class H, class P>
class functions
{
friend class boost::unordered::detail::set_hash_functions<H, P>;
public:
static const bool nothrow_move_assignable =
boost::is_nothrow_move_assignable<H>::value &&
boost::is_nothrow_move_assignable<P>::value;
static const bool nothrow_move_constructible =
boost::is_nothrow_move_constructible<H>::value &&
boost::is_nothrow_move_constructible<P>::value;
private:
friend class boost::unordered::detail::set_hash_functions<H, P,
nothrow_move_assignable>;
functions& operator=(functions const&);
typedef compressed<H, P> function_pair;
@ -686,23 +717,40 @@ namespace boost { namespace unordered { namespace detail {
static_cast<void const*>(&funcs_[current_]));
}
function_pair& current() {
return *static_cast<function_pair*>(
static_cast<void*>(&funcs_[current_]));
}
void construct(bool which, H const& hf, P const& eq)
{
new((void*) &funcs_[which]) function_pair(hf, eq);
}
void construct(bool which, function_pair const& f)
void construct(bool which, function_pair const& f,
boost::unordered::detail::false_type =
boost::unordered::detail::false_type())
{
new((void*) &funcs_[which]) function_pair(f);
}
void construct(bool which, function_pair& f,
boost::unordered::detail::true_type)
{
new((void*) &funcs_[which]) function_pair(f,
boost::unordered::detail::move_tag());
}
void destroy(bool which)
{
boost::unordered::detail::destroy((function_pair*)(&funcs_[which]));
boost::unordered::detail::func::destroy((function_pair*)(&funcs_[which]));
}
public:
typedef boost::unordered::detail::set_hash_functions<H, P,
nothrow_move_assignable> set_hash_functions;
functions(H const& hf, P const& eq)
: current_(false)
{
@ -715,6 +763,14 @@ namespace boost { namespace unordered { namespace detail {
construct(current_, bf.current());
}
functions(functions& bf, boost::unordered::detail::move_tag)
: current_(false)
{
construct(current_, bf.current(),
boost::unordered::detail::integral_constant<bool,
nothrow_move_constructible>());
}
~functions() {
this->destroy(current_);
}
@ -727,26 +783,28 @@ namespace boost { namespace unordered { namespace detail {
return current().second();
}
};
template <class H, class P>
class set_hash_functions
class set_hash_functions<H, P, false>
{
set_hash_functions(set_hash_functions const&);
set_hash_functions& operator=(set_hash_functions const&);
typedef functions<H, P> functions_type;
functions<H,P>& functions_;
functions_type& functions_;
bool tmp_functions_;
public:
set_hash_functions(functions<H,P>& f, H const& h, P const& p)
set_hash_functions(functions_type& f, H const& h, P const& p)
: functions_(f),
tmp_functions_(!f.current_)
{
f.construct(tmp_functions_, h, p);
}
set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
set_hash_functions(functions_type& f, functions_type const& other)
: functions_(f),
tmp_functions_(!f.current_)
{
@ -765,11 +823,42 @@ namespace boost { namespace unordered { namespace detail {
}
};
template <class H, class P>
class set_hash_functions<H, P, true>
{
set_hash_functions(set_hash_functions const&);
set_hash_functions& operator=(set_hash_functions const&);
typedef functions<H, P> functions_type;
functions_type& functions_;
H hash_;
P pred_;
public:
set_hash_functions(functions_type& f, H const& h, P const& p) :
functions_(f),
hash_(h),
pred_(p) {}
set_hash_functions(functions_type& f, functions_type const& other) :
functions_(f),
hash_(other.hash_function()),
pred_(other.key_eq()) {}
void commit()
{
functions_.current().first() = boost::move(hash_);
functions_.current().second() = boost::move(pred_);
}
};
////////////////////////////////////////////////////////////////////////////
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
// e.g. for int
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
#else
struct please_ignore_this_overload {

View File

@ -25,10 +25,13 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::value_base<T>
{
typedef typename ::boost::unordered::detail::rebind_wrap<
A, grouped_node<A, T> >::type::pointer link_pointer;
A, grouped_node<A, T> >::type allocator;
typedef typename ::boost::unordered::detail::
allocator_traits<allocator>::pointer node_pointer;
typedef node_pointer link_pointer;
link_pointer next_;
link_pointer group_prev_;
node_pointer group_prev_;
std::size_t hash_;
grouped_node() :
@ -37,7 +40,7 @@ namespace boost { namespace unordered { namespace detail {
hash_(0)
{}
void init(link_pointer self)
void init(node_pointer self)
{
group_prev_ = self;
}
@ -52,9 +55,10 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::ptr_bucket
{
typedef boost::unordered::detail::ptr_bucket bucket_base;
typedef grouped_ptr_node<T>* node_pointer;
typedef ptr_bucket* link_pointer;
link_pointer group_prev_;
node_pointer group_prev_;
std::size_t hash_;
grouped_ptr_node() :
@ -63,7 +67,7 @@ namespace boost { namespace unordered { namespace detail {
hash_(0)
{}
void init(link_pointer self)
void init(node_pointer self)
{
group_prev_ = self;
}
@ -181,7 +185,6 @@ namespace boost { namespace unordered { namespace detail {
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;
@ -234,8 +237,7 @@ namespace boost { namespace unordered { namespace detail {
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, key_hash);
std::size_t bucket_index = this->hash_to_bucket(key_hash);
iterator n = this->begin(bucket_index);
for (;;)
@ -250,13 +252,11 @@ namespace boost { namespace unordered { namespace detail {
}
else
{
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
if (this->hash_to_bucket(node_hash) != bucket_index)
return iterator();
}
n = iterator(static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_));
n = iterator(n.node_->group_prev_->next_);
}
}
@ -268,7 +268,7 @@ namespace boost { namespace unordered { namespace detail {
std::size_t x = 0;
node_pointer it = n.node_;
do {
it = static_cast<node_pointer>(it->group_prev_);
it = it->group_prev_;
++x;
} while(it != n.node_);
@ -280,10 +280,7 @@ namespace boost { namespace unordered { namespace detail {
{
iterator n = this->find_node(k);
return std::make_pair(
n, n.node_ ? iterator(
static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_
)) : n);
n, n.node_ ? iterator(n.node_->group_prev_->next_) : n);
}
// Equality
@ -296,10 +293,8 @@ namespace boost { namespace unordered { namespace detail {
{
iterator n2 = other.find_matching_node(n1);
if (!n2.node_) return false;
iterator end1(static_cast<node_pointer>(
static_cast<node_pointer>(n1.node_->group_prev_)->next_));
iterator end2(static_cast<node_pointer>(
static_cast<node_pointer>(n2.node_->group_prev_)->next_));
iterator end1(n1.node_->group_prev_->next_);
iterator end2(n2.node_->group_prev_->next_);
if (!group_equals(n1, end1, n2, end2)) return false;
n1 = end1;
}
@ -307,8 +302,6 @@ namespace boost { namespace unordered { namespace detail {
return true;
}
#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
static bool group_equals(iterator n1, iterator end1,
iterator n2, iterator end2)
{
@ -369,37 +362,16 @@ namespace boost { namespace unordered { namespace detail {
return count;
}
#else
static bool group_equals(iterator n1, iterator end1,
iterator n2, iterator end2)
{
for(;;)
{
if(!extractor::compare_mapped(*n1, *n2))
return false;
++n1;
++n2;
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
}
}
#endif
// Emplace/Insert
static inline void add_after_node(
node_pointer n,
node_pointer pos)
{
n->next_ = static_cast<node_pointer>(pos->group_prev_)->next_;
n->next_ = 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);
pos->group_prev_->next_ = n;
pos->group_prev_ = n;
}
inline iterator add_node(
@ -412,37 +384,35 @@ namespace boost { namespace unordered { namespace detail {
if (pos.node_) {
this->add_after_node(n, pos.node_);
if (n->next_) {
std::size_t next_bucket = policy::to_bucket(
this->bucket_count_,
std::size_t next_bucket = this->hash_to_bucket(
static_cast<node_pointer>(n->next_)->hash_);
if (next_bucket !=
policy::to_bucket(this->bucket_count_, key_hash)) {
if (next_bucket != this->hash_to_bucket(key_hash)) {
this->get_bucket(next_bucket)->next_ = n;
}
}
}
else {
bucket_pointer b = this->get_bucket(
policy::to_bucket(this->bucket_count_, key_hash));
this->hash_to_bucket(key_hash));
if (!b->next_)
{
previous_pointer start_node = this->get_previous_start();
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
this->get_bucket(policy::to_bucket(this->bucket_count_,
this->get_bucket(this->hash_to_bucket(
static_cast<node_pointer>(start_node->next_)->hash_
))->next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = static_cast<link_pointer>(n);
start_node->next_ = n;
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = static_cast<link_pointer>(n);
b->next_->next_ = n;
}
}
++this->size_;
@ -468,8 +438,8 @@ namespace boost { namespace unordered { namespace detail {
this->add_node(a, key_hash, this->find_node(key_hash, k));
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
# if defined(BOOST_NO_VARIADIC_TEMPLATES)
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
iterator emplace(boost::unordered::detail::emplace_args1<
boost::unordered::detail::please_ignore_this_overload> const&)
{
@ -545,11 +515,8 @@ namespace boost { namespace unordered { namespace detail {
if(!this->size_) return 0;
std::size_t key_hash = this->hash(k);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, key_hash);
bucket_pointer this_bucket = this->get_bucket(bucket_index);
previous_pointer prev = this_bucket->next_;
std::size_t bucket_index = this->hash_to_bucket(key_hash);
link_pointer prev = this->get_previous_start(bucket_index);
if (!prev) return 0;
for (;;)
@ -557,24 +524,21 @@ namespace boost { namespace unordered { namespace detail {
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
if (this->hash_to_bucket(node_hash) != bucket_index)
return 0;
if (node_hash == key_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_);
prev = 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(this_bucket, prev, end);
return this->delete_nodes(c_iterator(pos), c_iterator(end));
node_pointer first_node = static_cast<node_pointer>(prev->next_);
link_pointer end = first_node->group_prev_->next_;
std::size_t count = this->delete_nodes(prev, end);
this->fix_bucket(bucket_index, prev);
return count;
}
iterator erase(c_iterator r)
@ -582,130 +546,70 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
bucket_pointer this_bucket = this->get_bucket(
policy::to_bucket(this->bucket_count_, r.node_->hash_));
previous_pointer prev = unlink_node(*this_bucket, r.node_);
this->fix_buckets(this_bucket, prev, next.node_);
this->delete_node(r);
erase_nodes(r.node_, next.node_);
return next;
}
iterator erase_range(c_iterator r1, c_iterator r2)
{
if (r1 == r2) return iterator(r2.node_);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, r1.node_->hash_);
previous_pointer prev = unlink_nodes(
*this->get_bucket(bucket_index), r1.node_, r2.node_);
this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_);
this->delete_nodes(r1, r2);
erase_nodes(r1.node_, r2.node_);
return iterator(r2.node_);
}
static previous_pointer unlink_node(bucket& b, node_pointer n)
link_pointer erase_nodes(node_pointer begin, node_pointer end)
{
node_pointer next = static_cast<node_pointer>(n->next_);
previous_pointer prev =
static_cast<previous_pointer>(n->group_prev_);
std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
if(prev->next_ != n) {
// The node is at the beginning of a group.
// Split the groups containing 'begin' and 'end'.
// And get the pointer to the node before begin while
// we're at it.
link_pointer prev = split_groups(begin, end);
// 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_;
// If we don't have a 'prev' it means that begin is at the
// beginning of a block, so search through the blocks in the
// same bucket.
if (!prev) {
prev = this->get_previous_start(bucket_index);
while (prev->next_ != begin)
prev = static_cast<node_pointer>(prev->next_)->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)) {
// 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 {
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 = end->group_prev_;
group1->group_prev_ = end2;
end->group_prev_ = end1;
}
}
}
prev->next_ = static_cast<link_pointer>(end);
// Delete the nodes.
do {
link_pointer group_end =
static_cast<node_pointer>(prev->next_)->group_prev_->next_;
this->delete_nodes(prev, group_end);
bucket_index = this->fix_bucket(bucket_index, prev);
} while(prev->next_ != 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)
static link_pointer split_groups(node_pointer begin, node_pointer end)
{
// 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_);
node_pointer prev = begin->group_prev_;
if (prev->next_ != begin) prev = node_pointer();
if(first == split) return split;
if (end) {
node_pointer first = end;
while (first != begin && first->group_prev_->next_ == first) {
first = first->group_prev_;
}
link_pointer last = first->group_prev_;
first->group_prev_ = split->group_prev_;
split->group_prev_ = last;
boost::swap(first->group_prev_, end->group_prev_);
if (first == begin) return prev;
}
return first;
if (prev) {
node_pointer first = prev;
while (first->group_prev_->next_ == first) {
first = first->group_prev_;
}
boost::swap(first->group_prev_, begin->group_prev_);
}
return prev;
}
////////////////////////////////////////////////////////////////////////
@ -715,19 +619,16 @@ namespace boost { namespace unordered { namespace detail {
static void fill_buckets(iterator n, table& dst,
NodeCreator& creator)
{
previous_pointer prev = dst.get_previous_start();
link_pointer prev = dst.get_previous_start();
while (n.node_) {
std::size_t key_hash = n.node_->hash_;
iterator group_end(
static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_
));
iterator group_end(n.node_->group_prev_->next_);
node_pointer first_node = creator.create(*n);
node_pointer end = first_node;
first_node->hash_ = key_hash;
prev->next_ = static_cast<link_pointer>(first_node);
prev->next_ = first_node;
++dst.size_;
for (++n; n != group_end; ++n)
@ -748,24 +649,22 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(this->buckets_);
this->create_buckets(num_buckets);
previous_pointer prev = this->get_previous_start();
link_pointer prev = this->get_previous_start();
while (prev->next_)
prev = place_in_bucket(*this, prev,
static_cast<node_pointer>(
static_cast<node_pointer>(prev->next_)->group_prev_));
static_cast<node_pointer>(prev->next_)->group_prev_);
}
// Iterate through the nodes placing them in the correct buckets.
// pre: prev->next_ is not null.
static previous_pointer place_in_bucket(table& dst,
previous_pointer prev, node_pointer end)
static link_pointer place_in_bucket(table& dst,
link_pointer prev, node_pointer end)
{
bucket_pointer b = dst.get_bucket(policy::to_bucket(
dst.bucket_count_, end->hash_));
bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_));
if (!b->next_) {
b->next_ = static_cast<node_pointer>(prev);
return static_cast<previous_pointer>(end);
b->next_ = prev;
return end;
}
else {
link_pointer next = end->next_;

View File

@ -56,30 +56,25 @@ namespace detail {
return no_key();
}
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
template <class... Args>
static no_key extract(Args const&...)
{
return no_key();
}
#else
template <class Arg>
static no_key extract(Arg const&)
{
return no_key();
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class Arg1, class Arg2, class... Args>
static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
{
return no_key();
}
#else
template <class Arg1, class Arg2>
static no_key extract(Arg1 const&, Arg2 const&)
{
return no_key();
}
#endif
static bool compare_mapped(value_type const&, value_type const&)
{
return true;
}
};
template <class Key, class ValueType>
@ -93,11 +88,6 @@ namespace detail {
return v.first;
}
static key_type const& extract(key_type const& v)
{
return v;
}
template <class Second>
static key_type const& extract(std::pair<key_type, Second> const& v)
{
@ -111,21 +101,6 @@ namespace detail {
return v.first;
}
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
template <class Arg1, class... Args>
static key_type const& extract(key_type const& k,
Arg1 const&, Args const&...)
{
return k;
}
template <class... Args>
static no_key extract(Args const&...)
{
return no_key();
}
#else
template <class Arg1>
static key_type const& extract(key_type const& k, Arg1 const&)
{
@ -143,19 +118,27 @@ namespace detail {
return no_key();
}
template <class Arg, class Arg1>
static no_key extract(Arg const&, Arg1 const&)
template <class Arg1, class Arg2>
static no_key extract(Arg1 const&, Arg2 const&)
{
return no_key();
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class Arg1, class Arg2, class Arg3, class... Args>
static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&,
Args const&...)
{
return no_key();
}
#endif
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
template <typename T2> \
static no_key extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<> const&, BOOST_FWD_REF(T2)) \
namespace_ tuple<> const&, T2 const&) \
{ \
return no_key(); \
} \
@ -163,17 +146,17 @@ namespace detail {
template <typename T, typename T2> \
static typename is_key<key_type, T>::type \
extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<T> const& k, BOOST_FWD_REF(T2)) \
namespace_ tuple<T> const& k, T2 const&) \
{ \
return typename is_key<key_type, T>::type( \
namespace_::get<0>(k)); \
namespace_ get<0>(k)); \
}
#else
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
static no_key extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<> const&) \
namespace_ tuple<> const&) \
{ \
return no_key(); \
} \
@ -181,25 +164,19 @@ namespace detail {
template <typename T> \
static typename is_key<key_type, T>::type \
extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<T> const& k) \
namespace_ tuple<T> const& k) \
{ \
return typename is_key<key_type, T>::type( \
namespace_::get<0>(k)); \
namespace_ get<0>(k)); \
}
#endif
BOOST_UNORDERED_KEY_FROM_TUPLE(boost)
BOOST_UNORDERED_KEY_FROM_TUPLE(boost::)
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
BOOST_UNORDERED_KEY_FROM_TUPLE(std)
BOOST_UNORDERED_KEY_FROM_TUPLE(std::)
#endif
static bool compare_mapped(value_type const& x, value_type const& y)
{
return x.second == y.second;
}
};
}}}

View File

@ -18,6 +18,18 @@
#pragma warning(disable:4127) // conditional expression is constant
#endif
#if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
#if defined(__EDG__)
#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__)
#pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.")
#elif defined(__GNUC__) || defined(__HP_aCC) || \
defined(__SUNPRO_CC) || defined(__IBMCPP__)
#warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported."
#endif
#endif
namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
@ -125,7 +137,6 @@ namespace boost { namespace unordered { namespace detail {
template <typename Types>
struct table :
Types::policy,
boost::unordered::detail::functions<
typename Types::hasher,
typename Types::key_equal>
@ -148,6 +159,7 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::functions<
typename Types::hasher,
typename Types::key_equal> functions;
typedef typename functions::set_hash_functions set_hash_functions;
typedef typename Types::allocator allocator;
typedef typename boost::unordered::detail::
@ -164,20 +176,17 @@ namespace boost { namespace unordered { namespace detail {
const_node_pointer;
typedef typename bucket_allocator_traits::pointer
bucket_pointer;
typedef typename bucket::previous_pointer
previous_pointer;
typedef boost::unordered::detail::node_constructor<node_allocator>
node_constructor;
typedef boost::unordered::iterator_detail::
iterator<node_pointer, value_type> iterator;
iterator<node> iterator;
typedef boost::unordered::iterator_detail::
c_iterator<const_node_pointer, node_pointer, value_type> c_iterator;
c_iterator<node, const_node_pointer> c_iterator;
typedef boost::unordered::iterator_detail::
l_iterator<node_pointer, value_type, policy> l_iterator;
l_iterator<node, policy> l_iterator;
typedef boost::unordered::iterator_detail::
cl_iterator<const_node_pointer, node_pointer, value_type, policy>
cl_iterator;
cl_iterator<node, const_node_pointer, policy> cl_iterator;
////////////////////////////////////////////////////////////////////////
// Members
@ -226,28 +235,31 @@ namespace boost { namespace unordered { namespace detail {
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
}
previous_pointer get_previous_start() const
link_pointer get_previous_start() const
{
return get_bucket(bucket_count_)->first_from_start();
}
previous_pointer get_previous_start(std::size_t bucket_index) const
link_pointer get_previous_start(std::size_t bucket_index) const
{
return get_bucket(bucket_index)->next_;
}
iterator begin() const
{
return size_ ? iterator(static_cast<node_pointer>(
get_previous_start()->next_)) : iterator();
return size_ ? iterator(get_previous_start()->next_) : iterator();
}
iterator begin(std::size_t bucket_index) const
{
if (!size_) return iterator();
previous_pointer prev = get_previous_start(bucket_index);
return prev ? iterator(static_cast<node_pointer>(prev->next_)) :
iterator();
link_pointer prev = get_previous_start(bucket_index);
return prev ? iterator(prev->next_) : iterator();
}
std::size_t hash_to_bucket(std::size_t hash) const
{
return policy::to_bucket(bucket_count_, hash);
}
float load_factor() const
@ -263,8 +275,7 @@ namespace boost { namespace unordered { namespace detail {
if (!it.node_) return 0;
std::size_t count = 0;
while(it.node_ && policy::to_bucket(
bucket_count_, it.node_->hash_) == index)
while(it.node_ && hash_to_bucket(it.node_->hash_) == index)
{
++count;
++it;
@ -353,7 +364,7 @@ namespace boost { namespace unordered { namespace detail {
{}
table(table& x, boost::unordered::detail::move_tag m) :
functions(x),
functions(x, m),
allocators_(x.allocators_, m),
bucket_count_(x.bucket_count_),
size_(x.size_),
@ -367,8 +378,8 @@ namespace boost { namespace unordered { namespace detail {
}
table(table& x, node_allocator const& a,
boost::unordered::detail::move_tag) :
functions(x),
boost::unordered::detail::move_tag m) :
functions(x, m),
allocators_(a, a),
bucket_count_(x.bucket_count_),
size_(0),
@ -445,6 +456,8 @@ namespace boost { namespace unordered { namespace detail {
void swap_allocators(table& other, false_type)
{
boost::unordered::detail::func::ignore_unused_variable_warning(other);
// According to 23.2.1.8, if propagate_on_container_swap is
// false the behaviour is undefined unless the allocators
// are equal.
@ -459,10 +472,8 @@ namespace boost { namespace unordered { namespace detail {
// Only swaps the allocators if propagate_on_container_swap
void swap(table& x)
{
boost::unordered::detail::set_hash_functions<hasher, key_equal>
op1(*this, x);
boost::unordered::detail::set_hash_functions<hasher, key_equal>
op2(x, *this);
set_hash_functions op1(*this, x);
set_hash_functions op2(x, *this);
// I think swap can throw if Propagate::value,
// since the allocators' swap can throw. Not sure though.
@ -500,26 +511,29 @@ namespace boost { namespace unordered { namespace detail {
delete_buckets();
}
void delete_node(c_iterator n)
void delete_node(link_pointer prev)
{
boost::unordered::detail::destroy_value_impl(node_alloc(),
n.node_->value_ptr());
node_pointer n = static_cast<node_pointer>(prev->next_);
prev->next_ = n->next_;
boost::unordered::detail::func::destroy_value_impl(node_alloc(),
n->value_ptr());
node_allocator_traits::destroy(node_alloc(),
boost::addressof(*n.node_));
node_allocator_traits::deallocate(node_alloc(), n.node_, 1);
boost::addressof(*n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
--size_;
}
std::size_t delete_nodes(c_iterator begin, c_iterator end)
std::size_t delete_nodes(link_pointer prev, link_pointer end)
{
BOOST_ASSERT(prev->next_ != end);
std::size_t count = 0;
while(begin != end) {
c_iterator n = begin;
++begin;
delete_node(n);
do {
delete_node(prev);
++count;
}
} while (prev->next_ != end);
return count;
}
@ -527,7 +541,7 @@ namespace boost { namespace unordered { namespace detail {
void delete_buckets()
{
if(buckets_) {
delete_nodes(begin(), iterator());
if (size_) delete_nodes(get_previous_start(), link_pointer());
if (bucket::extra_node) {
node_pointer n = static_cast<node_pointer>(
@ -547,10 +561,9 @@ namespace boost { namespace unordered { namespace detail {
void clear()
{
if(!size_) return;
if (!size_) return;
delete_nodes(begin(), iterator());
get_previous_start()->next_ = link_pointer();
delete_nodes(get_previous_start(), link_pointer());
clear_buckets();
BOOST_ASSERT(!size_);
@ -579,86 +592,33 @@ namespace boost { namespace unordered { namespace detail {
}
////////////////////////////////////////////////////////////////////////
// Fix buckets after erase
// Fix buckets after delete
//
// This is called after erasing a node or group of nodes to fix up
// the bucket pointers.
void fix_buckets(bucket_pointer this_bucket,
previous_pointer prev, node_pointer next)
std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev)
{
if (!next)
link_pointer end = prev->next_;
std::size_t bucket_index2 = bucket_index;
if (end)
{
if (this_bucket->next_ == prev)
this_bucket->next_ = node_pointer();
}
else
{
bucket_pointer next_bucket = get_bucket(
policy::to_bucket(bucket_count_, next->hash_));
bucket_index2 = hash_to_bucket(
static_cast<node_pointer>(end)->hash_);
if (next_bucket != this_bucket)
{
next_bucket->next_ = prev;
if (this_bucket->next_ == prev)
this_bucket->next_ = node_pointer();
}
}
}
// If begin and end are in the same bucket, then
// there's nothing to do.
if (bucket_index == bucket_index2) return bucket_index2;
// This is called after erasing a range of nodes to fix any bucket
// pointers into that range.
void fix_buckets_range(std::size_t bucket_index,
previous_pointer prev, node_pointer begin, node_pointer end)
{
node_pointer n = begin;
// If we're not at the start of the current bucket, then
// go to the start of the next bucket.
if (get_bucket(bucket_index)->next_ != prev)
{
for(;;) {
n = static_cast<node_pointer>(n->next_);
if (n == end) {
if (n) {
std::size_t new_bucket_index =
policy::to_bucket(bucket_count_, n->hash_);
if (bucket_index != new_bucket_index) {
get_bucket(new_bucket_index)->next_ = prev;
}
}
return;
}
std::size_t new_bucket_index =
policy::to_bucket(bucket_count_, n->hash_);
if (bucket_index != new_bucket_index) {
bucket_index = new_bucket_index;
break;
}
}
// Update the bucket containing end.
get_bucket(bucket_index2)->next_ = prev;
}
// Iterate through the remaining nodes, clearing out the bucket
// pointers.
get_bucket(bucket_index)->next_ = previous_pointer();
for(;;) {
n = static_cast<node_pointer>(n->next_);
if (n == end) break;
// Check if this bucket is now empty.
bucket_pointer this_bucket = get_bucket(bucket_index);
if (this_bucket->next_ == prev)
this_bucket->next_ = link_pointer();
std::size_t new_bucket_index =
policy::to_bucket(bucket_count_, n->hash_);
if (bucket_index != new_bucket_index) {
bucket_index = new_bucket_index;
get_bucket(bucket_index)->next_ = previous_pointer();
}
};
// Finally fix the bucket containing the trailing node.
if (n) {
get_bucket(
policy::to_bucket(bucket_count_, n->hash_))->next_
= prev;
}
return bucket_index2;
}
////////////////////////////////////////////////////////////////////////
@ -678,8 +638,7 @@ namespace boost { namespace unordered { namespace detail {
void assign(table const& x, false_type)
{
// Strong exception safety.
boost::unordered::detail::set_hash_functions<hasher, key_equal>
new_func_this(*this, x);
set_hash_functions new_func_this(*this, x);
new_func_this.commit();
mlf_ = x.mlf_;
recalculate_max_load();
@ -707,8 +666,7 @@ namespace boost { namespace unordered { namespace detail {
assign(x, false_type());
}
else {
boost::unordered::detail::set_hash_functions<hasher, key_equal>
new_func_this(*this, x);
set_hash_functions new_func_this(*this, x);
// Delete everything with current allocators before assigning
// the new ones.
@ -755,8 +713,7 @@ namespace boost { namespace unordered { namespace detail {
move_assign_no_alloc(x);
}
else {
boost::unordered::detail::set_hash_functions<hasher, key_equal>
new_func_this(*this, x);
set_hash_functions new_func_this(*this, x);
new_func_this.commit();
mlf_ = x.mlf_;
recalculate_max_load();
@ -781,8 +738,7 @@ namespace boost { namespace unordered { namespace detail {
void move_assign_no_alloc(table& x)
{
boost::unordered::detail::set_hash_functions<hasher, key_equal>
new_func_this(*this, x);
set_hash_functions new_func_this(*this, x);
// No throw from here.
mlf_ = x.mlf_;
max_load_ = x.max_load_;

View File

@ -27,7 +27,8 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::value_base<T>
{
typedef typename ::boost::unordered::detail::rebind_wrap<
A, unique_node<A, T> >::type::pointer link_pointer;
A, unique_node<A, T> >::type::pointer node_pointer;
typedef node_pointer link_pointer;
link_pointer next_;
std::size_t hash_;
@ -37,7 +38,7 @@ namespace boost { namespace unordered { namespace detail {
hash_(0)
{}
void init(link_pointer)
void init(node_pointer)
{
}
@ -51,6 +52,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::ptr_bucket
{
typedef boost::unordered::detail::ptr_bucket bucket_base;
typedef ptr_node<T>* node_pointer;
typedef ptr_bucket* link_pointer;
std::size_t hash_;
@ -60,7 +62,7 @@ namespace boost { namespace unordered { namespace detail {
hash_(0)
{}
void init(link_pointer)
void init(node_pointer)
{
}
@ -176,7 +178,6 @@ namespace boost { namespace unordered { namespace detail {
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;
@ -231,8 +232,7 @@ namespace boost { namespace unordered { namespace detail {
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, key_hash);
std::size_t bucket_index = this->hash_to_bucket(key_hash);
iterator n = this->begin(bucket_index);
for (;;)
@ -247,8 +247,7 @@ namespace boost { namespace unordered { namespace detail {
}
else
{
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
if (this->hash_to_bucket(node_hash) != bucket_index)
return iterator();
}
@ -291,13 +290,8 @@ namespace boost { namespace unordered { namespace detail {
{
iterator n2 = other.find_matching_node(n1);
#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
if (!n2.node_ || *n1 != *n2)
return false;
#else
if (!n2.node_ || !extractor::compare_mapped(*n1, *n2))
return false;
#endif
}
return true;
@ -312,27 +306,26 @@ namespace boost { namespace unordered { namespace detail {
node_pointer n = a.release();
n->hash_ = key_hash;
bucket_pointer b = this->get_bucket(
policy::to_bucket(this->bucket_count_, key_hash));
bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
if (!b->next_)
{
previous_pointer start_node = this->get_previous_start();
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
this->get_bucket(policy::to_bucket(this->bucket_count_,
this->get_bucket(this->hash_to_bucket(
static_cast<node_pointer>(start_node->next_)->hash_)
)->next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = static_cast<link_pointer>(n);
start_node->next_ = n;
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = static_cast<link_pointer>(n);
b->next_->next_ = n;
}
++this->size_;
@ -341,8 +334,6 @@ namespace boost { namespace unordered { namespace detail {
value_type& operator[](key_type const& k)
{
typedef typename value_type::second_type mapped_type;
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
@ -360,8 +351,8 @@ namespace boost { namespace unordered { namespace detail {
return *add_node(a, key_hash);
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
# if defined(BOOST_NO_VARIADIC_TEMPLATES)
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
emplace_return emplace(boost::unordered::detail::emplace_args1<
boost::unordered::detail::please_ignore_this_overload> const&)
{
@ -381,7 +372,7 @@ namespace boost { namespace unordered { namespace detail {
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
{
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
return emplace_impl(
extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
BOOST_UNORDERED_EMPLACE_FORWARD);
@ -392,7 +383,7 @@ namespace boost { namespace unordered { namespace detail {
#endif
}
#if defined(BOOST_NO_VARIADIC_TEMPLATES)
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename A0>
emplace_return emplace(
boost::unordered::detail::emplace_args1<A0> const& args)
@ -518,11 +509,8 @@ namespace boost { namespace unordered { namespace detail {
if(!this->size_) return 0;
std::size_t key_hash = this->hash(k);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, key_hash);
bucket_pointer this_bucket = this->get_bucket(bucket_index);
previous_pointer prev = this_bucket->next_;
std::size_t bucket_index = this->hash_to_bucket(key_hash);
link_pointer prev = this->get_previous_start(bucket_index);
if (!prev) return 0;
for (;;)
@ -530,21 +518,20 @@ namespace boost { namespace unordered { namespace detail {
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
if (this->hash_to_bucket(node_hash) != bucket_index)
return 0;
if (node_hash == key_hash &&
this->key_eq()(k, this->get_key(
static_cast<node_pointer>(prev->next_)->value())))
break;
prev = static_cast<previous_pointer>(prev->next_);
prev = 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(this_bucket, prev, end);
return this->delete_nodes(c_iterator(pos), c_iterator(end));
link_pointer end = static_cast<node_pointer>(prev->next_)->next_;
std::size_t count = this->delete_nodes(prev, end);
this->fix_bucket(bucket_index, prev);
return count;
}
iterator erase(c_iterator r)
@ -552,46 +539,30 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
bucket_pointer this_bucket = this->get_bucket(
policy::to_bucket(this->bucket_count_, r.node_->hash_));
previous_pointer prev = unlink_node(*this_bucket, r.node_);
this->fix_buckets(this_bucket, prev, next.node_);
this->delete_node(r);
erase_nodes(r.node_, next.node_);
return next;
}
iterator erase_range(c_iterator r1, c_iterator r2)
{
if (r1 == r2) return iterator(r2.node_);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, r1.node_->hash_);
previous_pointer prev = unlink_nodes(
*this->get_bucket(bucket_index), r1.node_, r2.node_);
this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_);
this->delete_nodes(r1, r2);
erase_nodes(r1.node_, r2.node_);
return iterator(r2.node_);
}
static previous_pointer unlink_node(bucket& b, node_pointer n)
void erase_nodes(node_pointer begin, node_pointer end)
{
return unlink_nodes(b, n, static_cast<node_pointer>(n->next_));
}
std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
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;
// Find the node before begin.
link_pointer prev = this->get_previous_start(bucket_index);
while(prev->next_ != begin) prev = prev->next_;
// Delete the nodes.
do {
this->delete_node(prev);
bucket_index = this->fix_bucket(bucket_index, prev);
} while (prev->next_ != end);
}
////////////////////////////////////////////////////////////////////////
@ -601,12 +572,12 @@ namespace boost { namespace unordered { namespace detail {
static void fill_buckets(iterator n, table& dst,
NodeCreator& creator)
{
previous_pointer prev = dst.get_previous_start();
link_pointer prev = dst.get_previous_start();
while (n.node_) {
node_pointer node = creator.create(*n);
node->hash_ = n.node_->hash_;
prev->next_ = static_cast<link_pointer>(node);
prev->next_ = node;
++dst.size_;
++n;
@ -620,28 +591,26 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(this->buckets_);
this->create_buckets(num_buckets);
previous_pointer prev = this->get_previous_start();
link_pointer prev = this->get_previous_start();
while (prev->next_)
prev = place_in_bucket(*this, prev);
}
// Iterate through the nodes placing them in the correct buckets.
// pre: prev->next_ is not null.
static previous_pointer place_in_bucket(table& dst,
previous_pointer prev)
static link_pointer place_in_bucket(table& dst, link_pointer prev)
{
node_pointer n = static_cast<node_pointer>(prev->next_);
bucket_pointer b = dst.get_bucket(
table::to_bucket(dst.bucket_count_, n->hash_));
bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_));
if (!b->next_) {
b->next_ = prev;
return static_cast<previous_pointer>(n);
return n;
}
else {
prev->next_ = n->next_;
n->next_ = b->next_->next_;
b->next_->next_ = static_cast<link_pointer>(n);
b->next_->next_ = n;
return prev;
}
}

View File

@ -28,6 +28,11 @@ namespace boost { namespace unordered { namespace detail {
struct move_tag {};
struct empty_emplace {};
namespace func {
template <class T>
inline void ignore_unused_variable_warning(T const&) {}
}
////////////////////////////////////////////////////////////////////////////
// iterator SFINAE

View File

@ -117,17 +117,19 @@ namespace unordered
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_map(BOOST_RV_REF(unordered_map) other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#elif !defined(BOOST_NO_RVALUE_REFERENCES)
#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_map(unordered_map&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_map(unordered_map&&, allocator_type const&);
#endif
@ -142,7 +144,7 @@ namespace unordered
// Destructor
~unordered_map();
~unordered_map() BOOST_NOEXCEPT;
// Assign
@ -165,7 +167,7 @@ namespace unordered
return *this;
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_map& operator=(unordered_map&& x)
{
table_.move_assign(x.table_);
@ -178,60 +180,60 @@ namespace unordered
unordered_map& operator=(std::initializer_list<value_type>);
#endif
allocator_type get_allocator() const
allocator_type get_allocator() const BOOST_NOEXCEPT
{
return table_.node_alloc();
}
// size and capacity
bool empty() const
bool empty() const BOOST_NOEXCEPT
{
return table_.size_ == 0;
}
size_type size() const
size_type size() const BOOST_NOEXCEPT
{
return table_.size_;
}
size_type max_size() const;
size_type max_size() const BOOST_NOEXCEPT;
// iterators
iterator begin()
iterator begin() BOOST_NOEXCEPT
{
return table_.begin();
}
const_iterator begin() const
const_iterator begin() const BOOST_NOEXCEPT
{
return table_.begin();
}
iterator end()
iterator end() BOOST_NOEXCEPT
{
return iterator();
}
const_iterator end() const
const_iterator end() const BOOST_NOEXCEPT
{
return const_iterator();
}
const_iterator cbegin() const
const_iterator cbegin() const BOOST_NOEXCEPT
{
return table_.begin();
}
const_iterator cend() const
const_iterator cend() const BOOST_NOEXCEPT
{
return const_iterator();
}
// emplace
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args>
std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args)
{
@ -449,12 +451,12 @@ namespace unordered
// bucket interface
size_type bucket_count() const
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
}
size_type max_bucket_count() const
size_type max_bucket_count() const BOOST_NOEXCEPT
{
return table_.max_bucket_count();
}
@ -463,8 +465,7 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
return table_.hash_to_bucket(table_.hash(k));
}
local_iterator begin(size_type n)
@ -502,13 +503,13 @@ namespace unordered
// hash policy
float max_load_factor() const
float max_load_factor() const BOOST_NOEXCEPT
{
return table_.mlf_;
}
float load_factor() const;
void max_load_factor(float);
float load_factor() const BOOST_NOEXCEPT;
void max_load_factor(float) BOOST_NOEXCEPT;
void rehash(size_type);
void reserve(size_type);
@ -599,17 +600,19 @@ namespace unordered
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_multimap(BOOST_RV_REF(unordered_multimap) other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#elif !defined(BOOST_NO_RVALUE_REFERENCES)
#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap&&, allocator_type const&);
#endif
@ -624,7 +627,7 @@ namespace unordered
// Destructor
~unordered_multimap();
~unordered_multimap() BOOST_NOEXCEPT;
// Assign
@ -648,7 +651,7 @@ namespace unordered
return *this;
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multimap& operator=(unordered_multimap&& x)
{
table_.move_assign(x.table_);
@ -661,60 +664,60 @@ namespace unordered
unordered_multimap& operator=(std::initializer_list<value_type>);
#endif
allocator_type get_allocator() const
allocator_type get_allocator() const BOOST_NOEXCEPT
{
return table_.node_alloc();
}
// size and capacity
bool empty() const
bool empty() const BOOST_NOEXCEPT
{
return table_.size_ == 0;
}
size_type size() const
size_type size() const BOOST_NOEXCEPT
{
return table_.size_;
}
size_type max_size() const;
size_type max_size() const BOOST_NOEXCEPT;
// iterators
iterator begin()
iterator begin() BOOST_NOEXCEPT
{
return table_.begin();
}
const_iterator begin() const
const_iterator begin() const BOOST_NOEXCEPT
{
return table_.begin();
}
iterator end()
iterator end() BOOST_NOEXCEPT
{
return iterator();
}
const_iterator end() const
const_iterator end() const BOOST_NOEXCEPT
{
return const_iterator();
}
const_iterator cbegin() const
const_iterator cbegin() const BOOST_NOEXCEPT
{
return table_.begin();
}
const_iterator cend() const
const_iterator cend() const BOOST_NOEXCEPT
{
return const_iterator();
}
// emplace
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args>
iterator emplace(BOOST_FWD_REF(Args)... args)
{
@ -928,12 +931,12 @@ namespace unordered
// bucket interface
size_type bucket_count() const
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
}
size_type max_bucket_count() const
size_type max_bucket_count() const BOOST_NOEXCEPT
{
return table_.max_bucket_count();
}
@ -942,8 +945,7 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
return table_.hash_to_bucket(table_.hash(k));
}
local_iterator begin(size_type n)
@ -981,13 +983,13 @@ namespace unordered
// hash policy
float max_load_factor() const
float max_load_factor() const BOOST_NOEXCEPT
{
return table_.mlf_;
}
float load_factor() const;
void max_load_factor(float);
float load_factor() const BOOST_NOEXCEPT;
void max_load_factor(float) BOOST_NOEXCEPT;
void rehash(size_type);
void reserve(size_type);
@ -1059,7 +1061,7 @@ namespace unordered
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::~unordered_map() {}
unordered_map<K,T,H,P,A>::~unordered_map() BOOST_NOEXCEPT {}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
@ -1068,7 +1070,7 @@ namespace unordered
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
@ -1107,7 +1109,7 @@ namespace unordered
// size and capacity
template <class K, class T, class H, class P, class A>
std::size_t unordered_map<K,T,H,P,A>::max_size() const
std::size_t unordered_map<K,T,H,P,A>::max_size() const BOOST_NOEXCEPT
{
return table_.max_size();
}
@ -1276,13 +1278,13 @@ namespace unordered
// hash policy
template <class K, class T, class H, class P, class A>
float unordered_map<K,T,H,P,A>::load_factor() const
float unordered_map<K,T,H,P,A>::load_factor() const BOOST_NOEXCEPT
{
return table_.load_factor();
}
template <class K, class T, class H, class P, class A>
void unordered_map<K,T,H,P,A>::max_load_factor(float m)
void unordered_map<K,T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT
{
table_.max_load_factor(m);
}
@ -1392,7 +1394,7 @@ namespace unordered
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::~unordered_multimap() {}
unordered_multimap<K,T,H,P,A>::~unordered_multimap() BOOST_NOEXCEPT {}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
@ -1401,7 +1403,7 @@ namespace unordered
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
@ -1440,7 +1442,7 @@ namespace unordered
// size and capacity
template <class K, class T, class H, class P, class A>
std::size_t unordered_multimap<K,T,H,P,A>::max_size() const
std::size_t unordered_multimap<K,T,H,P,A>::max_size() const BOOST_NOEXCEPT
{
return table_.max_size();
}
@ -1588,13 +1590,13 @@ namespace unordered
// hash policy
template <class K, class T, class H, class P, class A>
float unordered_multimap<K,T,H,P,A>::load_factor() const
float unordered_multimap<K,T,H,P,A>::load_factor() const BOOST_NOEXCEPT
{
return table_.load_factor();
}
template <class K, class T, class H, class P, class A>
void unordered_multimap<K,T,H,P,A>::max_load_factor(float m)
void unordered_multimap<K,T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT
{
table_.max_load_factor(m);
}

View File

@ -115,17 +115,19 @@ namespace unordered
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_set(BOOST_RV_REF(unordered_set) other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#elif !defined(BOOST_NO_RVALUE_REFERENCES)
#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_set(unordered_set&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_set(unordered_set&&, allocator_type const&);
#endif
@ -140,7 +142,7 @@ namespace unordered
// Destructor
~unordered_set();
~unordered_set() BOOST_NOEXCEPT;
// Assign
@ -163,7 +165,7 @@ namespace unordered
return *this;
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_set& operator=(unordered_set&& x)
{
table_.move_assign(x.table_);
@ -176,60 +178,60 @@ namespace unordered
unordered_set& operator=(std::initializer_list<value_type>);
#endif
allocator_type get_allocator() const
allocator_type get_allocator() const BOOST_NOEXCEPT
{
return table_.node_alloc();
}
// size and capacity
bool empty() const
bool empty() const BOOST_NOEXCEPT
{
return table_.size_ == 0;
}
size_type size() const
size_type size() const BOOST_NOEXCEPT
{
return table_.size_;
}
size_type max_size() const;
size_type max_size() const BOOST_NOEXCEPT;
// iterators
iterator begin()
iterator begin() BOOST_NOEXCEPT
{
return table_.begin();
}
const_iterator begin() const
const_iterator begin() const BOOST_NOEXCEPT
{
return table_.begin();
}
iterator end()
iterator end() BOOST_NOEXCEPT
{
return iterator();
}
const_iterator end() const
const_iterator end() const BOOST_NOEXCEPT
{
return const_iterator();
}
const_iterator cbegin() const
const_iterator cbegin() const BOOST_NOEXCEPT
{
return table_.begin();
}
const_iterator cend() const
const_iterator cend() const BOOST_NOEXCEPT
{
return const_iterator();
}
// emplace
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args>
std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args)
{
@ -434,12 +436,12 @@ namespace unordered
// bucket interface
size_type bucket_count() const
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
}
size_type max_bucket_count() const
size_type max_bucket_count() const BOOST_NOEXCEPT
{
return table_.max_bucket_count();
}
@ -448,8 +450,7 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
return table_.hash_to_bucket(table_.hash(k));
}
local_iterator begin(size_type n)
@ -487,13 +488,13 @@ namespace unordered
// hash policy
float max_load_factor() const
float max_load_factor() const BOOST_NOEXCEPT
{
return table_.mlf_;
}
float load_factor() const;
void max_load_factor(float);
float load_factor() const BOOST_NOEXCEPT;
void max_load_factor(float) BOOST_NOEXCEPT;
void rehash(size_type);
void reserve(size_type);
@ -583,17 +584,19 @@ namespace unordered
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_multiset(BOOST_RV_REF(unordered_multiset) other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#elif !defined(BOOST_NO_RVALUE_REFERENCES)
#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset&&, allocator_type const&);
#endif
@ -608,7 +611,7 @@ namespace unordered
// Destructor
~unordered_multiset();
~unordered_multiset() BOOST_NOEXCEPT;
// Assign
@ -632,7 +635,7 @@ namespace unordered
return *this;
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multiset& operator=(unordered_multiset&& x)
{
table_.move_assign(x.table_);
@ -645,60 +648,60 @@ namespace unordered
unordered_multiset& operator=(std::initializer_list<value_type>);
#endif
allocator_type get_allocator() const
allocator_type get_allocator() const BOOST_NOEXCEPT
{
return table_.node_alloc();
}
// size and capacity
bool empty() const
bool empty() const BOOST_NOEXCEPT
{
return table_.size_ == 0;
}
size_type size() const
size_type size() const BOOST_NOEXCEPT
{
return table_.size_;
}
size_type max_size() const;
size_type max_size() const BOOST_NOEXCEPT;
// iterators
iterator begin()
iterator begin() BOOST_NOEXCEPT
{
return iterator(table_.begin());
}
const_iterator begin() const
const_iterator begin() const BOOST_NOEXCEPT
{
return const_iterator(table_.begin());
}
iterator end()
iterator end() BOOST_NOEXCEPT
{
return iterator();
}
const_iterator end() const
const_iterator end() const BOOST_NOEXCEPT
{
return const_iterator();
}
const_iterator cbegin() const
const_iterator cbegin() const BOOST_NOEXCEPT
{
return const_iterator(table_.begin());
}
const_iterator cend() const
const_iterator cend() const BOOST_NOEXCEPT
{
return const_iterator();
}
// emplace
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args>
iterator emplace(BOOST_FWD_REF(Args)... args)
{
@ -903,12 +906,12 @@ namespace unordered
// bucket interface
size_type bucket_count() const
size_type bucket_count() const BOOST_NOEXCEPT
{
return table_.bucket_count_;
}
size_type max_bucket_count() const
size_type max_bucket_count() const BOOST_NOEXCEPT
{
return table_.max_bucket_count();
}
@ -917,8 +920,7 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
return table_.hash_to_bucket(table_.hash(k));
}
local_iterator begin(size_type n)
@ -956,13 +958,13 @@ namespace unordered
// hash policy
float max_load_factor() const
float max_load_factor() const BOOST_NOEXCEPT
{
return table_.mlf_;
}
float load_factor() const;
void max_load_factor(float);
float load_factor() const BOOST_NOEXCEPT;
void max_load_factor(float) BOOST_NOEXCEPT;
void rehash(size_type);
void reserve(size_type);
@ -1034,7 +1036,7 @@ namespace unordered
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::~unordered_set() {}
unordered_set<T,H,P,A>::~unordered_set() BOOST_NOEXCEPT {}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
@ -1043,7 +1045,7 @@ namespace unordered
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
@ -1082,7 +1084,7 @@ namespace unordered
// size and capacity
template <class T, class H, class P, class A>
std::size_t unordered_set<T,H,P,A>::max_size() const
std::size_t unordered_set<T,H,P,A>::max_size() const BOOST_NOEXCEPT
{
return table_.max_size();
}
@ -1202,13 +1204,13 @@ namespace unordered
// hash policy
template <class T, class H, class P, class A>
float unordered_set<T,H,P,A>::load_factor() const
float unordered_set<T,H,P,A>::load_factor() const BOOST_NOEXCEPT
{
return table_.load_factor();
}
template <class T, class H, class P, class A>
void unordered_set<T,H,P,A>::max_load_factor(float m)
void unordered_set<T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT
{
table_.max_load_factor(m);
}
@ -1318,7 +1320,7 @@ namespace unordered
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::~unordered_multiset() {}
unordered_multiset<T,H,P,A>::~unordered_multiset() BOOST_NOEXCEPT {}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
@ -1327,7 +1329,7 @@ namespace unordered
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
@ -1366,7 +1368,7 @@ namespace unordered
// size and capacity
template <class T, class H, class P, class A>
std::size_t unordered_multiset<T,H,P,A>::max_size() const
std::size_t unordered_multiset<T,H,P,A>::max_size() const BOOST_NOEXCEPT
{
return table_.max_size();
}
@ -1486,13 +1488,13 @@ namespace unordered
// hash policy
template <class T, class H, class P, class A>
float unordered_multiset<T,H,P,A>::load_factor() const
float unordered_multiset<T,H,P,A>::load_factor() const BOOST_NOEXCEPT
{
return table_.load_factor();
}
template <class T, class H, class P, class A>
void unordered_multiset<T,H,P,A>::max_load_factor(float m)
void unordered_multiset<T,H,P,A>::max_load_factor(float m) BOOST_NOEXCEPT
{
table_.max_load_factor(m);
}

View File

@ -105,7 +105,8 @@ struct assign_test5 : assign_base<T>
assign_test5() : assign_base<T>(5, 60, 0, 0, 1.0, 0.1) {}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(self_assign_test1)(self_assign_test2)
(assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -159,7 +159,7 @@ struct copy_range_construct_test : public range<T>, objects
}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(construct_test1)
(construct_test2)
(construct_test3)
@ -174,3 +174,4 @@ RUN_EXCEPTION_TESTS(
(input_range_construct_test)
(copy_range_construct_test),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -64,6 +64,7 @@ struct copy_with_allocator_test : public test::exception_base
}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -49,6 +49,7 @@ struct erase_by_key_test1 : public erase_test_base<T>
}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(erase_by_key_test1),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -37,7 +37,7 @@ struct insert_test_base : public test::exception_base
}
};
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class T>
struct emplace_test1 : public insert_test_base<T>
@ -236,11 +236,12 @@ struct insert_test_rehash3 : public insert_test_base<T>
(insert_test1)(insert_test2)(insert_test3)(insert_test4) \
(insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define ALL_TESTS (emplace_test1)BASIC_TESTS
#else
#define ALL_TESTS BASIC_TESTS
#endif
RUN_EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
RUN_TESTS()

View File

@ -79,7 +79,7 @@ struct rehash_test4 : rehash_test_base<T>
void run(T& x) const { x.rehash(0); }
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -118,7 +118,8 @@ struct swap_test4 : swap_base<T>
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(self_swap_test1)(self_swap_test2)
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -20,22 +20,37 @@
fixture, BOOST_STRINGIZE(test_func<type>)); \
} \
# define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type) \
UNORDERED_AUTO_TEST(name) \
{ \
for (unsigned i = 0; i < n; ++i) { \
test_func< type > fixture; \
::test::lightweight::exception_safety( \
fixture, BOOST_STRINGIZE(test_func<type>)); \
} \
} \
# define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
#define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, \
(test_seq)(param_seq)) \
RUN_TESTS() \
#define EXCEPTION_TESTS(test_seq, param_seq) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, \
(test_seq)((1))(param_seq))
#define RUN_EXCEPTION_TESTS_OP(r, product) \
UNORDERED_EXCEPTION_TEST_CASE( \
#define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, \
(test_seq)((n))(param_seq))
#define EXCEPTION_TESTS_OP(r, product) \
UNORDERED_EXCEPTION_TEST_CASE_REPEAT( \
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product)) \
), \
BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_SEQ_ELEM(1, product) \
BOOST_PP_SEQ_ELEM(1, product), \
BOOST_PP_SEQ_ELEM(2, product) \
) \
#define UNORDERED_SCOPE(scope_name) \

View File

@ -170,7 +170,7 @@ namespace test
new(p) T(t);
}
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<typename... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(boost::forward<Args>(args)...);

View File

@ -348,7 +348,7 @@ namespace exception
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
}
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
UNORDERED_SCOPE(allocator::construct(pointer, BOOST_FWD_REF(Args)...)) {
UNORDERED_EPOINT("Mock allocator construct function.");
@ -528,7 +528,7 @@ namespace exception
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
}
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...)) {
UNORDERED_EPOINT("Mock allocator2 construct function.");

View File

@ -155,7 +155,7 @@ namespace minimal
~movable1() {}
};
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
class movable2
{
public:
@ -371,7 +371,7 @@ namespace minimal
void construct(T* p, T const& t) { new((void*)p) T(t); }
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
new((void*)p) T(boost::forward<Args>(args)...);
}
@ -443,7 +443,7 @@ namespace minimal
void construct(T* p, T const& t) { new((void*)p) T(t); }
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
new((void*)p) T(boost::forward<Args>(args)...);
}

View File

@ -591,7 +591,7 @@ namespace test
new(p) T(t);
}
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(boost::forward<Args>(args)...);

View File

@ -25,6 +25,7 @@ test-suite unordered
[ run minimal_allocator.cpp ]
[ run compile_set.cpp ]
[ run compile_map.cpp ]
[ run noexcept_tests.cpp ]
[ run link_test_1.cpp link_test_2.cpp ]
[ run incomplete_test.cpp ]
[ run simple_tests.cpp ]
@ -34,9 +35,6 @@ test-suite unordered
[ run move_tests.cpp ]
[ run assign_tests.cpp ]
[ run insert_tests.cpp ]
[ run insert_tests.cpp : :
: <define>BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
: insert_deprecated ]
[ run insert_stable_tests.cpp ]
[ run unnecessary_copy_tests.cpp ]
[ run erase_tests.cpp ]
@ -47,7 +45,6 @@ test-suite unordered
[ run load_factor_tests.cpp ]
[ run rehash_tests.cpp ]
[ run equality_tests.cpp ]
[ run equality_deprecated.cpp ]
[ run swap_tests.cpp ]
[ run compile_set.cpp : :

View File

@ -137,7 +137,7 @@ void unordered_destructible_test(X&)
X x1;
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
X x2(rvalue_default<X>());
X x3 = rvalue_default<X>();
// This can only be done if propagate_on_container_move_assignment::value
@ -453,7 +453,7 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
X x1(rvalue_default<X>());
X x2(boost::move(x1));
x1 = rvalue_default<X>();

View File

@ -1,174 +0,0 @@
// Copyright 2008-2009 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)
#define BOOST_UNORDERED_DEPRECATED_EQUALITY
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <boost/preprocessor/seq.hpp>
#include <list>
#include "../helpers/test.hpp"
namespace equality_tests
{
struct mod_compare
{
bool alt_hash_;
explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {}
bool operator()(int x, int y) const
{
return x % 1000 == y % 1000;
}
int operator()(int x) const
{
return alt_hash_ ? x % 250 : (x + 5) % 250;
}
};
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
{ \
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
BOOST_TEST(set1 op set2); \
}
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
{ \
boost::unordered_multiset<int, mod_compare, mod_compare> \
set1, set2; \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
BOOST_TEST(set1 op set2); \
}
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
{ \
boost::unordered_map<int, int, mod_compare, mod_compare> \
map1, map2; \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
BOOST_TEST(map1 op map2); \
}
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
{ \
boost::unordered_multimap<int, int, mod_compare, mod_compare> \
map1, map2; \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
BOOST_TEST(map1 op map2); \
}
#define UNORDERED_SET_INSERT(r, set, item) set.insert(item);
#define UNORDERED_MAP_INSERT(r, map, item) \
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
UNORDERED_AUTO_TEST(equality_size_tests)
{
boost::unordered_set<int> x1, x2;
BOOST_TEST(x1 == x2);
BOOST_TEST(!(x1 != x2));
x1.insert(1);
BOOST_TEST(x1 != x2);
BOOST_TEST(!(x1 == x2));
BOOST_TEST(x2 != x1);
BOOST_TEST(!(x2 == x1));
x2.insert(1);
BOOST_TEST(x1 == x2);
BOOST_TEST(!(x1 != x2));
x2.insert(2);
BOOST_TEST(x1 != x2);
BOOST_TEST(!(x1 == x2));
BOOST_TEST(x2 != x1);
BOOST_TEST(!(x2 == x1));
}
UNORDERED_AUTO_TEST(equality_key_value_tests)
{
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2))
UNORDERED_EQUALITY_SET_TEST((2), ==, (2))
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)))
}
UNORDERED_AUTO_TEST(equality_collision_test)
{
UNORDERED_EQUALITY_MULTISET_TEST(
(1), !=, (501))
UNORDERED_EQUALITY_MULTISET_TEST(
(1)(251), !=, (1)(501))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((251)(1))((1)(1)), !=, ((501)(1))((1)(1)))
UNORDERED_EQUALITY_MULTISET_TEST(
(1)(501), ==, (1)(501))
UNORDERED_EQUALITY_SET_TEST(
(1)(501), ==, (501)(1))
}
UNORDERED_AUTO_TEST(equality_group_size_test)
{
UNORDERED_EQUALITY_MULTISET_TEST(
(10)(20)(20), !=, (10)(10)(20))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((10)(1))((20)(1))((20)(1)), !=,
((10)(1))((20)(1))((10)(1)))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((20)(1))((10)(1))((10)(1)), ==,
((10)(1))((20)(1))((10)(1)))
}
UNORDERED_AUTO_TEST(equality_map_value_test)
{
UNORDERED_EQUALITY_MAP_TEST(
((1)(1)), !=, ((1)(2)))
UNORDERED_EQUALITY_MAP_TEST(
((1)(1)), ==, ((1)(1)))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((1)(1)), !=, ((1)(2)))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((1)(2))((1)(1)), !=, ((1)(1))((1)(2)))
}
UNORDERED_AUTO_TEST(equality_predicate_test)
{
UNORDERED_EQUALITY_SET_TEST(
(1), ==, (1001))
UNORDERED_EQUALITY_MAP_TEST(
((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)))
}
// Test that equality still works when the two containers have
// different hash functions but the same equality predicate.
UNORDERED_AUTO_TEST(equality_different_hash_test)
{
typedef boost::unordered_set<int, mod_compare, mod_compare> set;
set set1(0, mod_compare(false), mod_compare(false));
set set2(0, mod_compare(true), mod_compare(true));
BOOST_TEST(set1 == set2);
set1.insert(1); set2.insert(2);
BOOST_TEST(set1 != set2);
set1.insert(2); set2.insert(1);
BOOST_TEST(set1 == set2);
set1.insert(10); set2.insert(20);
BOOST_TEST(set1 != set2);
set1.insert(20); set2.insert(10);
BOOST_TEST(set1 == set2);
}
}
RUN_TESTS()

View File

@ -380,7 +380,7 @@ void move_emplace_tests(X*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
typename X::value_type value = *it;
typename X::value_type value = *it;
x.emplace(boost::move(value));
tracker.insert(*it);
tracker.compare_key(x, *it);
@ -549,13 +549,13 @@ UNORDERED_TEST(equivalent_emplace_tests1,
UNORDERED_TEST(move_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(default_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
)
@ -576,6 +576,21 @@ UNORDERED_TEST(map_insert_range_test2,
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
struct initialize_from_two_ints
{
int a, b;
friend std::size_t hash_value(initialize_from_two_ints const& x)
{
return x.a + x.b;
}
bool operator==(initialize_from_two_ints const& x) const
{
return a == x.a && b == x.b;
}
};
UNORDERED_AUTO_TEST(insert_initializer_list_set)
{
boost::unordered_set<int> set;
@ -583,6 +598,30 @@ UNORDERED_AUTO_TEST(insert_initializer_list_set)
BOOST_TEST_EQ(set.size(), 3u);
BOOST_TEST(set.find(1) != set.end());
BOOST_TEST(set.find(4) == set.end());
boost::unordered_set<initialize_from_two_ints> set2;
set2.insert({1, 2});
BOOST_TEST(set2.size() == 1);
BOOST_TEST(set2.find({1,2}) != set2.end());
BOOST_TEST(set2.find({2,1}) == set2.end());
set2.insert({{3,4},{5,6},{7,8}});
BOOST_TEST(set2.size() == 4);
BOOST_TEST(set2.find({1,2}) != set2.end());
BOOST_TEST(set2.find({3,4}) != set2.end());
BOOST_TEST(set2.find({5,6}) != set2.end());
BOOST_TEST(set2.find({7,8}) != set2.end());
BOOST_TEST(set2.find({8,7}) == set2.end());
set2.insert({{2, 1}, {3,4}});
BOOST_TEST(set2.size() == 5);
BOOST_TEST(set2.find({1,2}) != set2.end());
BOOST_TEST(set2.find({2,1}) != set2.end());
BOOST_TEST(set2.find({3,4}) != set2.end());
BOOST_TEST(set2.find({5,6}) != set2.end());
BOOST_TEST(set2.find({7,8}) != set2.end());
BOOST_TEST(set2.find({8,7}) == set2.end());
}
UNORDERED_AUTO_TEST(insert_initializer_list_multiset)
@ -658,20 +697,6 @@ UNORDERED_AUTO_TEST(map_emplace_test)
x.emplace(2, 3);
BOOST_TEST(x.find(2) != x.end() &&
x.find(2)->second == overloaded_constructor(3));
#if defined (BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
x.emplace(1);
BOOST_TEST(x.find(1) != x.end() &&
x.find(1)->second == overloaded_constructor());
x.emplace(4, 5, 6);
BOOST_TEST(x.find(4) != x.end() &&
x.find(4)->second == overloaded_constructor(5, 6));
x.emplace(7, 8, 9, 10);
BOOST_TEST(x.find(7) != x.end() &&
x.find(7)->second == overloaded_constructor(8, 9, 10));
#endif
}
UNORDERED_AUTO_TEST(set_emplace_test)
@ -705,6 +730,19 @@ UNORDERED_AUTO_TEST(set_emplace_test)
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
}
struct derived_from_piecewise_construct_t :
boost::unordered::piecewise_construct_t {};
derived_from_piecewise_construct_t piecewise_rvalue() {
return derived_from_piecewise_construct_t();
}
struct convertible_to_piecewise {
operator boost::unordered::piecewise_construct_t() const {
return boost::unordered::piecewise_construct;
}
};
UNORDERED_AUTO_TEST(map_emplace_test2)
{
boost::unordered_map<overloaded_constructor, overloaded_constructor> x;
@ -713,13 +751,18 @@ UNORDERED_AUTO_TEST(map_emplace_test2)
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second == overloaded_constructor());
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(1), boost::make_tuple());
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(2,3), boost::make_tuple(4,5,6));
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)

View File

@ -23,7 +23,7 @@
namespace move_tests
{
test::seed_t initialize_seed(98624);
#if defined(BOOST_UNORDERED_USE_MOVE) || !defined(BOOST_NO_RVALUE_REFERENCES)
#if defined(BOOST_UNORDERED_USE_MOVE) || !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_UNORDERED_TEST_MOVING 1
#else
#define BOOST_UNORDERED_TEST_MOVING 0
@ -154,7 +154,7 @@ namespace move_tests
test::random_values<T> v(25, generator);
T y(create(v, count, hf, eq, al, 1.0), al);
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
BOOST_TEST(count == test::global_object_count);
#elif defined(BOOST_HAS_NRVO)
BOOST_TEST(

View File

@ -0,0 +1,125 @@
// Copyright 2013 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)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
namespace noexcept_tests
{
// Test the noexcept is set correctly for the move constructor.
struct hash_possible_exception : boost::hash<int>
{
hash_possible_exception(hash_possible_exception const&) {}
};
struct equal_to_possible_exception : std::equal_to<int>
{
equal_to_possible_exception(equal_to_possible_exception const&) {}
};
UNORDERED_AUTO_TEST(test_noexcept)
{
#if !defined(BOOST_NO_CXX11_NOEXCEPT)
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_set<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multiset<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_map<int, int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multimap<int, int> >::value));
#endif
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_set<int, hash_possible_exception>
>::value));
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_multiset<int, boost::hash<int>,
equal_to_possible_exception>
>::value));
}
// Test that the move constructor does actually move without throwing
// an exception when it claims to.
struct test_exception {};
bool throwing_test_exception = false;
void test_throw(char const* name) {
if (throwing_test_exception) {
std::cerr << "Throw exception in: " << name << std::endl;
throw test_exception();
}
}
class hash_nothrow_move : boost::hash<int>
{
BOOST_COPYABLE_AND_MOVABLE(hash_nothrow_move)
typedef boost::hash<int> base;
public:
hash_nothrow_move(BOOST_RV_REF(hash_nothrow_move))
BOOST_NOEXCEPT {}
hash_nothrow_move() { test_throw("Constructor"); }
hash_nothrow_move(hash_nothrow_move const& x) { test_throw("Copy"); }
hash_nothrow_move& operator=(hash_nothrow_move const&)
{ test_throw("Assign"); return *this; }
std::size_t operator()(int x) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x); }
};
class equal_to_nothrow_move : std::equal_to<int>
{
BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow_move)
typedef std::equal_to<int> base;
public:
equal_to_nothrow_move(BOOST_RV_REF(equal_to_nothrow_move))
BOOST_NOEXCEPT {}
equal_to_nothrow_move() { test_throw("Constructor"); }
equal_to_nothrow_move(equal_to_nothrow_move const& x)
{ test_throw("Copy"); }
equal_to_nothrow_move& operator=(equal_to_nothrow_move const&)
{ test_throw("Assign"); return *this; }
std::size_t operator()(int x, int y) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x, y); }
};
UNORDERED_AUTO_TEST(test_no_throw_when_noexcept)
{
typedef boost::unordered_set<int,
hash_nothrow_move, equal_to_nothrow_move> throwing_set;
if (boost::is_nothrow_move_constructible<throwing_set>::value)
{
throwing_test_exception = false;
throwing_set x1;
x1.insert(10);
x1.insert(50);
try {
throwing_test_exception = true;
throwing_set x2 = boost::move(x1);
BOOST_TEST(x2.size() == 2);
BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
} catch(test_exception) {
BOOST_TEST(false);
}
throwing_test_exception = false;
}
}
}
RUN_TESTS()

View File

@ -195,7 +195,7 @@ namespace unnecessary_copy_tests
reset();
T x;
x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(1);
#else
COPY_COUNT(2);
@ -215,7 +215,7 @@ namespace unnecessary_copy_tests
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(boost::move(a));
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(1); MOVE_COUNT(1);
#else
// Since std::pair isn't movable, move only works for sets.
@ -249,7 +249,7 @@ namespace unnecessary_copy_tests
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(boost::move(a));
#if defined(BOOST_NO_RVALUE_REFERENCES)
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(2); MOVE_COUNT(0);
#else
COPY_COUNT(1); MOVE_COUNT(1);
@ -285,8 +285,8 @@ namespace unnecessary_copy_tests
// the existing element.
reset();
x.emplace();
#if !defined(BOOST_NO_VARIADIC_TEMPLATES) || \
!defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
// source_cost doesn't make much sense here, but it seems to fit.
COPY_COUNT(1); MOVE_COUNT(source_cost);
#else
@ -313,7 +313,7 @@ namespace unnecessary_copy_tests
// No move should take place.
reset();
x.emplace(boost::move(a));
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(0); MOVE_COUNT(0);
#else
COPY_COUNT(0); MOVE_COUNT(1);
@ -374,7 +374,7 @@ namespace unnecessary_copy_tests
// COPY_COUNT(1) would be okay here.
reset();
x.emplace();
# if BOOST_WORKAROUND(BOOST_MSVC, >= 1700)
# if BOOST_WORKAROUND(BOOST_MSVC, == 1700)
// This is a little odd, Visual C++ 11 seems to move the pair, which
// results in one copy (for the const key) and one move (for the
// non-const mapped value). Since 'emplace(boost::move(a))' (see below)