Compare commits

..

7 Commits

Author SHA1 Message Date
Daniel James 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
Daniel James 6ca8d5e0d9 Merge Visual C++ 12 fix for Unordered.
[SVN r86551]
2013-11-03 19:20:09 +00:00
Daniel James 9b9a1d21a6 Merge release notes + float hash fix. Ref #8822.
[SVN r86210]
2013-10-08 21:26:30 +00:00
Daniel James 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
Daniel James 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
Daniel James 0c7c7cc6ad Merge some change log entries to release.
[SVN r84497]
2013-05-25 15:53:49 +00:00
Daniel James 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
15 changed files with 463 additions and 185 deletions
+12
View File
@@ -228,4 +228,16 @@ C++11 support has resulted in some breaking changes:
* 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]
+5 -4
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]
+13 -8
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]
+29 -25
View File
@@ -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); \
@@ -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,7 +766,7 @@ namespace boost { namespace unordered { namespace detail {
#endif
namespace boost { namespace unordered { namespace detail {
namespace boost { namespace unordered { namespace detail { namespace func {
////////////////////////////////////////////////////////////////////////////
// call_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
@@ -818,7 +826,7 @@ namespace boost { namespace unordered { namespace detail {
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_) \
); \
}
@@ -945,7 +953,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
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)...);
}
@@ -960,9 +968,9 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
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));
}
@@ -1032,19 +1040,15 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
boost::unordered::detail::emplace_args3<A0, A1, A2> const& args,
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);
}
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
}}}
////////////////////////////////////////////////////////////////////////////////
//
// Some helper functions for allocating & constructing
}}}}
namespace boost { namespace unordered { namespace detail {
+115 -32
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 {
////////////////////////////////////////////////////////////////////////////
@@ -71,9 +77,9 @@ namespace boost { namespace unordered { namespace iterator_detail {
typedef typename Node::value_type value_type;
l_iterator() : ptr_() {}
l_iterator() BOOST_NOEXCEPT : ptr_() {}
l_iterator(iterator x, std::size_t b, std::size_t c)
l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT
: ptr_(x.node_), bucket_(b), bucket_count_(c) {}
value_type& operator*() const {
@@ -98,11 +104,11 @@ 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_;
}
};
@@ -130,13 +136,13 @@ namespace boost { namespace unordered { namespace iterator_detail {
typedef typename Node::value_type value_type;
cl_iterator() : ptr_() {}
cl_iterator() BOOST_NOEXCEPT : ptr_() {}
cl_iterator(iterator x, std::size_t b, std::size_t c) :
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<
Node, Policy> const& x) :
Node, Policy> const& x) BOOST_NOEXCEPT :
ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
{}
@@ -162,11 +168,15 @@ 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_;
}
};
@@ -202,9 +212,9 @@ namespace boost { namespace unordered { namespace iterator_detail {
typedef typename Node::value_type value_type;
iterator() : node_() {}
iterator() BOOST_NOEXCEPT : node_() {}
explicit iterator(typename Node::link_pointer x) :
explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
node_(static_cast<node_pointer>(x)) {}
value_type& operator*() const {
@@ -226,11 +236,11 @@ 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_;
}
};
@@ -264,12 +274,12 @@ namespace boost { namespace unordered { namespace iterator_detail {
typedef typename Node::value_type value_type;
c_iterator() : node_() {}
c_iterator() BOOST_NOEXCEPT : node_() {}
explicit c_iterator(typename Node::link_pointer x) :
explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
node_(static_cast<node_pointer>(x)) {}
c_iterator(iterator const& x) : node_(x.node_) {}
c_iterator(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {}
value_type const& operator*() const {
return node_->value();
@@ -290,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_;
}
};
@@ -343,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;
}
@@ -352,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;
@@ -382,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());
}
@@ -414,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;
}
@@ -531,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);
@@ -670,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;
@@ -692,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)
{
@@ -721,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_);
}
@@ -733,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_)
{
@@ -771,6 +823,37 @@ 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
+17 -17
View File
@@ -56,19 +56,19 @@ namespace detail {
return no_key();
}
#if !defined(BOOST_NO_CXX11_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&)
{
@@ -107,14 +107,6 @@ namespace detail {
return k;
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class... Args>
static no_key extract(Args const&...)
{
return no_key();
}
#else
static no_key extract()
{
return no_key();
@@ -126,8 +118,16 @@ 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();
}
+13 -16
View File
@@ -159,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::
@@ -363,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_),
@@ -377,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),
@@ -455,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.
@@ -469,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.
@@ -515,7 +516,7 @@ namespace boost { namespace unordered { namespace detail {
node_pointer n = static_cast<node_pointer>(prev->next_);
prev->next_ = n->next_;
boost::unordered::detail::destroy_value_impl(node_alloc(),
boost::unordered::detail::func::destroy_value_impl(node_alloc(),
n->value_ptr());
node_allocator_traits::destroy(node_alloc(),
boost::addressof(*n));
@@ -637,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();
@@ -666,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.
@@ -714,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();
@@ -740,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_;
@@ -334,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);
+5
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
+44 -40
View File
@@ -117,11 +117,13 @@ 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_CXX11_RVALUE_REFERENCES)
unordered_map(unordered_map&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
@@ -142,7 +144,7 @@ namespace unordered
// Destructor
~unordered_map();
~unordered_map() BOOST_NOEXCEPT;
// Assign
@@ -178,53 +180,53 @@ 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();
}
@@ -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();
}
@@ -501,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);
@@ -598,11 +600,13 @@ 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_CXX11_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
@@ -623,7 +627,7 @@ namespace unordered
// Destructor
~unordered_multimap();
~unordered_multimap() BOOST_NOEXCEPT;
// Assign
@@ -660,53 +664,53 @@ 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();
}
@@ -927,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();
}
@@ -979,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);
@@ -1057,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(
@@ -1105,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();
}
@@ -1274,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);
}
@@ -1390,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(
@@ -1438,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();
}
@@ -1586,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);
}
+44 -40
View File
@@ -115,11 +115,13 @@ 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_CXX11_RVALUE_REFERENCES)
unordered_set(unordered_set&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
@@ -140,7 +142,7 @@ namespace unordered
// Destructor
~unordered_set();
~unordered_set() BOOST_NOEXCEPT;
// Assign
@@ -176,53 +178,53 @@ 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();
}
@@ -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();
}
@@ -486,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);
@@ -582,11 +584,13 @@ 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_CXX11_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset&& other)
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
: table_(other.table_, boost::unordered::detail::move_tag())
{
}
@@ -607,7 +611,7 @@ namespace unordered
// Destructor
~unordered_multiset();
~unordered_multiset() BOOST_NOEXCEPT;
// Assign
@@ -644,53 +648,53 @@ 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();
}
@@ -902,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();
}
@@ -954,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);
@@ -1032,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(
@@ -1080,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();
}
@@ -1200,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);
}
@@ -1316,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(
@@ -1364,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();
}
@@ -1484,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);
}
+1
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 ]
+39
View File
@@ -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)
+125
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()
+1 -1
View File
@@ -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)