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