1 // Copyright (c) 2011 Helge Bahmann
2 // Copyright (c) 2017 - 2019 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>
16 #include <boost/config.hpp>
17 #include <boost/cstdint.hpp>
18 #include <boost/type_traits/integral_constant.hpp>
19 #include <boost/type_traits/is_pointer.hpp>
20 #include <boost/type_traits/is_signed.hpp>
21 #include <boost/type_traits/is_unsigned.hpp>
22 #include <boost/type_traits/make_signed.hpp>
23 #include <boost/type_traits/make_unsigned.hpp>
24 #include <boost/type_traits/conditional.hpp>
26 struct test_stream_type
28 typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
29 typedef std::basic_ios< char, std::char_traits< char > >& (*basic_ios_manip)(std::basic_ios< char, std::char_traits< char > >&);
30 typedef std::ostream& (*stream_manip)(std::ostream&);
32 template< typename T >
33 test_stream_type const& operator<< (T const& value) const
39 test_stream_type const& operator<< (ios_base_manip manip) const
44 test_stream_type const& operator<< (basic_ios_manip manip) const
49 test_stream_type const& operator<< (stream_manip manip) const
55 // Make sure characters are printed as numbers if tests fail
56 test_stream_type const& operator<< (char value) const
58 std::cerr << static_cast< int >(value);
61 test_stream_type const& operator<< (signed char value) const
63 std::cerr << static_cast< int >(value);
66 test_stream_type const& operator<< (unsigned char value) const
68 std::cerr << static_cast< unsigned int >(value);
71 test_stream_type const& operator<< (short value) const
73 std::cerr << static_cast< int >(value);
76 test_stream_type const& operator<< (unsigned short value) const
78 std::cerr << static_cast< unsigned int >(value);
82 #if defined(BOOST_HAS_INT128)
83 // Some GCC versions don't provide output operators for __int128
84 test_stream_type const& operator<< (boost::int128_type const& v) const
86 std::cerr << static_cast< long long >(v);
89 test_stream_type const& operator<< (boost::uint128_type const& v) const
91 std::cerr << static_cast< unsigned long long >(v);
94 #endif // defined(BOOST_HAS_INT128)
95 #if defined(BOOST_HAS_FLOAT128)
96 // libstdc++ does not provide output operators for __float128
97 test_stream_type const& operator<< (boost::float128_type const& v) const
99 std::cerr << static_cast< double >(v);
102 #endif // defined(BOOST_HAS_FLOAT128)
105 const test_stream_type test_stream = {};
107 #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
109 #include <boost/core/lightweight_test.hpp>
111 #include "value_with_epsilon.hpp"
113 /* provide helpers that exercise whether the API
114 functions of "boost::atomic" provide the correct
115 operational semantic in the case of sequential
121 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
122 boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
124 boost::atomic_flag f;
127 BOOST_TEST( !f.test_and_set() );
128 BOOST_TEST( f.test_and_set() );
130 BOOST_TEST( !f.test_and_set() );
134 void test_base_operators(T value1, T value2, T value3)
136 /* explicit load/store */
138 boost::atomic<T> a(value1);
139 BOOST_TEST_EQ( a.load(), value1 );
143 boost::atomic<T> a(value1);
145 BOOST_TEST_EQ( a.load(), value2 );
148 /* overloaded assignment/conversion */
150 boost::atomic<T> a(value1);
151 BOOST_TEST( value1 == a );
157 BOOST_TEST( value2 == a );
160 /* exchange-type operators */
162 boost::atomic<T> a(value1);
163 T n = a.exchange(value2);
164 BOOST_TEST_EQ( a.load(), value2 );
165 BOOST_TEST_EQ( n, value1 );
169 boost::atomic<T> a(value1);
171 bool success = a.compare_exchange_strong(expected, value3);
172 BOOST_TEST( success );
173 BOOST_TEST_EQ( a.load(), value3 );
174 BOOST_TEST_EQ( expected, value1 );
178 boost::atomic<T> a(value1);
180 bool success = a.compare_exchange_strong(expected, value3);
181 BOOST_TEST( !success );
182 BOOST_TEST_EQ( a.load(), value1 );
183 BOOST_TEST_EQ( expected, value1 );
187 boost::atomic<T> a(value1);
192 success = a.compare_exchange_weak(expected, value3);
194 BOOST_TEST( success );
195 BOOST_TEST_EQ( a.load(), value3 );
196 BOOST_TEST_EQ( expected, value1 );
200 boost::atomic<T> a(value1);
205 success = a.compare_exchange_weak(expected, value3);
206 if (expected != value2)
209 BOOST_TEST( !success );
210 BOOST_TEST_EQ( a.load(), value1 );
211 BOOST_TEST_EQ( expected, value1 );
215 // T requires an int constructor
216 template <typename T>
217 void test_constexpr_ctor()
219 #ifndef BOOST_NO_CXX11_CONSTEXPR
221 const boost::atomic<T> tester(value);
222 BOOST_TEST( tester == value );
226 //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
227 template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
228 struct distance_limits
230 //! Difference type D promoted to the width of type T
231 typedef typename boost::conditional<
233 typename boost::make_signed< T >::type,
234 typename boost::make_unsigned< T >::type
235 >::type promoted_difference_type;
237 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
239 return (std::numeric_limits< D >::min)();
241 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
243 return (std::numeric_limits< D >::max)();
247 #if defined(BOOST_MSVC)
248 #pragma warning(push)
249 // 'static_cast': truncation of constant value. There is no actual truncation happening because
250 // the cast is only performed if the value fits in the range of the result.
251 #pragma warning(disable: 4309)
254 template< typename T, typename D >
255 struct distance_limits< T*, D, true >
257 //! Difference type D promoted to the width of type T
258 typedef std::ptrdiff_t promoted_difference_type;
260 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
262 const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
263 const D diff = (std::numeric_limits< D >::min)();
264 // Both values are negative. Return the closest value to zero.
265 return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
267 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
269 const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
270 const D diff = (std::numeric_limits< D >::max)();
271 // Both values are positive. Return the closest value to zero.
272 return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
276 template< typename T, typename D >
277 struct distance_limits< T*, D, false >
279 //! Difference type D promoted to the width of type T
280 typedef std::size_t promoted_difference_type;
282 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
284 return (std::numeric_limits< D >::min)();
286 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
288 const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
289 const D diff = (std::numeric_limits< D >::max)();
290 return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
294 #if defined(BOOST_HAS_INT128)
296 // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
297 // So we have to specialize the limits ourself. We assume two's complement signed representation.
298 template< typename T, bool IsSigned >
299 struct distance_limits< T, boost::int128_type, IsSigned >
301 //! Difference type D promoted to the width of type T
302 typedef boost::int128_type promoted_difference_type;
304 static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
308 static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
310 return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
314 template< typename T, bool IsSigned >
315 struct distance_limits< T, boost::uint128_type, IsSigned >
317 //! Difference type D promoted to the width of type T
318 typedef boost::uint128_type promoted_difference_type;
320 static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
324 static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
326 return ~static_cast< boost::uint128_type >(0u);
330 #endif // defined(BOOST_HAS_INT128)
332 #if defined(BOOST_MSVC)
336 template<typename T, typename D, typename AddType>
337 void test_additive_operators_with_type_and_test()
340 // clang UBSAN flags this test when AddType is a pointer as it considers subtracting from a null pointer (zero_add) an UB
341 if (boost::is_pointer< AddType >::value)
345 // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
346 typedef typename distance_limits< T, D >::promoted_difference_type promoted_difference_type;
347 typedef typename boost::make_unsigned< promoted_difference_type >::type unsigned_promoted_difference_type;
348 const T zero_value = 0;
349 const D zero_diff = 0;
350 const D one_diff = 1;
351 const AddType zero_add = 0;
353 boost::atomic<T> a(zero_value);
354 bool f = a.add_and_test(zero_diff);
355 BOOST_TEST_EQ( f, false );
356 BOOST_TEST_EQ( a.load(), zero_value );
358 f = a.add_and_test(one_diff);
359 BOOST_TEST_EQ( f, true );
360 BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
363 boost::atomic<T> a(zero_value);
364 bool f = a.add_and_test((distance_limits< T, D >::max)());
365 BOOST_TEST_EQ( f, true );
366 BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
369 boost::atomic<T> a(zero_value);
370 bool f = a.add_and_test((distance_limits< T, D >::min)());
371 BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
372 BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
376 boost::atomic<T> a(zero_value);
377 bool f = a.sub_and_test(zero_diff);
378 BOOST_TEST_EQ( f, false );
379 BOOST_TEST_EQ( a.load(), zero_value );
381 f = a.sub_and_test(one_diff);
382 BOOST_TEST_EQ( f, true );
383 BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
386 boost::atomic<T> a(zero_value);
387 bool f = a.sub_and_test((distance_limits< T, D >::max)());
388 BOOST_TEST_EQ( f, true );
389 BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
392 boost::atomic<T> a(zero_value);
393 bool f = a.sub_and_test((distance_limits< T, D >::min)());
394 BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
395 // Be very careful as to not cause signed overflow on negation
396 unsigned_promoted_difference_type umin = static_cast< unsigned_promoted_difference_type >(
397 static_cast< promoted_difference_type >((distance_limits< T, D >::min)()));
399 promoted_difference_type neg_min;
400 std::memcpy(&neg_min, &umin, sizeof(neg_min));
401 BOOST_TEST_EQ( a.load(), T(zero_add + neg_min) );
405 template<typename T, typename D, typename AddType>
406 void test_additive_operators_with_type(T value, D delta)
408 /* note: the tests explicitly cast the result of any addition
409 to the type to be tested to force truncation of the result to
410 the correct range in case of overflow */
412 /* explicit add/sub */
414 boost::atomic<T> a(value);
415 T n = a.fetch_add(delta);
416 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
417 BOOST_TEST_EQ( n, value );
421 boost::atomic<T> a(value);
422 T n = a.fetch_sub(delta);
423 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
424 BOOST_TEST_EQ( n, value );
427 /* overloaded modify/assign*/
429 boost::atomic<T> a(value);
431 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
432 BOOST_TEST_EQ( n, T((AddType)value + delta) );
436 boost::atomic<T> a(value);
438 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
439 BOOST_TEST_EQ( n, T((AddType)value - delta) );
442 /* overloaded increment/decrement */
444 boost::atomic<T> a(value);
446 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
447 BOOST_TEST_EQ( n, value );
451 boost::atomic<T> a(value);
453 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
454 BOOST_TEST_EQ( n, T((AddType)value + 1) );
458 boost::atomic<T> a(value);
460 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
461 BOOST_TEST_EQ( n, value );
465 boost::atomic<T> a(value);
467 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
468 BOOST_TEST_EQ( n, T((AddType)value - 1) );
471 // Operations returning the actual resulting value
473 boost::atomic<T> a(value);
475 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
476 BOOST_TEST_EQ( n, T((AddType)value + delta) );
480 boost::atomic<T> a(value);
482 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
483 BOOST_TEST_EQ( n, T((AddType)value - delta) );
488 boost::atomic<T> a(value);
490 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
494 boost::atomic<T> a(value);
496 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
499 // Modify and test operations
500 test_additive_operators_with_type_and_test< T, D, AddType >();
503 template<typename T, typename D>
504 void test_additive_operators(T value, D delta)
506 test_additive_operators_with_type<T, D, T>(value, delta);
509 template< typename T >
513 boost::atomic<T> a((T)1);
514 T n = a.fetch_negate();
515 BOOST_TEST_EQ( a.load(), (T)-1 );
516 BOOST_TEST_EQ( n, (T)1 );
518 n = a.fetch_negate();
519 BOOST_TEST_EQ( a.load(), (T)1 );
520 BOOST_TEST_EQ( n, (T)-1 );
523 boost::atomic<T> a((T)1);
525 BOOST_TEST_EQ( a.load(), (T)-1 );
526 BOOST_TEST_EQ( n, (T)-1 );
529 BOOST_TEST_EQ( a.load(), (T)1 );
530 BOOST_TEST_EQ( n, (T)1 );
533 boost::atomic<T> a((T)1);
535 BOOST_TEST_EQ( a.load(), (T)-1 );
538 BOOST_TEST_EQ( a.load(), (T)1 );
541 boost::atomic<T> a((T)1);
542 bool f = a.negate_and_test();
543 BOOST_TEST_EQ( f, true );
544 BOOST_TEST_EQ( a.load(), (T)-1 );
546 f = a.negate_and_test();
547 BOOST_TEST_EQ( f, true );
548 BOOST_TEST_EQ( a.load(), (T)1 );
551 boost::atomic<T> a((T)0);
552 bool f = a.negate_and_test();
553 BOOST_TEST_EQ( f, false );
554 BOOST_TEST_EQ( a.load(), (T)0 );
559 void test_additive_wrap(T value)
562 boost::atomic<T> a(value);
563 T n = a.fetch_add(1) + (T)1;
564 BOOST_TEST_EQ( a.load(), n );
567 boost::atomic<T> a(value);
568 T n = a.fetch_sub(1) - (T)1;
569 BOOST_TEST_EQ( a.load(), n );
574 void test_bit_operators(T value, T delta)
576 /* explicit and/or/xor */
578 boost::atomic<T> a(value);
579 T n = a.fetch_and(delta);
580 BOOST_TEST_EQ( a.load(), T(value & delta) );
581 BOOST_TEST_EQ( n, value );
585 boost::atomic<T> a(value);
586 T n = a.fetch_or(delta);
587 BOOST_TEST_EQ( a.load(), T(value | delta) );
588 BOOST_TEST_EQ( n, value );
592 boost::atomic<T> a(value);
593 T n = a.fetch_xor(delta);
594 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
595 BOOST_TEST_EQ( n, value );
599 boost::atomic<T> a(value);
600 T n = a.fetch_complement();
601 BOOST_TEST_EQ( a.load(), T(~value) );
602 BOOST_TEST_EQ( n, value );
605 /* overloaded modify/assign */
607 boost::atomic<T> a(value);
609 BOOST_TEST_EQ( a.load(), T(value & delta) );
610 BOOST_TEST_EQ( n, T(value & delta) );
614 boost::atomic<T> a(value);
616 BOOST_TEST_EQ( a.load(), T(value | delta) );
617 BOOST_TEST_EQ( n, T(value | delta) );
621 boost::atomic<T> a(value);
623 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
624 BOOST_TEST_EQ( n, T(value ^ delta) );
627 // Operations returning the actual resulting value
629 boost::atomic<T> a(value);
630 T n = a.bitwise_and(delta);
631 BOOST_TEST_EQ( a.load(), T(value & delta) );
632 BOOST_TEST_EQ( n, T(value & delta) );
636 boost::atomic<T> a(value);
637 T n = a.bitwise_or(delta);
638 BOOST_TEST_EQ( a.load(), T(value | delta) );
639 BOOST_TEST_EQ( n, T(value | delta) );
643 boost::atomic<T> a(value);
644 T n = a.bitwise_xor(delta);
645 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
646 BOOST_TEST_EQ( n, T(value ^ delta) );
650 boost::atomic<T> a(value);
651 T n = a.bitwise_complement();
652 BOOST_TEST_EQ( a.load(), T(~value) );
653 BOOST_TEST_EQ( n, T(~value) );
658 boost::atomic<T> a(value);
660 BOOST_TEST_EQ( a.load(), T(value & delta) );
664 boost::atomic<T> a(value);
666 BOOST_TEST_EQ( a.load(), T(value | delta) );
670 boost::atomic<T> a(value);
672 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
676 boost::atomic<T> a(value);
677 a.opaque_complement();
678 BOOST_TEST_EQ( a.load(), T(~value) );
681 // Modify and test operations
683 boost::atomic<T> a((T)1);
684 bool f = a.and_and_test((T)1);
685 BOOST_TEST_EQ( f, true );
686 BOOST_TEST_EQ( a.load(), T(1) );
688 f = a.and_and_test((T)0);
689 BOOST_TEST_EQ( f, false );
690 BOOST_TEST_EQ( a.load(), T(0) );
692 f = a.and_and_test((T)0);
693 BOOST_TEST_EQ( f, false );
694 BOOST_TEST_EQ( a.load(), T(0) );
698 boost::atomic<T> a((T)0);
699 bool f = a.or_and_test((T)0);
700 BOOST_TEST_EQ( f, false );
701 BOOST_TEST_EQ( a.load(), T(0) );
703 f = a.or_and_test((T)1);
704 BOOST_TEST_EQ( f, true );
705 BOOST_TEST_EQ( a.load(), T(1) );
707 f = a.or_and_test((T)1);
708 BOOST_TEST_EQ( f, true );
709 BOOST_TEST_EQ( a.load(), T(1) );
713 boost::atomic<T> a((T)0);
714 bool f = a.xor_and_test((T)0);
715 BOOST_TEST_EQ( f, false );
716 BOOST_TEST_EQ( a.load(), T(0) );
718 f = a.xor_and_test((T)1);
719 BOOST_TEST_EQ( f, true );
720 BOOST_TEST_EQ( a.load(), T(1) );
722 f = a.xor_and_test((T)1);
723 BOOST_TEST_EQ( f, false );
724 BOOST_TEST_EQ( a.load(), T(0) );
728 boost::atomic<T> a((T)0);
729 bool f = a.complement_and_test();
730 BOOST_TEST_EQ( f, true );
731 BOOST_TEST_EQ( a.load(), static_cast< T >(~static_cast< T >(0)) );
733 f = a.complement_and_test();
734 BOOST_TEST_EQ( f, false );
735 BOOST_TEST_EQ( a.load(), T(0) );
738 // Bit test and modify operations
740 boost::atomic<T> a((T)42);
741 bool f = a.bit_test_and_set(0);
742 BOOST_TEST_EQ( f, false );
743 BOOST_TEST_EQ( a.load(), T(43) );
745 f = a.bit_test_and_set(1);
746 BOOST_TEST_EQ( f, true );
747 BOOST_TEST_EQ( a.load(), T(43) );
749 f = a.bit_test_and_set(2);
750 BOOST_TEST_EQ( f, false );
751 BOOST_TEST_EQ( a.load(), T(47) );
755 boost::atomic<T> a((T)42);
756 bool f = a.bit_test_and_reset(0);
757 BOOST_TEST_EQ( f, false );
758 BOOST_TEST_EQ( a.load(), T(42) );
760 f = a.bit_test_and_reset(1);
761 BOOST_TEST_EQ( f, true );
762 BOOST_TEST_EQ( a.load(), T(40) );
764 f = a.bit_test_and_set(2);
765 BOOST_TEST_EQ( f, false );
766 BOOST_TEST_EQ( a.load(), T(44) );
770 boost::atomic<T> a((T)42);
771 bool f = a.bit_test_and_complement(0);
772 BOOST_TEST_EQ( f, false );
773 BOOST_TEST_EQ( a.load(), T(43) );
775 f = a.bit_test_and_complement(1);
776 BOOST_TEST_EQ( f, true );
777 BOOST_TEST_EQ( a.load(), T(41) );
779 f = a.bit_test_and_complement(2);
780 BOOST_TEST_EQ( f, false );
781 BOOST_TEST_EQ( a.load(), T(45) );
786 void do_test_integral_api(boost::false_type)
788 BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
790 test_base_operators<T>(42, 43, 44);
791 test_additive_operators<T, T>(42, 17);
792 test_bit_operators<T>((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
794 /* test for unsigned overflow/underflow */
795 test_additive_operators<T, T>((T)-1, 1);
796 test_additive_operators<T, T>(0, 1);
797 /* test for signed overflow/underflow */
798 test_additive_operators<T, T>(((T)-1) >> (sizeof(T) * 8 - 1), 1);
799 test_additive_operators<T, T>(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
803 void do_test_integral_api(boost::true_type)
805 do_test_integral_api<T>(boost::false_type());
807 test_additive_wrap<T>(0u);
808 BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
809 test_additive_wrap<T>(all_ones);
810 BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
811 test_additive_wrap<T>(all_ones ^ max_signed_twos_compl);
812 test_additive_wrap<T>(max_signed_twos_compl);
816 inline void test_integral_api(void)
818 do_test_integral_api<T>(boost::is_unsigned<T>());
820 if (boost::is_signed<T>::value)
824 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
826 template<typename T, typename D>
827 void test_fp_additive_operators(T value, D delta)
829 /* explicit add/sub */
831 boost::atomic<T> a(value);
832 T n = a.fetch_add(delta);
833 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
834 BOOST_TEST_EQ( n, approx(value) );
838 boost::atomic<T> a(value);
839 T n = a.fetch_sub(delta);
840 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
841 BOOST_TEST_EQ( n, approx(value) );
844 /* overloaded modify/assign*/
846 boost::atomic<T> a(value);
848 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
849 BOOST_TEST_EQ( n, approx(T(value + delta)) );
853 boost::atomic<T> a(value);
855 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
856 BOOST_TEST_EQ( n, approx(T(value - delta)) );
859 // Operations returning the actual resulting value
861 boost::atomic<T> a(value);
863 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
864 BOOST_TEST_EQ( n, approx(T(value + delta)) );
868 boost::atomic<T> a(value);
870 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
871 BOOST_TEST_EQ( n, approx(T(value - delta)) );
876 boost::atomic<T> a(value);
878 BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
882 boost::atomic<T> a(value);
884 BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
888 template< typename T >
889 void test_fp_negation()
892 boost::atomic<T> a((T)1);
893 T n = a.fetch_negate();
894 BOOST_TEST_EQ( a.load(), approx((T)-1) );
895 BOOST_TEST_EQ( n, approx((T)1) );
897 n = a.fetch_negate();
898 BOOST_TEST_EQ( a.load(), approx((T)1) );
899 BOOST_TEST_EQ( n, approx((T)-1) );
902 boost::atomic<T> a((T)1);
904 BOOST_TEST_EQ( a.load(), approx((T)-1) );
905 BOOST_TEST_EQ( n, approx((T)-1) );
908 BOOST_TEST_EQ( a.load(), approx((T)1) );
909 BOOST_TEST_EQ( n, approx((T)1) );
912 boost::atomic<T> a((T)1);
914 BOOST_TEST_EQ( a.load(), approx((T)-1) );
917 BOOST_TEST_EQ( a.load(), approx((T)1) );
921 #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
924 inline void test_floating_point_api(void)
926 BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
928 // Note: When support for floating point is disabled, even the base operation tests may fail because
929 // the generic template specialization does not account for garbage in padding bits that are present in some FP types.
930 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
931 test_base_operators<T>(static_cast<T>(42.1), static_cast<T>(43.2), static_cast<T>(44.3));
933 test_fp_additive_operators<T, T>(static_cast<T>(42.5), static_cast<T>(17.7));
934 test_fp_additive_operators<T, T>(static_cast<T>(-42.5), static_cast<T>(-17.7));
936 test_fp_negation<T>();
942 void test_pointer_api(void)
944 BOOST_TEST_GE( sizeof(boost::atomic<T *>), sizeof(T *));
945 BOOST_TEST_GE( sizeof(boost::atomic<void *>), sizeof(T *));
949 test_base_operators<T*>(&values[0], &values[1], &values[2]);
950 test_additive_operators<T*>(&values[1], 1);
952 test_base_operators<void*>(&values[0], &values[1], &values[2]);
954 #if defined(BOOST_HAS_INTPTR_T)
955 boost::atomic<void *> ptr;
956 boost::atomic<boost::intptr_t> integral;
957 BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
969 test_base_operators(foo, bar, baz);
975 typedef T value_type;
977 inline bool operator==(const test_struct & c) const {return i == c.i;}
978 inline bool operator!=(const test_struct & c) const {return i != c.i;}
981 template< typename Char, typename Traits, typename T >
982 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
984 test_stream << "{" << s.i << "}";
990 test_struct_api(void)
992 T a = {1}, b = {2}, c = {3};
994 test_base_operators(a, b, c);
998 boost::atomic<typename T::value_type> si;
999 BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
1003 template<typename T>
1004 struct test_struct_x2
1006 typedef T value_type;
1008 inline bool operator==(const test_struct_x2 & c) const {return i == c.i && j == c.j;}
1009 inline bool operator!=(const test_struct_x2 & c) const {return i != c.i && j != c.j;}
1012 template< typename Char, typename Traits, typename T >
1013 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
1015 test_stream << "{" << s.i << ", " << s.j << "}";
1019 template<typename T>
1021 test_struct_x2_api(void)
1023 T a = {1, 1}, b = {2, 2}, c = {3, 3};
1025 test_base_operators(a, b, c);
1032 inline bool operator==(const large_struct & c) const
1034 return std::memcmp(data, &c.data, sizeof(data)) == 0;
1036 inline bool operator!=(const large_struct & c) const
1038 return std::memcmp(data, &c.data, sizeof(data)) != 0;
1042 template< typename Char, typename Traits >
1043 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
1045 strm << "[large_struct]";
1050 test_large_struct_api(void)
1052 large_struct a = {{1}}, b = {{2}}, c = {{3}};
1053 test_base_operators(a, b, c);
1056 struct test_struct_with_ctor
1058 typedef unsigned int value_type;
1060 test_struct_with_ctor() : i(0x01234567) {}
1061 inline bool operator==(const test_struct_with_ctor & c) const {return i == c.i;}
1062 inline bool operator!=(const test_struct_with_ctor & c) const {return i != c.i;}
1065 template< typename Char, typename Traits >
1066 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const&)
1068 strm << "[test_struct_with_ctor]";
1073 test_struct_with_ctor_api(void)
1076 test_struct_with_ctor s;
1077 boost::atomic<test_struct_with_ctor> sa;
1078 // Check that the default constructor was called
1079 BOOST_TEST( sa.load() == s );
1082 test_struct_with_ctor a, b, c;
1087 test_base_operators(a, b, c);