Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / atomic / test / api_test_helpers.hpp
1 //  Copyright (c) 2011 Helge Bahmann
2 //  Copyright (c) 2017 - 2019 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 <limits>
15 #include <iostream>
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>
25
26 struct test_stream_type
27 {
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&);
31
32     template< typename T >
33     test_stream_type const& operator<< (T const& value) const
34     {
35         std::cerr << value;
36         return *this;
37     }
38
39     test_stream_type const& operator<< (ios_base_manip manip) const
40     {
41         std::cerr << manip;
42         return *this;
43     }
44     test_stream_type const& operator<< (basic_ios_manip manip) const
45     {
46         std::cerr << manip;
47         return *this;
48     }
49     test_stream_type const& operator<< (stream_manip manip) const
50     {
51         std::cerr << manip;
52         return *this;
53     }
54
55     // Make sure characters are printed as numbers if tests fail
56     test_stream_type const& operator<< (char value) const
57     {
58         std::cerr << static_cast< int >(value);
59         return *this;
60     }
61     test_stream_type const& operator<< (signed char value) const
62     {
63         std::cerr << static_cast< int >(value);
64         return *this;
65     }
66     test_stream_type const& operator<< (unsigned char value) const
67     {
68         std::cerr << static_cast< unsigned int >(value);
69         return *this;
70     }
71     test_stream_type const& operator<< (short value) const
72     {
73         std::cerr << static_cast< int >(value);
74         return *this;
75     }
76     test_stream_type const& operator<< (unsigned short value) const
77     {
78         std::cerr << static_cast< unsigned int >(value);
79         return *this;
80     }
81
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
85     {
86         std::cerr << static_cast< long long >(v);
87         return *this;
88     }
89     test_stream_type const& operator<< (boost::uint128_type const& v) const
90     {
91         std::cerr << static_cast< unsigned long long >(v);
92         return *this;
93     }
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
98     {
99         std::cerr << static_cast< double >(v);
100         return *this;
101     }
102 #endif // defined(BOOST_HAS_FLOAT128)
103 };
104
105 const test_stream_type test_stream = {};
106
107 #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
108
109 #include <boost/core/lightweight_test.hpp>
110
111 #include "value_with_epsilon.hpp"
112
113 /* provide helpers that exercise whether the API
114 functions of "boost::atomic" provide the correct
115 operational semantic in the case of sequential
116 execution */
117
118 static void
119 test_flag_api(void)
120 {
121 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
122     boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
123 #else
124     boost::atomic_flag f;
125 #endif
126
127     BOOST_TEST( !f.test_and_set() );
128     BOOST_TEST( f.test_and_set() );
129     f.clear();
130     BOOST_TEST( !f.test_and_set() );
131 }
132
133 template<typename T>
134 void test_base_operators(T value1, T value2, T value3)
135 {
136     /* explicit load/store */
137     {
138         boost::atomic<T> a(value1);
139         BOOST_TEST_EQ( a.load(), value1 );
140     }
141
142     {
143         boost::atomic<T> a(value1);
144         a.store(value2);
145         BOOST_TEST_EQ( a.load(), value2 );
146     }
147
148     /* overloaded assignment/conversion */
149     {
150         boost::atomic<T> a(value1);
151         BOOST_TEST( value1 == a );
152     }
153
154     {
155         boost::atomic<T> a;
156         a = value2;
157         BOOST_TEST( value2 == a );
158     }
159
160     /* exchange-type operators */
161     {
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 );
166     }
167
168     {
169         boost::atomic<T> a(value1);
170         T expected = 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 );
175     }
176
177     {
178         boost::atomic<T> a(value1);
179         T expected = value2;
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 );
184     }
185
186     {
187         boost::atomic<T> a(value1);
188         T expected;
189         bool success;
190         do {
191             expected = value1;
192             success = a.compare_exchange_weak(expected, value3);
193         } while(!success);
194         BOOST_TEST( success );
195         BOOST_TEST_EQ( a.load(), value3 );
196         BOOST_TEST_EQ( expected, value1 );
197     }
198
199     {
200         boost::atomic<T> a(value1);
201         T expected;
202         bool success;
203         do {
204             expected = value2;
205             success = a.compare_exchange_weak(expected, value3);
206             if (expected != value2)
207                 break;
208         } while(!success);
209         BOOST_TEST( !success );
210         BOOST_TEST_EQ( a.load(), value1 );
211         BOOST_TEST_EQ( expected, value1 );
212     }
213 }
214
215 // T requires an int constructor
216 template <typename T>
217 void test_constexpr_ctor()
218 {
219 #ifndef BOOST_NO_CXX11_CONSTEXPR
220     const T value(0);
221     const boost::atomic<T> tester(value);
222     BOOST_TEST( tester == value );
223 #endif
224 }
225
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
229 {
230     //! Difference type D promoted to the width of type T
231     typedef typename boost::conditional<
232         IsSigned,
233         typename boost::make_signed< T >::type,
234         typename boost::make_unsigned< T >::type
235     >::type promoted_difference_type;
236
237     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
238     {
239         return (std::numeric_limits< D >::min)();
240     }
241     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
242     {
243         return (std::numeric_limits< D >::max)();
244     }
245 };
246
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)
252 #endif
253
254 template< typename T, typename D >
255 struct distance_limits< T*, D, true >
256 {
257     //! Difference type D promoted to the width of type T
258     typedef std::ptrdiff_t promoted_difference_type;
259
260     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
261     {
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;
266     }
267     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
268     {
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;
273     }
274 };
275
276 template< typename T, typename D >
277 struct distance_limits< T*, D, false >
278 {
279     //! Difference type D promoted to the width of type T
280     typedef std::size_t promoted_difference_type;
281
282     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
283     {
284         return (std::numeric_limits< D >::min)();
285     }
286     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
287     {
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;
291     }
292 };
293
294 #if defined(BOOST_HAS_INT128)
295
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 >
300 {
301     //! Difference type D promoted to the width of type T
302     typedef boost::int128_type promoted_difference_type;
303
304     static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
305     {
306         return -(max)() - 1;
307     }
308     static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
309     {
310         return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
311     }
312 };
313
314 template< typename T, bool IsSigned >
315 struct distance_limits< T, boost::uint128_type, IsSigned >
316 {
317     //! Difference type D promoted to the width of type T
318     typedef boost::uint128_type promoted_difference_type;
319
320     static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
321     {
322         return 0u;
323     }
324     static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
325     {
326         return ~static_cast< boost::uint128_type >(0u);
327     }
328 };
329
330 #endif // defined(BOOST_HAS_INT128)
331
332 #if defined(BOOST_MSVC)
333 #pragma warning(pop)
334 #endif
335
336 template<typename T, typename D, typename AddType>
337 void test_additive_operators_with_type_and_test()
338 {
339 #if defined(UBSAN)
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)
342         return;
343 #endif
344
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;
352     {
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 );
357
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) );
361     }
362     {
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)()) );
367     }
368     {
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)()) );
373     }
374
375     {
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 );
380
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) );
384     }
385     {
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)()) );
390     }
391     {
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)()));
398         umin = -umin;
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) );
402     }
403 }
404
405 template<typename T, typename D, typename AddType>
406 void test_additive_operators_with_type(T value, D delta)
407 {
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 */
411
412     /* explicit add/sub */
413     {
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 );
418     }
419
420     {
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 );
425     }
426
427     /* overloaded modify/assign*/
428     {
429         boost::atomic<T> a(value);
430         T n = (a += delta);
431         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
432         BOOST_TEST_EQ( n, T((AddType)value + delta) );
433     }
434
435     {
436         boost::atomic<T> a(value);
437         T n = (a -= delta);
438         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
439         BOOST_TEST_EQ( n, T((AddType)value - delta) );
440     }
441
442     /* overloaded increment/decrement */
443     {
444         boost::atomic<T> a(value);
445         T n = a++;
446         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
447         BOOST_TEST_EQ( n, value );
448     }
449
450     {
451         boost::atomic<T> a(value);
452         T n = ++a;
453         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
454         BOOST_TEST_EQ( n, T((AddType)value + 1) );
455     }
456
457     {
458         boost::atomic<T> a(value);
459         T n = a--;
460         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
461         BOOST_TEST_EQ( n, value );
462     }
463
464     {
465         boost::atomic<T> a(value);
466         T n = --a;
467         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
468         BOOST_TEST_EQ( n, T((AddType)value - 1) );
469     }
470
471     // Operations returning the actual resulting value
472     {
473         boost::atomic<T> a(value);
474         T n = a.add(delta);
475         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
476         BOOST_TEST_EQ( n, T((AddType)value + delta) );
477     }
478
479     {
480         boost::atomic<T> a(value);
481         T n = a.sub(delta);
482         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
483         BOOST_TEST_EQ( n, T((AddType)value - delta) );
484     }
485
486     // Opaque operations
487     {
488         boost::atomic<T> a(value);
489         a.opaque_add(delta);
490         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
491     }
492
493     {
494         boost::atomic<T> a(value);
495         a.opaque_sub(delta);
496         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
497     }
498
499     // Modify and test operations
500     test_additive_operators_with_type_and_test< T, D, AddType >();
501 }
502
503 template<typename T, typename D>
504 void test_additive_operators(T value, D delta)
505 {
506     test_additive_operators_with_type<T, D, T>(value, delta);
507 }
508
509 template< typename T >
510 void test_negation()
511 {
512     {
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 );
517
518         n = a.fetch_negate();
519         BOOST_TEST_EQ( a.load(), (T)1 );
520         BOOST_TEST_EQ( n, (T)-1 );
521     }
522     {
523         boost::atomic<T> a((T)1);
524         T n = a.negate();
525         BOOST_TEST_EQ( a.load(), (T)-1 );
526         BOOST_TEST_EQ( n, (T)-1 );
527
528         n = a.negate();
529         BOOST_TEST_EQ( a.load(), (T)1 );
530         BOOST_TEST_EQ( n, (T)1 );
531     }
532     {
533         boost::atomic<T> a((T)1);
534         a.opaque_negate();
535         BOOST_TEST_EQ( a.load(), (T)-1 );
536
537         a.opaque_negate();
538         BOOST_TEST_EQ( a.load(), (T)1 );
539     }
540     {
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 );
545
546         f = a.negate_and_test();
547         BOOST_TEST_EQ( f, true );
548         BOOST_TEST_EQ( a.load(), (T)1 );
549     }
550     {
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 );
555     }
556 }
557
558 template<typename T>
559 void test_additive_wrap(T value)
560 {
561     {
562         boost::atomic<T> a(value);
563         T n = a.fetch_add(1) + (T)1;
564         BOOST_TEST_EQ( a.load(), n );
565     }
566     {
567         boost::atomic<T> a(value);
568         T n = a.fetch_sub(1) - (T)1;
569         BOOST_TEST_EQ( a.load(), n );
570     }
571 }
572
573 template<typename T>
574 void test_bit_operators(T value, T delta)
575 {
576     /* explicit and/or/xor */
577     {
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 );
582     }
583
584     {
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 );
589     }
590
591     {
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 );
596     }
597
598     {
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 );
603     }
604
605     /* overloaded modify/assign */
606     {
607         boost::atomic<T> a(value);
608         T n = (a &= delta);
609         BOOST_TEST_EQ( a.load(), T(value & delta) );
610         BOOST_TEST_EQ( n, T(value & delta) );
611     }
612
613     {
614         boost::atomic<T> a(value);
615         T n = (a |= delta);
616         BOOST_TEST_EQ( a.load(), T(value | delta) );
617         BOOST_TEST_EQ( n, T(value | delta) );
618     }
619
620     {
621         boost::atomic<T> a(value);
622         T n = (a ^= delta);
623         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
624         BOOST_TEST_EQ( n, T(value ^ delta) );
625     }
626
627     // Operations returning the actual resulting value
628     {
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) );
633     }
634
635     {
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) );
640     }
641
642     {
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) );
647     }
648
649     {
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) );
654     }
655
656     // Opaque operations
657     {
658         boost::atomic<T> a(value);
659         a.opaque_and(delta);
660         BOOST_TEST_EQ( a.load(), T(value & delta) );
661     }
662
663     {
664         boost::atomic<T> a(value);
665         a.opaque_or(delta);
666         BOOST_TEST_EQ( a.load(), T(value | delta) );
667     }
668
669     {
670         boost::atomic<T> a(value);
671         a.opaque_xor(delta);
672         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
673     }
674
675     {
676         boost::atomic<T> a(value);
677         a.opaque_complement();
678         BOOST_TEST_EQ( a.load(), T(~value) );
679     }
680
681     // Modify and test operations
682     {
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) );
687
688         f = a.and_and_test((T)0);
689         BOOST_TEST_EQ( f, false );
690         BOOST_TEST_EQ( a.load(), T(0) );
691
692         f = a.and_and_test((T)0);
693         BOOST_TEST_EQ( f, false );
694         BOOST_TEST_EQ( a.load(), T(0) );
695     }
696
697     {
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) );
702
703         f = a.or_and_test((T)1);
704         BOOST_TEST_EQ( f, true );
705         BOOST_TEST_EQ( a.load(), T(1) );
706
707         f = a.or_and_test((T)1);
708         BOOST_TEST_EQ( f, true );
709         BOOST_TEST_EQ( a.load(), T(1) );
710     }
711
712     {
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) );
717
718         f = a.xor_and_test((T)1);
719         BOOST_TEST_EQ( f, true );
720         BOOST_TEST_EQ( a.load(), T(1) );
721
722         f = a.xor_and_test((T)1);
723         BOOST_TEST_EQ( f, false );
724         BOOST_TEST_EQ( a.load(), T(0) );
725     }
726
727     {
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)) );
732
733         f = a.complement_and_test();
734         BOOST_TEST_EQ( f, false );
735         BOOST_TEST_EQ( a.load(), T(0) );
736     }
737
738     // Bit test and modify operations
739     {
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) );
744
745         f = a.bit_test_and_set(1);
746         BOOST_TEST_EQ( f, true );
747         BOOST_TEST_EQ( a.load(), T(43) );
748
749         f = a.bit_test_and_set(2);
750         BOOST_TEST_EQ( f, false );
751         BOOST_TEST_EQ( a.load(), T(47) );
752     }
753
754     {
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) );
759
760         f = a.bit_test_and_reset(1);
761         BOOST_TEST_EQ( f, true );
762         BOOST_TEST_EQ( a.load(), T(40) );
763
764         f = a.bit_test_and_set(2);
765         BOOST_TEST_EQ( f, false );
766         BOOST_TEST_EQ( a.load(), T(44) );
767     }
768
769     {
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) );
774
775         f = a.bit_test_and_complement(1);
776         BOOST_TEST_EQ( f, true );
777         BOOST_TEST_EQ( a.load(), T(41) );
778
779         f = a.bit_test_and_complement(2);
780         BOOST_TEST_EQ( f, false );
781         BOOST_TEST_EQ( a.load(), T(45) );
782     }
783 }
784
785 template<typename T>
786 void do_test_integral_api(boost::false_type)
787 {
788     BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
789
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);
793
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);
800 }
801
802 template<typename T>
803 void do_test_integral_api(boost::true_type)
804 {
805     do_test_integral_api<T>(boost::false_type());
806
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);
813 }
814
815 template<typename T>
816 inline void test_integral_api(void)
817 {
818     do_test_integral_api<T>(boost::is_unsigned<T>());
819
820     if (boost::is_signed<T>::value)
821         test_negation<T>();
822 }
823
824 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
825
826 template<typename T, typename D>
827 void test_fp_additive_operators(T value, D delta)
828 {
829     /* explicit add/sub */
830     {
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) );
835     }
836
837     {
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) );
842     }
843
844     /* overloaded modify/assign*/
845     {
846         boost::atomic<T> a(value);
847         T n = (a += delta);
848         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
849         BOOST_TEST_EQ( n, approx(T(value + delta)) );
850     }
851
852     {
853         boost::atomic<T> a(value);
854         T n = (a -= delta);
855         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
856         BOOST_TEST_EQ( n, approx(T(value - delta)) );
857     }
858
859     // Operations returning the actual resulting value
860     {
861         boost::atomic<T> a(value);
862         T n = a.add(delta);
863         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
864         BOOST_TEST_EQ( n, approx(T(value + delta)) );
865     }
866
867     {
868         boost::atomic<T> a(value);
869         T n = a.sub(delta);
870         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
871         BOOST_TEST_EQ( n, approx(T(value - delta)) );
872     }
873
874     // Opaque operations
875     {
876         boost::atomic<T> a(value);
877         a.opaque_add(delta);
878         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
879     }
880
881     {
882         boost::atomic<T> a(value);
883         a.opaque_sub(delta);
884         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
885     }
886 }
887
888 template< typename T >
889 void test_fp_negation()
890 {
891     {
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) );
896
897         n = a.fetch_negate();
898         BOOST_TEST_EQ( a.load(), approx((T)1) );
899         BOOST_TEST_EQ( n, approx((T)-1) );
900     }
901     {
902         boost::atomic<T> a((T)1);
903         T n = a.negate();
904         BOOST_TEST_EQ( a.load(), approx((T)-1) );
905         BOOST_TEST_EQ( n, approx((T)-1) );
906
907         n = a.negate();
908         BOOST_TEST_EQ( a.load(), approx((T)1) );
909         BOOST_TEST_EQ( n, approx((T)1) );
910     }
911     {
912         boost::atomic<T> a((T)1);
913         a.opaque_negate();
914         BOOST_TEST_EQ( a.load(), approx((T)-1) );
915
916         a.opaque_negate();
917         BOOST_TEST_EQ( a.load(), approx((T)1) );
918     }
919 }
920
921 #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
922
923 template<typename T>
924 inline void test_floating_point_api(void)
925 {
926     BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
927
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));
932
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));
935
936     test_fp_negation<T>();
937 #endif
938 }
939
940
941 template<typename T>
942 void test_pointer_api(void)
943 {
944     BOOST_TEST_GE( sizeof(boost::atomic<T *>), sizeof(T *));
945     BOOST_TEST_GE( sizeof(boost::atomic<void *>), sizeof(T *));
946
947     T values[3];
948
949     test_base_operators<T*>(&values[0], &values[1], &values[2]);
950     test_additive_operators<T*>(&values[1], 1);
951
952     test_base_operators<void*>(&values[0], &values[1], &values[2]);
953
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() );
958 #endif
959 }
960
961 enum test_enum
962 {
963     foo, bar, baz
964 };
965
966 static void
967 test_enum_api(void)
968 {
969     test_base_operators(foo, bar, baz);
970 }
971
972 template<typename T>
973 struct test_struct
974 {
975     typedef T value_type;
976     value_type i;
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;}
979 };
980
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)
983 {
984     test_stream << "{" << s.i << "}";
985     return strm;
986 }
987
988 template<typename T>
989 void
990 test_struct_api(void)
991 {
992     T a = {1}, b = {2}, c = {3};
993
994     test_base_operators(a, b, c);
995
996     {
997         boost::atomic<T> sa;
998         boost::atomic<typename T::value_type> si;
999         BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
1000     }
1001 }
1002
1003 template<typename T>
1004 struct test_struct_x2
1005 {
1006     typedef T value_type;
1007     value_type i, j;
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;}
1010 };
1011
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)
1014 {
1015     test_stream << "{" << s.i << ", " << s.j << "}";
1016     return strm;
1017 }
1018
1019 template<typename T>
1020 void
1021 test_struct_x2_api(void)
1022 {
1023     T a = {1, 1}, b = {2, 2}, c = {3, 3};
1024
1025     test_base_operators(a, b, c);
1026 }
1027
1028 struct large_struct
1029 {
1030     long data[64];
1031
1032     inline bool operator==(const large_struct & c) const
1033     {
1034         return std::memcmp(data, &c.data, sizeof(data)) == 0;
1035     }
1036     inline bool operator!=(const large_struct & c) const
1037     {
1038         return std::memcmp(data, &c.data, sizeof(data)) != 0;
1039     }
1040 };
1041
1042 template< typename Char, typename Traits >
1043 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
1044 {
1045     strm << "[large_struct]";
1046     return strm;
1047 }
1048
1049 static void
1050 test_large_struct_api(void)
1051 {
1052     large_struct a = {{1}}, b = {{2}}, c = {{3}};
1053     test_base_operators(a, b, c);
1054 }
1055
1056 struct test_struct_with_ctor
1057 {
1058     typedef unsigned int value_type;
1059     value_type i;
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;}
1063 };
1064
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&)
1067 {
1068     strm << "[test_struct_with_ctor]";
1069     return strm;
1070 }
1071
1072 static void
1073 test_struct_with_ctor_api(void)
1074 {
1075     {
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 );
1080     }
1081
1082     test_struct_with_ctor a, b, c;
1083     a.i = 1;
1084     b.i = 2;
1085     c.i = 3;
1086
1087     test_base_operators(a, b, c);
1088 }
1089
1090 #endif