1 // Copyright (c) 2011 Helge Bahmann
2 // Copyright (c) 2017 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_signed.hpp>
20 #include <boost/type_traits/is_unsigned.hpp>
22 struct test_stream_type
24 typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
25 typedef std::basic_ios< char, std::char_traits< char > >& (*basic_ios_manip)(std::basic_ios< char, std::char_traits< char > >&);
26 typedef std::ostream& (*stream_manip)(std::ostream&);
28 template< typename T >
29 test_stream_type const& operator<< (T const& value) const
35 test_stream_type const& operator<< (ios_base_manip manip) const
40 test_stream_type const& operator<< (basic_ios_manip manip) const
45 test_stream_type const& operator<< (stream_manip manip) const
51 // Make sure characters are printed as numbers if tests fail
52 test_stream_type const& operator<< (char value) const
54 std::cerr << static_cast< int >(value);
57 test_stream_type const& operator<< (signed char value) const
59 std::cerr << static_cast< int >(value);
62 test_stream_type const& operator<< (unsigned char value) const
64 std::cerr << static_cast< unsigned int >(value);
67 test_stream_type const& operator<< (short value) const
69 std::cerr << static_cast< int >(value);
72 test_stream_type const& operator<< (unsigned short value) const
74 std::cerr << static_cast< unsigned int >(value);
78 #if defined(BOOST_HAS_INT128)
79 // Some GCC versions don't provide output operators for __int128
80 test_stream_type const& operator<< (boost::int128_type const& v) const
82 std::cerr << static_cast< long long >(v);
85 test_stream_type const& operator<< (boost::uint128_type const& v) const
87 std::cerr << static_cast< unsigned long long >(v);
90 #endif // defined(BOOST_HAS_INT128)
93 const test_stream_type test_stream = {};
95 #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
97 #include <boost/core/lightweight_test.hpp>
99 /* provide helpers that exercise whether the API
100 functions of "boost::atomic" provide the correct
101 operational semantic in the case of sequential
107 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
108 boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
110 boost::atomic_flag f;
113 BOOST_TEST( !f.test_and_set() );
114 BOOST_TEST( f.test_and_set() );
116 BOOST_TEST( !f.test_and_set() );
120 void test_base_operators(T value1, T value2, T value3)
122 /* explicit load/store */
124 boost::atomic<T> a(value1);
125 BOOST_TEST_EQ( a.load(), value1 );
129 boost::atomic<T> a(value1);
131 BOOST_TEST_EQ( a.load(), value2 );
134 /* overloaded assignment/conversion */
136 boost::atomic<T> a(value1);
137 BOOST_TEST( value1 == a );
143 BOOST_TEST( value2 == a );
146 /* exchange-type operators */
148 boost::atomic<T> a(value1);
149 T n = a.exchange(value2);
150 BOOST_TEST_EQ( a.load(), value2 );
151 BOOST_TEST_EQ( n, value1 );
155 boost::atomic<T> a(value1);
157 bool success = a.compare_exchange_strong(expected, value3);
158 BOOST_TEST( success );
159 BOOST_TEST_EQ( a.load(), value3 );
160 BOOST_TEST_EQ( expected, value1 );
164 boost::atomic<T> a(value1);
166 bool success = a.compare_exchange_strong(expected, value3);
167 BOOST_TEST( !success );
168 BOOST_TEST_EQ( a.load(), value1 );
169 BOOST_TEST_EQ( expected, value1 );
173 boost::atomic<T> a(value1);
178 success = a.compare_exchange_weak(expected, value3);
180 BOOST_TEST( success );
181 BOOST_TEST_EQ( a.load(), value3 );
182 BOOST_TEST_EQ( expected, value1 );
186 boost::atomic<T> a(value1);
191 success = a.compare_exchange_weak(expected, value3);
192 if (expected != value2)
195 BOOST_TEST( !success );
196 BOOST_TEST_EQ( a.load(), value1 );
197 BOOST_TEST_EQ( expected, value1 );
201 // T requires an int constructor
202 template <typename T>
203 void test_constexpr_ctor()
205 #ifndef BOOST_NO_CXX11_CONSTEXPR
207 const boost::atomic<T> tester(value);
208 BOOST_TEST( tester == value );
212 //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
213 template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
214 struct distance_limits
216 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
218 return (std::numeric_limits< D >::min)();
220 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
222 return (std::numeric_limits< D >::max)();
226 #if defined(BOOST_MSVC)
227 #pragma warning(push)
228 // 'static_cast': truncation of constant value. There is no actual truncation happening because
229 // the cast is only performed if the value fits in the range of the result.
230 #pragma warning(disable: 4309)
233 template< typename T, typename D >
234 struct distance_limits< T*, D, true >
236 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
238 const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
239 const D diff = (std::numeric_limits< D >::min)();
240 // Both values are negative. Return the closest value to zero.
241 return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
243 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
245 const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
246 const D diff = (std::numeric_limits< D >::max)();
247 // Both values are positive. Return the closest value to zero.
248 return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
252 template< typename T, typename D >
253 struct distance_limits< T*, D, false >
255 static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
257 return (std::numeric_limits< D >::min)();
259 static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
261 const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
262 const D diff = (std::numeric_limits< D >::max)();
263 return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
267 #if defined(BOOST_HAS_INT128)
269 // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
270 // So we have to specialize the limits ourself. We assume two's complement signed representation.
271 template< typename T, bool IsSigned >
272 struct distance_limits< T, boost::int128_type, IsSigned >
274 static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
278 static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
280 return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
284 template< typename T, bool IsSigned >
285 struct distance_limits< T, boost::uint128_type, IsSigned >
287 static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
291 static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
293 return ~static_cast< boost::uint128_type >(0u);
297 #endif // defined(BOOST_HAS_INT128)
299 #if defined(BOOST_MSVC)
303 template<typename T, typename D, typename AddType>
304 void test_additive_operators_with_type_and_test()
306 // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
307 const T zero_value = 0;
308 const D zero_diff = 0;
309 const D one_diff = 1;
310 const AddType zero_add = 0;
312 boost::atomic<T> a(zero_value);
313 bool f = a.add_and_test(zero_diff);
314 BOOST_TEST_EQ( f, true );
315 BOOST_TEST_EQ( a.load(), zero_value );
317 f = a.add_and_test(one_diff);
318 BOOST_TEST_EQ( f, false );
319 BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
322 boost::atomic<T> a(zero_value);
323 bool f = a.add_and_test((distance_limits< T, D >::max)());
324 BOOST_TEST_EQ( f, false );
325 BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
328 boost::atomic<T> a(zero_value);
329 bool f = a.add_and_test((distance_limits< T, D >::min)());
330 BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() == 0) );
331 BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
335 boost::atomic<T> a(zero_value);
336 bool f = a.sub_and_test(zero_diff);
337 BOOST_TEST_EQ( f, true );
338 BOOST_TEST_EQ( a.load(), zero_value );
340 f = a.sub_and_test(one_diff);
341 BOOST_TEST_EQ( f, false );
342 BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
345 boost::atomic<T> a(zero_value);
346 bool f = a.sub_and_test((distance_limits< T, D >::max)());
347 BOOST_TEST_EQ( f, false );
348 BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
351 boost::atomic<T> a(zero_value);
352 bool f = a.sub_and_test((distance_limits< T, D >::min)());
353 BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() == 0) );
354 BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::min)()) );
358 template<typename T, typename D, typename AddType>
359 void test_additive_operators_with_type(T value, D delta)
361 /* note: the tests explicitly cast the result of any addition
362 to the type to be tested to force truncation of the result to
363 the correct range in case of overflow */
365 /* explicit add/sub */
367 boost::atomic<T> a(value);
368 T n = a.fetch_add(delta);
369 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
370 BOOST_TEST_EQ( n, value );
374 boost::atomic<T> a(value);
375 T n = a.fetch_sub(delta);
376 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
377 BOOST_TEST_EQ( n, value );
380 /* overloaded modify/assign*/
382 boost::atomic<T> a(value);
384 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
385 BOOST_TEST_EQ( n, T((AddType)value + delta) );
389 boost::atomic<T> a(value);
391 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
392 BOOST_TEST_EQ( n, T((AddType)value - delta) );
395 /* overloaded increment/decrement */
397 boost::atomic<T> a(value);
399 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
400 BOOST_TEST_EQ( n, value );
404 boost::atomic<T> a(value);
406 BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
407 BOOST_TEST_EQ( n, T((AddType)value + 1) );
411 boost::atomic<T> a(value);
413 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
414 BOOST_TEST_EQ( n, value );
418 boost::atomic<T> a(value);
420 BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
421 BOOST_TEST_EQ( n, T((AddType)value - 1) );
426 boost::atomic<T> a(value);
428 BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
432 boost::atomic<T> a(value);
434 BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
437 // Modify and test operations
438 test_additive_operators_with_type_and_test< T, D, AddType >();
441 template<typename T, typename D>
442 void test_additive_operators(T value, D delta)
444 test_additive_operators_with_type<T, D, T>(value, delta);
447 template< typename T >
451 boost::atomic<T> a((T)1);
452 T n = a.fetch_negate();
453 BOOST_TEST_EQ( a.load(), (T)-1 );
454 BOOST_TEST_EQ( n, (T)1 );
456 n = a.fetch_negate();
457 BOOST_TEST_EQ( a.load(), (T)1 );
458 BOOST_TEST_EQ( n, (T)-1 );
461 boost::atomic<T> a((T)1);
463 BOOST_TEST_EQ( a.load(), (T)-1 );
466 BOOST_TEST_EQ( a.load(), (T)1 );
471 void test_additive_wrap(T value)
474 boost::atomic<T> a(value);
475 T n = a.fetch_add(1) + (T)1;
476 BOOST_TEST_EQ( a.load(), n );
479 boost::atomic<T> a(value);
480 T n = a.fetch_sub(1) - (T)1;
481 BOOST_TEST_EQ( a.load(), n );
486 void test_bit_operators(T value, T delta)
488 /* explicit and/or/xor */
490 boost::atomic<T> a(value);
491 T n = a.fetch_and(delta);
492 BOOST_TEST_EQ( a.load(), T(value & delta) );
493 BOOST_TEST_EQ( n, value );
497 boost::atomic<T> a(value);
498 T n = a.fetch_or(delta);
499 BOOST_TEST_EQ( a.load(), T(value | delta) );
500 BOOST_TEST_EQ( n, value );
504 boost::atomic<T> a(value);
505 T n = a.fetch_xor(delta);
506 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
507 BOOST_TEST_EQ( n, value );
511 boost::atomic<T> a(value);
512 T n = a.fetch_complement();
513 BOOST_TEST_EQ( a.load(), T(~value) );
514 BOOST_TEST_EQ( n, value );
517 /* overloaded modify/assign */
519 boost::atomic<T> a(value);
521 BOOST_TEST_EQ( a.load(), T(value & delta) );
522 BOOST_TEST_EQ( n, T(value & delta) );
526 boost::atomic<T> a(value);
528 BOOST_TEST_EQ( a.load(), T(value | delta) );
529 BOOST_TEST_EQ( n, T(value | delta) );
533 boost::atomic<T> a(value);
535 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
536 BOOST_TEST_EQ( n, T(value ^ delta) );
541 boost::atomic<T> a(value);
543 BOOST_TEST_EQ( a.load(), T(value & delta) );
547 boost::atomic<T> a(value);
549 BOOST_TEST_EQ( a.load(), T(value | delta) );
553 boost::atomic<T> a(value);
555 BOOST_TEST_EQ( a.load(), T(value ^ delta) );
559 boost::atomic<T> a(value);
560 a.opaque_complement();
561 BOOST_TEST_EQ( a.load(), T(~value) );
564 // Modify and test operations
566 boost::atomic<T> a((T)1);
567 bool f = a.and_and_test((T)1);
568 BOOST_TEST_EQ( f, false );
569 BOOST_TEST_EQ( a.load(), T(1) );
571 f = a.and_and_test((T)0);
572 BOOST_TEST_EQ( f, true );
573 BOOST_TEST_EQ( a.load(), T(0) );
575 f = a.and_and_test((T)0);
576 BOOST_TEST_EQ( f, true );
577 BOOST_TEST_EQ( a.load(), T(0) );
581 boost::atomic<T> a((T)0);
582 bool f = a.or_and_test((T)0);
583 BOOST_TEST_EQ( f, true );
584 BOOST_TEST_EQ( a.load(), T(0) );
586 f = a.or_and_test((T)1);
587 BOOST_TEST_EQ( f, false );
588 BOOST_TEST_EQ( a.load(), T(1) );
590 f = a.or_and_test((T)1);
591 BOOST_TEST_EQ( f, false );
592 BOOST_TEST_EQ( a.load(), T(1) );
596 boost::atomic<T> a((T)0);
597 bool f = a.xor_and_test((T)0);
598 BOOST_TEST_EQ( f, true );
599 BOOST_TEST_EQ( a.load(), T(0) );
601 f = a.xor_and_test((T)1);
602 BOOST_TEST_EQ( f, false );
603 BOOST_TEST_EQ( a.load(), T(1) );
605 f = a.xor_and_test((T)1);
606 BOOST_TEST_EQ( f, true );
607 BOOST_TEST_EQ( a.load(), T(0) );
610 // Bit test and modify operations
612 boost::atomic<T> a((T)42);
613 bool f = a.bit_test_and_set(0);
614 BOOST_TEST_EQ( f, false );
615 BOOST_TEST_EQ( a.load(), T(43) );
617 f = a.bit_test_and_set(1);
618 BOOST_TEST_EQ( f, true );
619 BOOST_TEST_EQ( a.load(), T(43) );
621 f = a.bit_test_and_set(2);
622 BOOST_TEST_EQ( f, false );
623 BOOST_TEST_EQ( a.load(), T(47) );
627 boost::atomic<T> a((T)42);
628 bool f = a.bit_test_and_reset(0);
629 BOOST_TEST_EQ( f, false );
630 BOOST_TEST_EQ( a.load(), T(42) );
632 f = a.bit_test_and_reset(1);
633 BOOST_TEST_EQ( f, true );
634 BOOST_TEST_EQ( a.load(), T(40) );
636 f = a.bit_test_and_set(2);
637 BOOST_TEST_EQ( f, false );
638 BOOST_TEST_EQ( a.load(), T(44) );
642 boost::atomic<T> a((T)42);
643 bool f = a.bit_test_and_complement(0);
644 BOOST_TEST_EQ( f, false );
645 BOOST_TEST_EQ( a.load(), T(43) );
647 f = a.bit_test_and_complement(1);
648 BOOST_TEST_EQ( f, true );
649 BOOST_TEST_EQ( a.load(), T(41) );
651 f = a.bit_test_and_complement(2);
652 BOOST_TEST_EQ( f, false );
653 BOOST_TEST_EQ( a.load(), T(45) );
658 void do_test_integral_api(boost::false_type)
660 BOOST_TEST( sizeof(boost::atomic<T>) >= sizeof(T));
662 test_base_operators<T>(42, 43, 44);
663 test_additive_operators<T, T>(42, 17);
664 test_bit_operators<T>((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
666 /* test for unsigned overflow/underflow */
667 test_additive_operators<T, T>((T)-1, 1);
668 test_additive_operators<T, T>(0, 1);
669 /* test for signed overflow/underflow */
670 test_additive_operators<T, T>(((T)-1) >> (sizeof(T) * 8 - 1), 1);
671 test_additive_operators<T, T>(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
675 void do_test_integral_api(boost::true_type)
677 do_test_integral_api<T>(boost::false_type());
679 test_additive_wrap<T>(0u);
680 BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
681 test_additive_wrap<T>(all_ones);
682 BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
683 test_additive_wrap<T>(all_ones ^ max_signed_twos_compl);
684 test_additive_wrap<T>(max_signed_twos_compl);
688 inline void test_integral_api(void)
690 do_test_integral_api<T>(boost::is_unsigned<T>());
692 if (boost::is_signed<T>::value)
697 void test_pointer_api(void)
699 BOOST_TEST_GE( sizeof(boost::atomic<T *>), sizeof(T *));
700 BOOST_TEST_GE( sizeof(boost::atomic<void *>), sizeof(T *));
704 test_base_operators<T*>(&values[0], &values[1], &values[2]);
705 test_additive_operators<T*>(&values[1], 1);
707 test_base_operators<void*>(&values[0], &values[1], &values[2]);
709 #if defined(BOOST_HAS_INTPTR_T)
710 boost::atomic<void *> ptr;
711 boost::atomic<boost::intptr_t> integral;
712 BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
724 test_base_operators(foo, bar, baz);
730 typedef T value_type;
732 inline bool operator==(const test_struct & c) const {return i == c.i;}
733 inline bool operator!=(const test_struct & c) const {return i != c.i;}
736 template< typename Char, typename Traits, typename T >
737 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
739 test_stream << "{" << s.i << "}";
745 test_struct_api(void)
747 T a = {1}, b = {2}, c = {3};
749 test_base_operators(a, b, c);
753 boost::atomic<typename T::value_type> si;
754 BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
759 struct test_struct_x2
761 typedef T value_type;
763 inline bool operator==(const test_struct_x2 & c) const {return i == c.i && j == c.j;}
764 inline bool operator!=(const test_struct_x2 & c) const {return i != c.i && j != c.j;}
767 template< typename Char, typename Traits, typename T >
768 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
770 test_stream << "{" << s.i << ", " << s.j << "}";
776 test_struct_x2_api(void)
778 T a = {1, 1}, b = {2, 2}, c = {3, 3};
780 test_base_operators(a, b, c);
787 inline bool operator==(const large_struct & c) const
789 return std::memcmp(data, &c.data, sizeof(data)) == 0;
791 inline bool operator!=(const large_struct & c) const
793 return std::memcmp(data, &c.data, sizeof(data)) != 0;
797 template< typename Char, typename Traits >
798 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
800 strm << "[large_struct]";
805 test_large_struct_api(void)
807 large_struct a = {{1}}, b = {{2}}, c = {{3}};
808 test_base_operators(a, b, c);
811 struct test_struct_with_ctor
813 typedef unsigned int value_type;
815 test_struct_with_ctor() : i(0x01234567) {}
816 inline bool operator==(const test_struct_with_ctor & c) const {return i == c.i;}
817 inline bool operator!=(const test_struct_with_ctor & c) const {return i != c.i;}
820 template< typename Char, typename Traits >
821 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const&)
823 strm << "[test_struct_with_ctor]";
828 test_struct_with_ctor_api(void)
831 test_struct_with_ctor s;
832 boost::atomic<test_struct_with_ctor> sa;
833 // Check that the default constructor was called
834 BOOST_TEST( sa.load() == s );
837 test_struct_with_ctor a, b, c;
842 test_base_operators(a, b, c);