]>
Commit | Line | Data |
---|---|---|
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 |
30 | struct 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 | ||
109 | const 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 |
117 | const unsigned int max_weak_cas_loops = 1000; |
118 | ||
119 | //! Wrapper type for atomic template | |
120 | template< typename T > | |
121 | struct 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 | |
132 | template< typename T > | |
133 | struct 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 |
145 | functions of "boost::atomic" provide the correct | |
146 | operational semantic in the case of sequential | |
147 | execution */ | |
148 | ||
f67539c2 | 149 | inline 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 |
167 | template< typename T > |
168 | inline void test_atomic_type_traits(boost::type< boost::atomic< T > >) | |
169 | { | |
170 | BOOST_TEST_GE(sizeof(boost::atomic< T >), sizeof(T)); | |
171 | } | |
172 | ||
173 | template< typename T > | |
174 | inline 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 | ||
187 | template< template< typename > class Wrapper, typename T > | |
7c673cae FG |
188 | void 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. |
289 | template< typename T > | |
7c673cae FG |
290 | void 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 |
300 | template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value > | |
301 | struct 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 | ||
327 | template< typename T, typename D > | |
328 | struct 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 | ||
349 | template< typename T, typename D > | |
350 | struct 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. | |
371 | template< typename T, bool IsSigned > | |
372 | struct 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 | ||
387 | template< typename T, bool IsSigned > | |
388 | struct 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 | ||
415 | template< template< typename > class Wrapper, typename T, typename D, typename AddType > | |
b32b8144 FG |
416 | void 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 | ||
494 | template< template< typename > class Wrapper, typename T, typename D, typename AddType > | |
7c673cae FG |
495 | void 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 | 604 | template< template< typename > class Wrapper, typename T, typename D > |
7c673cae FG |
605 | void 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 | 610 | template< template< typename > class Wrapper, typename T > |
b32b8144 FG |
611 | void 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 | 664 | template< template< typename > class Wrapper, typename T > |
7c673cae FG |
665 | void 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 | 681 | template< template< typename > class Wrapper, typename T > |
7c673cae FG |
682 | void 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 | 926 | template< template< typename > class Wrapper, typename T > |
7c673cae FG |
927 | void 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 | 941 | template< template< typename > class Wrapper, typename T > |
7c673cae FG |
942 | void 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 | 954 | template< template< typename > class Wrapper, typename T > |
7c673cae FG |
955 | inline 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 | 965 | template< template< typename > class Wrapper, typename T, typename D > |
11fdf7f2 TL |
966 | void 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 | 1035 | template< template< typename > class Wrapper, typename T > |
11fdf7f2 TL |
1036 | void 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 |
1073 | template< template< typename > class Wrapper, typename T > |
1074 | void 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 | 1089 | template< template< typename > class Wrapper, typename T > |
7c673cae FG |
1090 | void 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 |
1108 | enum test_enum |
1109 | { | |
7c673cae FG |
1110 | foo, bar, baz |
1111 | }; | |
1112 | ||
f67539c2 TL |
1113 | template< template< typename > class Wrapper > |
1114 | void test_enum_api(void) | |
7c673cae | 1115 | { |
f67539c2 | 1116 | test_base_operators< Wrapper >(foo, bar, baz); |
7c673cae FG |
1117 | } |
1118 | ||
f67539c2 | 1119 | template< typename T > |
b32b8144 FG |
1120 | struct 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 |
1128 | template< typename Char, typename Traits, typename T > |
1129 | inline 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 |
1135 | template< template< typename > class Wrapper, typename T > |
1136 | void 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 | 1151 | template< typename T > |
b32b8144 FG |
1152 | struct 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 |
1160 | template< typename Char, typename Traits, typename T > |
1161 | inline 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 |
1167 | template< template< typename > class Wrapper, typename T > |
1168 | void 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 |
1175 | struct 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 |
1189 | template< typename Char, typename Traits > |
1190 | inline 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 |
1196 | template< template< typename > class Wrapper > |
1197 | void 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 |
1203 | struct 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 | 1212 | template< typename Char, typename Traits > |
f67539c2 | 1213 | inline 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 |
1219 | template< template< typename > class Wrapper > |
1220 | void 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 |