Compare commits

..
Author SHA1 Message Date
Marshall Clow b1c1e96476 Release 1.55.0
[SVN r86621]
2013-11-11 19:45:21 +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
12 changed files with 252 additions and 91 deletions
+5
View File
@@ -235,4 +235,9 @@ C++11 support has resulted in some breaking changes:
* 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]
+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 {
+46 -34
View File
@@ -32,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 {
////////////////////////////////////////////////////////////////////////////
@@ -73,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 {
@@ -100,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_;
}
};
@@ -132,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_)
{}
@@ -164,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_;
}
};
@@ -204,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 {
@@ -228,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_;
}
};
@@ -266,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();
@@ -292,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_;
}
};
@@ -345,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;
}
@@ -354,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;
@@ -384,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());
}
@@ -416,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;
}
@@ -533,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);
@@ -715,20 +727,23 @@ namespace boost { namespace unordered { namespace detail {
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::move_tag m)
boost::unordered::detail::true_type)
{
new((void*) &funcs_[which]) function_pair(f, m);
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:
@@ -748,15 +763,12 @@ namespace boost { namespace unordered { namespace detail {
construct(current_, bf.current());
}
functions(functions& bf, boost::unordered::detail::move_tag m)
functions(functions& bf, boost::unordered::detail::move_tag)
: current_(false)
{
if (nothrow_move_constructible) {
construct(current_, bf.current(), m);
}
else {
construct(current_, bf.current());
}
construct(current_, bf.current(),
boost::unordered::detail::integral_constant<bool,
nothrow_move_constructible>());
}
~functions() {
+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();
}
+3 -1
View File
@@ -456,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.
@@ -514,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));
@@ -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
+8 -4
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
@@ -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
@@ -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(
@@ -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(
+8 -4
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
@@ -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
@@ -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(
@@ -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(
+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 ]
+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()