• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if defined(BOOST_MSVC)
16 #pragma warning(push)
17 // conditional expression is constant
18 #pragma warning(disable : 4127)
19 #endif
20 
21 namespace noexcept_tests {
22   // Test the noexcept is set correctly for the move constructor.
23 
24   struct hash_possible_exception : boost::hash<int>
25   {
hash_possible_exceptionnoexcept_tests::hash_possible_exception26     hash_possible_exception(hash_possible_exception const&) {}
operator =noexcept_tests::hash_possible_exception27     hash_possible_exception& operator=(hash_possible_exception const&)
28     {
29       return *this;
30     }
31   };
32 
33   struct equal_to_possible_exception : std::equal_to<int>
34   {
equal_to_possible_exceptionnoexcept_tests::equal_to_possible_exception35     equal_to_possible_exception(equal_to_possible_exception const&) {}
operator =noexcept_tests::equal_to_possible_exception36     equal_to_possible_exception& operator=(equal_to_possible_exception const&)
37     {
38       return *this;
39     }
40   };
41 
42   // Test that the move constructor does actually move without throwing
43   // an exception when it claims to.
44 
45   struct test_exception
46   {
47   };
48 
49   bool throwing_test_exception = false;
test_throw(char const * name)50   void test_throw(char const* name)
51   {
52     if (throwing_test_exception) {
53       BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Throw exception in: " << name
54                                      << std::endl;
55       throw test_exception();
56     }
57   }
58 
59   template <bool nothrow_move_construct, bool nothrow_move_assign,
60     bool nothrow_swap>
61   class hash_nothrow : boost::hash<int>
62   {
63     BOOST_COPYABLE_AND_MOVABLE(hash_nothrow)
64 
65     typedef boost::hash<int> base;
66 
67   public:
68     hash_nothrow(BOOST_RV_REF(hash_nothrow))
BOOST_NOEXCEPT_IF(nothrow_move_construct)69       BOOST_NOEXCEPT_IF(nothrow_move_construct)
70     {
71       if (!nothrow_move_construct) {
72         test_throw("Move Constructor");
73       }
74     }
75 
hash_nothrow()76     hash_nothrow() { test_throw("Constructor"); }
hash_nothrow(hash_nothrow const &)77     hash_nothrow(hash_nothrow const&) { test_throw("Copy"); }
operator =(BOOST_COPY_ASSIGN_REF (hash_nothrow))78     hash_nothrow& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow))
79     {
80       test_throw("Assign");
81       return *this;
82     }
operator =(BOOST_RV_REF (hash_nothrow))83     hash_nothrow& operator=(BOOST_RV_REF(hash_nothrow))
84       BOOST_NOEXCEPT_IF(nothrow_move_assign)
85     {
86       if (!nothrow_move_assign) {
87         test_throw("Move Assign");
88       }
89       return *this;
90     }
operator ()(int x) const91     std::size_t operator()(int x) const
92     {
93       test_throw("Operator");
94       return static_cast<base const&>(*this)(x);
95     }
swap(hash_nothrow &,hash_nothrow &)96     friend void swap(hash_nothrow&, hash_nothrow&)
97       BOOST_NOEXCEPT_IF(nothrow_swap)
98     {
99       if (!nothrow_swap) {
100         test_throw("Swap");
101       }
102     }
103   };
104 
105   typedef hash_nothrow<true, false, false> hash_nothrow_move_construct;
106   typedef hash_nothrow<false, true, false> hash_nothrow_move_assign;
107   typedef hash_nothrow<false, false, true> hash_nothrow_swap;
108 
109   template <bool nothrow_move_construct, bool nothrow_move_assign,
110     bool nothrow_swap>
111   class equal_to_nothrow
112   {
113     BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow)
114 
115     typedef boost::hash<int> base;
116 
117   public:
118     equal_to_nothrow(BOOST_RV_REF(equal_to_nothrow))
BOOST_NOEXCEPT_IF(nothrow_move_construct)119       BOOST_NOEXCEPT_IF(nothrow_move_construct)
120     {
121       if (!nothrow_move_construct) {
122         test_throw("Move Constructor");
123       }
124     }
125 
equal_to_nothrow()126     equal_to_nothrow() { test_throw("Constructor"); }
equal_to_nothrow(equal_to_nothrow const &)127     equal_to_nothrow(equal_to_nothrow const&) { test_throw("Copy"); }
operator =(BOOST_COPY_ASSIGN_REF (equal_to_nothrow))128     equal_to_nothrow& operator=(BOOST_COPY_ASSIGN_REF(equal_to_nothrow))
129     {
130       test_throw("Assign");
131       return *this;
132     }
operator =(BOOST_RV_REF (equal_to_nothrow))133     equal_to_nothrow& operator=(BOOST_RV_REF(equal_to_nothrow))
134       BOOST_NOEXCEPT_IF(nothrow_move_assign)
135     {
136       if (!nothrow_move_assign) {
137         test_throw("Move Assign");
138       }
139       return *this;
140     }
operator ()(int x,int y) const141     std::size_t operator()(int x, int y) const
142     {
143       test_throw("Operator");
144       return x == y;
145     }
swap(equal_to_nothrow &,equal_to_nothrow &)146     friend void swap(equal_to_nothrow&, equal_to_nothrow&)
147       BOOST_NOEXCEPT_IF(nothrow_swap)
148     {
149       if (!nothrow_swap) {
150         test_throw("Swap");
151       }
152     }
153   };
154 
155   typedef equal_to_nothrow<true, false, false> equal_to_nothrow_move_construct;
156   typedef equal_to_nothrow<false, true, false> equal_to_nothrow_move_assign;
157   typedef equal_to_nothrow<false, false, true> equal_to_nothrow_swap;
158 
159   bool have_is_nothrow_move = false;
160   bool have_is_nothrow_move_assign = false;
161   bool have_is_nothrow_swap = false;
162 
UNORDERED_AUTO_TEST(check_is_nothrow_move)163   UNORDERED_AUTO_TEST (check_is_nothrow_move) {
164     BOOST_TEST(
165       !boost::is_nothrow_move_constructible<hash_possible_exception>::value);
166     BOOST_TEST(
167       !boost::is_nothrow_move_assignable<hash_possible_exception>::value);
168     BOOST_TEST(!boost::is_nothrow_swappable<hash_possible_exception>::value);
169     BOOST_TEST((!boost::is_nothrow_move_constructible<
170                 equal_to_nothrow<false, false, false> >::value));
171     BOOST_TEST((!boost::is_nothrow_move_assignable<
172                 equal_to_nothrow<false, false, false> >::value));
173     BOOST_TEST((!boost::is_nothrow_swappable<
174                 equal_to_nothrow<false, false, false> >::value));
175 
176     have_is_nothrow_move =
177       boost::is_nothrow_move_constructible<hash_nothrow_move_construct>::value;
178     have_is_nothrow_move_assign =
179       boost::is_nothrow_move_assignable<hash_nothrow_move_assign>::value;
180     have_is_nothrow_swap =
181       boost::is_nothrow_swappable<hash_nothrow_swap>::value;
182 
183 // Check that the traits work when expected.
184 #if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) &&     \
185   !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
186     BOOST_TEST(have_is_nothrow_move);
187     BOOST_TEST(have_is_nothrow_move_assign);
188 #endif
189 
190 #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_NOEXCEPT) &&     \
191   !defined(BOOST_NO_CXX11_DECLTYPE) &&                                         \
192   !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS)
193     BOOST_TEST(have_is_nothrow_swap);
194 #endif
195 
196     BOOST_LIGHTWEIGHT_TEST_OSTREAM
197       << "have_is_nothrow_move: " << have_is_nothrow_move << std::endl
198       << "have_is_nothrow_swap: " << have_is_nothrow_swap << std::endl;
199   }
200 
UNORDERED_AUTO_TEST(test_noexcept)201   UNORDERED_AUTO_TEST (test_noexcept) {
202     if (have_is_nothrow_move) {
203       BOOST_TEST((boost::is_nothrow_move_constructible<
204         boost::unordered_set<int> >::value));
205       BOOST_TEST((boost::is_nothrow_move_constructible<
206         boost::unordered_multiset<int> >::value));
207       BOOST_TEST((boost::is_nothrow_move_constructible<
208         boost::unordered_map<int, int> >::value));
209       BOOST_TEST((boost::is_nothrow_move_constructible<
210         boost::unordered_multimap<int, int> >::value));
211     }
212 
213     BOOST_TEST((!boost::is_nothrow_move_constructible<
214                 boost::unordered_set<int, hash_possible_exception> >::value));
215     BOOST_TEST(
216       (!boost::is_nothrow_move_constructible<boost::unordered_multiset<int,
217           boost::hash<int>, equal_to_possible_exception> >::value));
218   }
219 
UNORDERED_AUTO_TEST(test_nothrow_move_when_noexcept)220   UNORDERED_AUTO_TEST (test_nothrow_move_when_noexcept) {
221     typedef boost::unordered_set<int, hash_nothrow_move_construct,
222       equal_to_nothrow_move_construct>
223       throwing_set;
224 
225     if (have_is_nothrow_move) {
226       BOOST_TEST(boost::is_nothrow_move_constructible<throwing_set>::value);
227     }
228 
229     throwing_test_exception = false;
230 
231     throwing_set x1;
232     x1.insert(10);
233     x1.insert(50);
234 
235     try {
236       throwing_test_exception = true;
237 
238       throwing_set x2 = boost::move(x1);
239       BOOST_TEST(x2.size() == 2);
240       BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
241       BOOST_TEST(have_is_nothrow_move);
242     } catch (test_exception) {
243       BOOST_TEST(!have_is_nothrow_move);
244     }
245 
246     throwing_test_exception = false;
247   }
248 
UNORDERED_AUTO_TEST(test_nothrow_move_assign_when_noexcept)249   UNORDERED_AUTO_TEST (test_nothrow_move_assign_when_noexcept) {
250     typedef boost::unordered_set<int, hash_nothrow_move_assign,
251       equal_to_nothrow_move_assign>
252       throwing_set;
253 
254     if (have_is_nothrow_move_assign) {
255       BOOST_TEST(boost::is_nothrow_move_assignable<throwing_set>::value);
256     }
257 
258     throwing_test_exception = false;
259 
260     throwing_set x1;
261     throwing_set x2;
262     x1.insert(10);
263     x1.insert(50);
264     for (int i = 0; i < 100; ++i) {
265       x2.insert(i);
266     }
267 
268     try {
269       throwing_test_exception = true;
270 
271       x2 = boost::move(x1);
272       BOOST_TEST(x2.size() == 2);
273       BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
274       BOOST_TEST(have_is_nothrow_move_assign);
275     } catch (test_exception) {
276       BOOST_TEST(!have_is_nothrow_move_assign);
277     }
278 
279     throwing_test_exception = false;
280   }
281 
UNORDERED_AUTO_TEST(test_nothrow_swap_when_noexcept)282   UNORDERED_AUTO_TEST (test_nothrow_swap_when_noexcept) {
283     typedef boost::unordered_set<int, hash_nothrow_swap, equal_to_nothrow_swap>
284       throwing_set;
285 
286     if (have_is_nothrow_swap) {
287       BOOST_TEST(boost::is_nothrow_swappable<throwing_set>::value);
288     }
289 
290     throwing_test_exception = false;
291 
292     throwing_set x1;
293     throwing_set x2;
294     x1.insert(10);
295     x1.insert(50);
296     for (int i = 0; i < 100; ++i) {
297       x2.insert(i);
298     }
299 
300     try {
301       throwing_test_exception = true;
302 
303       x1.swap(x2);
304       BOOST_TEST(x1.size() == 100);
305       BOOST_TEST(x2.size() == 2);
306       BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
307       BOOST_TEST(have_is_nothrow_swap);
308     } catch (test_exception) {
309       BOOST_TEST(!have_is_nothrow_swap);
310     }
311 
312     throwing_test_exception = false;
313   }
314 }
315 
316 #if defined(BOOST_MSVC)
317 #pragma warning(pop)
318 #endif
319 
320 RUN_TESTS()
321