2 // Copyright 2013 Daniel James.
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #include "../helpers/prefix.hpp"
8 #include <boost/unordered_set.hpp>
9 #include <boost/unordered_map.hpp>
10 #include "../helpers/postfix.hpp"
13 #include "../helpers/test.hpp"
15 namespace noexcept_tests
{
16 // Test the noexcept is set correctly for the move constructor.
18 struct hash_possible_exception
: boost::hash
<int>
20 hash_possible_exception(hash_possible_exception
const&) {}
23 struct equal_to_possible_exception
: std::equal_to
<int>
25 equal_to_possible_exception(equal_to_possible_exception
const&) {}
28 // Test that the move constructor does actually move without throwing
29 // an exception when it claims to.
35 bool throwing_test_exception
= false;
36 void test_throw(char const* name
)
38 if (throwing_test_exception
) {
39 BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< "Throw exception in: " << name
41 throw test_exception();
45 class hash_nothrow_move
: boost::hash
<int>
47 BOOST_COPYABLE_AND_MOVABLE(hash_nothrow_move
)
49 typedef boost::hash
<int> base
;
52 hash_nothrow_move(BOOST_RV_REF(hash_nothrow_move
)) BOOST_NOEXCEPT
{}
54 hash_nothrow_move() { test_throw("Constructor"); }
55 hash_nothrow_move(hash_nothrow_move
const&) { test_throw("Copy"); }
56 hash_nothrow_move
& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow_move
))
61 hash_nothrow_move
& operator=(BOOST_RV_REF(hash_nothrow_move
))
63 test_throw("Move Assign");
66 std::size_t operator()(int x
) const
68 test_throw("Operator");
69 return static_cast<base
const&>(*this)(x
);
73 class equal_to_nothrow_move
: std::equal_to
<int>
75 BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow_move
)
77 typedef std::equal_to
<int> base
;
80 equal_to_nothrow_move(BOOST_RV_REF(equal_to_nothrow_move
)) BOOST_NOEXCEPT
{}
81 equal_to_nothrow_move() { test_throw("Constructor"); }
82 equal_to_nothrow_move(equal_to_nothrow_move
const&) { test_throw("Copy"); }
83 equal_to_nothrow_move
& operator=(
84 BOOST_COPY_ASSIGN_REF(equal_to_nothrow_move
))
89 equal_to_nothrow_move
& operator=(BOOST_RV_REF(equal_to_nothrow_move
))
91 test_throw("Move Assign");
94 std::size_t operator()(int x
, int y
) const
96 test_throw("Operator");
97 return static_cast<base
const&>(*this)(x
, y
);
101 bool have_is_nothrow_move
= false;
103 UNORDERED_AUTO_TEST (check_is_nothrow_move
) {
105 !boost::is_nothrow_move_constructible
<hash_possible_exception
>::value
);
106 have_is_nothrow_move
=
107 boost::is_nothrow_move_constructible
<hash_nothrow_move
>::value
;
109 // Copied from boost::is_nothrow_move_constructible implementation
110 // to make sure this does actually detect it when expected.
112 // The type trait is also available when BOOST_IS_NOTHROW_MOVE_CONSTRUCT
113 // is defined (for some versions of Visual C++?) but detects 'throw()',
115 #if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && \
116 !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
117 BOOST_TEST(have_is_nothrow_move
);
121 UNORDERED_AUTO_TEST (test_noexcept
) {
122 if (have_is_nothrow_move
) {
123 BOOST_TEST((boost::is_nothrow_move_constructible
<
124 boost::unordered_set
<int> >::value
));
125 BOOST_TEST((boost::is_nothrow_move_constructible
<
126 boost::unordered_multiset
<int> >::value
));
127 BOOST_TEST((boost::is_nothrow_move_constructible
<
128 boost::unordered_map
<int, int> >::value
));
129 BOOST_TEST((boost::is_nothrow_move_constructible
<
130 boost::unordered_multimap
<int, int> >::value
));
133 BOOST_TEST((!boost::is_nothrow_move_constructible
<
134 boost::unordered_set
<int, hash_possible_exception
> >::value
));
136 (!boost::is_nothrow_move_constructible
<boost::unordered_multiset
<int,
137 boost::hash
<int>, equal_to_possible_exception
> >::value
));
140 UNORDERED_AUTO_TEST (test_no_throw_when_noexcept
) {
141 typedef boost::unordered_set
<int, hash_nothrow_move
, equal_to_nothrow_move
>
144 if (have_is_nothrow_move
) {
145 BOOST_TEST(boost::is_nothrow_move_constructible
<throwing_set
>::value
);
147 throwing_test_exception
= false;
154 throwing_test_exception
= true;
156 throwing_set x2
= boost::move(x1
);
157 BOOST_TEST(x2
.size() == 2);
158 BOOST_TEST(*x2
.begin() == 10 || *x2
.begin() == 50);
159 } catch (test_exception
) {
163 throwing_test_exception
= false;