• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <iostream>
17 #include <boost/config.hpp>
18 #include <boost/cstdint.hpp>
19 #include <boost/type.hpp>
20 #include <boost/core/enable_if.hpp>
21 #include <boost/type_traits/integral_constant.hpp>
22 #include <boost/type_traits/alignment_of.hpp>
23 #include <boost/type_traits/is_pointer.hpp>
24 #include <boost/type_traits/is_signed.hpp>
25 #include <boost/type_traits/is_unsigned.hpp>
26 #include <boost/type_traits/make_signed.hpp>
27 #include <boost/type_traits/make_unsigned.hpp>
28 #include <boost/type_traits/conditional.hpp>
29 
30 #include "lightweight_test_stream.hpp"
31 #include "value_with_epsilon.hpp"
32 #include "atomic_wrapper.hpp"
33 
34 const unsigned int max_weak_cas_loops = 1000;
35 
36 template< typename T >
37 struct is_atomic :
38     public boost::false_type
39 {
40 };
41 
42 template< typename T >
43 struct is_atomic< boost::atomic< T > > :
44     public boost::true_type
45 {
46 };
47 
48 template< typename T >
49 struct is_atomic< boost::ipc_atomic< T > > :
50     public boost::true_type
51 {
52 };
53 
54 template< typename T >
55 struct is_atomic_ref :
56     public boost::false_type
57 {
58 };
59 
60 template< typename T >
61 struct is_atomic_ref< boost::atomic_ref< T > > :
62     public boost::true_type
63 {
64 };
65 
66 template< typename T >
67 struct is_atomic_ref< boost::ipc_atomic_ref< T > > :
68     public boost::true_type
69 {
70 };
71 
72 template< typename Flag >
test_flag_api(void)73 inline void test_flag_api(void)
74 {
75 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
76     Flag f = BOOST_ATOMIC_FLAG_INIT;
77 #else
78     Flag f;
79 #endif
80 
81     BOOST_TEST( !f.test() );
82     BOOST_TEST( !f.test_and_set() );
83     BOOST_TEST( f.test() );
84     BOOST_TEST( f.test_and_set() );
85     BOOST_TEST( f.test() );
86     f.clear();
87     BOOST_TEST( !f.test() );
88     BOOST_TEST( !f.test_and_set() );
89 }
90 
91 template< typename T >
test_atomic_type_traits(boost::type<T>)92 inline typename boost::enable_if< is_atomic< T > >::type test_atomic_type_traits(boost::type< T >)
93 {
94     BOOST_TEST_GE(sizeof(T), sizeof(typename T::value_type));
95 }
96 
97 template< typename T >
test_atomic_type_traits(boost::type<T>)98 inline typename boost::enable_if< is_atomic_ref< T > >::type test_atomic_type_traits(boost::type< T >)
99 {
100     if (T::is_always_lock_free)
101     {
102         BOOST_TEST_GE(T::required_alignment, boost::alignment_of< typename T::value_type >::value);
103     }
104     else
105     {
106         // Lock-based implementation should not require alignment higher than alignof(T)
107         BOOST_TEST_EQ(T::required_alignment, boost::alignment_of< typename T::value_type >::value);
108     }
109 }
110 
111 template< template< typename > class Wrapper, typename T >
test_base_operators(T value1,T value2,T value3)112 void test_base_operators(T value1, T value2, T value3)
113 {
114     test_atomic_type_traits(boost::type< typename Wrapper<T>::atomic_type >());
115 
116     // explicit load/store
117     {
118         Wrapper<T> wrapper(value1);
119         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
120         BOOST_TEST_EQ( a.load(), value1 );
121     }
122 
123     {
124         Wrapper<T> wrapper(value1);
125         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
126         a.store(value2);
127         BOOST_TEST_EQ( a.load(), value2 );
128     }
129 
130     // overloaded assignment/conversion
131     {
132         Wrapper<T> wrapper(value1);
133         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
134         BOOST_TEST( value1 == a );
135     }
136 
137     {
138         Wrapper<T> wrapper(value1);
139         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
140         a = value2;
141         BOOST_TEST( value2 == a );
142     }
143 
144     // exchange-type operators
145     {
146         Wrapper<T> wrapper(value1);
147         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
148         T n = a.exchange(value2);
149         BOOST_TEST_EQ( a.load(), value2 );
150         BOOST_TEST_EQ( n, value1 );
151     }
152 
153     {
154         Wrapper<T> wrapper(value1);
155         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
156         T expected = 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 );
161     }
162 
163     {
164         Wrapper<T> wrapper(value1);
165         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
166         T expected = value2;
167         bool success = a.compare_exchange_strong(expected, value3);
168         BOOST_TEST( !success );
169         BOOST_TEST_EQ( a.load(), value1 );
170         BOOST_TEST_EQ( expected, value1 );
171     }
172 
173     {
174         Wrapper<T> wrapper(value1);
175         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
176         T expected;
177         unsigned int loops = 0;
178         bool success = false;
179         do
180         {
181             expected = value1;
182             success = a.compare_exchange_weak(expected, value3);
183             ++loops;
184         }
185         while (!success && loops < max_weak_cas_loops);
186         BOOST_TEST( success );
187         BOOST_TEST_EQ( a.load(), value3 );
188         BOOST_TEST_EQ( expected, value1 );
189     }
190 
191     {
192         Wrapper<T> wrapper(value1);
193         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
194         T expected;
195         unsigned int loops = 0;
196         bool success = false;
197         do
198         {
199             expected = value2;
200             success = a.compare_exchange_weak(expected, value3);
201             if (expected != value2)
202                 break;
203             ++loops;
204         }
205         while (!success && loops < max_weak_cas_loops);
206         BOOST_TEST( !success );
207         BOOST_TEST_EQ( a.load(), value1 );
208         BOOST_TEST_EQ( expected, value1 );
209     }
210 }
211 
212 //! Tests whether boost::atomic supports constexpr constructor. Note that boost::atomic_ref (as std::atomic_ref) does not support constexpr constructor.
213 template< typename T >
test_constexpr_ctor()214 void test_constexpr_ctor()
215 {
216 #ifndef BOOST_ATOMIC_DETAIL_NO_CXX11_CONSTEXPR_UNION_INIT
217     constexpr T value(0);
218     constexpr boost::atomic<T> tester(value);
219     BOOST_TEST( tester == value );
220 #endif
221 }
222 
223 //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
224 template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
225 struct distance_limits
226 {
227     //! Difference type D promoted to the width of type T
228     typedef typename boost::conditional<
229         IsSigned,
230         boost::make_signed< T >,
231         boost::make_unsigned< T >
232     >::type::type promoted_difference_type;
233 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits234     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
235     {
236         return (std::numeric_limits< D >::min)();
237     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits238     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
239     {
240         return (std::numeric_limits< D >::max)();
241     }
242 };
243 
244 #if defined(BOOST_MSVC)
245 #pragma warning(push)
246 // 'static_cast': truncation of constant value. There is no actual truncation happening because
247 // the cast is only performed if the value fits in the range of the result.
248 #pragma warning(disable: 4309)
249 #endif
250 
251 template< typename T, typename D >
252 struct distance_limits< T*, D, true >
253 {
254     //! Difference type D promoted to the width of type T
255     typedef std::ptrdiff_t promoted_difference_type;
256 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits257     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
258     {
259         const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
260         const D diff = (std::numeric_limits< D >::min)();
261         // Both values are negative. Return the closest value to zero.
262         return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
263     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits264     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
265     {
266         const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
267         const D diff = (std::numeric_limits< D >::max)();
268         // Both values are positive. Return the closest value to zero.
269         return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
270     }
271 };
272 
273 template< typename T, typename D >
274 struct distance_limits< T*, D, false >
275 {
276     //! Difference type D promoted to the width of type T
277     typedef std::size_t promoted_difference_type;
278 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits279     static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
280     {
281         return (std::numeric_limits< D >::min)();
282     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits283     static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
284     {
285         const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
286         const D diff = (std::numeric_limits< D >::max)();
287         return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
288     }
289 };
290 
291 #if defined(BOOST_HAS_INT128)
292 
293 // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
294 // So we have to specialize the limits ourself. We assume two's complement signed representation.
295 template< typename T, bool IsSigned >
296 struct distance_limits< T, boost::int128_type, IsSigned >
297 {
298     //! Difference type D promoted to the width of type T
299     typedef boost::int128_type promoted_difference_type;
300 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits301     static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
302     {
303         return -(max)() - 1;
304     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits305     static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
306     {
307         return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
308     }
309 };
310 
311 template< typename T, bool IsSigned >
312 struct distance_limits< T, boost::uint128_type, IsSigned >
313 {
314     //! Difference type D promoted to the width of type T
315     typedef boost::uint128_type promoted_difference_type;
316 
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits317     static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
318     {
319         return 0u;
320     }
BOOST_PREVENT_MACRO_SUBSTITUTIONdistance_limits321     static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
322     {
323         return ~static_cast< boost::uint128_type >(0u);
324     }
325 };
326 
327 #endif // defined(BOOST_HAS_INT128)
328 
329 #if defined(BOOST_MSVC)
330 #pragma warning(pop)
331 #endif
332 
333 #if defined(BOOST_MSVC)
334 #pragma warning(push)
335 // unary minus operator applied to unsigned type, result still unsigned
336 #pragma warning(disable: 4146)
337 #endif
338 
339 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
test_additive_operators_with_type_and_test()340 void test_additive_operators_with_type_and_test()
341 {
342 #if defined(UBSAN)
343     // clang UBSAN flags this test when AddType is a pointer as it considers subtracting from a null pointer (zero_add) an UB
344     if (boost::is_pointer< AddType >::value)
345         return;
346 #endif
347 
348     // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
349     typedef typename distance_limits< T, D >::promoted_difference_type promoted_difference_type;
350     typedef typename boost::make_unsigned< promoted_difference_type >::type unsigned_promoted_difference_type;
351     const T zero_value = 0;
352     const D zero_diff = 0;
353     const D one_diff = 1;
354     const AddType zero_add = 0;
355     {
356         Wrapper<T> wrapper(zero_value);
357         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
358         bool f = a.add_and_test(zero_diff);
359         BOOST_TEST_EQ( f, false );
360         BOOST_TEST_EQ( a.load(), zero_value );
361 
362         f = a.add_and_test(one_diff);
363         BOOST_TEST_EQ( f, true );
364         BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
365     }
366     {
367         Wrapper<T> wrapper(zero_value);
368         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
369         bool f = a.add_and_test((distance_limits< T, D >::max)());
370         BOOST_TEST_EQ( f, true );
371         BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
372     }
373     {
374         Wrapper<T> wrapper(zero_value);
375         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
376         bool f = a.add_and_test((distance_limits< T, D >::min)());
377         BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
378         BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
379     }
380 
381     {
382         Wrapper<T> wrapper(zero_value);
383         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
384         bool f = a.sub_and_test(zero_diff);
385         BOOST_TEST_EQ( f, false );
386         BOOST_TEST_EQ( a.load(), zero_value );
387 
388         f = a.sub_and_test(one_diff);
389         BOOST_TEST_EQ( f, true );
390         BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
391     }
392     {
393         Wrapper<T> wrapper(zero_value);
394         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
395         bool f = a.sub_and_test((distance_limits< T, D >::max)());
396         BOOST_TEST_EQ( f, true );
397         BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
398     }
399     {
400         Wrapper<T> wrapper(zero_value);
401         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
402         bool f = a.sub_and_test((distance_limits< T, D >::min)());
403         BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
404         // Be very careful as to not cause signed overflow on negation
405         unsigned_promoted_difference_type umin = static_cast< unsigned_promoted_difference_type >(
406             static_cast< promoted_difference_type >((distance_limits< T, D >::min)()));
407         umin = -umin;
408         promoted_difference_type neg_min;
409         std::memcpy(&neg_min, &umin, sizeof(neg_min));
410         BOOST_TEST_EQ( a.load(), T(zero_add + neg_min) );
411     }
412 }
413 
414 #if defined(BOOST_MSVC)
415 #pragma warning(pop)
416 #endif
417 
418 template< template< typename > class Wrapper, typename T, typename D, typename AddType >
test_additive_operators_with_type(T value,D delta)419 void test_additive_operators_with_type(T value, D delta)
420 {
421     /* note: the tests explicitly cast the result of any addition
422     to the type to be tested to force truncation of the result to
423     the correct range in case of overflow */
424 
425     // explicit add/sub
426     {
427         Wrapper<T> wrapper(value);
428         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
429         T n = a.fetch_add(delta);
430         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
431         BOOST_TEST_EQ( n, value );
432     }
433 
434     {
435         Wrapper<T> wrapper(value);
436         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
437         T n = a.fetch_sub(delta);
438         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
439         BOOST_TEST_EQ( n, value );
440     }
441 
442     // overloaded modify/assign
443     {
444         Wrapper<T> wrapper(value);
445         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
446         T n = (a += delta);
447         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
448         BOOST_TEST_EQ( n, T((AddType)value + delta) );
449     }
450 
451     {
452         Wrapper<T> wrapper(value);
453         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
454         T n = (a -= delta);
455         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
456         BOOST_TEST_EQ( n, T((AddType)value - delta) );
457     }
458 
459     // overloaded increment/decrement
460     {
461         Wrapper<T> wrapper(value);
462         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
463         T n = a++;
464         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
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;
472         BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
473         BOOST_TEST_EQ( n, T((AddType)value + 1) );
474     }
475 
476     {
477         Wrapper<T> wrapper(value);
478         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
479         T n = a--;
480         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
481         BOOST_TEST_EQ( n, value );
482     }
483 
484     {
485         Wrapper<T> wrapper(value);
486         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
487         T n = --a;
488         BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
489         BOOST_TEST_EQ( n, T((AddType)value - 1) );
490     }
491 
492     // Operations returning the actual resulting value
493     {
494         Wrapper<T> wrapper(value);
495         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
496         T n = a.add(delta);
497         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
498         BOOST_TEST_EQ( n, T((AddType)value + delta) );
499     }
500 
501     {
502         Wrapper<T> wrapper(value);
503         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
504         T n = a.sub(delta);
505         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
506         BOOST_TEST_EQ( n, T((AddType)value - delta) );
507     }
508 
509     // Opaque operations
510     {
511         Wrapper<T> wrapper(value);
512         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
513         a.opaque_add(delta);
514         BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
515     }
516 
517     {
518         Wrapper<T> wrapper(value);
519         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
520         a.opaque_sub(delta);
521         BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
522     }
523 
524     // Modify and test operations
525     test_additive_operators_with_type_and_test< Wrapper, T, D, AddType >();
526 }
527 
528 template< template< typename > class Wrapper, typename T, typename D >
test_additive_operators(T value,D delta)529 void test_additive_operators(T value, D delta)
530 {
531     test_additive_operators_with_type< Wrapper, T, D, T >(value, delta);
532 }
533 
534 template< template< typename > class Wrapper, typename T >
test_negation()535 void test_negation()
536 {
537     {
538         Wrapper<T> wrapper((T)1);
539         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
540         T n = a.fetch_negate();
541         BOOST_TEST_EQ( a.load(), (T)-1 );
542         BOOST_TEST_EQ( n, (T)1 );
543 
544         n = a.fetch_negate();
545         BOOST_TEST_EQ( a.load(), (T)1 );
546         BOOST_TEST_EQ( n, (T)-1 );
547     }
548     {
549         Wrapper<T> wrapper((T)1);
550         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
551         T n = a.negate();
552         BOOST_TEST_EQ( a.load(), (T)-1 );
553         BOOST_TEST_EQ( n, (T)-1 );
554 
555         n = a.negate();
556         BOOST_TEST_EQ( a.load(), (T)1 );
557         BOOST_TEST_EQ( n, (T)1 );
558     }
559     {
560         Wrapper<T> wrapper((T)1);
561         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
562         a.opaque_negate();
563         BOOST_TEST_EQ( a.load(), (T)-1 );
564 
565         a.opaque_negate();
566         BOOST_TEST_EQ( a.load(), (T)1 );
567     }
568     {
569         Wrapper<T> wrapper((T)1);
570         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
571         bool f = a.negate_and_test();
572         BOOST_TEST_EQ( f, true );
573         BOOST_TEST_EQ( a.load(), (T)-1 );
574 
575         f = a.negate_and_test();
576         BOOST_TEST_EQ( f, true );
577         BOOST_TEST_EQ( a.load(), (T)1 );
578     }
579     {
580         Wrapper<T> wrapper((T)0);
581         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
582         bool f = a.negate_and_test();
583         BOOST_TEST_EQ( f, false );
584         BOOST_TEST_EQ( a.load(), (T)0 );
585     }
586 }
587 
588 template< template< typename > class Wrapper, typename T >
test_additive_wrap(T value)589 void test_additive_wrap(T value)
590 {
591     {
592         Wrapper<T> wrapper(value);
593         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
594         T n = a.fetch_add(1) + (T)1;
595         BOOST_TEST_EQ( a.load(), n );
596     }
597     {
598         Wrapper<T> wrapper(value);
599         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
600         T n = a.fetch_sub(1) - (T)1;
601         BOOST_TEST_EQ( a.load(), n );
602     }
603 }
604 
605 template< template< typename > class Wrapper, typename T >
test_bit_operators(T value,T delta)606 void test_bit_operators(T value, T delta)
607 {
608     // explicit and/or/xor
609     {
610         Wrapper<T> wrapper(value);
611         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
612         T n = a.fetch_and(delta);
613         BOOST_TEST_EQ( a.load(), T(value & delta) );
614         BOOST_TEST_EQ( n, value );
615     }
616 
617     {
618         Wrapper<T> wrapper(value);
619         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
620         T n = a.fetch_or(delta);
621         BOOST_TEST_EQ( a.load(), T(value | delta) );
622         BOOST_TEST_EQ( n, value );
623     }
624 
625     {
626         Wrapper<T> wrapper(value);
627         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
628         T n = a.fetch_xor(delta);
629         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
630         BOOST_TEST_EQ( n, value );
631     }
632 
633     {
634         Wrapper<T> wrapper(value);
635         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
636         T n = a.fetch_complement();
637         BOOST_TEST_EQ( a.load(), T(~value) );
638         BOOST_TEST_EQ( n, value );
639     }
640 
641     // overloaded modify/assign
642     {
643         Wrapper<T> wrapper(value);
644         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
645         T n = (a &= delta);
646         BOOST_TEST_EQ( a.load(), T(value & delta) );
647         BOOST_TEST_EQ( n, T(value & delta) );
648     }
649 
650     {
651         Wrapper<T> wrapper(value);
652         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
653         T n = (a |= delta);
654         BOOST_TEST_EQ( a.load(), T(value | delta) );
655         BOOST_TEST_EQ( n, T(value | delta) );
656     }
657 
658     {
659         Wrapper<T> wrapper(value);
660         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
661         T n = (a ^= delta);
662         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
663         BOOST_TEST_EQ( n, T(value ^ delta) );
664     }
665 
666     // Operations returning the actual resulting value
667     {
668         Wrapper<T> wrapper(value);
669         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
670         T n = a.bitwise_and(delta);
671         BOOST_TEST_EQ( a.load(), T(value & delta) );
672         BOOST_TEST_EQ( n, T(value & delta) );
673     }
674 
675     {
676         Wrapper<T> wrapper(value);
677         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
678         T n = a.bitwise_or(delta);
679         BOOST_TEST_EQ( a.load(), T(value | delta) );
680         BOOST_TEST_EQ( n, T(value | delta) );
681     }
682 
683     {
684         Wrapper<T> wrapper(value);
685         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
686         T n = a.bitwise_xor(delta);
687         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
688         BOOST_TEST_EQ( n, T(value ^ delta) );
689     }
690 
691     {
692         Wrapper<T> wrapper(value);
693         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
694         T n = a.bitwise_complement();
695         BOOST_TEST_EQ( a.load(), T(~value) );
696         BOOST_TEST_EQ( n, T(~value) );
697     }
698 
699     // Opaque operations
700     {
701         Wrapper<T> wrapper(value);
702         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
703         a.opaque_and(delta);
704         BOOST_TEST_EQ( a.load(), T(value & delta) );
705     }
706 
707     {
708         Wrapper<T> wrapper(value);
709         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
710         a.opaque_or(delta);
711         BOOST_TEST_EQ( a.load(), T(value | delta) );
712     }
713 
714     {
715         Wrapper<T> wrapper(value);
716         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
717         a.opaque_xor(delta);
718         BOOST_TEST_EQ( a.load(), T(value ^ delta) );
719     }
720 
721     {
722         Wrapper<T> wrapper(value);
723         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
724         a.opaque_complement();
725         BOOST_TEST_EQ( a.load(), T(~value) );
726     }
727 
728     // Modify and test operations
729     {
730         Wrapper<T> wrapper((T)1);
731         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
732         bool f = a.and_and_test((T)1);
733         BOOST_TEST_EQ( f, true );
734         BOOST_TEST_EQ( a.load(), T(1) );
735 
736         f = a.and_and_test((T)0);
737         BOOST_TEST_EQ( f, false );
738         BOOST_TEST_EQ( a.load(), T(0) );
739 
740         f = a.and_and_test((T)0);
741         BOOST_TEST_EQ( f, false );
742         BOOST_TEST_EQ( a.load(), T(0) );
743     }
744 
745     {
746         Wrapper<T> wrapper((T)0);
747         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
748         bool f = a.or_and_test((T)0);
749         BOOST_TEST_EQ( f, false );
750         BOOST_TEST_EQ( a.load(), T(0) );
751 
752         f = a.or_and_test((T)1);
753         BOOST_TEST_EQ( f, true );
754         BOOST_TEST_EQ( a.load(), T(1) );
755 
756         f = a.or_and_test((T)1);
757         BOOST_TEST_EQ( f, true );
758         BOOST_TEST_EQ( a.load(), T(1) );
759     }
760 
761     {
762         Wrapper<T> wrapper((T)0);
763         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
764         bool f = a.xor_and_test((T)0);
765         BOOST_TEST_EQ( f, false );
766         BOOST_TEST_EQ( a.load(), T(0) );
767 
768         f = a.xor_and_test((T)1);
769         BOOST_TEST_EQ( f, true );
770         BOOST_TEST_EQ( a.load(), T(1) );
771 
772         f = a.xor_and_test((T)1);
773         BOOST_TEST_EQ( f, false );
774         BOOST_TEST_EQ( a.load(), T(0) );
775     }
776 
777     {
778         Wrapper<T> wrapper((T)0);
779         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
780         bool f = a.complement_and_test();
781         BOOST_TEST_EQ( f, true );
782         BOOST_TEST_EQ( a.load(), static_cast< T >(~static_cast< T >(0)) );
783 
784         f = a.complement_and_test();
785         BOOST_TEST_EQ( f, false );
786         BOOST_TEST_EQ( a.load(), T(0) );
787     }
788 
789     // Bit test and modify operations
790     {
791         Wrapper<T> wrapper((T)42);
792         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
793         bool f = a.bit_test_and_set(0);
794         BOOST_TEST_EQ( f, false );
795         BOOST_TEST_EQ( a.load(), T(43) );
796 
797         f = a.bit_test_and_set(1);
798         BOOST_TEST_EQ( f, true );
799         BOOST_TEST_EQ( a.load(), T(43) );
800 
801         f = a.bit_test_and_set(2);
802         BOOST_TEST_EQ( f, false );
803         BOOST_TEST_EQ( a.load(), T(47) );
804     }
805 
806     {
807         Wrapper<T> wrapper((T)42);
808         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
809         bool f = a.bit_test_and_reset(0);
810         BOOST_TEST_EQ( f, false );
811         BOOST_TEST_EQ( a.load(), T(42) );
812 
813         f = a.bit_test_and_reset(1);
814         BOOST_TEST_EQ( f, true );
815         BOOST_TEST_EQ( a.load(), T(40) );
816 
817         f = a.bit_test_and_set(2);
818         BOOST_TEST_EQ( f, false );
819         BOOST_TEST_EQ( a.load(), T(44) );
820     }
821 
822     {
823         Wrapper<T> wrapper((T)42);
824         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
825         bool f = a.bit_test_and_complement(0);
826         BOOST_TEST_EQ( f, false );
827         BOOST_TEST_EQ( a.load(), T(43) );
828 
829         f = a.bit_test_and_complement(1);
830         BOOST_TEST_EQ( f, true );
831         BOOST_TEST_EQ( a.load(), T(41) );
832 
833         f = a.bit_test_and_complement(2);
834         BOOST_TEST_EQ( f, false );
835         BOOST_TEST_EQ( a.load(), T(45) );
836     }
837 
838     // Test that a runtime value works for the bit index. This is important for asm block constraints.
839     {
840         unsigned int runtime_bit_index = std::rand() & 7u;
841         Wrapper<T> wrapper((T)42);
842         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
843 
844         a.bit_test_and_set(runtime_bit_index);
845         a.bit_test_and_reset(runtime_bit_index);
846         a.bit_test_and_complement(runtime_bit_index);
847     }
848 }
849 
850 template< template< typename > class Wrapper, typename T >
do_test_integral_api(boost::false_type)851 void do_test_integral_api(boost::false_type)
852 {
853     test_base_operators< Wrapper, T >(42, 43, 44);
854     test_additive_operators< Wrapper, T, T >(42, 17);
855     test_bit_operators< Wrapper, T >((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
856 
857     /* test for unsigned overflow/underflow */
858     test_additive_operators< Wrapper, T, T >((T)-1, 1);
859     test_additive_operators< Wrapper, T, T >(0, 1);
860     /* test for signed overflow/underflow */
861     test_additive_operators< Wrapper, T, T >(((T)-1) >> (sizeof(T) * 8 - 1), 1);
862     test_additive_operators< Wrapper, T, T >(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
863 }
864 
865 template< template< typename > class Wrapper, typename T >
do_test_integral_api(boost::true_type)866 void do_test_integral_api(boost::true_type)
867 {
868     do_test_integral_api< Wrapper, T >(boost::false_type());
869 
870     test_additive_wrap< Wrapper, T >(0u);
871     BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
872     test_additive_wrap< Wrapper, T >(all_ones);
873     BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
874     test_additive_wrap< Wrapper, T >(all_ones ^ max_signed_twos_compl);
875     test_additive_wrap< Wrapper, T >(max_signed_twos_compl);
876 }
877 
878 template< template< typename > class Wrapper, typename T >
test_integral_api(void)879 inline void test_integral_api(void)
880 {
881     do_test_integral_api< Wrapper, T >(boost::is_unsigned<T>());
882 
883     if (boost::is_signed<T>::value)
884         test_negation< Wrapper, T >();
885 }
886 
887 template< template< typename > class Wrapper, typename T >
test_lock_free_integral_api(boost::true_type)888 inline void test_lock_free_integral_api(boost::true_type)
889 {
890     test_integral_api< Wrapper, T >();
891 }
892 
893 template< template< typename > class Wrapper, typename T >
test_lock_free_integral_api(boost::false_type)894 inline void test_lock_free_integral_api(boost::false_type)
895 {
896 }
897 
898 template< template< typename > class Wrapper, typename T >
test_lock_free_integral_api(void)899 inline void test_lock_free_integral_api(void)
900 {
901     test_lock_free_integral_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
902 }
903 
904 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
905 
906 template< template< typename > class Wrapper, typename T, typename D >
test_fp_additive_operators(T value,D delta)907 void test_fp_additive_operators(T value, D delta)
908 {
909     // explicit add/sub
910     {
911         Wrapper<T> wrapper(value);
912         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
913         T n = a.fetch_add(delta);
914         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
915         BOOST_TEST_EQ( n, approx(value) );
916     }
917 
918     {
919         Wrapper<T> wrapper(value);
920         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
921         T n = a.fetch_sub(delta);
922         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
923         BOOST_TEST_EQ( n, approx(value) );
924     }
925 
926     // overloaded modify/assign
927     {
928         Wrapper<T> wrapper(value);
929         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
930         T n = (a += delta);
931         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
932         BOOST_TEST_EQ( n, approx(T(value + delta)) );
933     }
934 
935     {
936         Wrapper<T> wrapper(value);
937         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
938         T n = (a -= delta);
939         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
940         BOOST_TEST_EQ( n, approx(T(value - delta)) );
941     }
942 
943     // Operations returning the actual resulting value
944     {
945         Wrapper<T> wrapper(value);
946         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
947         T n = a.add(delta);
948         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
949         BOOST_TEST_EQ( n, approx(T(value + delta)) );
950     }
951 
952     {
953         Wrapper<T> wrapper(value);
954         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
955         T n = a.sub(delta);
956         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
957         BOOST_TEST_EQ( n, approx(T(value - delta)) );
958     }
959 
960     // Opaque operations
961     {
962         Wrapper<T> wrapper(value);
963         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
964         a.opaque_add(delta);
965         BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
966     }
967 
968     {
969         Wrapper<T> wrapper(value);
970         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
971         a.opaque_sub(delta);
972         BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
973     }
974 }
975 
976 template< template< typename > class Wrapper, typename T >
test_fp_negation()977 void test_fp_negation()
978 {
979     {
980         Wrapper<T> wrapper((T)1);
981         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
982         T n = a.fetch_negate();
983         BOOST_TEST_EQ( a.load(), approx((T)-1) );
984         BOOST_TEST_EQ( n, approx((T)1) );
985 
986         n = a.fetch_negate();
987         BOOST_TEST_EQ( a.load(), approx((T)1) );
988         BOOST_TEST_EQ( n, approx((T)-1) );
989     }
990     {
991         Wrapper<T> wrapper((T)1);
992         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
993         T n = a.negate();
994         BOOST_TEST_EQ( a.load(), approx((T)-1) );
995         BOOST_TEST_EQ( n, approx((T)-1) );
996 
997         n = a.negate();
998         BOOST_TEST_EQ( a.load(), approx((T)1) );
999         BOOST_TEST_EQ( n, approx((T)1) );
1000     }
1001     {
1002         Wrapper<T> wrapper((T)1);
1003         typename Wrapper<T>::atomic_reference_type a = wrapper.a;
1004         a.opaque_negate();
1005         BOOST_TEST_EQ( a.load(), approx((T)-1) );
1006 
1007         a.opaque_negate();
1008         BOOST_TEST_EQ( a.load(), approx((T)1) );
1009     }
1010 }
1011 
1012 #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1013 
1014 template< template< typename > class Wrapper, typename T >
test_floating_point_api(void)1015 void test_floating_point_api(void)
1016 {
1017     // Note: When support for floating point is disabled, even the base operation tests may fail because
1018     // the generic template specialization does not account for garbage in padding bits that are present in some FP types.
1019 #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
1020     test_base_operators< Wrapper, T >(static_cast<T>(42.1), static_cast<T>(43.2), static_cast<T>(44.3));
1021 
1022     test_fp_additive_operators< Wrapper, T, T >(static_cast<T>(42.5), static_cast<T>(17.7));
1023     test_fp_additive_operators< Wrapper, T, T >(static_cast<T>(-42.5), static_cast<T>(-17.7));
1024 
1025     test_fp_negation< Wrapper, T >();
1026 #endif
1027 }
1028 
1029 template< template< typename > class Wrapper, typename T >
test_lock_free_floating_point_api(boost::true_type)1030 inline void test_lock_free_floating_point_api(boost::true_type)
1031 {
1032     test_floating_point_api< Wrapper, T >();
1033 }
1034 
1035 template< template< typename > class Wrapper, typename T >
test_lock_free_floating_point_api(boost::false_type)1036 inline void test_lock_free_floating_point_api(boost::false_type)
1037 {
1038 }
1039 
1040 template< template< typename > class Wrapper, typename T >
test_lock_free_floating_point_api(void)1041 inline void test_lock_free_floating_point_api(void)
1042 {
1043     test_lock_free_floating_point_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
1044 }
1045 
1046 
1047 template< template< typename > class Wrapper, typename T >
test_pointer_api(void)1048 void test_pointer_api(void)
1049 {
1050     T values[3];
1051 
1052     test_base_operators< Wrapper, T* >(&values[0], &values[1], &values[2]);
1053     test_additive_operators< Wrapper, T*>(&values[1], 1);
1054 
1055     test_base_operators< Wrapper, void*>(&values[0], &values[1], &values[2]);
1056 
1057 #if defined(BOOST_HAS_INTPTR_T)
1058     Wrapper<void*> wrapper_ptr;
1059     typename Wrapper<void*>::atomic_reference_type ptr = wrapper_ptr.a;
1060     Wrapper<boost::intptr_t> wrapper_integral;
1061     typename Wrapper<boost::intptr_t>::atomic_reference_type integral = wrapper_integral.a;
1062     BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
1063 #endif
1064 }
1065 
1066 enum test_enum
1067 {
1068     foo, bar, baz
1069 };
1070 
1071 template< template< typename > class Wrapper, typename T >
test_lock_free_pointer_api(boost::true_type)1072 inline void test_lock_free_pointer_api(boost::true_type)
1073 {
1074     test_pointer_api< Wrapper, T >();
1075 }
1076 
1077 template< template< typename > class Wrapper, typename T >
test_lock_free_pointer_api(boost::false_type)1078 inline void test_lock_free_pointer_api(boost::false_type)
1079 {
1080 }
1081 
1082 template< template< typename > class Wrapper, typename T >
test_lock_free_pointer_api(void)1083 inline void test_lock_free_pointer_api(void)
1084 {
1085     test_lock_free_pointer_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
1086 }
1087 
1088 
1089 template< template< typename > class Wrapper >
test_enum_api(void)1090 void test_enum_api(void)
1091 {
1092     test_base_operators< Wrapper >(foo, bar, baz);
1093 }
1094 
1095 template< template< typename > class Wrapper >
test_lock_free_enum_api(boost::true_type)1096 inline void test_lock_free_enum_api(boost::true_type)
1097 {
1098     test_enum_api< Wrapper >();
1099 }
1100 
1101 template< template< typename > class Wrapper >
test_lock_free_enum_api(boost::false_type)1102 inline void test_lock_free_enum_api(boost::false_type)
1103 {
1104 }
1105 
1106 template< template< typename > class Wrapper >
test_lock_free_enum_api(void)1107 inline void test_lock_free_enum_api(void)
1108 {
1109     test_lock_free_enum_api< Wrapper >(boost::integral_constant< bool, Wrapper< test_enum >::atomic_type::is_always_lock_free >());
1110 }
1111 
1112 
1113 template< typename T >
1114 struct test_struct
1115 {
1116     typedef T value_type;
1117     value_type i;
operator ==test_struct1118     inline bool operator==(test_struct const& c) const { return i == c.i; }
operator !=test_struct1119     inline bool operator!=(test_struct const& c) const { return !operator==(c); }
1120 };
1121 
1122 template< typename Char, typename Traits, typename T >
operator <<(std::basic_ostream<Char,Traits> & strm,test_struct<T> const & s)1123 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
1124 {
1125     test_stream << "{" << s.i << "}";
1126     return strm;
1127 }
1128 
1129 template< template< typename > class Wrapper, typename T >
test_struct_api(void)1130 void test_struct_api(void)
1131 {
1132     T a = {1}, b = {2}, c = {3};
1133 
1134     test_base_operators< Wrapper >(a, b, c);
1135 
1136     {
1137         Wrapper<T> wrapper_sa;
1138         typename Wrapper<T>::atomic_reference_type sa = wrapper_sa.a;
1139         Wrapper<typename T::value_type> wrapper_si;
1140         typename Wrapper<typename T::value_type>::atomic_reference_type si = wrapper_si.a;
1141         BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
1142     }
1143 }
1144 
1145 template< typename T >
1146 struct test_struct_x2
1147 {
1148     typedef T value_type;
1149     value_type i, j;
operator ==test_struct_x21150     inline bool operator==(test_struct_x2 const& c) const { return i == c.i && j == c.j; }
operator !=test_struct_x21151     inline bool operator!=(test_struct_x2 const& c) const { return !operator==(c); }
1152 };
1153 
1154 template< typename Char, typename Traits, typename T >
operator <<(std::basic_ostream<Char,Traits> & strm,test_struct_x2<T> const & s)1155 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
1156 {
1157     test_stream << "{" << s.i << ", " << s.j << "}";
1158     return strm;
1159 }
1160 
1161 template< template< typename > class Wrapper, typename T >
test_struct_x2_api(void)1162 void test_struct_x2_api(void)
1163 {
1164     T a = {1, 1}, b = {2, 2}, c = {3, 3};
1165 
1166     test_base_operators< Wrapper >(a, b, c);
1167 }
1168 
1169 struct large_struct
1170 {
1171     unsigned char data[256u];
1172 
operator ==large_struct1173     inline bool operator==(large_struct const& c) const
1174     {
1175         return std::memcmp(data, &c.data, sizeof(data)) == 0;
1176     }
operator !=large_struct1177     inline bool operator!=(large_struct const& c) const
1178     {
1179         return std::memcmp(data, &c.data, sizeof(data)) != 0;
1180     }
1181 };
1182 
1183 template< typename Char, typename Traits >
operator <<(std::basic_ostream<Char,Traits> & strm,large_struct const &)1184 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
1185 {
1186     strm << "[large_struct]";
1187     return strm;
1188 }
1189 
1190 template< template< typename > class Wrapper >
test_large_struct_api(void)1191 void test_large_struct_api(void)
1192 {
1193     large_struct a = {{1}}, b = {{2}}, c = {{3}};
1194     test_base_operators< Wrapper >(a, b, c);
1195 }
1196 
1197 struct test_struct_with_ctor
1198 {
1199     typedef unsigned int value_type;
1200     value_type i;
test_struct_with_ctortest_struct_with_ctor1201     test_struct_with_ctor() : i(0x01234567) {}
operator ==test_struct_with_ctor1202     inline bool operator==(test_struct_with_ctor const& c) const { return i == c.i; }
operator !=test_struct_with_ctor1203     inline bool operator!=(test_struct_with_ctor const& c) const { return !operator==(c); }
1204 };
1205 
1206 template< typename Char, typename Traits >
operator <<(std::basic_ostream<Char,Traits> & strm,test_struct_with_ctor const & s)1207 inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const& s)
1208 {
1209     strm << "{" << s.i << "}";
1210     return strm;
1211 }
1212 
1213 template< template< typename > class Wrapper >
test_struct_with_ctor_api(void)1214 void test_struct_with_ctor_api(void)
1215 {
1216     {
1217         test_struct_with_ctor s;
1218         Wrapper<test_struct_with_ctor> wrapper_sa;
1219         typename Wrapper<test_struct_with_ctor>::atomic_reference_type sa = wrapper_sa.a;
1220         // Check that the default constructor was called
1221         BOOST_TEST( sa.load() == s );
1222     }
1223 
1224     test_struct_with_ctor a, b, c;
1225     a.i = 1;
1226     b.i = 2;
1227     c.i = 3;
1228 
1229     test_base_operators< Wrapper >(a, b, c);
1230 }
1231 
1232 #endif
1233