]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011 Helge Bahmann |
b32b8144 | 2 | // Copyright (c) 2017 Andrey Semashev |
7c673cae FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. | |
5 | // See accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | #ifndef BOOST_ATOMIC_API_TEST_HELPERS_HPP | |
9 | #define BOOST_ATOMIC_API_TEST_HELPERS_HPP | |
10 | ||
11 | #include <boost/atomic.hpp> | |
b32b8144 | 12 | #include <cstddef> |
7c673cae | 13 | #include <cstring> |
b32b8144 FG |
14 | #include <limits> |
15 | #include <iostream> | |
7c673cae FG |
16 | #include <boost/config.hpp> |
17 | #include <boost/cstdint.hpp> | |
7c673cae | 18 | #include <boost/type_traits/integral_constant.hpp> |
b32b8144 | 19 | #include <boost/type_traits/is_signed.hpp> |
7c673cae FG |
20 | #include <boost/type_traits/is_unsigned.hpp> |
21 | ||
b32b8144 FG |
22 | struct test_stream_type |
23 | { | |
24 | typedef std::ios_base& (*ios_base_manip)(std::ios_base&); | |
25 | typedef std::basic_ios< char, std::char_traits< char > >& (*basic_ios_manip)(std::basic_ios< char, std::char_traits< char > >&); | |
26 | typedef std::ostream& (*stream_manip)(std::ostream&); | |
27 | ||
28 | template< typename T > | |
29 | test_stream_type const& operator<< (T const& value) const | |
30 | { | |
31 | std::cerr << value; | |
32 | return *this; | |
33 | } | |
34 | ||
35 | test_stream_type const& operator<< (ios_base_manip manip) const | |
36 | { | |
37 | std::cerr << manip; | |
38 | return *this; | |
39 | } | |
40 | test_stream_type const& operator<< (basic_ios_manip manip) const | |
41 | { | |
42 | std::cerr << manip; | |
43 | return *this; | |
44 | } | |
45 | test_stream_type const& operator<< (stream_manip manip) const | |
46 | { | |
47 | std::cerr << manip; | |
48 | return *this; | |
49 | } | |
50 | ||
51 | // Make sure characters are printed as numbers if tests fail | |
52 | test_stream_type const& operator<< (char value) const | |
53 | { | |
54 | std::cerr << static_cast< int >(value); | |
55 | return *this; | |
56 | } | |
57 | test_stream_type const& operator<< (signed char value) const | |
58 | { | |
59 | std::cerr << static_cast< int >(value); | |
60 | return *this; | |
61 | } | |
62 | test_stream_type const& operator<< (unsigned char value) const | |
63 | { | |
64 | std::cerr << static_cast< unsigned int >(value); | |
65 | return *this; | |
66 | } | |
67 | test_stream_type const& operator<< (short value) const | |
68 | { | |
69 | std::cerr << static_cast< int >(value); | |
70 | return *this; | |
71 | } | |
72 | test_stream_type const& operator<< (unsigned short value) const | |
73 | { | |
74 | std::cerr << static_cast< unsigned int >(value); | |
75 | return *this; | |
76 | } | |
77 | ||
78 | #if defined(BOOST_HAS_INT128) | |
79 | // Some GCC versions don't provide output operators for __int128 | |
80 | test_stream_type const& operator<< (boost::int128_type const& v) const | |
81 | { | |
82 | std::cerr << static_cast< long long >(v); | |
83 | return *this; | |
84 | } | |
85 | test_stream_type const& operator<< (boost::uint128_type const& v) const | |
86 | { | |
87 | std::cerr << static_cast< unsigned long long >(v); | |
88 | return *this; | |
89 | } | |
90 | #endif // defined(BOOST_HAS_INT128) | |
91 | }; | |
92 | ||
93 | const test_stream_type test_stream = {}; | |
94 | ||
95 | #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream | |
96 | ||
97 | #include <boost/core/lightweight_test.hpp> | |
98 | ||
7c673cae FG |
99 | /* provide helpers that exercise whether the API |
100 | functions of "boost::atomic" provide the correct | |
101 | operational semantic in the case of sequential | |
102 | execution */ | |
103 | ||
104 | static void | |
105 | test_flag_api(void) | |
106 | { | |
107 | #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT | |
108 | boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT; | |
109 | #else | |
110 | boost::atomic_flag f; | |
111 | #endif | |
112 | ||
113 | BOOST_TEST( !f.test_and_set() ); | |
114 | BOOST_TEST( f.test_and_set() ); | |
115 | f.clear(); | |
116 | BOOST_TEST( !f.test_and_set() ); | |
117 | } | |
118 | ||
119 | template<typename T> | |
120 | void test_base_operators(T value1, T value2, T value3) | |
121 | { | |
122 | /* explicit load/store */ | |
123 | { | |
124 | boost::atomic<T> a(value1); | |
b32b8144 | 125 | BOOST_TEST_EQ( a.load(), value1 ); |
7c673cae FG |
126 | } |
127 | ||
128 | { | |
129 | boost::atomic<T> a(value1); | |
130 | a.store(value2); | |
b32b8144 | 131 | BOOST_TEST_EQ( a.load(), value2 ); |
7c673cae FG |
132 | } |
133 | ||
134 | /* overloaded assignment/conversion */ | |
135 | { | |
136 | boost::atomic<T> a(value1); | |
137 | BOOST_TEST( value1 == a ); | |
138 | } | |
139 | ||
140 | { | |
141 | boost::atomic<T> a; | |
142 | a = value2; | |
143 | BOOST_TEST( value2 == a ); | |
144 | } | |
145 | ||
146 | /* exchange-type operators */ | |
147 | { | |
148 | boost::atomic<T> a(value1); | |
149 | T n = a.exchange(value2); | |
b32b8144 FG |
150 | BOOST_TEST_EQ( a.load(), value2 ); |
151 | BOOST_TEST_EQ( n, value1 ); | |
7c673cae FG |
152 | } |
153 | ||
154 | { | |
155 | boost::atomic<T> a(value1); | |
156 | T expected = value1; | |
157 | bool success = a.compare_exchange_strong(expected, value3); | |
158 | BOOST_TEST( success ); | |
b32b8144 FG |
159 | BOOST_TEST_EQ( a.load(), value3 ); |
160 | BOOST_TEST_EQ( expected, value1 ); | |
7c673cae FG |
161 | } |
162 | ||
163 | { | |
164 | boost::atomic<T> a(value1); | |
165 | T expected = value2; | |
166 | bool success = a.compare_exchange_strong(expected, value3); | |
167 | BOOST_TEST( !success ); | |
b32b8144 FG |
168 | BOOST_TEST_EQ( a.load(), value1 ); |
169 | BOOST_TEST_EQ( expected, value1 ); | |
7c673cae FG |
170 | } |
171 | ||
172 | { | |
173 | boost::atomic<T> a(value1); | |
174 | T expected; | |
175 | bool success; | |
176 | do { | |
177 | expected = value1; | |
178 | success = a.compare_exchange_weak(expected, value3); | |
179 | } while(!success); | |
180 | BOOST_TEST( success ); | |
b32b8144 FG |
181 | BOOST_TEST_EQ( a.load(), value3 ); |
182 | BOOST_TEST_EQ( expected, value1 ); | |
7c673cae FG |
183 | } |
184 | ||
185 | { | |
186 | boost::atomic<T> a(value1); | |
187 | T expected; | |
188 | bool success; | |
189 | do { | |
190 | expected = value2; | |
191 | success = a.compare_exchange_weak(expected, value3); | |
192 | if (expected != value2) | |
193 | break; | |
194 | } while(!success); | |
195 | BOOST_TEST( !success ); | |
b32b8144 FG |
196 | BOOST_TEST_EQ( a.load(), value1 ); |
197 | BOOST_TEST_EQ( expected, value1 ); | |
7c673cae FG |
198 | } |
199 | } | |
200 | ||
201 | // T requires an int constructor | |
202 | template <typename T> | |
203 | void test_constexpr_ctor() | |
204 | { | |
205 | #ifndef BOOST_NO_CXX11_CONSTEXPR | |
206 | const T value(0); | |
207 | const boost::atomic<T> tester(value); | |
208 | BOOST_TEST( tester == value ); | |
209 | #endif | |
210 | } | |
211 | ||
b32b8144 FG |
212 | //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow |
213 | template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value > | |
214 | struct distance_limits | |
215 | { | |
216 | static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
217 | { | |
218 | return (std::numeric_limits< D >::min)(); | |
219 | } | |
220 | static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
221 | { | |
222 | return (std::numeric_limits< D >::max)(); | |
223 | } | |
224 | }; | |
225 | ||
226 | #if defined(BOOST_MSVC) | |
227 | #pragma warning(push) | |
228 | // 'static_cast': truncation of constant value. There is no actual truncation happening because | |
229 | // the cast is only performed if the value fits in the range of the result. | |
230 | #pragma warning(disable: 4309) | |
231 | #endif | |
232 | ||
233 | template< typename T, typename D > | |
234 | struct distance_limits< T*, D, true > | |
235 | { | |
236 | static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
237 | { | |
238 | const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T)); | |
239 | const D diff = (std::numeric_limits< D >::min)(); | |
240 | // Both values are negative. Return the closest value to zero. | |
241 | return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff; | |
242 | } | |
243 | static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
244 | { | |
245 | const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T)); | |
246 | const D diff = (std::numeric_limits< D >::max)(); | |
247 | // Both values are positive. Return the closest value to zero. | |
248 | return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff; | |
249 | } | |
250 | }; | |
251 | ||
252 | template< typename T, typename D > | |
253 | struct distance_limits< T*, D, false > | |
254 | { | |
255 | static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
256 | { | |
257 | return (std::numeric_limits< D >::min)(); | |
258 | } | |
259 | static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
260 | { | |
261 | const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T); | |
262 | const D diff = (std::numeric_limits< D >::max)(); | |
263 | return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff; | |
264 | } | |
265 | }; | |
266 | ||
267 | #if defined(BOOST_HAS_INT128) | |
268 | ||
269 | // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled). | |
270 | // So we have to specialize the limits ourself. We assume two's complement signed representation. | |
271 | template< typename T, bool IsSigned > | |
272 | struct distance_limits< T, boost::int128_type, IsSigned > | |
273 | { | |
274 | static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
275 | { | |
276 | return -(max)() - 1; | |
277 | } | |
278 | static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
279 | { | |
280 | return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1); | |
281 | } | |
282 | }; | |
283 | ||
284 | template< typename T, bool IsSigned > | |
285 | struct distance_limits< T, boost::uint128_type, IsSigned > | |
286 | { | |
287 | static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
288 | { | |
289 | return 0u; | |
290 | } | |
291 | static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT | |
292 | { | |
293 | return ~static_cast< boost::uint128_type >(0u); | |
294 | } | |
295 | }; | |
296 | ||
297 | #endif // defined(BOOST_HAS_INT128) | |
298 | ||
299 | #if defined(BOOST_MSVC) | |
300 | #pragma warning(pop) | |
301 | #endif | |
302 | ||
303 | template<typename T, typename D, typename AddType> | |
304 | void test_additive_operators_with_type_and_test() | |
305 | { | |
306 | // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code | |
307 | const T zero_value = 0; | |
308 | const D zero_diff = 0; | |
309 | const D one_diff = 1; | |
310 | const AddType zero_add = 0; | |
311 | { | |
312 | boost::atomic<T> a(zero_value); | |
313 | bool f = a.add_and_test(zero_diff); | |
314 | BOOST_TEST_EQ( f, true ); | |
315 | BOOST_TEST_EQ( a.load(), zero_value ); | |
316 | ||
317 | f = a.add_and_test(one_diff); | |
318 | BOOST_TEST_EQ( f, false ); | |
319 | BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) ); | |
320 | } | |
321 | { | |
322 | boost::atomic<T> a(zero_value); | |
323 | bool f = a.add_and_test((distance_limits< T, D >::max)()); | |
324 | BOOST_TEST_EQ( f, false ); | |
325 | BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) ); | |
326 | } | |
327 | { | |
328 | boost::atomic<T> a(zero_value); | |
329 | bool f = a.add_and_test((distance_limits< T, D >::min)()); | |
330 | BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() == 0) ); | |
331 | BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) ); | |
332 | } | |
333 | ||
334 | { | |
335 | boost::atomic<T> a(zero_value); | |
336 | bool f = a.sub_and_test(zero_diff); | |
337 | BOOST_TEST_EQ( f, true ); | |
338 | BOOST_TEST_EQ( a.load(), zero_value ); | |
339 | ||
340 | f = a.sub_and_test(one_diff); | |
341 | BOOST_TEST_EQ( f, false ); | |
342 | BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) ); | |
343 | } | |
344 | { | |
345 | boost::atomic<T> a(zero_value); | |
346 | bool f = a.sub_and_test((distance_limits< T, D >::max)()); | |
347 | BOOST_TEST_EQ( f, false ); | |
348 | BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) ); | |
349 | } | |
350 | { | |
351 | boost::atomic<T> a(zero_value); | |
352 | bool f = a.sub_and_test((distance_limits< T, D >::min)()); | |
353 | BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() == 0) ); | |
354 | BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::min)()) ); | |
355 | } | |
356 | } | |
357 | ||
7c673cae FG |
358 | template<typename T, typename D, typename AddType> |
359 | void test_additive_operators_with_type(T value, D delta) | |
360 | { | |
361 | /* note: the tests explicitly cast the result of any addition | |
362 | to the type to be tested to force truncation of the result to | |
363 | the correct range in case of overflow */ | |
364 | ||
365 | /* explicit add/sub */ | |
366 | { | |
367 | boost::atomic<T> a(value); | |
368 | T n = a.fetch_add(delta); | |
b32b8144 FG |
369 | BOOST_TEST_EQ( a.load(), T((AddType)value + delta) ); |
370 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
371 | } |
372 | ||
373 | { | |
374 | boost::atomic<T> a(value); | |
375 | T n = a.fetch_sub(delta); | |
b32b8144 FG |
376 | BOOST_TEST_EQ( a.load(), T((AddType)value - delta) ); |
377 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
378 | } |
379 | ||
380 | /* overloaded modify/assign*/ | |
381 | { | |
382 | boost::atomic<T> a(value); | |
383 | T n = (a += delta); | |
b32b8144 FG |
384 | BOOST_TEST_EQ( a.load(), T((AddType)value + delta) ); |
385 | BOOST_TEST_EQ( n, T((AddType)value + delta) ); | |
7c673cae FG |
386 | } |
387 | ||
388 | { | |
389 | boost::atomic<T> a(value); | |
390 | T n = (a -= delta); | |
b32b8144 FG |
391 | BOOST_TEST_EQ( a.load(), T((AddType)value - delta) ); |
392 | BOOST_TEST_EQ( n, T((AddType)value - delta) ); | |
7c673cae FG |
393 | } |
394 | ||
395 | /* overloaded increment/decrement */ | |
396 | { | |
397 | boost::atomic<T> a(value); | |
398 | T n = a++; | |
b32b8144 FG |
399 | BOOST_TEST_EQ( a.load(), T((AddType)value + 1) ); |
400 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
401 | } |
402 | ||
403 | { | |
404 | boost::atomic<T> a(value); | |
405 | T n = ++a; | |
b32b8144 FG |
406 | BOOST_TEST_EQ( a.load(), T((AddType)value + 1) ); |
407 | BOOST_TEST_EQ( n, T((AddType)value + 1) ); | |
7c673cae FG |
408 | } |
409 | ||
410 | { | |
411 | boost::atomic<T> a(value); | |
412 | T n = a--; | |
b32b8144 FG |
413 | BOOST_TEST_EQ( a.load(), T((AddType)value - 1) ); |
414 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
415 | } |
416 | ||
417 | { | |
418 | boost::atomic<T> a(value); | |
419 | T n = --a; | |
b32b8144 FG |
420 | BOOST_TEST_EQ( a.load(), T((AddType)value - 1) ); |
421 | BOOST_TEST_EQ( n, T((AddType)value - 1) ); | |
7c673cae | 422 | } |
b32b8144 FG |
423 | |
424 | // Opaque operations | |
425 | { | |
426 | boost::atomic<T> a(value); | |
427 | a.opaque_add(delta); | |
428 | BOOST_TEST_EQ( a.load(), T((AddType)value + delta) ); | |
429 | } | |
430 | ||
431 | { | |
432 | boost::atomic<T> a(value); | |
433 | a.opaque_sub(delta); | |
434 | BOOST_TEST_EQ( a.load(), T((AddType)value - delta) ); | |
435 | } | |
436 | ||
437 | // Modify and test operations | |
438 | test_additive_operators_with_type_and_test< T, D, AddType >(); | |
7c673cae FG |
439 | } |
440 | ||
441 | template<typename T, typename D> | |
442 | void test_additive_operators(T value, D delta) | |
443 | { | |
444 | test_additive_operators_with_type<T, D, T>(value, delta); | |
445 | } | |
446 | ||
b32b8144 FG |
447 | template< typename T > |
448 | void test_negation() | |
449 | { | |
450 | { | |
451 | boost::atomic<T> a((T)1); | |
452 | T n = a.fetch_negate(); | |
453 | BOOST_TEST_EQ( a.load(), (T)-1 ); | |
454 | BOOST_TEST_EQ( n, (T)1 ); | |
455 | ||
456 | n = a.fetch_negate(); | |
457 | BOOST_TEST_EQ( a.load(), (T)1 ); | |
458 | BOOST_TEST_EQ( n, (T)-1 ); | |
459 | } | |
460 | { | |
461 | boost::atomic<T> a((T)1); | |
462 | a.opaque_negate(); | |
463 | BOOST_TEST_EQ( a.load(), (T)-1 ); | |
464 | ||
465 | a.opaque_negate(); | |
466 | BOOST_TEST_EQ( a.load(), (T)1 ); | |
467 | } | |
468 | } | |
469 | ||
7c673cae FG |
470 | template<typename T> |
471 | void test_additive_wrap(T value) | |
472 | { | |
473 | { | |
474 | boost::atomic<T> a(value); | |
b32b8144 FG |
475 | T n = a.fetch_add(1) + (T)1; |
476 | BOOST_TEST_EQ( a.load(), n ); | |
7c673cae FG |
477 | } |
478 | { | |
479 | boost::atomic<T> a(value); | |
b32b8144 FG |
480 | T n = a.fetch_sub(1) - (T)1; |
481 | BOOST_TEST_EQ( a.load(), n ); | |
7c673cae FG |
482 | } |
483 | } | |
484 | ||
485 | template<typename T> | |
486 | void test_bit_operators(T value, T delta) | |
487 | { | |
488 | /* explicit and/or/xor */ | |
489 | { | |
490 | boost::atomic<T> a(value); | |
491 | T n = a.fetch_and(delta); | |
b32b8144 FG |
492 | BOOST_TEST_EQ( a.load(), T(value & delta) ); |
493 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
494 | } |
495 | ||
496 | { | |
497 | boost::atomic<T> a(value); | |
498 | T n = a.fetch_or(delta); | |
b32b8144 FG |
499 | BOOST_TEST_EQ( a.load(), T(value | delta) ); |
500 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
501 | } |
502 | ||
503 | { | |
504 | boost::atomic<T> a(value); | |
505 | T n = a.fetch_xor(delta); | |
b32b8144 FG |
506 | BOOST_TEST_EQ( a.load(), T(value ^ delta) ); |
507 | BOOST_TEST_EQ( n, value ); | |
508 | } | |
509 | ||
510 | { | |
511 | boost::atomic<T> a(value); | |
512 | T n = a.fetch_complement(); | |
513 | BOOST_TEST_EQ( a.load(), T(~value) ); | |
514 | BOOST_TEST_EQ( n, value ); | |
7c673cae FG |
515 | } |
516 | ||
517 | /* overloaded modify/assign */ | |
518 | { | |
519 | boost::atomic<T> a(value); | |
520 | T n = (a &= delta); | |
b32b8144 FG |
521 | BOOST_TEST_EQ( a.load(), T(value & delta) ); |
522 | BOOST_TEST_EQ( n, T(value & delta) ); | |
7c673cae FG |
523 | } |
524 | ||
525 | { | |
526 | boost::atomic<T> a(value); | |
527 | T n = (a |= delta); | |
b32b8144 FG |
528 | BOOST_TEST_EQ( a.load(), T(value | delta) ); |
529 | BOOST_TEST_EQ( n, T(value | delta) ); | |
7c673cae FG |
530 | } |
531 | ||
532 | { | |
533 | boost::atomic<T> a(value); | |
534 | T n = (a ^= delta); | |
b32b8144 FG |
535 | BOOST_TEST_EQ( a.load(), T(value ^ delta) ); |
536 | BOOST_TEST_EQ( n, T(value ^ delta) ); | |
537 | } | |
538 | ||
539 | // Opaque operations | |
540 | { | |
541 | boost::atomic<T> a(value); | |
542 | a.opaque_and(delta); | |
543 | BOOST_TEST_EQ( a.load(), T(value & delta) ); | |
544 | } | |
545 | ||
546 | { | |
547 | boost::atomic<T> a(value); | |
548 | a.opaque_or(delta); | |
549 | BOOST_TEST_EQ( a.load(), T(value | delta) ); | |
550 | } | |
551 | ||
552 | { | |
553 | boost::atomic<T> a(value); | |
554 | a.opaque_xor(delta); | |
555 | BOOST_TEST_EQ( a.load(), T(value ^ delta) ); | |
556 | } | |
557 | ||
558 | { | |
559 | boost::atomic<T> a(value); | |
560 | a.opaque_complement(); | |
561 | BOOST_TEST_EQ( a.load(), T(~value) ); | |
562 | } | |
563 | ||
564 | // Modify and test operations | |
565 | { | |
566 | boost::atomic<T> a((T)1); | |
567 | bool f = a.and_and_test((T)1); | |
568 | BOOST_TEST_EQ( f, false ); | |
569 | BOOST_TEST_EQ( a.load(), T(1) ); | |
570 | ||
571 | f = a.and_and_test((T)0); | |
572 | BOOST_TEST_EQ( f, true ); | |
573 | BOOST_TEST_EQ( a.load(), T(0) ); | |
574 | ||
575 | f = a.and_and_test((T)0); | |
576 | BOOST_TEST_EQ( f, true ); | |
577 | BOOST_TEST_EQ( a.load(), T(0) ); | |
578 | } | |
579 | ||
580 | { | |
581 | boost::atomic<T> a((T)0); | |
582 | bool f = a.or_and_test((T)0); | |
583 | BOOST_TEST_EQ( f, true ); | |
584 | BOOST_TEST_EQ( a.load(), T(0) ); | |
585 | ||
586 | f = a.or_and_test((T)1); | |
587 | BOOST_TEST_EQ( f, false ); | |
588 | BOOST_TEST_EQ( a.load(), T(1) ); | |
589 | ||
590 | f = a.or_and_test((T)1); | |
591 | BOOST_TEST_EQ( f, false ); | |
592 | BOOST_TEST_EQ( a.load(), T(1) ); | |
593 | } | |
594 | ||
595 | { | |
596 | boost::atomic<T> a((T)0); | |
597 | bool f = a.xor_and_test((T)0); | |
598 | BOOST_TEST_EQ( f, true ); | |
599 | BOOST_TEST_EQ( a.load(), T(0) ); | |
600 | ||
601 | f = a.xor_and_test((T)1); | |
602 | BOOST_TEST_EQ( f, false ); | |
603 | BOOST_TEST_EQ( a.load(), T(1) ); | |
604 | ||
605 | f = a.xor_and_test((T)1); | |
606 | BOOST_TEST_EQ( f, true ); | |
607 | BOOST_TEST_EQ( a.load(), T(0) ); | |
608 | } | |
609 | ||
610 | // Bit test and modify operations | |
611 | { | |
612 | boost::atomic<T> a((T)42); | |
613 | bool f = a.bit_test_and_set(0); | |
614 | BOOST_TEST_EQ( f, false ); | |
615 | BOOST_TEST_EQ( a.load(), T(43) ); | |
616 | ||
617 | f = a.bit_test_and_set(1); | |
618 | BOOST_TEST_EQ( f, true ); | |
619 | BOOST_TEST_EQ( a.load(), T(43) ); | |
620 | ||
621 | f = a.bit_test_and_set(2); | |
622 | BOOST_TEST_EQ( f, false ); | |
623 | BOOST_TEST_EQ( a.load(), T(47) ); | |
624 | } | |
625 | ||
626 | { | |
627 | boost::atomic<T> a((T)42); | |
628 | bool f = a.bit_test_and_reset(0); | |
629 | BOOST_TEST_EQ( f, false ); | |
630 | BOOST_TEST_EQ( a.load(), T(42) ); | |
631 | ||
632 | f = a.bit_test_and_reset(1); | |
633 | BOOST_TEST_EQ( f, true ); | |
634 | BOOST_TEST_EQ( a.load(), T(40) ); | |
635 | ||
636 | f = a.bit_test_and_set(2); | |
637 | BOOST_TEST_EQ( f, false ); | |
638 | BOOST_TEST_EQ( a.load(), T(44) ); | |
639 | } | |
640 | ||
641 | { | |
642 | boost::atomic<T> a((T)42); | |
643 | bool f = a.bit_test_and_complement(0); | |
644 | BOOST_TEST_EQ( f, false ); | |
645 | BOOST_TEST_EQ( a.load(), T(43) ); | |
646 | ||
647 | f = a.bit_test_and_complement(1); | |
648 | BOOST_TEST_EQ( f, true ); | |
649 | BOOST_TEST_EQ( a.load(), T(41) ); | |
650 | ||
651 | f = a.bit_test_and_complement(2); | |
652 | BOOST_TEST_EQ( f, false ); | |
653 | BOOST_TEST_EQ( a.load(), T(45) ); | |
7c673cae FG |
654 | } |
655 | } | |
656 | ||
657 | template<typename T> | |
658 | void do_test_integral_api(boost::false_type) | |
659 | { | |
660 | BOOST_TEST( sizeof(boost::atomic<T>) >= sizeof(T)); | |
661 | ||
662 | test_base_operators<T>(42, 43, 44); | |
663 | test_additive_operators<T, T>(42, 17); | |
664 | test_bit_operators<T>((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL); | |
665 | ||
666 | /* test for unsigned overflow/underflow */ | |
667 | test_additive_operators<T, T>((T)-1, 1); | |
668 | test_additive_operators<T, T>(0, 1); | |
669 | /* test for signed overflow/underflow */ | |
670 | test_additive_operators<T, T>(((T)-1) >> (sizeof(T) * 8 - 1), 1); | |
671 | test_additive_operators<T, T>(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1); | |
672 | } | |
673 | ||
674 | template<typename T> | |
675 | void do_test_integral_api(boost::true_type) | |
676 | { | |
677 | do_test_integral_api<T>(boost::false_type()); | |
678 | ||
679 | test_additive_wrap<T>(0u); | |
b32b8144 FG |
680 | BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u; |
681 | test_additive_wrap<T>(all_ones); | |
682 | BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1; | |
683 | test_additive_wrap<T>(all_ones ^ max_signed_twos_compl); | |
684 | test_additive_wrap<T>(max_signed_twos_compl); | |
7c673cae FG |
685 | } |
686 | ||
687 | template<typename T> | |
688 | inline void test_integral_api(void) | |
689 | { | |
690 | do_test_integral_api<T>(boost::is_unsigned<T>()); | |
b32b8144 FG |
691 | |
692 | if (boost::is_signed<T>::value) | |
693 | test_negation<T>(); | |
7c673cae FG |
694 | } |
695 | ||
696 | template<typename T> | |
697 | void test_pointer_api(void) | |
698 | { | |
b32b8144 FG |
699 | BOOST_TEST_GE( sizeof(boost::atomic<T *>), sizeof(T *)); |
700 | BOOST_TEST_GE( sizeof(boost::atomic<void *>), sizeof(T *)); | |
7c673cae FG |
701 | |
702 | T values[3]; | |
703 | ||
704 | test_base_operators<T*>(&values[0], &values[1], &values[2]); | |
705 | test_additive_operators<T*>(&values[1], 1); | |
706 | ||
707 | test_base_operators<void*>(&values[0], &values[1], &values[2]); | |
7c673cae FG |
708 | |
709 | #if defined(BOOST_HAS_INTPTR_T) | |
710 | boost::atomic<void *> ptr; | |
711 | boost::atomic<boost::intptr_t> integral; | |
b32b8144 | 712 | BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() ); |
7c673cae FG |
713 | #endif |
714 | } | |
715 | ||
b32b8144 FG |
716 | enum test_enum |
717 | { | |
7c673cae FG |
718 | foo, bar, baz |
719 | }; | |
720 | ||
721 | static void | |
722 | test_enum_api(void) | |
723 | { | |
724 | test_base_operators(foo, bar, baz); | |
725 | } | |
726 | ||
727 | template<typename T> | |
b32b8144 FG |
728 | struct test_struct |
729 | { | |
7c673cae FG |
730 | typedef T value_type; |
731 | value_type i; | |
732 | inline bool operator==(const test_struct & c) const {return i == c.i;} | |
733 | inline bool operator!=(const test_struct & c) const {return i != c.i;} | |
734 | }; | |
735 | ||
b32b8144 FG |
736 | template< typename Char, typename Traits, typename T > |
737 | inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s) | |
738 | { | |
739 | test_stream << "{" << s.i << "}"; | |
740 | return strm; | |
741 | } | |
742 | ||
7c673cae FG |
743 | template<typename T> |
744 | void | |
745 | test_struct_api(void) | |
746 | { | |
747 | T a = {1}, b = {2}, c = {3}; | |
748 | ||
749 | test_base_operators(a, b, c); | |
750 | ||
751 | { | |
752 | boost::atomic<T> sa; | |
753 | boost::atomic<typename T::value_type> si; | |
b32b8144 | 754 | BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() ); |
7c673cae FG |
755 | } |
756 | } | |
757 | ||
758 | template<typename T> | |
b32b8144 FG |
759 | struct test_struct_x2 |
760 | { | |
7c673cae FG |
761 | typedef T value_type; |
762 | value_type i, j; | |
763 | inline bool operator==(const test_struct_x2 & c) const {return i == c.i && j == c.j;} | |
764 | inline bool operator!=(const test_struct_x2 & c) const {return i != c.i && j != c.j;} | |
765 | }; | |
766 | ||
b32b8144 FG |
767 | template< typename Char, typename Traits, typename T > |
768 | inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s) | |
769 | { | |
770 | test_stream << "{" << s.i << ", " << s.j << "}"; | |
771 | return strm; | |
772 | } | |
773 | ||
7c673cae FG |
774 | template<typename T> |
775 | void | |
776 | test_struct_x2_api(void) | |
777 | { | |
778 | T a = {1, 1}, b = {2, 2}, c = {3, 3}; | |
779 | ||
780 | test_base_operators(a, b, c); | |
781 | } | |
782 | ||
b32b8144 FG |
783 | struct large_struct |
784 | { | |
7c673cae FG |
785 | long data[64]; |
786 | ||
787 | inline bool operator==(const large_struct & c) const | |
788 | { | |
789 | return std::memcmp(data, &c.data, sizeof(data)) == 0; | |
790 | } | |
791 | inline bool operator!=(const large_struct & c) const | |
792 | { | |
793 | return std::memcmp(data, &c.data, sizeof(data)) != 0; | |
794 | } | |
795 | }; | |
796 | ||
b32b8144 FG |
797 | template< typename Char, typename Traits > |
798 | inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&) | |
799 | { | |
800 | strm << "[large_struct]"; | |
801 | return strm; | |
802 | } | |
803 | ||
7c673cae FG |
804 | static void |
805 | test_large_struct_api(void) | |
806 | { | |
807 | large_struct a = {{1}}, b = {{2}}, c = {{3}}; | |
808 | test_base_operators(a, b, c); | |
809 | } | |
810 | ||
b32b8144 FG |
811 | struct test_struct_with_ctor |
812 | { | |
7c673cae FG |
813 | typedef unsigned int value_type; |
814 | value_type i; | |
815 | test_struct_with_ctor() : i(0x01234567) {} | |
816 | inline bool operator==(const test_struct_with_ctor & c) const {return i == c.i;} | |
817 | inline bool operator!=(const test_struct_with_ctor & c) const {return i != c.i;} | |
818 | }; | |
819 | ||
b32b8144 FG |
820 | template< typename Char, typename Traits > |
821 | inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const&) | |
822 | { | |
823 | strm << "[test_struct_with_ctor]"; | |
824 | return strm; | |
825 | } | |
826 | ||
7c673cae FG |
827 | static void |
828 | test_struct_with_ctor_api(void) | |
829 | { | |
830 | { | |
831 | test_struct_with_ctor s; | |
832 | boost::atomic<test_struct_with_ctor> sa; | |
833 | // Check that the default constructor was called | |
834 | BOOST_TEST( sa.load() == s ); | |
835 | } | |
836 | ||
837 | test_struct_with_ctor a, b, c; | |
838 | a.i = 1; | |
839 | b.i = 2; | |
840 | c.i = 3; | |
841 | ||
842 | test_base_operators(a, b, c); | |
843 | } | |
844 | ||
845 | #endif |