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