]>
Commit | Line | Data |
---|---|---|
1 | ||
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) | |
5 | ||
6 | // clang-format off | |
7 | #include "../helpers/prefix.hpp" | |
8 | #include <boost/unordered_set.hpp> | |
9 | #include <boost/unordered_map.hpp> | |
10 | #include "../helpers/postfix.hpp" | |
11 | // clang-format on | |
12 | ||
13 | #include "../helpers/test.hpp" | |
14 | ||
15 | namespace noexcept_tests { | |
16 | // Test the noexcept is set correctly for the move constructor. | |
17 | ||
18 | struct hash_possible_exception : boost::hash<int> | |
19 | { | |
20 | hash_possible_exception(hash_possible_exception const&) {} | |
21 | }; | |
22 | ||
23 | struct equal_to_possible_exception : std::equal_to<int> | |
24 | { | |
25 | equal_to_possible_exception(equal_to_possible_exception const&) {} | |
26 | }; | |
27 | ||
28 | // Test that the move constructor does actually move without throwing | |
29 | // an exception when it claims to. | |
30 | ||
31 | struct test_exception | |
32 | { | |
33 | }; | |
34 | ||
35 | bool throwing_test_exception = false; | |
36 | void test_throw(char const* name) | |
37 | { | |
38 | if (throwing_test_exception) { | |
39 | BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Throw exception in: " << name | |
40 | << std::endl; | |
41 | throw test_exception(); | |
42 | } | |
43 | } | |
44 | ||
45 | class hash_nothrow_move : boost::hash<int> | |
46 | { | |
47 | BOOST_COPYABLE_AND_MOVABLE(hash_nothrow_move) | |
48 | ||
49 | typedef boost::hash<int> base; | |
50 | ||
51 | public: | |
52 | hash_nothrow_move(BOOST_RV_REF(hash_nothrow_move)) BOOST_NOEXCEPT {} | |
53 | ||
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)) | |
57 | { | |
58 | test_throw("Assign"); | |
59 | return *this; | |
60 | } | |
61 | hash_nothrow_move& operator=(BOOST_RV_REF(hash_nothrow_move)) | |
62 | { | |
63 | test_throw("Move Assign"); | |
64 | return *this; | |
65 | } | |
66 | std::size_t operator()(int x) const | |
67 | { | |
68 | test_throw("Operator"); | |
69 | return static_cast<base const&>(*this)(x); | |
70 | } | |
71 | }; | |
72 | ||
73 | class equal_to_nothrow_move : std::equal_to<int> | |
74 | { | |
75 | BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow_move) | |
76 | ||
77 | typedef std::equal_to<int> base; | |
78 | ||
79 | public: | |
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)) | |
85 | { | |
86 | test_throw("Assign"); | |
87 | return *this; | |
88 | } | |
89 | equal_to_nothrow_move& operator=(BOOST_RV_REF(equal_to_nothrow_move)) | |
90 | { | |
91 | test_throw("Move Assign"); | |
92 | return *this; | |
93 | } | |
94 | std::size_t operator()(int x, int y) const | |
95 | { | |
96 | test_throw("Operator"); | |
97 | return static_cast<base const&>(*this)(x, y); | |
98 | } | |
99 | }; | |
100 | ||
101 | bool have_is_nothrow_move = false; | |
102 | ||
103 | UNORDERED_AUTO_TEST (check_is_nothrow_move) { | |
104 | BOOST_TEST( | |
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; | |
108 | ||
109 | // Copied from boost::is_nothrow_move_constructible implementation | |
110 | // to make sure this does actually detect it when expected. | |
111 | // | |
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()', | |
114 | // not noexcept. | |
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); | |
118 | #endif | |
119 | } | |
120 | ||
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)); | |
131 | } | |
132 | ||
133 | BOOST_TEST((!boost::is_nothrow_move_constructible< | |
134 | boost::unordered_set<int, hash_possible_exception> >::value)); | |
135 | BOOST_TEST( | |
136 | (!boost::is_nothrow_move_constructible<boost::unordered_multiset<int, | |
137 | boost::hash<int>, equal_to_possible_exception> >::value)); | |
138 | } | |
139 | ||
140 | UNORDERED_AUTO_TEST (test_no_throw_when_noexcept) { | |
141 | typedef boost::unordered_set<int, hash_nothrow_move, equal_to_nothrow_move> | |
142 | throwing_set; | |
143 | ||
144 | if (have_is_nothrow_move) { | |
145 | BOOST_TEST(boost::is_nothrow_move_constructible<throwing_set>::value); | |
146 | ||
147 | throwing_test_exception = false; | |
148 | ||
149 | throwing_set x1; | |
150 | x1.insert(10); | |
151 | x1.insert(50); | |
152 | ||
153 | try { | |
154 | throwing_test_exception = true; | |
155 | ||
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) { | |
160 | BOOST_TEST(false); | |
161 | } | |
162 | ||
163 | throwing_test_exception = false; | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | RUN_TESTS() |