1 // Copyright (c) 2011 Helge Bahmann
3 // Distributed under the Boost Software License, Version 1.0.
4 // See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_ATOMIC_API_TEST_HELPERS_HPP
8 #define BOOST_ATOMIC_API_TEST_HELPERS_HPP
10 #include <boost/atomic.hpp>
12 #include <boost/config.hpp>
13 #include <boost/cstdint.hpp>
14 #include <boost/core/lightweight_test.hpp>
15 #include <boost/type_traits/integral_constant.hpp>
16 #include <boost/type_traits/is_unsigned.hpp>
18 /* provide helpers that exercise whether the API
19 functions of "boost::atomic" provide the correct
20 operational semantic in the case of sequential
26 #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
27 boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
32 BOOST_TEST( !f.test_and_set() );
33 BOOST_TEST( f.test_and_set() );
35 BOOST_TEST( !f.test_and_set() );
39 void test_base_operators(T value1, T value2, T value3)
41 /* explicit load/store */
43 boost::atomic<T> a(value1);
44 BOOST_TEST( a.load() == value1 );
48 boost::atomic<T> a(value1);
50 BOOST_TEST( a.load() == value2 );
53 /* overloaded assignment/conversion */
55 boost::atomic<T> a(value1);
56 BOOST_TEST( value1 == a );
62 BOOST_TEST( value2 == a );
65 /* exchange-type operators */
67 boost::atomic<T> a(value1);
68 T n = a.exchange(value2);
69 BOOST_TEST( a.load() == value2 && n == value1 );
73 boost::atomic<T> a(value1);
75 bool success = a.compare_exchange_strong(expected, value3);
76 BOOST_TEST( success );
77 BOOST_TEST( a.load() == value3 && expected == value1 );
81 boost::atomic<T> a(value1);
83 bool success = a.compare_exchange_strong(expected, value3);
84 BOOST_TEST( !success );
85 BOOST_TEST( a.load() == value1 && expected == value1 );
89 boost::atomic<T> a(value1);
94 success = a.compare_exchange_weak(expected, value3);
96 BOOST_TEST( success );
97 BOOST_TEST( a.load() == value3 && expected == value1 );
101 boost::atomic<T> a(value1);
106 success = a.compare_exchange_weak(expected, value3);
107 if (expected != value2)
110 BOOST_TEST( !success );
111 BOOST_TEST( a.load() == value1 && expected == value1 );
115 // T requires an int constructor
116 template <typename T>
117 void test_constexpr_ctor()
119 #ifndef BOOST_NO_CXX11_CONSTEXPR
121 const boost::atomic<T> tester(value);
122 BOOST_TEST( tester == value );
126 template<typename T, typename D, typename AddType>
127 void test_additive_operators_with_type(T value, D delta)
129 /* note: the tests explicitly cast the result of any addition
130 to the type to be tested to force truncation of the result to
131 the correct range in case of overflow */
133 /* explicit add/sub */
135 boost::atomic<T> a(value);
136 T n = a.fetch_add(delta);
137 BOOST_TEST( a.load() == T((AddType)value + delta) );
138 BOOST_TEST( n == value );
142 boost::atomic<T> a(value);
143 T n = a.fetch_sub(delta);
144 BOOST_TEST( a.load() == T((AddType)value - delta) );
145 BOOST_TEST( n == value );
148 /* overloaded modify/assign*/
150 boost::atomic<T> a(value);
152 BOOST_TEST( a.load() == T((AddType)value + delta) );
153 BOOST_TEST( n == T((AddType)value + delta) );
157 boost::atomic<T> a(value);
159 BOOST_TEST( a.load() == T((AddType)value - delta) );
160 BOOST_TEST( n == T((AddType)value - delta) );
163 /* overloaded increment/decrement */
165 boost::atomic<T> a(value);
167 BOOST_TEST( a.load() == T((AddType)value + 1) );
168 BOOST_TEST( n == value );
172 boost::atomic<T> a(value);
174 BOOST_TEST( a.load() == T((AddType)value + 1) );
175 BOOST_TEST( n == T((AddType)value + 1) );
179 boost::atomic<T> a(value);
181 BOOST_TEST( a.load() == T((AddType)value - 1) );
182 BOOST_TEST( n == value );
186 boost::atomic<T> a(value);
188 BOOST_TEST( a.load() == T((AddType)value - 1) );
189 BOOST_TEST( n == T((AddType)value - 1) );
193 template<typename T, typename D>
194 void test_additive_operators(T value, D delta)
196 test_additive_operators_with_type<T, D, T>(value, delta);
200 void test_additive_wrap(T value)
203 boost::atomic<T> a(value);
204 T n = a.fetch_add(1) + 1;
205 BOOST_TEST( a.compare_exchange_strong(n, n) );
208 boost::atomic<T> a(value);
209 T n = a.fetch_sub(1) - 1;
210 BOOST_TEST( a.compare_exchange_strong(n, n) );
215 void test_bit_operators(T value, T delta)
217 /* explicit and/or/xor */
219 boost::atomic<T> a(value);
220 T n = a.fetch_and(delta);
221 BOOST_TEST( a.load() == T(value & delta) );
222 BOOST_TEST( n == value );
226 boost::atomic<T> a(value);
227 T n = a.fetch_or(delta);
228 BOOST_TEST( a.load() == T(value | delta) );
229 BOOST_TEST( n == value );
233 boost::atomic<T> a(value);
234 T n = a.fetch_xor(delta);
235 BOOST_TEST( a.load() == T(value ^ delta) );
236 BOOST_TEST( n == value );
239 /* overloaded modify/assign */
241 boost::atomic<T> a(value);
243 BOOST_TEST( a.load() == T(value & delta) );
244 BOOST_TEST( n == T(value & delta) );
248 boost::atomic<T> a(value);
250 BOOST_TEST( a.load() == T(value | delta) );
251 BOOST_TEST( n == T(value | delta) );
255 boost::atomic<T> a(value);
257 BOOST_TEST( a.load() == T(value ^ delta) );
258 BOOST_TEST( n == T(value ^ delta) );
263 void do_test_integral_api(boost::false_type)
265 BOOST_TEST( sizeof(boost::atomic<T>) >= sizeof(T));
267 test_base_operators<T>(42, 43, 44);
268 test_additive_operators<T, T>(42, 17);
269 test_bit_operators<T>((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
271 /* test for unsigned overflow/underflow */
272 test_additive_operators<T, T>((T)-1, 1);
273 test_additive_operators<T, T>(0, 1);
274 /* test for signed overflow/underflow */
275 test_additive_operators<T, T>(((T)-1) >> (sizeof(T) * 8 - 1), 1);
276 test_additive_operators<T, T>(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
280 void do_test_integral_api(boost::true_type)
282 do_test_integral_api<T>(boost::false_type());
284 test_additive_wrap<T>(0u);
285 test_additive_wrap<T>(~(T)0u);
286 test_additive_wrap<T>((~(T)0u) << (sizeof(T) * 8 - 1));
287 test_additive_wrap<T>(~((~(T)0u) << (sizeof(T) * 8 - 1)));
291 inline void test_integral_api(void)
293 do_test_integral_api<T>(boost::is_unsigned<T>());
297 void test_pointer_api(void)
299 BOOST_TEST( sizeof(boost::atomic<T *>) >= sizeof(T *));
300 BOOST_TEST( sizeof(boost::atomic<void *>) >= sizeof(T *));
304 test_base_operators<T*>(&values[0], &values[1], &values[2]);
305 test_additive_operators<T*>(&values[1], 1);
307 test_base_operators<void*>(&values[0], &values[1], &values[2]);
308 test_additive_operators_with_type<void*, int, char*>(&values[1], 1);
310 #if defined(BOOST_HAS_INTPTR_T)
311 boost::atomic<void *> ptr;
312 boost::atomic<boost::intptr_t> integral;
313 BOOST_TEST( ptr.is_lock_free() == integral.is_lock_free() );
324 test_base_operators(foo, bar, baz);
329 typedef T value_type;
331 inline bool operator==(const test_struct & c) const {return i == c.i;}
332 inline bool operator!=(const test_struct & c) const {return i != c.i;}
337 test_struct_api(void)
339 T a = {1}, b = {2}, c = {3};
341 test_base_operators(a, b, c);
345 boost::atomic<typename T::value_type> si;
346 BOOST_TEST( sa.is_lock_free() == si.is_lock_free() );
351 struct test_struct_x2 {
352 typedef T value_type;
354 inline bool operator==(const test_struct_x2 & c) const {return i == c.i && j == c.j;}
355 inline bool operator!=(const test_struct_x2 & c) const {return i != c.i && j != c.j;}
360 test_struct_x2_api(void)
362 T a = {1, 1}, b = {2, 2}, c = {3, 3};
364 test_base_operators(a, b, c);
367 struct large_struct {
370 inline bool operator==(const large_struct & c) const
372 return std::memcmp(data, &c.data, sizeof(data)) == 0;
374 inline bool operator!=(const large_struct & c) const
376 return std::memcmp(data, &c.data, sizeof(data)) != 0;
381 test_large_struct_api(void)
383 large_struct a = {{1}}, b = {{2}}, c = {{3}};
384 test_base_operators(a, b, c);
387 struct test_struct_with_ctor {
388 typedef unsigned int value_type;
390 test_struct_with_ctor() : i(0x01234567) {}
391 inline bool operator==(const test_struct_with_ctor & c) const {return i == c.i;}
392 inline bool operator!=(const test_struct_with_ctor & c) const {return i != c.i;}
396 test_struct_with_ctor_api(void)
399 test_struct_with_ctor s;
400 boost::atomic<test_struct_with_ctor> sa;
401 // Check that the default constructor was called
402 BOOST_TEST( sa.load() == s );
405 test_struct_with_ctor a, b, c;
410 test_base_operators(a, b, c);