]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/atomic/test/api_test_helpers.hpp
buildsys: switch source download to quincy
[ceph.git] / ceph / src / boost / libs / atomic / test / api_test_helpers.hpp
1 // Copyright (c) 2011 Helge Bahmann
2 // Copyright (c) 2017 - 2020 Andrey Semashev
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>
12 #include <cstddef>
13 #include <cstring>
14 #include <cstdlib>
15 #include <limits>
16 #include <iostream>
17 #include <boost/config.hpp>
18 #include <boost/cstdint.hpp>
19 #include <boost/type.hpp>
20 #include <boost/type_traits/integral_constant.hpp>
21 #include <boost/type_traits/alignment_of.hpp>
22 #include <boost/type_traits/is_pointer.hpp>
23 #include <boost/type_traits/is_signed.hpp>
24 #include <boost/type_traits/is_unsigned.hpp>
25 #include <boost/type_traits/make_signed.hpp>
26 #include <boost/type_traits/make_unsigned.hpp>
27 #include <boost/type_traits/conditional.hpp>
28 #include "aligned_object.hpp"
29
30 struct test_stream_type
31 {
32 typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
33 typedef std::basic_ios< char, std::char_traits< char > >& (*basic_ios_manip)(std::basic_ios< char, std::char_traits< char > >&);
34 typedef std::ostream& (*stream_manip)(std::ostream&);
35
36 template< typename T >
37 test_stream_type const& operator<< (T const& value) const
38 {
39 std::cerr << value;
40 return *this;
41 }
42
43 test_stream_type const& operator<< (ios_base_manip manip) const
44 {
45 std::cerr << manip;
46 return *this;
47 }
48 test_stream_type const& operator<< (basic_ios_manip manip) const
49 {
50 std::cerr << manip;
51 return *this;
52 }
53 test_stream_type const& operator<< (stream_manip manip) const
54 {
55 std::cerr << manip;
56 return *this;
57 }
58
59 // Make sure characters are printed as numbers if tests fail
60 test_stream_type const& operator<< (char value) const
61 {
62 std::cerr << static_cast< int >(value);
63 return *this;
64 }
65 test_stream_type const& operator<< (signed char value) const
66 {
67 std::cerr << static_cast< int >(value);
68 return *this;
69 }
70 test_stream_type const& operator<< (unsigned char value) const
71 {
72 std::cerr << static_cast< unsigned int >(value);
73 return *this;
74 }
75 test_stream_type const& operator<< (short value) const
76 {
77 std::cerr << static_cast< int >(value);
78 return *this;
79 }
80 test_stream_type const& operator<< (unsigned short value) const
81 {
82 std::cerr << static_cast< unsigned int >(value);
83 return *this;
84 }
85
86 #if defined(BOOST_HAS_INT128)
87 // Some GCC versions don't provide output operators for __int128
88 test_stream_type const& operator<< (boost::int128_type const& v) const
89 {
90 std::cerr << static_cast< long long >(v);
91 return *this;
92 }
93 test_stream_type const& operator<< (boost::uint128_type const& v) const
94 {
95 std::cerr << static_cast< unsigned long long >(v);
96 return *this;
97 }
98 #endif // defined(BOOST_HAS_INT128)
99 #if defined(BOOST_HAS_FLOAT128)
100 // libstdc++ does not provide output operators for __float128
101 test_stream_type const& operator<< (boost::float128_type const& v) const
102 {
103 std::cerr << static_cast< double >(v);
104 return *this;
105 }
106 #endif // defined(BOOST_HAS_FLOAT128)
107 };
108
109 const test_stream_type test_stream = {};
110
111 #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
112
113 #include <boost/core/lightweight_test.hpp>
114
115 #include "value_with_epsilon.hpp"
116
117 const unsigned int max_weak_cas_loops = 1000;
118
119 //! Wrapper type for atomic template
120 template< typename T >
121 struct atomic_wrapper
122 {
123 typedef boost::atomic< T > atomic_type;
124
125 atomic_type a;
126
127 BOOST_DEFAULTED_FUNCTION(atomic_wrapper(), {})
128 explicit atomic_wrapper(T const& value) : a(value) {}
129 };
130
131 //! Wrapper type for atomic_ref template
132 template< typename T >
133 struct atomic_ref_wrapper
134 {
135 typedef boost::atomic_ref< T > atomic_type;
136
137 aligned_object< T, atomic_type::required_alignment > object;
138 atomic_type a;
139
140 atomic_ref_wrapper() : a(object.get()) {}
141 explicit atomic_ref_wrapper(T const& value) : object(value), a(object.get()) {}
142 };
143
144 /* provide helpers that exercise whether the API
145 functions of "boost::atomic" provide the correct
146 operational semantic in the case of sequential
147 execution */
148
149 inline void test_flag_api(void)
150 {
151 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
152 boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
153 #else
154 boost::atomic_flag f;
155 #endif
156
157 BOOST_TEST( !f.test() );
158 BOOST_TEST( !f.test_and_set() );
159 BOOST_TEST( f.test() );
160 BOOST_TEST( f.test_and_set() );
161 BOOST_TEST( f.test() );
162 f.clear();
163 BOOST_TEST( !f.test() );
164 BOOST_TEST( !f.test_and_set() );
165 }
166
167 template< typename T >
168 inline void test_atomic_type_traits(boost::type< boost::atomic< T > >)
169 {
170 BOOST_TEST_GE(sizeof(boost::atomic< T >), sizeof(T));
171 }
172
173 template< typename T >
174 inline void test_atomic_type_traits(boost::type< boost::atomic_ref< T > >)
175 {
176 if (boost::atomic_ref< T >::is_always_lock_free)
177 {
178 BOOST_TEST_GE(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value);
179 }
180 else
181 {
182 // Lock-based implementation should not require alignment higher than alignof(T)
183 BOOST_TEST_EQ(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value);
184 }
185 }
186
187 template< template< typename > class Wrapper, typename T >
188 void test_base_operators(T value1, T value2, T value3)
189 {
190 test_atomic_type_traits(boost::type< typename Wrapper<T>::atomic_type >());
191
192 // explicit load/store
193 {
194 Wrapper<T> wrapper(value1);
195 typename Wrapper<T>::atomic_type& a = wrapper.a;
196 BOOST_TEST_EQ( a.load(), value1 );
197 }
198
199 {
200 Wrapper<T> wrapper(value1);
201 typename Wrapper<T>::atomic_type& a = wrapper.a;
202 a.store(value2);
203 BOOST_TEST_EQ( a.load(), value2 );
204 }
205
206 // overloaded assignment/conversion
207 {
208 Wrapper<T> wrapper(value1);
209 typename Wrapper<T>::atomic_type& a = wrapper.a;
210 BOOST_TEST( value1 == a );
211 }
212
213 {
214 Wrapper<T> wrapper(value1);
215 typename Wrapper<T>::atomic_type& a = wrapper.a;
216 a = value2;
217 BOOST_TEST( value2 == a );
218 }
219
220 // exchange-type operators
221 {
222 Wrapper<T> wrapper(value1);
223 typename Wrapper<T>::atomic_type& a = wrapper.a;
224 T n = a.exchange(value2);
225 BOOST_TEST_EQ( a.load(), value2 );
226 BOOST_TEST_EQ( n, value1 );
227 }
228
229 {
230 Wrapper<T> wrapper(value1);
231 typename Wrapper<T>::atomic_type& a = wrapper.a;
232 T expected = value1;
233 bool success = a.compare_exchange_strong(expected, value3);
234 BOOST_TEST( success );
235 BOOST_TEST_EQ( a.load(), value3 );
236 BOOST_TEST_EQ( expected, value1 );
237 }
238
239 {
240 Wrapper<T> wrapper(value1);
241 typename Wrapper<T>::atomic_type& a = wrapper.a;
242 T expected = value2;
243 bool success = a.compare_exchange_strong(expected, value3);
244 BOOST_TEST( !success );
245 BOOST_TEST_EQ( a.load(), value1 );
246 BOOST_TEST_EQ( expected, value1 );
247 }
248
249 {
250 Wrapper<T> wrapper(value1);
251 typename Wrapper<T>::atomic_type& a = wrapper.a;
252 T expected;
253 unsigned int loops = 0;
254 bool success = false;
255 do
256 {
257 expected = value1;
258 success = a.compare_exchange_weak(expected, value3);
259 ++loops;
260 }
261 while (!success && loops < max_weak_cas_loops);
262 BOOST_TEST( success );
263 BOOST_TEST_EQ( a.load(), value3 );
264 BOOST_TEST_EQ( expected, value1 );
265 }
266
267 {
268 Wrapper<T> wrapper(value1);
269 typename Wrapper<T>::atomic_type& a = wrapper.a;
270 T expected;
271 unsigned int loops = 0;
272 bool success = false;
273 do
274 {
275 expected = value2;
276 success = a.compare_exchange_weak(expected, value3);
277 if (expected != value2)
278 break;
279 ++loops;
280 }
281 while (!success && loops < max_weak_cas_loops);
282 BOOST_TEST( !success );
283 BOOST_TEST_EQ( a.load(), value1 );
284 BOOST_TEST_EQ( expected, value1 );
285 }
286 }
287
288 //! Tests whether boost::atomic supports constexpr constructor. Note that boost::atomic_ref (as std::atomic_ref) does not support constexpr constructor.
289 template< typename T >
290 void test_constexpr_ctor()
291 {
292 #ifndef BOOST_ATOMIC_DETAIL_NO_CXX11_CONSTEXPR_UNION_INIT
293 constexpr T value(0);
294 constexpr boost::atomic<T> tester(value);
295 BOOST_TEST( tester == value );
296 #endif
297 }
298
299 //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
300 template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
301 struct distance_limits
302 {
303 //! Difference type D promoted to the width of type T
304 typedef typename boost::conditional<
305 IsSigned,
306 boost::make_signed< T >,
307 boost::make_unsigned< T >
308 >::type::type promoted_difference_type;
309
310 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
311 {
312 return (std::numeric_limits< D >::min)();
313 }
314 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
315 {
316 return (std::numeric_limits< D >::max)();
317 }
318 };
319
320 #if defined(BOOST_MSVC)
321 #pragma warning(push)
322 // 'static_cast': truncation of constant value. There is no actual truncation happening because
323 // the cast is only performed if the value fits in the range of the result.
324 #pragma warning(disable: 4309)
325 #endif
326
327 template< typename T, typename D >
328 struct distance_limits< T*, D, true >
329 {
330 //! Difference type D promoted to the width of type T
331 typedef std::ptrdiff_t promoted_difference_type;
332
333 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
334 {
335 const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
336 const D diff = (std::numeric_limits< D >::min)();
337 // Both values are negative. Return the closest value to zero.
338 return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
339 }
340 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
341 {
342 const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
343 const D diff = (std::numeric_limits< D >::max)();
344 // Both values are positive. Return the closest value to zero.
345 return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
346 }
347 };
348
349 template< typename T, typename D >
350 struct distance_limits< T*, D, false >
351 {
352 //! Difference type D promoted to the width of type T
353 typedef std::size_t promoted_difference_type;
354
355 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
356 {
357 return (std::numeric_limits< D >::min)();
358 }
359 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
360 {
361 const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
362 const D diff = (std::numeric_limits< D >::max)();
363 return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
364 }
365 };
366
367 #if defined(BOOST_HAS_INT128)
368
369 // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
370 // So we have to specialize the limits ourself. We assume two's complement signed representation.
371 template< typename T, bool IsSigned >
372 struct distance_limits< T, boost::int128_type, IsSigned >
373 {
374 //! Difference type D promoted to the width of type T
375 typedef boost::int128_type promoted_difference_type;
376
377 static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
378 {
379 return -(max)() - 1;
380 }
381 static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
382 {
383 return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
384 }
385 };
386
387 template< typename T, bool IsSigned >
388 struct distance_limits< T, boost::uint128_type, IsSigned >
389 {
390 //! Difference type D promoted to the width of type T
391 typedef boost::uint128_type promoted_difference_type;
392
393 static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
394 {
395 return 0u;
396 }
397 static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
398 {
399 return ~static_cast< boost::uint128_type >(0u);
400 }
401 };
402
403 #endif // defined(BOOST_HAS_INT128)
404
405 #if defined(BOOST_MSVC)
406 #pragma warning(pop)
407 #endif
408
409 #if defined(BOOST_MSVC)
410 #pragma warning(push)
411 // unary minus operator applied to unsigned type, result still unsigned
412 #pragma warning(disable: 4146)
413 #endif
414
415 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
416 void test_additive_operators_with_type_and_test()
417 {
418 #if defined(UBSAN)
419 // clang UBSAN flags this test when AddType is a pointer as it considers subtracting from a null pointer (zero_add) an UB
420 if (boost::is_pointer< AddType >::value)
421 return;
422 #endif
423
424 // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
425 typedef typename distance_limits< T, D >::promoted_difference_type promoted_difference_type;
426 typedef typename boost::make_unsigned< promoted_difference_type >::type unsigned_promoted_difference_type;
427 const T zero_value = 0;
428 const D zero_diff = 0;
429 const D one_diff = 1;
430 const AddType zero_add = 0;
431 {
432 Wrapper<T> wrapper(zero_value);
433 typename Wrapper<T>::atomic_type& a = wrapper.a;
434 bool f = a.add_and_test(zero_diff);
435 BOOST_TEST_EQ( f, false );
436 BOOST_TEST_EQ( a.load(), zero_value );
437
438 f = a.add_and_test(one_diff);
439 BOOST_TEST_EQ( f, true );
440 BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
441 }
442 {
443 Wrapper<T> wrapper(zero_value);
444 typename Wrapper<T>::atomic_type& a = wrapper.a;
445 bool f = a.add_and_test((distance_limits< T, D >::max)());
446 BOOST_TEST_EQ( f, true );
447 BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
448 }
449 {
450 Wrapper<T> wrapper(zero_value);
451 typename Wrapper<T>::atomic_type& a = wrapper.a;
452 bool f = a.add_and_test((distance_limits< T, D >::min)());
453 BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
454 BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
455 }
456
457 {
458 Wrapper<T> wrapper(zero_value);
459 typename Wrapper<T>::atomic_type& a = wrapper.a;
460 bool f = a.sub_and_test(zero_diff);
461 BOOST_TEST_EQ( f, false );
462 BOOST_TEST_EQ( a.load(), zero_value );
463
464 f = a.sub_and_test(one_diff);
465 BOOST_TEST_EQ( f, true );
466 BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
467 }
468 {
469 Wrapper<T> wrapper(zero_value);
470 typename Wrapper<T>::atomic_type& a = wrapper.a;
471 bool f = a.sub_and_test((distance_limits< T, D >::max)());
472 BOOST_TEST_EQ( f, true );
473 BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
474 }
475 {
476 Wrapper<T> wrapper(zero_value);
477 typename Wrapper<T>::atomic_type& a = wrapper.a;
478 bool f = a.sub_and_test((distance_limits< T, D >::min)());
479 BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
480 // Be very careful as to not cause signed overflow on negation
481 unsigned_promoted_difference_type umin = static_cast< unsigned_promoted_difference_type >(
482 static_cast< promoted_difference_type >((distance_limits< T, D >::min)()));
483 umin = -umin;
484 promoted_difference_type neg_min;
485 std::memcpy(&neg_min, &umin, sizeof(neg_min));
486 BOOST_TEST_EQ( a.load(), T(zero_add + neg_min) );
487 }
488 }
489
490 #if defined(BOOST_MSVC)
491 #pragma warning(pop)
492 #endif
493
494 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
495 void test_additive_operators_with_type(T value, D delta)
496 {
497 /* note: the tests explicitly cast the result of any addition
498 to the type to be tested to force truncation of the result to
499 the correct range in case of overflow */
500
501 // explicit add/sub
502 {
503 Wrapper<T> wrapper(value);
504 typename Wrapper<T>::atomic_type& a = wrapper.a;
505 T n = a.fetch_add(delta);
506 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
507 BOOST_TEST_EQ( n, value );
508 }
509
510 {
511 Wrapper<T> wrapper(value);
512 typename Wrapper<T>::atomic_type& a = wrapper.a;
513 T n = a.fetch_sub(delta);
514 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
515 BOOST_TEST_EQ( n, value );
516 }
517
518 // overloaded modify/assign
519 {
520 Wrapper<T> wrapper(value);
521 typename Wrapper<T>::atomic_type& a = wrapper.a;
522 T n = (a += delta);
523 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
524 BOOST_TEST_EQ( n, T((AddType)value + delta) );
525 }
526
527 {
528 Wrapper<T> wrapper(value);
529 typename Wrapper<T>::atomic_type& a = wrapper.a;
530 T n = (a -= delta);
531 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
532 BOOST_TEST_EQ( n, T((AddType)value - delta) );
533 }
534
535 // overloaded increment/decrement
536 {
537 Wrapper<T> wrapper(value);
538 typename Wrapper<T>::atomic_type& a = wrapper.a;
539 T n = a++;
540 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
541 BOOST_TEST_EQ( n, value );
542 }
543
544 {
545 Wrapper<T> wrapper(value);
546 typename Wrapper<T>::atomic_type& a = wrapper.a;
547 T n = ++a;
548 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
549 BOOST_TEST_EQ( n, T((AddType)value + 1) );
550 }
551
552 {
553 Wrapper<T> wrapper(value);
554 typename Wrapper<T>::atomic_type& a = wrapper.a;
555 T n = a--;
556 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
557 BOOST_TEST_EQ( n, value );
558 }
559
560 {
561 Wrapper<T> wrapper(value);
562 typename Wrapper<T>::atomic_type& a = wrapper.a;
563 T n = --a;
564 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
565 BOOST_TEST_EQ( n, T((AddType)value - 1) );
566 }
567
568 // Operations returning the actual resulting value
569 {
570 Wrapper<T> wrapper(value);
571 typename Wrapper<T>::atomic_type& a = wrapper.a;
572 T n = a.add(delta);
573 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
574 BOOST_TEST_EQ( n, T((AddType)value + delta) );
575 }
576
577 {
578 Wrapper<T> wrapper(value);
579 typename Wrapper<T>::atomic_type& a = wrapper.a;
580 T n = a.sub(delta);
581 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
582 BOOST_TEST_EQ( n, T((AddType)value - delta) );
583 }
584
585 // Opaque operations
586 {
587 Wrapper<T> wrapper(value);
588 typename Wrapper<T>::atomic_type& a = wrapper.a;
589 a.opaque_add(delta);
590 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
591 }
592
593 {
594 Wrapper<T> wrapper(value);
595 typename Wrapper<T>::atomic_type& a = wrapper.a;
596 a.opaque_sub(delta);
597 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
598 }
599
600 // Modify and test operations
601 test_additive_operators_with_type_and_test< Wrapper, T, D, AddType >();
602 }
603
604 template< template< typename > class Wrapper, typename T, typename D >
605 void test_additive_operators(T value, D delta)
606 {
607 test_additive_operators_with_type< Wrapper, T, D, T >(value, delta);
608 }
609
610 template< template< typename > class Wrapper, typename T >
611 void test_negation()
612 {
613 {
614 Wrapper<T> wrapper((T)1);
615 typename Wrapper<T>::atomic_type& a = wrapper.a;
616 T n = a.fetch_negate();
617 BOOST_TEST_EQ( a.load(), (T)-1 );
618 BOOST_TEST_EQ( n, (T)1 );
619
620 n = a.fetch_negate();
621 BOOST_TEST_EQ( a.load(), (T)1 );
622 BOOST_TEST_EQ( n, (T)-1 );
623 }
624 {
625 Wrapper<T> wrapper((T)1);
626 typename Wrapper<T>::atomic_type& a = wrapper.a;
627 T n = a.negate();
628 BOOST_TEST_EQ( a.load(), (T)-1 );
629 BOOST_TEST_EQ( n, (T)-1 );
630
631 n = a.negate();
632 BOOST_TEST_EQ( a.load(), (T)1 );
633 BOOST_TEST_EQ( n, (T)1 );
634 }
635 {
636 Wrapper<T> wrapper((T)1);
637 typename Wrapper<T>::atomic_type& a = wrapper.a;
638 a.opaque_negate();
639 BOOST_TEST_EQ( a.load(), (T)-1 );
640
641 a.opaque_negate();
642 BOOST_TEST_EQ( a.load(), (T)1 );
643 }
644 {
645 Wrapper<T> wrapper((T)1);
646 typename Wrapper<T>::atomic_type& a = wrapper.a;
647 bool f = a.negate_and_test();
648 BOOST_TEST_EQ( f, true );
649 BOOST_TEST_EQ( a.load(), (T)-1 );
650
651 f = a.negate_and_test();
652 BOOST_TEST_EQ( f, true );
653 BOOST_TEST_EQ( a.load(), (T)1 );
654 }
655 {
656 Wrapper<T> wrapper((T)0);
657 typename Wrapper<T>::atomic_type& a = wrapper.a;
658 bool f = a.negate_and_test();
659 BOOST_TEST_EQ( f, false );
660 BOOST_TEST_EQ( a.load(), (T)0 );
661 }
662 }
663
664 template< template< typename > class Wrapper, typename T >
665 void test_additive_wrap(T value)
666 {
667 {
668 Wrapper<T> wrapper(value);
669 typename Wrapper<T>::atomic_type& a = wrapper.a;
670 T n = a.fetch_add(1) + (T)1;
671 BOOST_TEST_EQ( a.load(), n );
672 }
673 {
674 Wrapper<T> wrapper(value);
675 typename Wrapper<T>::atomic_type& a = wrapper.a;
676 T n = a.fetch_sub(1) - (T)1;
677 BOOST_TEST_EQ( a.load(), n );
678 }
679 }
680
681 template< template< typename > class Wrapper, typename T >
682 void test_bit_operators(T value, T delta)
683 {
684 // explicit and/or/xor
685 {
686 Wrapper<T> wrapper(value);
687 typename Wrapper<T>::atomic_type& a = wrapper.a;
688 T n = a.fetch_and(delta);
689 BOOST_TEST_EQ( a.load(), T(value & delta) );
690 BOOST_TEST_EQ( n, value );
691 }
692
693 {
694 Wrapper<T> wrapper(value);
695 typename Wrapper<T>::atomic_type& a = wrapper.a;
696 T n = a.fetch_or(delta);
697 BOOST_TEST_EQ( a.load(), T(value | delta) );
698 BOOST_TEST_EQ( n, value );
699 }
700
701 {
702 Wrapper<T> wrapper(value);
703 typename Wrapper<T>::atomic_type& a = wrapper.a;
704 T n = a.fetch_xor(delta);
705 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
706 BOOST_TEST_EQ( n, value );
707 }
708
709 {
710 Wrapper<T> wrapper(value);
711 typename Wrapper<T>::atomic_type& a = wrapper.a;
712 T n = a.fetch_complement();
713 BOOST_TEST_EQ( a.load(), T(~value) );
714 BOOST_TEST_EQ( n, value );
715 }
716
717 // overloaded modify/assign
718 {
719 Wrapper<T> wrapper(value);
720 typename Wrapper<T>::atomic_type& a = wrapper.a;
721 T n = (a &= delta);
722 BOOST_TEST_EQ( a.load(), T(value & delta) );
723 BOOST_TEST_EQ( n, T(value & delta) );
724 }
725
726 {
727 Wrapper<T> wrapper(value);
728 typename Wrapper<T>::atomic_type& a = wrapper.a;
729 T n = (a |= delta);
730 BOOST_TEST_EQ( a.load(), T(value | delta) );
731 BOOST_TEST_EQ( n, T(value | delta) );
732 }
733
734 {
735 Wrapper<T> wrapper(value);
736 typename Wrapper<T>::atomic_type& a = wrapper.a;
737 T n = (a ^= delta);
738 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
739 BOOST_TEST_EQ( n, T(value ^ delta) );
740 }
741
742 // Operations returning the actual resulting value
743 {
744 Wrapper<T> wrapper(value);
745 typename Wrapper<T>::atomic_type& a = wrapper.a;
746 T n = a.bitwise_and(delta);
747 BOOST_TEST_EQ( a.load(), T(value & delta) );
748 BOOST_TEST_EQ( n, T(value & delta) );
749 }
750
751 {
752 Wrapper<T> wrapper(value);
753 typename Wrapper<T>::atomic_type& a = wrapper.a;
754 T n = a.bitwise_or(delta);
755 BOOST_TEST_EQ( a.load(), T(value | delta) );
756 BOOST_TEST_EQ( n, T(value | delta) );
757 }
758
759 {
760 Wrapper<T> wrapper(value);
761 typename Wrapper<T>::atomic_type& a = wrapper.a;
762 T n = a.bitwise_xor(delta);
763 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
764 BOOST_TEST_EQ( n, T(value ^ delta) );
765 }
766
767 {
768 Wrapper<T> wrapper(value);
769 typename Wrapper<T>::atomic_type& a = wrapper.a;
770 T n = a.bitwise_complement();
771 BOOST_TEST_EQ( a.load(), T(~value) );
772 BOOST_TEST_EQ( n, T(~value) );
773 }
774
775 // Opaque operations
776 {
777 Wrapper<T> wrapper(value);
778 typename Wrapper<T>::atomic_type& a = wrapper.a;
779 a.opaque_and(delta);
780 BOOST_TEST_EQ( a.load(), T(value & delta) );
781 }
782
783 {
784 Wrapper<T> wrapper(value);
785 typename Wrapper<T>::atomic_type& a = wrapper.a;
786 a.opaque_or(delta);
787 BOOST_TEST_EQ( a.load(), T(value | delta) );
788 }
789
790 {
791 Wrapper<T> wrapper(value);
792 typename Wrapper<T>::atomic_type& a = wrapper.a;
793 a.opaque_xor(delta);
794 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
795 }
796
797 {
798 Wrapper<T> wrapper(value);
799 typename Wrapper<T>::atomic_type& a = wrapper.a;
800 a.opaque_complement();
801 BOOST_TEST_EQ( a.load(), T(~value) );
802 }
803
804 // Modify and test operations
805 {
806 Wrapper<T> wrapper((T)1);
807 typename Wrapper<T>::atomic_type& a = wrapper.a;
808 bool f = a.and_and_test((T)1);
809 BOOST_TEST_EQ( f, true );
810 BOOST_TEST_EQ( a.load(), T(1) );
811
812 f = a.and_and_test((T)0);
813 BOOST_TEST_EQ( f, false );
814 BOOST_TEST_EQ( a.load(), T(0) );
815
816 f = a.and_and_test((T)0);
817 BOOST_TEST_EQ( f, false );
818 BOOST_TEST_EQ( a.load(), T(0) );
819 }
820
821 {
822 Wrapper<T> wrapper((T)0);
823 typename Wrapper<T>::atomic_type& a = wrapper.a;
824 bool f = a.or_and_test((T)0);
825 BOOST_TEST_EQ( f, false );
826 BOOST_TEST_EQ( a.load(), T(0) );
827
828 f = a.or_and_test((T)1);
829 BOOST_TEST_EQ( f, true );
830 BOOST_TEST_EQ( a.load(), T(1) );
831
832 f = a.or_and_test((T)1);
833 BOOST_TEST_EQ( f, true );
834 BOOST_TEST_EQ( a.load(), T(1) );
835 }
836
837 {
838 Wrapper<T> wrapper((T)0);
839 typename Wrapper<T>::atomic_type& a = wrapper.a;
840 bool f = a.xor_and_test((T)0);
841 BOOST_TEST_EQ( f, false );
842 BOOST_TEST_EQ( a.load(), T(0) );
843
844 f = a.xor_and_test((T)1);
845 BOOST_TEST_EQ( f, true );
846 BOOST_TEST_EQ( a.load(), T(1) );
847
848 f = a.xor_and_test((T)1);
849 BOOST_TEST_EQ( f, false );
850 BOOST_TEST_EQ( a.load(), T(0) );
851 }
852
853 {
854 Wrapper<T> wrapper((T)0);
855 typename Wrapper<T>::atomic_type& a = wrapper.a;
856 bool f = a.complement_and_test();
857 BOOST_TEST_EQ( f, true );
858 BOOST_TEST_EQ( a.load(), static_cast< T >(~static_cast< T >(0)) );
859
860 f = a.complement_and_test();
861 BOOST_TEST_EQ( f, false );
862 BOOST_TEST_EQ( a.load(), T(0) );
863 }
864
865 // Bit test and modify operations
866 {
867 Wrapper<T> wrapper((T)42);
868 typename Wrapper<T>::atomic_type& a = wrapper.a;
869 bool f = a.bit_test_and_set(0);
870 BOOST_TEST_EQ( f, false );
871 BOOST_TEST_EQ( a.load(), T(43) );
872
873 f = a.bit_test_and_set(1);
874 BOOST_TEST_EQ( f, true );
875 BOOST_TEST_EQ( a.load(), T(43) );
876
877 f = a.bit_test_and_set(2);
878 BOOST_TEST_EQ( f, false );
879 BOOST_TEST_EQ( a.load(), T(47) );
880 }
881
882 {
883 Wrapper<T> wrapper((T)42);
884 typename Wrapper<T>::atomic_type& a = wrapper.a;
885 bool f = a.bit_test_and_reset(0);
886 BOOST_TEST_EQ( f, false );
887 BOOST_TEST_EQ( a.load(), T(42) );
888
889 f = a.bit_test_and_reset(1);
890 BOOST_TEST_EQ( f, true );
891 BOOST_TEST_EQ( a.load(), T(40) );
892
893 f = a.bit_test_and_set(2);
894 BOOST_TEST_EQ( f, false );
895 BOOST_TEST_EQ( a.load(), T(44) );
896 }
897
898 {
899 Wrapper<T> wrapper((T)42);
900 typename Wrapper<T>::atomic_type& a = wrapper.a;
901 bool f = a.bit_test_and_complement(0);
902 BOOST_TEST_EQ( f, false );
903 BOOST_TEST_EQ( a.load(), T(43) );
904
905 f = a.bit_test_and_complement(1);
906 BOOST_TEST_EQ( f, true );
907 BOOST_TEST_EQ( a.load(), T(41) );
908
909 f = a.bit_test_and_complement(2);
910 BOOST_TEST_EQ( f, false );
911 BOOST_TEST_EQ( a.load(), T(45) );
912 }
913
914 // Test that a runtime value works for the bit index. This is important for asm block constraints.
915 {
916 unsigned int runtime_bit_index = std::rand() & 7u;
917 Wrapper<T> wrapper((T)42);
918 typename Wrapper<T>::atomic_type& a = wrapper.a;
919
920 a.bit_test_and_set(runtime_bit_index);
921 a.bit_test_and_reset(runtime_bit_index);
922 a.bit_test_and_complement(runtime_bit_index);
923 }
924 }
925
926 template< template< typename > class Wrapper, typename T >
927 void do_test_integral_api(boost::false_type)
928 {
929 test_base_operators< Wrapper, T >(42, 43, 44);
930 test_additive_operators< Wrapper, T, T >(42, 17);
931 test_bit_operators< Wrapper, T >((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
932
933 /* test for unsigned overflow/underflow */
934 test_additive_operators< Wrapper, T, T >((T)-1, 1);
935 test_additive_operators< Wrapper, T, T >(0, 1);
936 /* test for signed overflow/underflow */
937 test_additive_operators< Wrapper, T, T >(((T)-1) >> (sizeof(T) * 8 - 1), 1);
938 test_additive_operators< Wrapper, T, T >(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
939 }
940
941 template< template< typename > class Wrapper, typename T >
942 void do_test_integral_api(boost::true_type)
943 {
944 do_test_integral_api< Wrapper, T >(boost::false_type());
945
946 test_additive_wrap< Wrapper, T >(0u);
947 BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
948 test_additive_wrap< Wrapper, T >(all_ones);
949 BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
950 test_additive_wrap< Wrapper, T >(all_ones ^ max_signed_twos_compl);
951 test_additive_wrap< Wrapper, T >(max_signed_twos_compl);
952 }
953
954 template< template< typename > class Wrapper, typename T >
955 inline void test_integral_api(void)
956 {
957 do_test_integral_api< Wrapper, T >(boost::is_unsigned<T>());
958
959 if (boost::is_signed<T>::value)
960 test_negation< Wrapper, T >();
961 }
962
963 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
964
965 template< template< typename > class Wrapper, typename T, typename D >
966 void test_fp_additive_operators(T value, D delta)
967 {
968 // explicit add/sub
969 {
970 Wrapper<T> wrapper(value);
971 typename Wrapper<T>::atomic_type& a = wrapper.a;
972 T n = a.fetch_add(delta);
973 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
974 BOOST_TEST_EQ( n, approx(value) );
975 }
976
977 {
978 Wrapper<T> wrapper(value);
979 typename Wrapper<T>::atomic_type& a = wrapper.a;
980 T n = a.fetch_sub(delta);
981 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
982 BOOST_TEST_EQ( n, approx(value) );
983 }
984
985 // overloaded modify/assign
986 {
987 Wrapper<T> wrapper(value);
988 typename Wrapper<T>::atomic_type& a = wrapper.a;
989 T n = (a += delta);
990 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
991 BOOST_TEST_EQ( n, approx(T(value + delta)) );
992 }
993
994 {
995 Wrapper<T> wrapper(value);
996 typename Wrapper<T>::atomic_type& a = wrapper.a;
997 T n = (a -= delta);
998 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
999 BOOST_TEST_EQ( n, approx(T(value - delta)) );
1000 }
1001
1002 // Operations returning the actual resulting value
1003 {
1004 Wrapper<T> wrapper(value);
1005 typename Wrapper<T>::atomic_type& a = wrapper.a;
1006 T n = a.add(delta);
1007 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1008 BOOST_TEST_EQ( n, approx(T(value + delta)) );
1009 }
1010
1011 {
1012 Wrapper<T> wrapper(value);
1013 typename Wrapper<T>::atomic_type& a = wrapper.a;
1014 T n = a.sub(delta);
1015 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1016 BOOST_TEST_EQ( n, approx(T(value - delta)) );
1017 }
1018
1019 // Opaque operations
1020 {
1021 Wrapper<T> wrapper(value);
1022 typename Wrapper<T>::atomic_type& a = wrapper.a;
1023 a.opaque_add(delta);
1024 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1025 }
1026
1027 {
1028 Wrapper<T> wrapper(value);
1029 typename Wrapper<T>::atomic_type& a = wrapper.a;
1030 a.opaque_sub(delta);
1031 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1032 }
1033 }
1034
1035 template< template< typename > class Wrapper, typename T >
1036 void test_fp_negation()
1037 {
1038 {
1039 Wrapper<T> wrapper((T)1);
1040 typename Wrapper<T>::atomic_type& a = wrapper.a;
1041 T n = a.fetch_negate();
1042 BOOST_TEST_EQ( a.load(), approx((T)-1) );
1043 BOOST_TEST_EQ( n, approx((T)1) );
1044
1045 n = a.fetch_negate();
1046 BOOST_TEST_EQ( a.load(), approx((T)1) );
1047 BOOST_TEST_EQ( n, approx((T)-1) );
1048 }
1049 {
1050 Wrapper<T> wrapper((T)1);
1051 typename Wrapper<T>::atomic_type& a = wrapper.a;
1052 T n = a.negate();
1053 BOOST_TEST_EQ( a.load(), approx((T)-1) );
1054 BOOST_TEST_EQ( n, approx((T)-1) );
1055
1056 n = a.negate();
1057 BOOST_TEST_EQ( a.load(), approx((T)1) );
1058 BOOST_TEST_EQ( n, approx((T)1) );
1059 }
1060 {
1061 Wrapper<T> wrapper((T)1);
1062 typename Wrapper<T>::atomic_type& a = wrapper.a;
1063 a.opaque_negate();
1064 BOOST_TEST_EQ( a.load(), approx((T)-1) );
1065
1066 a.opaque_negate();
1067 BOOST_TEST_EQ( a.load(), approx((T)1) );
1068 }
1069 }
1070
1071 #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1072
1073 template< template< typename > class Wrapper, typename T >
1074 void test_floating_point_api(void)
1075 {
1076 // Note: When support for floating point is disabled, even the base operation tests may fail because
1077 // the generic template specialization does not account for garbage in padding bits that are present in some FP types.
1078 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1079 test_base_operators< Wrapper, T >(static_cast<T>(42.1), static_cast<T>(43.2), static_cast<T>(44.3));
1080
1081 test_fp_additive_operators< Wrapper, T, T >(static_cast<T>(42.5), static_cast<T>(17.7));
1082 test_fp_additive_operators< Wrapper, T, T >(static_cast<T>(-42.5), static_cast<T>(-17.7));
1083
1084 test_fp_negation< Wrapper, T >();
1085 #endif
1086 }
1087
1088
1089 template< template< typename > class Wrapper, typename T >
1090 void test_pointer_api(void)
1091 {
1092 T values[3];
1093
1094 test_base_operators< Wrapper, T* >(&values[0], &values[1], &values[2]);
1095 test_additive_operators< Wrapper, T*>(&values[1], 1);
1096
1097 test_base_operators< Wrapper, void*>(&values[0], &values[1], &values[2]);
1098
1099 #if defined(BOOST_HAS_INTPTR_T)
1100 Wrapper<void*> wrapper_ptr;
1101 typename Wrapper<void*>::atomic_type& ptr = wrapper_ptr.a;
1102 Wrapper<boost::intptr_t> wrapper_integral;
1103 typename Wrapper<boost::intptr_t>::atomic_type& integral = wrapper_integral.a;
1104 BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
1105 #endif
1106 }
1107
1108 enum test_enum
1109 {
1110 foo, bar, baz
1111 };
1112
1113 template< template< typename > class Wrapper >
1114 void test_enum_api(void)
1115 {
1116 test_base_operators< Wrapper >(foo, bar, baz);
1117 }
1118
1119 template< typename T >
1120 struct test_struct
1121 {
1122 typedef T value_type;
1123 value_type i;
1124 inline bool operator==(test_struct const& c) const { return i == c.i; }
1125 inline bool operator!=(test_struct const& c) const { return !operator==(c); }
1126 };
1127
1128 template< typename Char, typename Traits, typename T >
1129 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
1130 {
1131 test_stream << "{" << s.i << "}";
1132 return strm;
1133 }
1134
1135 template< template< typename > class Wrapper, typename T >
1136 void test_struct_api(void)
1137 {
1138 T a = {1}, b = {2}, c = {3};
1139
1140 test_base_operators< Wrapper >(a, b, c);
1141
1142 {
1143 Wrapper<T> wrapper_sa;
1144 typename Wrapper<T>::atomic_type& sa = wrapper_sa.a;
1145 Wrapper<typename T::value_type> wrapper_si;
1146 typename Wrapper<typename T::value_type>::atomic_type& si = wrapper_si.a;
1147 BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
1148 }
1149 }
1150
1151 template< typename T >
1152 struct test_struct_x2
1153 {
1154 typedef T value_type;
1155 value_type i, j;
1156 inline bool operator==(test_struct_x2 const& c) const { return i == c.i && j == c.j; }
1157 inline bool operator!=(test_struct_x2 const& c) const { return !operator==(c); }
1158 };
1159
1160 template< typename Char, typename Traits, typename T >
1161 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
1162 {
1163 test_stream << "{" << s.i << ", " << s.j << "}";
1164 return strm;
1165 }
1166
1167 template< template< typename > class Wrapper, typename T >
1168 void test_struct_x2_api(void)
1169 {
1170 T a = {1, 1}, b = {2, 2}, c = {3, 3};
1171
1172 test_base_operators< Wrapper >(a, b, c);
1173 }
1174
1175 struct large_struct
1176 {
1177 unsigned char data[256u];
1178
1179 inline bool operator==(large_struct const& c) const
1180 {
1181 return std::memcmp(data, &c.data, sizeof(data)) == 0;
1182 }
1183 inline bool operator!=(large_struct const& c) const
1184 {
1185 return std::memcmp(data, &c.data, sizeof(data)) != 0;
1186 }
1187 };
1188
1189 template< typename Char, typename Traits >
1190 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
1191 {
1192 strm << "[large_struct]";
1193 return strm;
1194 }
1195
1196 template< template< typename > class Wrapper >
1197 void test_large_struct_api(void)
1198 {
1199 large_struct a = {{1}}, b = {{2}}, c = {{3}};
1200 test_base_operators< Wrapper >(a, b, c);
1201 }
1202
1203 struct test_struct_with_ctor
1204 {
1205 typedef unsigned int value_type;
1206 value_type i;
1207 test_struct_with_ctor() : i(0x01234567) {}
1208 inline bool operator==(test_struct_with_ctor const& c) const { return i == c.i; }
1209 inline bool operator!=(test_struct_with_ctor const& c) const { return !operator==(c); }
1210 };
1211
1212 template< typename Char, typename Traits >
1213 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const& s)
1214 {
1215 strm << "{" << s.i << "}";
1216 return strm;
1217 }
1218
1219 template< template< typename > class Wrapper >
1220 void test_struct_with_ctor_api(void)
1221 {
1222 {
1223 test_struct_with_ctor s;
1224 Wrapper<test_struct_with_ctor> wrapper_sa;
1225 typename Wrapper<test_struct_with_ctor>::atomic_type& sa = wrapper_sa.a;
1226 // Check that the default constructor was called
1227 BOOST_TEST( sa.load() == s );
1228 }
1229
1230 test_struct_with_ctor a, b, c;
1231 a.i = 1;
1232 b.i = 2;
1233 c.i = 3;
1234
1235 test_base_operators< Wrapper >(a, b, c);
1236 }
1237
1238 #endif