1 //  Copyright (c) 2011 Helge Bahmann
2 //  Copyright (c) 2017 - 2020 Andrey Semashev
3 //
4 //  Distributed under the Boost Software License, Version 1.0.
5 //  See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_ATOMIC_API_TEST_HELPERS_HPP
9 #define BOOST_ATOMIC_API_TEST_HELPERS_HPP
10 
11 #include <boost/atomic.hpp>
12 #include <cstddef>
13 #include <cstring>
14 #include <cstdlib>
15 #include <limits>
16 #include <vector>
17 #include <iostream>
18 #include <boost/config.hpp>
19 #include <boost/cstdint.hpp>
20 #include <boost/type.hpp>
21 #include <boost/core/enable_if.hpp>
22 #include <boost/type_traits/integral_constant.hpp>
23 #include <boost/type_traits/alignment_of.hpp>
24 #include <boost/type_traits/is_pointer.hpp>
25 #include <boost/type_traits/is_signed.hpp>
26 #include <boost/type_traits/is_unsigned.hpp>
27 #include <boost/type_traits/make_signed.hpp>
28 #include <boost/type_traits/make_unsigned.hpp>
29 #include <boost/type_traits/conditional.hpp>
30 
31 #include "lightweight_test_stream.hpp"
32 #include "value_with_epsilon.hpp"
33 #include "atomic_wrapper.hpp"
34 
35 const unsigned int max_weak_cas_loops = 1000;
36 
37 template< typename T >
38 struct is_atomic :
39     public boost::false_type
40 {
41 };
42 
43 template< typename T >
44 struct is_atomic< boost::atomic< T > > :
45     public boost::true_type
46 {
47 };
48 
49 template< typename T >
50 struct is_atomic< boost::ipc_atomic< T > > :
51     public boost::true_type
52 {
53 };
54 
55 template< typename T >
56 struct is_atomic_ref :
57     public boost::false_type
58 {
59 };
60 
61 template< typename T >
62 struct is_atomic_ref< boost::atomic_ref< T > > :
63     public boost::true_type
64 {
65 };
66 
67 template< typename T >
68 struct is_atomic_ref< boost::ipc_atomic_ref< T > > :
69     public boost::true_type
70 {
71 };
72 
73 template< typename Flag >
test_flag_api(void)74 inline void test_flag_api(void)
75 {
76 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
77     Flag f = BOOST_ATOMIC_FLAG_INIT;
78 #else
79     Flag f;
80 #endif
81 
82     BOOST_TEST( !f.test() );
83     BOOST_TEST( !f.test_and_set() );
84     BOOST_TEST( f.test() );
85     BOOST_TEST( f.test_and_set() );
86     BOOST_TEST( f.test() );
87     f.clear();
88     BOOST_TEST( !f.test() );
89     BOOST_TEST( !f.test_and_set() );
90 }
91 
92 template< typename T >
test_atomic_type_traits(boost::type<T>)93 inline typename boost::enable_if< is_atomic< T > >::type test_atomic_type_traits(boost::type< T >)
94 {
95     BOOST_TEST_GE(sizeof(T), sizeof(typename T::value_type));
96 }
97 
98 template< typename T >
test_atomic_type_traits(boost::type<T>)99 inline typename boost::enable_if< is_atomic_ref< T > >::type test_atomic_type_traits(boost::type< T >)
100 {
101     if (T::is_always_lock_free)
102     {
103         BOOST_TEST_GE(T::required_alignment, boost::alignment_of< typename T::value_type >::value);
104     }
105     else
106     {
107         // Lock-based implementation should not require alignment higher than alignof(T)
108         BOOST_TEST_EQ(T::required_alignment, boost::alignment_of< typename T::value_type >::value);
109     }
110 }
111 
112 template< template< typename > class Wrapper, typename T >
test_base_operators(T value1,T value2,T value3)113 void test_base_operators(T value1, T value2, T value3)
114 {
115     test_atomic_type_traits(boost::type< typename Wrapper<T>::atomic_type >());
116 
117     // explicit load/store
118     {
119         Wrapper<T> wrapper(value1);
120         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
121         BOOST_TEST_EQ( a.load(), value1 );
122     }
123 
124     {
125         Wrapper<T> wrapper(value1);
126         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
127         a.store(value2);
128         BOOST_TEST_EQ( a.load(), value2 );
129     }
130 
131     // overloaded assignment/conversion
132     {
133         Wrapper<T> wrapper(value1);
134         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
135         BOOST_TEST( value1 == a );
136     }
137 
138     {
139         Wrapper<T> wrapper(value1);
140         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
141         a = value2;
142         BOOST_TEST( value2 == a );
143     }
144 
145     // exchange-type operators
146     {
147         Wrapper<T> wrapper(value1);
148         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
149         T n = a.exchange(value2);
150         BOOST_TEST_EQ( a.load(), value2 );
151         BOOST_TEST_EQ( n, value1 );
152     }
153 
154     {
155         Wrapper<T> wrapper(value1);
156         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
157         T expected = value1;
158         bool success = a.compare_exchange_strong(expected, value3);
159         BOOST_TEST( success );
160         BOOST_TEST_EQ( a.load(), value3 );
161         BOOST_TEST_EQ( expected, value1 );
162     }
163 
164     {
165         Wrapper<T> wrapper(value1);
166         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
167         T expected = value2;
168         bool success = a.compare_exchange_strong(expected, value3);
169         BOOST_TEST( !success );
170         BOOST_TEST_EQ( a.load(), value1 );
171         BOOST_TEST_EQ( expected, value1 );
172     }
173 
174     {
175         Wrapper<T> wrapper(value1);
176         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
177         T expected;
178         unsigned int loops = 0;
179         bool success = false;
180         do
181         {
182             expected = value1;
183             success = a.compare_exchange_weak(expected, value3);
184             ++loops;
185         }
186         while (!success && loops < max_weak_cas_loops);
187         BOOST_TEST( success );
188         BOOST_TEST_EQ( a.load(), value3 );
189         BOOST_TEST_EQ( expected, value1 );
190     }
191 
192     {
193         Wrapper<T> wrapper(value1);
194         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
195         T expected;
196         unsigned int loops = 0;
197         bool success = false;
198         do
199         {
200             expected = value2;
201             success = a.compare_exchange_weak(expected, value3);
202             if (expected != value2)
203                 break;
204             ++loops;
205         }
206         while (!success && loops < max_weak_cas_loops);
207         BOOST_TEST( !success );
208         BOOST_TEST_EQ( a.load(), value1 );
209         BOOST_TEST_EQ( expected, value1 );
210     }
211 }
212 
213 //! Tests whether boost::atomic supports constexpr constructor. Note that boost::atomic_ref (as std::atomic_ref) does not support constexpr constructor.
214 template< typename T >
test_constexpr_ctor()215 void test_constexpr_ctor()
216 {
217 #ifndef BOOST_ATOMIC_DETAIL_NO_CXX11_CONSTEXPR_UNION_INIT
218     constexpr T value(0);
219     constexpr boost::atomic<T> tester(value);
220     BOOST_TEST( tester == value );
221 #endif
222 }
223 
224 //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
225 template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
226 struct distance_limits
227 {
228     //! Difference type D promoted to the width of type T
229     typedef typename boost::conditional<
230         IsSigned,
231         boost::make_signed< T >,
232         boost::make_unsigned< T >
233     >::type::type promoted_difference_type;
234 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits235     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
236     {
237         return (std::numeric_limits< D >::min)();
238     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits239     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
240     {
241         return (std::numeric_limits< D >::max)();
242     }
243 };
244 
245 #if defined(BOOST_MSVC)
246 #pragma warning(push)
247 // 'static_cast': truncation of constant value. There is no actual truncation happening because
248 // the cast is only performed if the value fits in the range of the result.
249 #pragma warning(disable: 4309)
250 #endif
251 
252 template< typename T, typename D >
253 struct distance_limits< T*, D, true >
254 {
255     //! Difference type D promoted to the width of type T
256     typedef std::ptrdiff_t promoted_difference_type;
257 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits258     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
259     {
260         const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
261         const D diff = (std::numeric_limits< D >::min)();
262         // Both values are negative. Return the closest value to zero.
263         return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
264     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits265     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
266     {
267         const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
268         const D diff = (std::numeric_limits< D >::max)();
269         // Both values are positive. Return the closest value to zero.
270         return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
271     }
272 };
273 
274 template< typename T, typename D >
275 struct distance_limits< T*, D, false >
276 {
277     //! Difference type D promoted to the width of type T
278     typedef std::size_t promoted_difference_type;
279 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits280     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
281     {
282         return (std::numeric_limits< D >::min)();
283     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits284     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
285     {
286         const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
287         const D diff = (std::numeric_limits< D >::max)();
288         return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
289     }
290 };
291 
292 #if defined(BOOST_HAS_INT128)
293 
294 // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
295 // So we have to specialize the limits ourself. We assume two's complement signed representation.
296 template< typename T, bool IsSigned >
297 struct distance_limits< T, boost::int128_type, IsSigned >
298 {
299     //! Difference type D promoted to the width of type T
300     typedef boost::int128_type promoted_difference_type;
301 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits302     static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
303     {
304         return -(max)() - 1;
305     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits306     static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
307     {
308         return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
309     }
310 };
311 
312 template< typename T, bool IsSigned >
313 struct distance_limits< T, boost::uint128_type, IsSigned >
314 {
315     //! Difference type D promoted to the width of type T
316     typedef boost::uint128_type promoted_difference_type;
317 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits318     static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
319     {
320         return 0u;
321     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits322     static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
323     {
324         return ~static_cast< boost::uint128_type >(0u);
325     }
326 };
327 
328 #endif // defined(BOOST_HAS_INT128)
329 
330 #if defined(BOOST_MSVC)
331 #pragma warning(pop)
332 #endif
333 
334 #if defined(BOOST_MSVC)
335 #pragma warning(push)
336 // unary minus operator applied to unsigned type, result still unsigned
337 #pragma warning(disable: 4146)
338 #endif
339 
340 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
test_additive_operators_with_type_and_test()341 void test_additive_operators_with_type_and_test()
342 {
343 #if defined(UBSAN)
344     // clang UBSAN flags this test when AddType is a pointer as it considers subtracting from a null pointer (zero_add) an UB
345     if (boost::is_pointer< AddType >::value)
346         return;
347 #endif
348 
349     // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
350     typedef typename distance_limits< T, D >::promoted_difference_type promoted_difference_type;
351     typedef typename boost::make_unsigned< promoted_difference_type >::type unsigned_promoted_difference_type;
352     const T zero_value = 0;
353     const D zero_diff = 0;
354     const D one_diff = 1;
355     const AddType zero_add = 0;
356     {
357         Wrapper<T> wrapper(zero_value);
358         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
359         bool f = a.add_and_test(zero_diff);
360         BOOST_TEST_EQ( f, false );
361         BOOST_TEST_EQ( a.load(), zero_value );
362 
363         f = a.add_and_test(one_diff);
364         BOOST_TEST_EQ( f, true );
365         BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
366     }
367     {
368         Wrapper<T> wrapper(zero_value);
369         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
370         bool f = a.add_and_test((distance_limits< T, D >::max)());
371         BOOST_TEST_EQ( f, true );
372         BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
373     }
374     {
375         Wrapper<T> wrapper(zero_value);
376         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
377         bool f = a.add_and_test((distance_limits< T, D >::min)());
378         BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
379         BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
380     }
381 
382     {
383         Wrapper<T> wrapper(zero_value);
384         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
385         bool f = a.sub_and_test(zero_diff);
386         BOOST_TEST_EQ( f, false );
387         BOOST_TEST_EQ( a.load(), zero_value );
388 
389         f = a.sub_and_test(one_diff);
390         BOOST_TEST_EQ( f, true );
391         BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
392     }
393     {
394         Wrapper<T> wrapper(zero_value);
395         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
396         bool f = a.sub_and_test((distance_limits< T, D >::max)());
397         BOOST_TEST_EQ( f, true );
398         BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
399     }
400     {
401         Wrapper<T> wrapper(zero_value);
402         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
403         bool f = a.sub_and_test((distance_limits< T, D >::min)());
404         BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
405         // Be very careful as to not cause signed overflow on negation
406         unsigned_promoted_difference_type umin = static_cast< unsigned_promoted_difference_type >(
407             static_cast< promoted_difference_type >((distance_limits< T, D >::min)()));
408         umin = -umin;
409         promoted_difference_type neg_min;
410         std::memcpy(&neg_min, &umin, sizeof(neg_min));
411         BOOST_TEST_EQ( a.load(), T(zero_add + neg_min) );
412     }
413 }
414 
415 #if defined(BOOST_MSVC)
416 #pragma warning(pop)
417 #endif
418 
419 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
test_additive_operators_with_type(T value,D delta)420 void test_additive_operators_with_type(T value, D delta)
421 {
422     /* note: the tests explicitly cast the result of any addition
423     to the type to be tested to force truncation of the result to
424     the correct range in case of overflow */
425 
426     // explicit add/sub
427     {
428         Wrapper<T> wrapper(value);
429         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
430         T n = a.fetch_add(delta);
431         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
432         BOOST_TEST_EQ( n, value );
433     }
434 
435     {
436         Wrapper<T> wrapper(value);
437         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
438         T n = a.fetch_sub(delta);
439         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
440         BOOST_TEST_EQ( n, value );
441     }
442 
443     // add/sub with an immediate
444     {
445         Wrapper<T> wrapper(value);
446         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
447         T n = a.fetch_add(1);
448         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
449         BOOST_TEST_EQ( n, value );
450     }
451 
452     {
453         Wrapper<T> wrapper(value);
454         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
455         T n = a.fetch_sub(1);
456         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
457         BOOST_TEST_EQ( n, value );
458     }
459 
460     {
461         Wrapper<T> wrapper(value);
462         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
463         T n = a.fetch_add(76);
464         BOOST_TEST_EQ( a.load(), T((AddType)value + 76) );
465         BOOST_TEST_EQ( n, value );
466     }
467 
468     {
469         Wrapper<T> wrapper(value);
470         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
471         T n = a.fetch_sub(76);
472         BOOST_TEST_EQ( a.load(), T((AddType)value - 76) );
473         BOOST_TEST_EQ( n, value );
474     }
475 
476     if ((std::numeric_limits< D >::max)() >= 4097)
477     {
478         Wrapper<T> wrapper(value);
479         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
480         T n = a.fetch_add((D)4097);
481         BOOST_TEST_EQ( a.load(), T((AddType)value + (D)4097) );
482         BOOST_TEST_EQ( n, value );
483     }
484 
485     if ((std::numeric_limits< D >::max)() >= 4097)
486     {
487         Wrapper<T> wrapper(value);
488         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
489         T n = a.fetch_sub((D)4097);
490         BOOST_TEST_EQ( a.load(), T((AddType)value - (D)4097) );
491         BOOST_TEST_EQ( n, value );
492     }
493 
494     // overloaded modify/assign
495     {
496         Wrapper<T> wrapper(value);
497         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
498         T n = (a += delta);
499         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
500         BOOST_TEST_EQ( n, T((AddType)value + delta) );
501     }
502 
503     {
504         Wrapper<T> wrapper(value);
505         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
506         T n = (a -= delta);
507         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
508         BOOST_TEST_EQ( n, T((AddType)value - delta) );
509     }
510 
511     // overloaded increment/decrement
512     {
513         Wrapper<T> wrapper(value);
514         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
515         T n = a++;
516         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
517         BOOST_TEST_EQ( n, value );
518     }
519 
520     {
521         Wrapper<T> wrapper(value);
522         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
523         T n = ++a;
524         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
525         BOOST_TEST_EQ( n, T((AddType)value + 1) );
526     }
527 
528     {
529         Wrapper<T> wrapper(value);
530         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
531         T n = a--;
532         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
533         BOOST_TEST_EQ( n, value );
534     }
535 
536     {
537         Wrapper<T> wrapper(value);
538         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
539         T n = --a;
540         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
541         BOOST_TEST_EQ( n, T((AddType)value - 1) );
542     }
543 
544     // Operations returning the actual resulting value
545     {
546         Wrapper<T> wrapper(value);
547         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
548         T n = a.add(delta);
549         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
550         BOOST_TEST_EQ( n, T((AddType)value + delta) );
551     }
552 
553     {
554         Wrapper<T> wrapper(value);
555         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
556         T n = a.sub(delta);
557         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
558         BOOST_TEST_EQ( n, T((AddType)value - delta) );
559     }
560 
561     // The same with an immediate
562     {
563         Wrapper<T> wrapper(value);
564         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
565         T n = a.add(1);
566         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
567         BOOST_TEST_EQ( n, T((AddType)value + 1) );
568     }
569 
570     {
571         Wrapper<T> wrapper(value);
572         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
573         T n = a.sub(1);
574         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
575         BOOST_TEST_EQ( n, T((AddType)value - 1) );
576     }
577 
578     {
579         Wrapper<T> wrapper(value);
580         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
581         T n = a.add(76);
582         BOOST_TEST_EQ( a.load(), T((AddType)value + 76) );
583         BOOST_TEST_EQ( n, T((AddType)value + 76) );
584     }
585 
586     {
587         Wrapper<T> wrapper(value);
588         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
589         T n = a.sub(76);
590         BOOST_TEST_EQ( a.load(), T((AddType)value - 76) );
591         BOOST_TEST_EQ( n, T((AddType)value - 76) );
592     }
593 
594     if ((std::numeric_limits< D >::max)() >= 4097)
595     {
596         Wrapper<T> wrapper(value);
597         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
598         T n = a.add((D)4097);
599         BOOST_TEST_EQ( a.load(), T((AddType)value + (D)4097) );
600         BOOST_TEST_EQ( n, T((AddType)value + (D)4097) );
601     }
602 
603     if ((std::numeric_limits< D >::max)() >= 4097)
604     {
605         Wrapper<T> wrapper(value);
606         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
607         T n = a.sub((D)4097);
608         BOOST_TEST_EQ( a.load(), T((AddType)value - (D)4097) );
609         BOOST_TEST_EQ( n, T((AddType)value - (D)4097) );
610     }
611 
612     // Opaque operations
613     {
614         Wrapper<T> wrapper(value);
615         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
616         a.opaque_add(delta);
617         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
618     }
619 
620     {
621         Wrapper<T> wrapper(value);
622         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
623         a.opaque_sub(delta);
624         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
625     }
626 
627     // The same with an immediate
628     {
629         Wrapper<T> wrapper(value);
630         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
631         a.opaque_add(1);
632         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
633     }
634 
635     {
636         Wrapper<T> wrapper(value);
637         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
638         a.opaque_sub(1);
639         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
640     }
641 
642     {
643         Wrapper<T> wrapper(value);
644         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
645         a.opaque_add(76);
646         BOOST_TEST_EQ( a.load(), T((AddType)value + 76) );
647     }
648 
649     {
650         Wrapper<T> wrapper(value);
651         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
652         a.opaque_sub(76);
653         BOOST_TEST_EQ( a.load(), T((AddType)value - 76) );
654     }
655 
656     if ((std::numeric_limits< D >::max)() >= 4097)
657     {
658         Wrapper<T> wrapper(value);
659         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
660         a.opaque_add((D)4097);
661         BOOST_TEST_EQ( a.load(), T((AddType)value + (D)4097) );
662     }
663 
664     if ((std::numeric_limits< D >::max)() >= 4097)
665     {
666         Wrapper<T> wrapper(value);
667         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
668         a.opaque_sub((D)4097);
669         BOOST_TEST_EQ( a.load(), T((AddType)value - (D)4097) );
670     }
671 
672     // Modify and test operations
673     test_additive_operators_with_type_and_test< Wrapper, T, D, AddType >();
674 }
675 
676 template< template< typename > class Wrapper, typename T, typename D >
test_additive_operators(T value,D delta)677 void test_additive_operators(T value, D delta)
678 {
679     test_additive_operators_with_type< Wrapper, T, D, T >(value, delta);
680 }
681 
682 template< template< typename > class Wrapper, typename T >
test_negation()683 void test_negation()
684 {
685     {
686         Wrapper<T> wrapper((T)1);
687         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
688         T n = a.fetch_negate();
689         BOOST_TEST_EQ( a.load(), (T)-1 );
690         BOOST_TEST_EQ( n, (T)1 );
691 
692         n = a.fetch_negate();
693         BOOST_TEST_EQ( a.load(), (T)1 );
694         BOOST_TEST_EQ( n, (T)-1 );
695     }
696     {
697         Wrapper<T> wrapper((T)1);
698         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
699         T n = a.negate();
700         BOOST_TEST_EQ( a.load(), (T)-1 );
701         BOOST_TEST_EQ( n, (T)-1 );
702 
703         n = a.negate();
704         BOOST_TEST_EQ( a.load(), (T)1 );
705         BOOST_TEST_EQ( n, (T)1 );
706     }
707     {
708         Wrapper<T> wrapper((T)1);
709         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
710         a.opaque_negate();
711         BOOST_TEST_EQ( a.load(), (T)-1 );
712 
713         a.opaque_negate();
714         BOOST_TEST_EQ( a.load(), (T)1 );
715     }
716     {
717         Wrapper<T> wrapper((T)1);
718         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
719         bool f = a.negate_and_test();
720         BOOST_TEST_EQ( f, true );
721         BOOST_TEST_EQ( a.load(), (T)-1 );
722 
723         f = a.negate_and_test();
724         BOOST_TEST_EQ( f, true );
725         BOOST_TEST_EQ( a.load(), (T)1 );
726     }
727     {
728         Wrapper<T> wrapper((T)0);
729         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
730         bool f = a.negate_and_test();
731         BOOST_TEST_EQ( f, false );
732         BOOST_TEST_EQ( a.load(), (T)0 );
733     }
734 }
735 
736 template< template< typename > class Wrapper, typename T >
test_additive_wrap(T value)737 void test_additive_wrap(T value)
738 {
739     {
740         Wrapper<T> wrapper(value);
741         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
742         T n = a.fetch_add(1) + (T)1;
743         BOOST_TEST_EQ( a.load(), n );
744     }
745     {
746         Wrapper<T> wrapper(value);
747         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
748         T n = a.fetch_sub(1) - (T)1;
749         BOOST_TEST_EQ( a.load(), n );
750     }
751 }
752 
753 template< template< typename > class Wrapper, typename T >
test_bit_operators(T value,T delta)754 void test_bit_operators(T value, T delta)
755 {
756     // explicit and/or/xor
757     {
758         Wrapper<T> wrapper(value);
759         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
760         T n = a.fetch_and(delta);
761         BOOST_TEST_EQ( a.load(), T(value & delta) );
762         BOOST_TEST_EQ( n, value );
763     }
764 
765     {
766         Wrapper<T> wrapper(value);
767         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
768         T n = a.fetch_or(delta);
769         BOOST_TEST_EQ( a.load(), T(value | delta) );
770         BOOST_TEST_EQ( n, value );
771     }
772 
773     {
774         Wrapper<T> wrapper(value);
775         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
776         T n = a.fetch_xor(delta);
777         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
778         BOOST_TEST_EQ( n, value );
779     }
780 
781     {
782         Wrapper<T> wrapper(value);
783         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
784         T n = a.fetch_complement();
785         BOOST_TEST_EQ( a.load(), T(~value) );
786         BOOST_TEST_EQ( n, value );
787     }
788 
789     // and/or/xor with an immediate. The immediates below are chosen to either be encodable in an instruction or not for various target architectures.
790     {
791         Wrapper<T> wrapper(value);
792         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
793         T n = a.fetch_and((T)1);
794         BOOST_TEST_EQ( a.load(), T(value & (T)1) );
795         BOOST_TEST_EQ( n, value );
796     }
797 
798     {
799         Wrapper<T> wrapper(value);
800         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
801         T n = a.fetch_or((T)1);
802         BOOST_TEST_EQ( a.load(), T(value | (T)1) );
803         BOOST_TEST_EQ( n, value );
804     }
805 
806     {
807         Wrapper<T> wrapper(value);
808         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
809         T n = a.fetch_xor((T)1);
810         BOOST_TEST_EQ( a.load(), T(value ^ (T)1) );
811         BOOST_TEST_EQ( n, value );
812     }
813 
814     // The following constants are not encodable in AArch64
815     {
816         Wrapper<T> wrapper(value);
817         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
818         T n = a.fetch_and((T)76);
819         BOOST_TEST_EQ( a.load(), T(value & (T)76) );
820         BOOST_TEST_EQ( n, value );
821     }
822 
823     {
824         Wrapper<T> wrapper(value);
825         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
826         T n = a.fetch_or((T)76);
827         BOOST_TEST_EQ( a.load(), T(value | (T)76) );
828         BOOST_TEST_EQ( n, value );
829     }
830 
831     {
832         Wrapper<T> wrapper(value);
833         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
834         T n = a.fetch_xor((T)76);
835         BOOST_TEST_EQ( a.load(), T(value ^ (T)76) );
836         BOOST_TEST_EQ( n, value );
837     }
838 
839     // overloaded modify/assign
840     {
841         Wrapper<T> wrapper(value);
842         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
843         T n = (a &= delta);
844         BOOST_TEST_EQ( a.load(), T(value & delta) );
845         BOOST_TEST_EQ( n, T(value & delta) );
846     }
847 
848     {
849         Wrapper<T> wrapper(value);
850         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
851         T n = (a |= delta);
852         BOOST_TEST_EQ( a.load(), T(value | delta) );
853         BOOST_TEST_EQ( n, T(value | delta) );
854     }
855 
856     {
857         Wrapper<T> wrapper(value);
858         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
859         T n = (a ^= delta);
860         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
861         BOOST_TEST_EQ( n, T(value ^ delta) );
862     }
863 
864     // Operations returning the actual resulting value
865     {
866         Wrapper<T> wrapper(value);
867         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
868         T n = a.bitwise_and(delta);
869         BOOST_TEST_EQ( a.load(), T(value & delta) );
870         BOOST_TEST_EQ( n, T(value & delta) );
871     }
872 
873     {
874         Wrapper<T> wrapper(value);
875         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
876         T n = a.bitwise_or(delta);
877         BOOST_TEST_EQ( a.load(), T(value | delta) );
878         BOOST_TEST_EQ( n, T(value | delta) );
879     }
880 
881     {
882         Wrapper<T> wrapper(value);
883         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
884         T n = a.bitwise_xor(delta);
885         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
886         BOOST_TEST_EQ( n, T(value ^ delta) );
887     }
888 
889     {
890         Wrapper<T> wrapper(value);
891         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
892         T n = a.bitwise_complement();
893         BOOST_TEST_EQ( a.load(), T(~value) );
894         BOOST_TEST_EQ( n, T(~value) );
895     }
896 
897     // The same with an immediate
898     {
899         Wrapper<T> wrapper(value);
900         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
901         T n = a.bitwise_and((T)1);
902         BOOST_TEST_EQ( a.load(), T(value & (T)1) );
903         BOOST_TEST_EQ( n, T(value & (T)1) );
904     }
905 
906     {
907         Wrapper<T> wrapper(value);
908         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
909         T n = a.bitwise_or((T)1);
910         BOOST_TEST_EQ( a.load(), T(value | (T)1) );
911         BOOST_TEST_EQ( n, T(value | (T)1) );
912     }
913 
914     {
915         Wrapper<T> wrapper(value);
916         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
917         T n = a.bitwise_xor((T)1);
918         BOOST_TEST_EQ( a.load(), T(value ^ (T)1) );
919         BOOST_TEST_EQ( n, T(value ^ (T)1) );
920     }
921 
922     // The following constants are not encodable in AArch64
923     {
924         Wrapper<T> wrapper(value);
925         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
926         T n = a.bitwise_and((T)76);
927         BOOST_TEST_EQ( a.load(), T(value & (T)76) );
928         BOOST_TEST_EQ( n, T(value & (T)76) );
929     }
930 
931     {
932         Wrapper<T> wrapper(value);
933         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
934         T n = a.bitwise_or((T)76);
935         BOOST_TEST_EQ( a.load(), T(value | (T)76) );
936         BOOST_TEST_EQ( n, T(value | (T)76) );
937     }
938 
939     {
940         Wrapper<T> wrapper(value);
941         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
942         T n = a.bitwise_xor((T)76);
943         BOOST_TEST_EQ( a.load(), T(value ^ (T)76) );
944         BOOST_TEST_EQ( n, T(value ^ (T)76) );
945     }
946 
947     // Opaque operations
948     {
949         Wrapper<T> wrapper(value);
950         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
951         a.opaque_and(delta);
952         BOOST_TEST_EQ( a.load(), T(value & delta) );
953     }
954 
955     {
956         Wrapper<T> wrapper(value);
957         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
958         a.opaque_or(delta);
959         BOOST_TEST_EQ( a.load(), T(value | delta) );
960     }
961 
962     {
963         Wrapper<T> wrapper(value);
964         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
965         a.opaque_xor(delta);
966         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
967     }
968 
969     {
970         Wrapper<T> wrapper(value);
971         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
972         a.opaque_complement();
973         BOOST_TEST_EQ( a.load(), T(~value) );
974     }
975 
976     // The same with an immediate
977     {
978         Wrapper<T> wrapper(value);
979         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
980         a.opaque_and((T)1);
981         BOOST_TEST_EQ( a.load(), T(value & (T)1) );
982     }
983 
984     {
985         Wrapper<T> wrapper(value);
986         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
987         a.opaque_or((T)1);
988         BOOST_TEST_EQ( a.load(), T(value | (T)1) );
989     }
990 
991     {
992         Wrapper<T> wrapper(value);
993         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
994         a.opaque_xor((T)1);
995         BOOST_TEST_EQ( a.load(), T(value ^ (T)1) );
996     }
997 
998     // The following constants are not encodable in AArch64
999     {
1000         Wrapper<T> wrapper(value);
1001         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1002         a.opaque_and((T)76);
1003         BOOST_TEST_EQ( a.load(), T(value & (T)76) );
1004     }
1005 
1006     {
1007         Wrapper<T> wrapper(value);
1008         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1009         a.opaque_or((T)76);
1010         BOOST_TEST_EQ( a.load(), T(value | (T)76) );
1011     }
1012 
1013     {
1014         Wrapper<T> wrapper(value);
1015         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1016         a.opaque_xor((T)76);
1017         BOOST_TEST_EQ( a.load(), T(value ^ (T)76) );
1018     }
1019 
1020     // Modify and test operations
1021     {
1022         Wrapper<T> wrapper((T)1);
1023         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1024         bool f = a.and_and_test((T)1);
1025         BOOST_TEST_EQ( f, true );
1026         BOOST_TEST_EQ( a.load(), T(1) );
1027 
1028         f = a.and_and_test((T)0);
1029         BOOST_TEST_EQ( f, false );
1030         BOOST_TEST_EQ( a.load(), T(0) );
1031 
1032         f = a.and_and_test((T)0);
1033         BOOST_TEST_EQ( f, false );
1034         BOOST_TEST_EQ( a.load(), T(0) );
1035     }
1036 
1037     {
1038         Wrapper<T> wrapper((T)0);
1039         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1040         bool f = a.or_and_test((T)0);
1041         BOOST_TEST_EQ( f, false );
1042         BOOST_TEST_EQ( a.load(), T(0) );
1043 
1044         f = a.or_and_test((T)1);
1045         BOOST_TEST_EQ( f, true );
1046         BOOST_TEST_EQ( a.load(), T(1) );
1047 
1048         f = a.or_and_test((T)1);
1049         BOOST_TEST_EQ( f, true );
1050         BOOST_TEST_EQ( a.load(), T(1) );
1051     }
1052 
1053     {
1054         Wrapper<T> wrapper((T)0);
1055         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1056         bool f = a.xor_and_test((T)0);
1057         BOOST_TEST_EQ( f, false );
1058         BOOST_TEST_EQ( a.load(), T(0) );
1059 
1060         f = a.xor_and_test((T)1);
1061         BOOST_TEST_EQ( f, true );
1062         BOOST_TEST_EQ( a.load(), T(1) );
1063 
1064         f = a.xor_and_test((T)1);
1065         BOOST_TEST_EQ( f, false );
1066         BOOST_TEST_EQ( a.load(), T(0) );
1067     }
1068 
1069     {
1070         Wrapper<T> wrapper((T)0);
1071         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1072         bool f = a.complement_and_test();
1073         BOOST_TEST_EQ( f, true );
1074         BOOST_TEST_EQ( a.load(), static_cast< T >(~static_cast< T >(0)) );
1075 
1076         f = a.complement_and_test();
1077         BOOST_TEST_EQ( f, false );
1078         BOOST_TEST_EQ( a.load(), T(0) );
1079     }
1080 
1081     // Bit test and modify operations
1082     {
1083         Wrapper<T> wrapper((T)42);
1084         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1085         bool f = a.bit_test_and_set(0);
1086         BOOST_TEST_EQ( f, false );
1087         BOOST_TEST_EQ( a.load(), T(43) );
1088 
1089         f = a.bit_test_and_set(1);
1090         BOOST_TEST_EQ( f, true );
1091         BOOST_TEST_EQ( a.load(), T(43) );
1092 
1093         f = a.bit_test_and_set(2);
1094         BOOST_TEST_EQ( f, false );
1095         BOOST_TEST_EQ( a.load(), T(47) );
1096     }
1097 
1098     {
1099         Wrapper<T> wrapper((T)42);
1100         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1101         bool f = a.bit_test_and_reset(0);
1102         BOOST_TEST_EQ( f, false );
1103         BOOST_TEST_EQ( a.load(), T(42) );
1104 
1105         f = a.bit_test_and_reset(1);
1106         BOOST_TEST_EQ( f, true );
1107         BOOST_TEST_EQ( a.load(), T(40) );
1108 
1109         f = a.bit_test_and_set(2);
1110         BOOST_TEST_EQ( f, false );
1111         BOOST_TEST_EQ( a.load(), T(44) );
1112     }
1113 
1114     {
1115         Wrapper<T> wrapper((T)42);
1116         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1117         bool f = a.bit_test_and_complement(0);
1118         BOOST_TEST_EQ( f, false );
1119         BOOST_TEST_EQ( a.load(), T(43) );
1120 
1121         f = a.bit_test_and_complement(1);
1122         BOOST_TEST_EQ( f, true );
1123         BOOST_TEST_EQ( a.load(), T(41) );
1124 
1125         f = a.bit_test_and_complement(2);
1126         BOOST_TEST_EQ( f, false );
1127         BOOST_TEST_EQ( a.load(), T(45) );
1128     }
1129 
1130     // Test that a runtime value works for the bit index. This is important for asm block constraints.
1131     {
1132         unsigned int runtime_bit_index = std::rand() & 7u;
1133         Wrapper<T> wrapper((T)42);
1134         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1135 
1136         a.bit_test_and_set(runtime_bit_index);
1137         a.bit_test_and_reset(runtime_bit_index);
1138         a.bit_test_and_complement(runtime_bit_index);
1139     }
1140 }
1141 
1142 template< template< typename > class Wrapper, typename T >
do_test_integral_api(boost::false_type)1143 void do_test_integral_api(boost::false_type)
1144 {
1145     test_base_operators< Wrapper, T >(42, 43, 44);
1146     test_additive_operators< Wrapper, T, T >(42, 17);
1147     test_bit_operators< Wrapper, T >((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
1148 
1149     /* test for unsigned overflow/underflow */
1150     test_additive_operators< Wrapper, T, T >((T)-1, 1);
1151     test_additive_operators< Wrapper, T, T >(0, 1);
1152     /* test for signed overflow/underflow */
1153     test_additive_operators< Wrapper, T, T >(((T)-1) >> (sizeof(T) * 8 - 1), 1);
1154     test_additive_operators< Wrapper, T, T >(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
1155 }
1156 
1157 template< template< typename > class Wrapper, typename T >
do_test_integral_api(boost::true_type)1158 void do_test_integral_api(boost::true_type)
1159 {
1160     do_test_integral_api< Wrapper, T >(boost::false_type());
1161 
1162     test_additive_wrap< Wrapper, T >(0u);
1163     BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
1164     test_additive_wrap< Wrapper, T >(all_ones);
1165     BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
1166     test_additive_wrap< Wrapper, T >(all_ones ^ max_signed_twos_compl);
1167     test_additive_wrap< Wrapper, T >(max_signed_twos_compl);
1168 }
1169 
1170 template< template< typename > class Wrapper, typename T >
test_integral_api(void)1171 inline void test_integral_api(void)
1172 {
1173     do_test_integral_api< Wrapper, T >(boost::is_unsigned<T>());
1174 
1175     if (boost::is_signed<T>::value)
1176         test_negation< Wrapper, T >();
1177 }
1178 
1179 template< template< typename > class Wrapper, typename T >
test_lock_free_integral_api(boost::true_type)1180 inline void test_lock_free_integral_api(boost::true_type)
1181 {
1182     test_integral_api< Wrapper, T >();
1183 }
1184 
1185 template< template< typename > class Wrapper, typename T >
test_lock_free_integral_api(boost::false_type)1186 inline void test_lock_free_integral_api(boost::false_type)
1187 {
1188 }
1189 
1190 template< template< typename > class Wrapper, typename T >
test_lock_free_integral_api(void)1191 inline void test_lock_free_integral_api(void)
1192 {
1193     test_lock_free_integral_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
1194 }
1195 
1196 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1197 
1198 template< template< typename > class Wrapper, typename T, typename D >
test_fp_additive_operators(T value,D delta)1199 void test_fp_additive_operators(T value, D delta)
1200 {
1201     // explicit add/sub
1202     {
1203         Wrapper<T> wrapper(value);
1204         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1205         T n = a.fetch_add(delta);
1206         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1207         BOOST_TEST_EQ( n, approx(value) );
1208     }
1209 
1210     {
1211         Wrapper<T> wrapper(value);
1212         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1213         T n = a.fetch_sub(delta);
1214         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1215         BOOST_TEST_EQ( n, approx(value) );
1216     }
1217 
1218     // overloaded modify/assign
1219     {
1220         Wrapper<T> wrapper(value);
1221         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1222         T n = (a += delta);
1223         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1224         BOOST_TEST_EQ( n, approx(T(value + delta)) );
1225     }
1226 
1227     {
1228         Wrapper<T> wrapper(value);
1229         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1230         T n = (a -= delta);
1231         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1232         BOOST_TEST_EQ( n, approx(T(value - delta)) );
1233     }
1234 
1235     // Operations returning the actual resulting value
1236     {
1237         Wrapper<T> wrapper(value);
1238         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1239         T n = a.add(delta);
1240         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1241         BOOST_TEST_EQ( n, approx(T(value + delta)) );
1242     }
1243 
1244     {
1245         Wrapper<T> wrapper(value);
1246         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1247         T n = a.sub(delta);
1248         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1249         BOOST_TEST_EQ( n, approx(T(value - delta)) );
1250     }
1251 
1252     // Opaque operations
1253     {
1254         Wrapper<T> wrapper(value);
1255         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1256         a.opaque_add(delta);
1257         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
1258     }
1259 
1260     {
1261         Wrapper<T> wrapper(value);
1262         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1263         a.opaque_sub(delta);
1264         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
1265     }
1266 }
1267 
1268 template< template< typename > class Wrapper, typename T >
test_fp_negation()1269 void test_fp_negation()
1270 {
1271     {
1272         Wrapper<T> wrapper((T)1);
1273         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1274         T n = a.fetch_negate();
1275         BOOST_TEST_EQ( a.load(), approx((T)-1) );
1276         BOOST_TEST_EQ( n, approx((T)1) );
1277 
1278         n = a.fetch_negate();
1279         BOOST_TEST_EQ( a.load(), approx((T)1) );
1280         BOOST_TEST_EQ( n, approx((T)-1) );
1281     }
1282     {
1283         Wrapper<T> wrapper((T)1);
1284         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1285         T n = a.negate();
1286         BOOST_TEST_EQ( a.load(), approx((T)-1) );
1287         BOOST_TEST_EQ( n, approx((T)-1) );
1288 
1289         n = a.negate();
1290         BOOST_TEST_EQ( a.load(), approx((T)1) );
1291         BOOST_TEST_EQ( n, approx((T)1) );
1292     }
1293     {
1294         Wrapper<T> wrapper((T)1);
1295         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1296         a.opaque_negate();
1297         BOOST_TEST_EQ( a.load(), approx((T)-1) );
1298 
1299         a.opaque_negate();
1300         BOOST_TEST_EQ( a.load(), approx((T)1) );
1301     }
1302 }
1303 
1304 #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1305 
1306 template< template< typename > class Wrapper, typename T >
test_floating_point_api(void)1307 void test_floating_point_api(void)
1308 {
1309     // Note: When support for floating point is disabled, even the base operation tests may fail because
1310     // the generic template specialization does not account for garbage in padding bits that are present in some FP types.
1311 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1312     test_base_operators< Wrapper, T >(static_cast<T>(42.1), static_cast<T>(43.2), static_cast<T>(44.3));
1313 
1314     test_fp_additive_operators< Wrapper, T, T >(static_cast<T>(42.5), static_cast<T>(17.7));
1315     test_fp_additive_operators< Wrapper, T, T >(static_cast<T>(-42.5), static_cast<T>(-17.7));
1316 
1317     test_fp_negation< Wrapper, T >();
1318 #endif
1319 }
1320 
1321 template< template< typename > class Wrapper, typename T >
test_lock_free_floating_point_api(boost::true_type)1322 inline void test_lock_free_floating_point_api(boost::true_type)
1323 {
1324     test_floating_point_api< Wrapper, T >();
1325 }
1326 
1327 template< template< typename > class Wrapper, typename T >
test_lock_free_floating_point_api(boost::false_type)1328 inline void test_lock_free_floating_point_api(boost::false_type)
1329 {
1330 }
1331 
1332 template< template< typename > class Wrapper, typename T >
test_lock_free_floating_point_api(void)1333 inline void test_lock_free_floating_point_api(void)
1334 {
1335     test_lock_free_floating_point_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
1336 }
1337 
1338 
1339 template< template< typename > class Wrapper, typename T >
test_pointer_api(void)1340 void test_pointer_api(void)
1341 {
1342     std::vector< T > values;
1343     values.resize(5000); // make the vector large enough to accommodate pointer arithmetics in the additive tests
1344 
1345     test_base_operators< Wrapper, T* >(&values[0], &values[1], &values[2]);
1346     test_additive_operators< Wrapper, T* >(&values[1], 1);
1347 
1348     test_base_operators< Wrapper, void* >(&values[0], &values[1], &values[2]);
1349 
1350 #if defined(BOOST_HAS_INTPTR_T)
1351     Wrapper<void*> wrapper_ptr;
1352     typename Wrapper<void*>::atomic_reference_type ptr = wrapper_ptr.a;
1353     Wrapper<boost::intptr_t> wrapper_integral;
1354     typename Wrapper<boost::intptr_t>::atomic_reference_type integral = wrapper_integral.a;
1355     BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
1356 #endif
1357 }
1358 
1359 enum test_enum
1360 {
1361     foo, bar, baz
1362 };
1363 
1364 template< template< typename > class Wrapper, typename T >
test_lock_free_pointer_api(boost::true_type)1365 inline void test_lock_free_pointer_api(boost::true_type)
1366 {
1367     test_pointer_api< Wrapper, T >();
1368 }
1369 
1370 template< template< typename > class Wrapper, typename T >
test_lock_free_pointer_api(boost::false_type)1371 inline void test_lock_free_pointer_api(boost::false_type)
1372 {
1373 }
1374 
1375 template< template< typename > class Wrapper, typename T >
test_lock_free_pointer_api(void)1376 inline void test_lock_free_pointer_api(void)
1377 {
1378     test_lock_free_pointer_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
1379 }
1380 
1381 
1382 template< template< typename > class Wrapper >
test_enum_api(void)1383 void test_enum_api(void)
1384 {
1385     test_base_operators< Wrapper >(foo, bar, baz);
1386 }
1387 
1388 template< template< typename > class Wrapper >
test_lock_free_enum_api(boost::true_type)1389 inline void test_lock_free_enum_api(boost::true_type)
1390 {
1391     test_enum_api< Wrapper >();
1392 }
1393 
1394 template< template< typename > class Wrapper >
test_lock_free_enum_api(boost::false_type)1395 inline void test_lock_free_enum_api(boost::false_type)
1396 {
1397 }
1398 
1399 template< template< typename > class Wrapper >
test_lock_free_enum_api(void)1400 inline void test_lock_free_enum_api(void)
1401 {
1402     test_lock_free_enum_api< Wrapper >(boost::integral_constant< bool, Wrapper< test_enum >::atomic_type::is_always_lock_free >());
1403 }
1404 
1405 
1406 template< typename T >
1407 struct test_struct
1408 {
1409     typedef T value_type;
1410     value_type i;
operator ==test_struct1411     inline bool operator==(test_struct const& c) const { return i == c.i; }
operator !=test_struct1412     inline bool operator!=(test_struct const& c) const { return !operator==(c); }
1413 };
1414 
1415 template< typename Char, typename Traits, typename T >
operator <<(std::basic_ostream<Char,Traits> & strm,test_struct<T> const & s)1416 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
1417 {
1418     test_stream << "{" << s.i << "}";
1419     return strm;
1420 }
1421 
1422 template< template< typename > class Wrapper, typename T >
test_struct_api(void)1423 void test_struct_api(void)
1424 {
1425     T a = {1}, b = {2}, c = {3};
1426 
1427     test_base_operators< Wrapper >(a, b, c);
1428 
1429     {
1430         Wrapper<T> wrapper_sa;
1431         typename Wrapper<T>::atomic_reference_type sa = wrapper_sa.a;
1432         Wrapper<typename T::value_type> wrapper_si;
1433         typename Wrapper<typename T::value_type>::atomic_reference_type si = wrapper_si.a;
1434         BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
1435     }
1436 }
1437 
1438 template< typename T >
1439 struct test_struct_x2
1440 {
1441     typedef T value_type;
1442     value_type i, j;
operator ==test_struct_x21443     inline bool operator==(test_struct_x2 const& c) const { return i == c.i && j == c.j; }
operator !=test_struct_x21444     inline bool operator!=(test_struct_x2 const& c) const { return !operator==(c); }
1445 };
1446 
1447 template< typename Char, typename Traits, typename T >
operator <<(std::basic_ostream<Char,Traits> & strm,test_struct_x2<T> const & s)1448 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
1449 {
1450     test_stream << "{" << s.i << ", " << s.j << "}";
1451     return strm;
1452 }
1453 
1454 template< template< typename > class Wrapper, typename T >
test_struct_x2_api(void)1455 void test_struct_x2_api(void)
1456 {
1457     T a = {1, 1}, b = {2, 2}, c = {3, 3};
1458 
1459     test_base_operators< Wrapper >(a, b, c);
1460 }
1461 
1462 struct large_struct
1463 {
1464     unsigned char data[256u];
1465 
operator ==large_struct1466     inline bool operator==(large_struct const& c) const
1467     {
1468         return std::memcmp(data, &c.data, sizeof(data)) == 0;
1469     }
operator !=large_struct1470     inline bool operator!=(large_struct const& c) const
1471     {
1472         return std::memcmp(data, &c.data, sizeof(data)) != 0;
1473     }
1474 };
1475 
1476 template< typename Char, typename Traits >
operator <<(std::basic_ostream<Char,Traits> & strm,large_struct const &)1477 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
1478 {
1479     strm << "[large_struct]";
1480     return strm;
1481 }
1482 
1483 template< template< typename > class Wrapper >
test_large_struct_api(void)1484 void test_large_struct_api(void)
1485 {
1486     large_struct a = {{1}}, b = {{2}}, c = {{3}};
1487     test_base_operators< Wrapper >(a, b, c);
1488 }
1489 
1490 struct test_struct_with_ctor
1491 {
1492     typedef unsigned int value_type;
1493     value_type i;
test_struct_with_ctortest_struct_with_ctor1494     test_struct_with_ctor() : i(0x01234567) {}
operator ==test_struct_with_ctor1495     inline bool operator==(test_struct_with_ctor const& c) const { return i == c.i; }
operator !=test_struct_with_ctor1496     inline bool operator!=(test_struct_with_ctor const& c) const { return !operator==(c); }
1497 };
1498 
1499 template< typename Char, typename Traits >
operator <<(std::basic_ostream<Char,Traits> & strm,test_struct_with_ctor const & s)1500 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const& s)
1501 {
1502     strm << "{" << s.i << "}";
1503     return strm;
1504 }
1505 
1506 template< template< typename > class Wrapper >
test_struct_with_ctor_api(void)1507 void test_struct_with_ctor_api(void)
1508 {
1509     {
1510         test_struct_with_ctor s;
1511         Wrapper<test_struct_with_ctor> wrapper_sa;
1512         typename Wrapper<test_struct_with_ctor>::atomic_reference_type sa = wrapper_sa.a;
1513         // Check that the default constructor was called
1514         BOOST_TEST( sa.load() == s );
1515     }
1516 
1517     test_struct_with_ctor a, b, c;
1518     a.i = 1;
1519     b.i = 2;
1520     c.i = 3;
1521 
1522     test_base_operators< Wrapper >(a, b, c);
1523 }
1524 
1525 #endif
1526