1 // Copyright (c) 2011 Helge Bahmann
2 // Copyright (c) 2017 - 2020 Andrey Semashev
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)
8 #ifndef BOOST_ATOMIC_API_TEST_HELPERS_HPP
9 #define BOOST_ATOMIC_API_TEST_HELPERS_HPP
11 #include <boost/atomic.hpp>
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"
30 struct test_stream_type
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&);
36 template< typename T >
37 test_stream_type const& operator<< (T const& value) const
43 test_stream_type const& operator<< (ios_base_manip manip) const
48 test_stream_type const& operator<< (basic_ios_manip manip) const
53 test_stream_type const& operator<< (stream_manip manip) const
59 // Make sure characters are printed as numbers if tests fail
60 test_stream_type const& operator<< (char value) const
62 std::cerr << static_cast< int >(value);
65 test_stream_type const& operator<< (signed char value) const
67 std::cerr << static_cast< int >(value);
70 test_stream_type const& operator<< (unsigned char value) const
72 std::cerr << static_cast< unsigned int >(value);
75 test_stream_type const& operator<< (short value) const
77 std::cerr << static_cast< int >(value);
80 test_stream_type const& operator<< (unsigned short value) const
82 std::cerr << static_cast< unsigned int >(value);
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
90 std::cerr << static_cast< long long >(v);
93 test_stream_type const& operator<< (boost::uint128_type const& v) const
95 std::cerr << static_cast< unsigned long long >(v);
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
103 std::cerr << static_cast< double >(v);
106 #endif // defined(BOOST_HAS_FLOAT128)
109 const test_stream_type test_stream = {};
111 #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
113 #include <boost/core/lightweight_test.hpp>
115 #include "value_with_epsilon.hpp"
117 const unsigned int max_weak_cas_loops = 1000;
119 //! Wrapper type for atomic template
120 template< typename T >
121 struct atomic_wrapper
123 typedef boost::atomic< T > atomic_type;
127 BOOST_DEFAULTED_FUNCTION(atomic_wrapper(), {})
128 explicit atomic_wrapper(T const& value) : a(value) {}
131 //! Wrapper type for atomic_ref template
132 template< typename T >
133 struct atomic_ref_wrapper
135 typedef boost::atomic_ref< T > atomic_type;
137 aligned_object< T, atomic_type::required_alignment > object;
140 atomic_ref_wrapper() : a(object.get()) {}
141 explicit atomic_ref_wrapper(T const& value) : object(value), a(object.get()) {}
144 /* provide helpers that exercise whether the API
145 functions of "boost::atomic" provide the correct
146 operational semantic in the case of sequential
149 inline void test_flag_api(void)
151 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
152 boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
154 boost::atomic_flag f;
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() );
163 BOOST_TEST( !f.test() );
164 BOOST_TEST( !f.test_and_set() );
167 template< typename T >
168 inline void test_atomic_type_traits(boost::type< boost::atomic< T > >)
170 BOOST_TEST_GE(sizeof(boost::atomic< T >), sizeof(T));
173 template< typename T >
174 inline void test_atomic_type_traits(boost::type< boost::atomic_ref< T > >)
176 if (boost::atomic_ref< T >::is_always_lock_free)
178 BOOST_TEST_GE(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value);
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);
187 template< template< typename > class Wrapper, typename T >
188 void test_base_operators(T value1, T value2, T value3)
190 test_atomic_type_traits(boost::type< typename Wrapper<T>::atomic_type >());
192 // explicit load/store
194 Wrapper<T> wrapper(value1);
195 typename Wrapper<T>::atomic_type& a = wrapper.a;
196 BOOST_TEST_EQ( a.load(), value1 );
200 Wrapper<T> wrapper(value1);
201 typename Wrapper<T>::atomic_type& a = wrapper.a;
203 BOOST_TEST_EQ( a.load(), value2 );
206 // overloaded assignment/conversion
208 Wrapper<T> wrapper(value1);
209 typename Wrapper<T>::atomic_type& a = wrapper.a;
210 BOOST_TEST( value1 == a );
214 Wrapper<T> wrapper(value1);
215 typename Wrapper<T>::atomic_type& a = wrapper.a;
217 BOOST_TEST( value2 == a );
220 // exchange-type operators
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 );
230 Wrapper<T> wrapper(value1);
231 typename Wrapper<T>::atomic_type& a = wrapper.a;
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 );
240 Wrapper<T> wrapper(value1);
241 typename Wrapper<T>::atomic_type& a = wrapper.a;
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 );
250 Wrapper<T> wrapper(value1);
251 typename Wrapper<T>::atomic_type& a = wrapper.a;
253 unsigned int loops = 0;
254 bool success = false;
258 success = a.compare_exchange_weak(expected, value3);
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 );
268 Wrapper<T> wrapper(value1);
269 typename Wrapper<T>::atomic_type& a = wrapper.a;
271 unsigned int loops = 0;
272 bool success = false;
276 success = a.compare_exchange_weak(expected, value3);
277 if (expected != value2)
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 );
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()
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 );
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
303 //! Difference type D promoted to the width of type T
304 typedef typename boost::conditional<
306 boost::make_signed< T >,
307 boost::make_unsigned< T >
308 >::type::type promoted_difference_type;
310 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
312 return (std::numeric_limits< D >::min)();
314 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
316 return (std::numeric_limits< D >::max)();
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)
327 template< typename T, typename D >
328 struct distance_limits< T*, D, true >
330 //! Difference type D promoted to the width of type T
331 typedef std::ptrdiff_t promoted_difference_type;
333 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
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;
340 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
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;
349 template< typename T, typename D >
350 struct distance_limits< T*, D, false >
352 //! Difference type D promoted to the width of type T
353 typedef std::size_t promoted_difference_type;
355 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
357 return (std::numeric_limits< D >::min)();
359 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
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;
367 #if defined(BOOST_HAS_INT128)
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 >
374 //! Difference type D promoted to the width of type T
375 typedef boost::int128_type promoted_difference_type;
377 static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
381 static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
383 return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
387 template< typename T, bool IsSigned >
388 struct distance_limits< T, boost::uint128_type, IsSigned >
390 //! Difference type D promoted to the width of type T
391 typedef boost::uint128_type promoted_difference_type;
393 static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
397 static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
399 return ~static_cast< boost::uint128_type >(0u);
403 #endif // defined(BOOST_HAS_INT128)
405 #if defined(BOOST_MSVC)
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)
415 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
416 void test_additive_operators_with_type_and_test()
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)
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;
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 );
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) );
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)()) );
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)()) );
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 );
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) );
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)()) );
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)()));
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) );
490 #if defined(BOOST_MSVC)
494 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
495 void test_additive_operators_with_type(T value, D delta)
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 */
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 );
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 );
518 // overloaded modify/assign
520 Wrapper<T> wrapper(value);
521 typename Wrapper<T>::atomic_type& a = wrapper.a;
523 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
524 BOOST_TEST_EQ( n, T((AddType)value + delta) );
528 Wrapper<T> wrapper(value);
529 typename Wrapper<T>::atomic_type& a = wrapper.a;
531 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
532 BOOST_TEST_EQ( n, T((AddType)value - delta) );
535 // overloaded increment/decrement
537 Wrapper<T> wrapper(value);
538 typename Wrapper<T>::atomic_type& a = wrapper.a;
540 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
541 BOOST_TEST_EQ( n, value );
545 Wrapper<T> wrapper(value);
546 typename Wrapper<T>::atomic_type& a = wrapper.a;
548 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
549 BOOST_TEST_EQ( n, T((AddType)value + 1) );
553 Wrapper<T> wrapper(value);
554 typename Wrapper<T>::atomic_type& a = wrapper.a;
556 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
557 BOOST_TEST_EQ( n, value );
561 Wrapper<T> wrapper(value);
562 typename Wrapper<T>::atomic_type& a = wrapper.a;
564 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
565 BOOST_TEST_EQ( n, T((AddType)value - 1) );
568 // Operations returning the actual resulting value
570 Wrapper<T> wrapper(value);
571 typename Wrapper<T>::atomic_type& a = wrapper.a;
573 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
574 BOOST_TEST_EQ( n, T((AddType)value + delta) );
578 Wrapper<T> wrapper(value);
579 typename Wrapper<T>::atomic_type& a = wrapper.a;
581 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
582 BOOST_TEST_EQ( n, T((AddType)value - delta) );
587 Wrapper<T> wrapper(value);
588 typename Wrapper<T>::atomic_type& a = wrapper.a;
590 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
594 Wrapper<T> wrapper(value);
595 typename Wrapper<T>::atomic_type& a = wrapper.a;
597 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
600 // Modify and test operations
601 test_additive_operators_with_type_and_test< Wrapper, T, D, AddType >();
604 template< template< typename > class Wrapper, typename T, typename D >
605 void test_additive_operators(T value, D delta)
607 test_additive_operators_with_type< Wrapper, T, D, T >(value, delta);
610 template< template< typename > class Wrapper, typename T >
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 );
620 n = a.fetch_negate();
621 BOOST_TEST_EQ( a.load(), (T)1 );
622 BOOST_TEST_EQ( n, (T)-1 );
625 Wrapper<T> wrapper((T)1);
626 typename Wrapper<T>::atomic_type& a = wrapper.a;
628 BOOST_TEST_EQ( a.load(), (T)-1 );
629 BOOST_TEST_EQ( n, (T)-1 );
632 BOOST_TEST_EQ( a.load(), (T)1 );
633 BOOST_TEST_EQ( n, (T)1 );
636 Wrapper<T> wrapper((T)1);
637 typename Wrapper<T>::atomic_type& a = wrapper.a;
639 BOOST_TEST_EQ( a.load(), (T)-1 );
642 BOOST_TEST_EQ( a.load(), (T)1 );
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 );
651 f = a.negate_and_test();
652 BOOST_TEST_EQ( f, true );
653 BOOST_TEST_EQ( a.load(), (T)1 );
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 );
664 template< template< typename > class Wrapper, typename T >
665 void test_additive_wrap(T value)
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 );
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 );
681 template< template< typename > class Wrapper, typename T >
682 void test_bit_operators(T value, T delta)
684 // explicit and/or/xor
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 );
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 );
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 );
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 );
717 // overloaded modify/assign
719 Wrapper<T> wrapper(value);
720 typename Wrapper<T>::atomic_type& a = wrapper.a;
722 BOOST_TEST_EQ( a.load(), T(value & delta) );
723 BOOST_TEST_EQ( n, T(value & delta) );
727 Wrapper<T> wrapper(value);
728 typename Wrapper<T>::atomic_type& a = wrapper.a;
730 BOOST_TEST_EQ( a.load(), T(value | delta) );
731 BOOST_TEST_EQ( n, T(value | delta) );
735 Wrapper<T> wrapper(value);
736 typename Wrapper<T>::atomic_type& a = wrapper.a;
738 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
739 BOOST_TEST_EQ( n, T(value ^ delta) );
742 // Operations returning the actual resulting value
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) );
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) );
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) );
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) );
777 Wrapper<T> wrapper(value);
778 typename Wrapper<T>::atomic_type& a = wrapper.a;
780 BOOST_TEST_EQ( a.load(), T(value & delta) );
784 Wrapper<T> wrapper(value);
785 typename Wrapper<T>::atomic_type& a = wrapper.a;
787 BOOST_TEST_EQ( a.load(), T(value | delta) );
791 Wrapper<T> wrapper(value);
792 typename Wrapper<T>::atomic_type& a = wrapper.a;
794 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
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) );
804 // Modify and test operations
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) );
812 f = a.and_and_test((T)0);
813 BOOST_TEST_EQ( f, false );
814 BOOST_TEST_EQ( a.load(), T(0) );
816 f = a.and_and_test((T)0);
817 BOOST_TEST_EQ( f, false );
818 BOOST_TEST_EQ( a.load(), T(0) );
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) );
828 f = a.or_and_test((T)1);
829 BOOST_TEST_EQ( f, true );
830 BOOST_TEST_EQ( a.load(), T(1) );
832 f = a.or_and_test((T)1);
833 BOOST_TEST_EQ( f, true );
834 BOOST_TEST_EQ( a.load(), T(1) );
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) );
844 f = a.xor_and_test((T)1);
845 BOOST_TEST_EQ( f, true );
846 BOOST_TEST_EQ( a.load(), T(1) );
848 f = a.xor_and_test((T)1);
849 BOOST_TEST_EQ( f, false );
850 BOOST_TEST_EQ( a.load(), T(0) );
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)) );
860 f = a.complement_and_test();
861 BOOST_TEST_EQ( f, false );
862 BOOST_TEST_EQ( a.load(), T(0) );
865 // Bit test and modify operations
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) );
873 f = a.bit_test_and_set(1);
874 BOOST_TEST_EQ( f, true );
875 BOOST_TEST_EQ( a.load(), T(43) );
877 f = a.bit_test_and_set(2);
878 BOOST_TEST_EQ( f, false );
879 BOOST_TEST_EQ( a.load(), T(47) );
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) );
889 f = a.bit_test_and_reset(1);
890 BOOST_TEST_EQ( f, true );
891 BOOST_TEST_EQ( a.load(), T(40) );
893 f = a.bit_test_and_set(2);
894 BOOST_TEST_EQ( f, false );
895 BOOST_TEST_EQ( a.load(), T(44) );
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) );
905 f = a.bit_test_and_complement(1);
906 BOOST_TEST_EQ( f, true );
907 BOOST_TEST_EQ( a.load(), T(41) );
909 f = a.bit_test_and_complement(2);
910 BOOST_TEST_EQ( f, false );
911 BOOST_TEST_EQ( a.load(), T(45) );
914 // Test that a runtime value works for the bit index. This is important for asm block constraints.
916 unsigned int runtime_bit_index = std::rand() & 7u;
917 Wrapper<T> wrapper((T)42);
918 typename Wrapper<T>::atomic_type& a = wrapper.a;
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);
926 template< template< typename > class Wrapper, typename T >
927 void do_test_integral_api(boost::false_type)
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);
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);
941 template< template< typename > class Wrapper, typename T >
942 void do_test_integral_api(boost::true_type)
944 do_test_integral_api< Wrapper, T >(boost::false_type());
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);
954 template< template< typename > class Wrapper, typename T >
955 inline void test_integral_api(void)
957 do_test_integral_api< Wrapper, T >(boost::is_unsigned<T>());
959 if (boost::is_signed<T>::value)
960 test_negation< Wrapper, T >();
963 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
965 template< template< typename > class Wrapper, typename T, typename D >
966 void test_fp_additive_operators(T value, D delta)
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) );
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) );
985 // overloaded modify/assign
987 Wrapper<T> wrapper(value);
988 typename Wrapper<T>::atomic_type& a = wrapper.a;
990 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
991 BOOST_TEST_EQ( n, approx(T(value + delta)) );
995 Wrapper<T> wrapper(value);
996 typename Wrapper<T>::atomic_type& a = wrapper.a;
998 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
999 BOOST_TEST_EQ( n, approx(T(value - delta)) );
1002 // Operations returning the actual resulting value
1004 Wrapper<T> wrapper(value);
1005 typename Wrapper<T>::atomic_type& a = wrapper.a;
1007 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1008 BOOST_TEST_EQ( n, approx(T(value + delta)) );
1012 Wrapper<T> wrapper(value);
1013 typename Wrapper<T>::atomic_type& a = wrapper.a;
1015 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1016 BOOST_TEST_EQ( n, approx(T(value - delta)) );
1019 // Opaque operations
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)) );
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)) );
1035 template< template< typename > class Wrapper, typename T >
1036 void test_fp_negation()
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) );
1045 n = a.fetch_negate();
1046 BOOST_TEST_EQ( a.load(), approx((T)1) );
1047 BOOST_TEST_EQ( n, approx((T)-1) );
1050 Wrapper<T> wrapper((T)1);
1051 typename Wrapper<T>::atomic_type& a = wrapper.a;
1053 BOOST_TEST_EQ( a.load(), approx((T)-1) );
1054 BOOST_TEST_EQ( n, approx((T)-1) );
1057 BOOST_TEST_EQ( a.load(), approx((T)1) );
1058 BOOST_TEST_EQ( n, approx((T)1) );
1061 Wrapper<T> wrapper((T)1);
1062 typename Wrapper<T>::atomic_type& a = wrapper.a;
1064 BOOST_TEST_EQ( a.load(), approx((T)-1) );
1067 BOOST_TEST_EQ( a.load(), approx((T)1) );
1071 #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1073 template< template< typename > class Wrapper, typename T >
1074 void test_floating_point_api(void)
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));
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));
1084 test_fp_negation< Wrapper, T >();
1089 template< template< typename > class Wrapper, typename T >
1090 void test_pointer_api(void)
1094 test_base_operators< Wrapper, T* >(&values[0], &values[1], &values[2]);
1095 test_additive_operators< Wrapper, T*>(&values[1], 1);
1097 test_base_operators< Wrapper, void*>(&values[0], &values[1], &values[2]);
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() );
1113 template< template< typename > class Wrapper >
1114 void test_enum_api(void)
1116 test_base_operators< Wrapper >(foo, bar, baz);
1119 template< typename T >
1122 typedef T value_type;
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); }
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)
1131 test_stream << "{" << s.i << "}";
1135 template< template< typename > class Wrapper, typename T >
1136 void test_struct_api(void)
1138 T a = {1}, b = {2}, c = {3};
1140 test_base_operators< Wrapper >(a, b, c);
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() );
1151 template< typename T >
1152 struct test_struct_x2
1154 typedef T value_type;
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); }
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)
1163 test_stream << "{" << s.i << ", " << s.j << "}";
1167 template< template< typename > class Wrapper, typename T >
1168 void test_struct_x2_api(void)
1170 T a = {1, 1}, b = {2, 2}, c = {3, 3};
1172 test_base_operators< Wrapper >(a, b, c);
1177 unsigned char data[256u];
1179 inline bool operator==(large_struct const& c) const
1181 return std::memcmp(data, &c.data, sizeof(data)) == 0;
1183 inline bool operator!=(large_struct const& c) const
1185 return std::memcmp(data, &c.data, sizeof(data)) != 0;
1189 template< typename Char, typename Traits >
1190 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
1192 strm << "[large_struct]";
1196 template< template< typename > class Wrapper >
1197 void test_large_struct_api(void)
1199 large_struct a = {{1}}, b = {{2}}, c = {{3}};
1200 test_base_operators< Wrapper >(a, b, c);
1203 struct test_struct_with_ctor
1205 typedef unsigned int value_type;
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); }
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)
1215 strm << "{" << s.i << "}";
1219 template< template< typename > class Wrapper >
1220 void test_struct_with_ctor_api(void)
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 );
1230 test_struct_with_ctor a, b, c;
1235 test_base_operators< Wrapper >(a, b, c);