1 /*
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
5 *
6 * Copyright (c) 2011 Helge Bahmann
7 * Copyright (c) 2013 Tim Blechmann
8 * Copyright (c) 2014 Andrey Semashev
9 */
10 /*!
11 * \file atomic/detail/atomic_template.hpp
12 *
13 * This header contains interface definition of \c atomic template.
14 */
15
16 #ifndef BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_
17 #define BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_
18
19 #include <cstddef>
20 #include <boost/cstdint.hpp>
21 #include <boost/assert.hpp>
22 #include <boost/atomic/detail/config.hpp>
23 #include <boost/atomic/detail/bitwise_cast.hpp>
24 #include <boost/atomic/detail/operations_fwd.hpp>
25 #include <boost/atomic/detail/extra_operations_fwd.hpp>
26 #include <boost/atomic/detail/type_traits/is_signed.hpp>
27 #include <boost/atomic/detail/type_traits/is_integral.hpp>
28 #include <boost/atomic/detail/type_traits/is_function.hpp>
29 #include <boost/atomic/detail/type_traits/conditional.hpp>
30
31 #ifdef BOOST_HAS_PRAGMA_ONCE
32 #pragma once
33 #endif
34
35 #if defined(BOOST_MSVC)
36 #pragma warning(push)
37 // 'boost::atomics::atomic<T>' : multiple assignment operators specified
38 #pragma warning(disable: 4522)
39 #endif
40
41 /*
42 * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE,
43 * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp.
44 */
45
46 namespace boost {
47 namespace atomics {
48 namespace detail {
49
deduce_failure_order(memory_order order)50 BOOST_FORCEINLINE BOOST_CONSTEXPR memory_order deduce_failure_order(memory_order order) BOOST_NOEXCEPT
51 {
52 return order == memory_order_acq_rel ? memory_order_acquire : (order == memory_order_release ? memory_order_relaxed : order);
53 }
54
cas_failure_order_must_not_be_stronger_than_success_order(memory_order success_order,memory_order failure_order)55 BOOST_FORCEINLINE BOOST_CONSTEXPR bool cas_failure_order_must_not_be_stronger_than_success_order(memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
56 {
57 // 15 == (memory_order_seq_cst | memory_order_consume), see memory_order.hpp
58 // Given the enum values we can test the strength of memory order requirements with this single condition.
59 return (failure_order & 15u) <= (success_order & 15u);
60 }
61
62 template< typename T, bool IsFunction = boost::atomics::detail::is_function< T >::value >
63 struct classify_pointer
64 {
65 typedef void* type;
66 };
67
68 template< typename T >
69 struct classify_pointer< T, true >
70 {
71 typedef void type;
72 };
73
74 template< typename T, bool IsInt = boost::atomics::detail::is_integral< T >::value >
75 struct classify
76 {
77 typedef void type;
78 };
79
80 template< typename T >
81 struct classify< T, true > { typedef int type; };
82
83 template< typename T >
84 struct classify< T*, false > { typedef typename classify_pointer< T >::type type; };
85
86 template< >
87 struct classify< void*, false > { typedef void type; };
88
89 template< >
90 struct classify< const void*, false > { typedef void type; };
91
92 template< >
93 struct classify< volatile void*, false > { typedef void type; };
94
95 template< >
96 struct classify< const volatile void*, false > { typedef void type; };
97
98 template< typename T, typename U >
99 struct classify< T U::*, false > { typedef void type; };
100
101 template< bool >
102 struct boolean_constant {};
103 typedef boolean_constant< true > true_constant;
104 typedef boolean_constant< false > false_constant;
105
106
107 template< typename T, typename Kind >
108 class base_atomic;
109
110 //! General template. Implementation for user-defined types, such as structs and enums, and pointers to non-object types
111 template< typename T >
112 class base_atomic< T, void >
113 {
114 public:
115 typedef T value_type;
116
117 protected:
118 typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations;
119 typedef typename boost::atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type;
120
121 public:
122 typedef typename operations::storage_type storage_type;
123
124 private:
125 typedef boolean_constant< sizeof(value_type) == sizeof(storage_type) > value_matches_storage;
126
127 protected:
128 typename operations::aligned_storage_type m_storage;
129
130 public:
base_atomic(value_arg_type v=value_type ())131 BOOST_FORCEINLINE explicit base_atomic(value_arg_type v = value_type()) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< storage_type >(v))
132 {
133 }
134
store(value_arg_type v,memory_order order=memory_order_seq_cst)135 BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
136 {
137 BOOST_ASSERT(order != memory_order_consume);
138 BOOST_ASSERT(order != memory_order_acquire);
139 BOOST_ASSERT(order != memory_order_acq_rel);
140
141 operations::store(m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order);
142 }
143
load(memory_order order=memory_order_seq_cst) const144 BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT
145 {
146 BOOST_ASSERT(order != memory_order_release);
147 BOOST_ASSERT(order != memory_order_acq_rel);
148
149 return atomics::detail::bitwise_cast< value_type >(operations::load(m_storage.value, order));
150 }
151
exchange(value_arg_type v,memory_order order=memory_order_seq_cst)152 BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
153 {
154 return atomics::detail::bitwise_cast< value_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order));
155 }
156
compare_exchange_strong(value_type & expected,value_arg_type desired,memory_order success_order,memory_order failure_order)157 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
158 {
159 BOOST_ASSERT(failure_order != memory_order_release);
160 BOOST_ASSERT(failure_order != memory_order_acq_rel);
161 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
162
163 return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage());
164 }
165
compare_exchange_strong(value_type & expected,value_arg_type desired,memory_order order=memory_order_seq_cst)166 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
167 {
168 return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order));
169 }
170
compare_exchange_weak(value_type & expected,value_arg_type desired,memory_order success_order,memory_order failure_order)171 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
172 {
173 BOOST_ASSERT(failure_order != memory_order_release);
174 BOOST_ASSERT(failure_order != memory_order_acq_rel);
175 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
176
177 return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage());
178 }
179
compare_exchange_weak(value_type & expected,value_arg_type desired,memory_order order=memory_order_seq_cst)180 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
181 {
182 return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order));
183 }
184
185 BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&))
186 BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&))
187
188 private:
compare_exchange_strong_impl(value_type & expected,value_arg_type desired,memory_order success_order,memory_order failure_order,true_constant)189 BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, true_constant) volatile BOOST_NOEXCEPT
190 {
191 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
192 return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
193 #else
194 return compare_exchange_strong_impl(expected, desired, success_order, failure_order, false_constant());
195 #endif
196 }
197
compare_exchange_strong_impl(value_type & expected,value_arg_type desired,memory_order success_order,memory_order failure_order,false_constant)198 BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, false_constant) volatile BOOST_NOEXCEPT
199 {
200 storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected);
201 const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
202 expected = atomics::detail::bitwise_cast< value_type >(old_value);
203 return res;
204 }
205
compare_exchange_weak_impl(value_type & expected,value_arg_type desired,memory_order success_order,memory_order failure_order,true_constant)206 BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, true_constant) volatile BOOST_NOEXCEPT
207 {
208 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
209 return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
210 #else
211 return compare_exchange_weak_impl(expected, desired, success_order, failure_order, false_constant());
212 #endif
213 }
214
compare_exchange_weak_impl(value_type & expected,value_arg_type desired,memory_order success_order,memory_order failure_order,false_constant)215 BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, false_constant) volatile BOOST_NOEXCEPT
216 {
217 storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected);
218 const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
219 expected = atomics::detail::bitwise_cast< value_type >(old_value);
220 return res;
221 }
222 };
223
224
225 //! Implementation for integers
226 template< typename T >
227 class base_atomic< T, int >
228 {
229 public:
230 typedef T value_type;
231 typedef T difference_type;
232
233 protected:
234 typedef atomics::detail::operations< storage_size_of< value_type >::value, boost::atomics::detail::is_signed< T >::value > operations;
235 typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations;
236 typedef value_type value_arg_type;
237
238 public:
239 typedef typename operations::storage_type storage_type;
240
241 protected:
242 typename operations::aligned_storage_type m_storage;
243
244 public:
base_atomic()245 BOOST_DEFAULTED_FUNCTION(base_atomic(), {})
246 BOOST_CONSTEXPR explicit base_atomic(value_type v) BOOST_NOEXCEPT : m_storage(v) {}
247
248 // Standard methods
store(value_type v,memory_order order=memory_order_seq_cst)249 BOOST_FORCEINLINE void store(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
250 {
251 BOOST_ASSERT(order != memory_order_consume);
252 BOOST_ASSERT(order != memory_order_acquire);
253 BOOST_ASSERT(order != memory_order_acq_rel);
254
255 operations::store(m_storage.value, static_cast< storage_type >(v), order);
256 }
257
load(memory_order order=memory_order_seq_cst) const258 BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT
259 {
260 BOOST_ASSERT(order != memory_order_release);
261 BOOST_ASSERT(order != memory_order_acq_rel);
262
263 return static_cast< value_type >(operations::load(m_storage.value, order));
264 }
265
fetch_add(difference_type v,memory_order order=memory_order_seq_cst)266 BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
267 {
268 return static_cast< value_type >(operations::fetch_add(m_storage.value, static_cast< storage_type >(v), order));
269 }
270
fetch_sub(difference_type v,memory_order order=memory_order_seq_cst)271 BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
272 {
273 return static_cast< value_type >(operations::fetch_sub(m_storage.value, static_cast< storage_type >(v), order));
274 }
275
exchange(value_type v,memory_order order=memory_order_seq_cst)276 BOOST_FORCEINLINE value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
277 {
278 return static_cast< value_type >(operations::exchange(m_storage.value, static_cast< storage_type >(v), order));
279 }
280
compare_exchange_strong(value_type & expected,value_type desired,memory_order success_order,memory_order failure_order)281 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
282 {
283 BOOST_ASSERT(failure_order != memory_order_release);
284 BOOST_ASSERT(failure_order != memory_order_acq_rel);
285 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
286
287 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
288 return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order);
289 #else
290 storage_type old_value = static_cast< storage_type >(expected);
291 const bool res = operations::compare_exchange_strong(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order);
292 expected = static_cast< value_type >(old_value);
293 return res;
294 #endif
295 }
296
compare_exchange_strong(value_type & expected,value_type desired,memory_order order=memory_order_seq_cst)297 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
298 {
299 return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order));
300 }
301
compare_exchange_weak(value_type & expected,value_type desired,memory_order success_order,memory_order failure_order)302 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
303 {
304 BOOST_ASSERT(failure_order != memory_order_release);
305 BOOST_ASSERT(failure_order != memory_order_acq_rel);
306 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
307
308 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
309 return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order);
310 #else
311 storage_type old_value = static_cast< storage_type >(expected);
312 const bool res = operations::compare_exchange_weak(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order);
313 expected = static_cast< value_type >(old_value);
314 return res;
315 #endif
316 }
317
compare_exchange_weak(value_type & expected,value_type desired,memory_order order=memory_order_seq_cst)318 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
319 {
320 return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order));
321 }
322
fetch_and(value_type v,memory_order order=memory_order_seq_cst)323 BOOST_FORCEINLINE value_type fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
324 {
325 return static_cast< value_type >(operations::fetch_and(m_storage.value, static_cast< storage_type >(v), order));
326 }
327
fetch_or(value_type v,memory_order order=memory_order_seq_cst)328 BOOST_FORCEINLINE value_type fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
329 {
330 return static_cast< value_type >(operations::fetch_or(m_storage.value, static_cast< storage_type >(v), order));
331 }
332
fetch_xor(value_type v,memory_order order=memory_order_seq_cst)333 BOOST_FORCEINLINE value_type fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
334 {
335 return static_cast< value_type >(operations::fetch_xor(m_storage.value, static_cast< storage_type >(v), order));
336 }
337
338 // Boost.Atomic extensions
fetch_negate(memory_order order=memory_order_seq_cst)339 BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
340 {
341 return static_cast< value_type >(extra_operations::fetch_negate(m_storage.value, order));
342 }
343
fetch_complement(memory_order order=memory_order_seq_cst)344 BOOST_FORCEINLINE value_type fetch_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
345 {
346 return static_cast< value_type >(extra_operations::fetch_complement(m_storage.value, order));
347 }
348
opaque_add(difference_type v,memory_order order=memory_order_seq_cst)349 BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
350 {
351 extra_operations::opaque_add(m_storage.value, static_cast< storage_type >(v), order);
352 }
353
opaque_sub(difference_type v,memory_order order=memory_order_seq_cst)354 BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
355 {
356 extra_operations::opaque_sub(m_storage.value, static_cast< storage_type >(v), order);
357 }
358
opaque_negate(memory_order order=memory_order_seq_cst)359 BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
360 {
361 extra_operations::opaque_negate(m_storage.value, order);
362 }
363
opaque_and(value_type v,memory_order order=memory_order_seq_cst)364 BOOST_FORCEINLINE void opaque_and(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
365 {
366 extra_operations::opaque_and(m_storage.value, static_cast< storage_type >(v), order);
367 }
368
opaque_or(value_type v,memory_order order=memory_order_seq_cst)369 BOOST_FORCEINLINE void opaque_or(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
370 {
371 extra_operations::opaque_or(m_storage.value, static_cast< storage_type >(v), order);
372 }
373
opaque_xor(value_type v,memory_order order=memory_order_seq_cst)374 BOOST_FORCEINLINE void opaque_xor(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
375 {
376 extra_operations::opaque_xor(m_storage.value, static_cast< storage_type >(v), order);
377 }
378
opaque_complement(memory_order order=memory_order_seq_cst)379 BOOST_FORCEINLINE void opaque_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
380 {
381 extra_operations::opaque_complement(m_storage.value, order);
382 }
383
add_and_test(difference_type v,memory_order order=memory_order_seq_cst)384 BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
385 {
386 return extra_operations::add_and_test(m_storage.value, static_cast< storage_type >(v), order);
387 }
388
sub_and_test(difference_type v,memory_order order=memory_order_seq_cst)389 BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
390 {
391 return extra_operations::sub_and_test(m_storage.value, static_cast< storage_type >(v), order);
392 }
393
and_and_test(value_type v,memory_order order=memory_order_seq_cst)394 BOOST_FORCEINLINE bool and_and_test(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
395 {
396 return extra_operations::and_and_test(m_storage.value, static_cast< storage_type >(v), order);
397 }
398
or_and_test(value_type v,memory_order order=memory_order_seq_cst)399 BOOST_FORCEINLINE bool or_and_test(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
400 {
401 return extra_operations::or_and_test(m_storage.value, static_cast< storage_type >(v), order);
402 }
403
xor_and_test(value_type v,memory_order order=memory_order_seq_cst)404 BOOST_FORCEINLINE bool xor_and_test(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
405 {
406 return extra_operations::xor_and_test(m_storage.value, static_cast< storage_type >(v), order);
407 }
408
bit_test_and_set(unsigned int bit_number,memory_order order=memory_order_seq_cst)409 BOOST_FORCEINLINE bool bit_test_and_set(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
410 {
411 BOOST_ASSERT(bit_number < sizeof(value_type) * 8u);
412 return extra_operations::bit_test_and_set(m_storage.value, bit_number, order);
413 }
414
bit_test_and_reset(unsigned int bit_number,memory_order order=memory_order_seq_cst)415 BOOST_FORCEINLINE bool bit_test_and_reset(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
416 {
417 BOOST_ASSERT(bit_number < sizeof(value_type) * 8u);
418 return extra_operations::bit_test_and_reset(m_storage.value, bit_number, order);
419 }
420
bit_test_and_complement(unsigned int bit_number,memory_order order=memory_order_seq_cst)421 BOOST_FORCEINLINE bool bit_test_and_complement(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
422 {
423 BOOST_ASSERT(bit_number < sizeof(value_type) * 8u);
424 return extra_operations::bit_test_and_complement(m_storage.value, bit_number, order);
425 }
426
427 // Operators
operator ++(int)428 BOOST_FORCEINLINE value_type operator++(int) volatile BOOST_NOEXCEPT
429 {
430 return fetch_add(1);
431 }
432
operator ++()433 BOOST_FORCEINLINE value_type operator++() volatile BOOST_NOEXCEPT
434 {
435 return fetch_add(1) + 1;
436 }
437
operator --(int)438 BOOST_FORCEINLINE value_type operator--(int) volatile BOOST_NOEXCEPT
439 {
440 return fetch_sub(1);
441 }
442
operator --()443 BOOST_FORCEINLINE value_type operator--() volatile BOOST_NOEXCEPT
444 {
445 return fetch_sub(1) - 1;
446 }
447
operator +=(difference_type v)448 BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT
449 {
450 return fetch_add(v) + v;
451 }
452
operator -=(difference_type v)453 BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT
454 {
455 return fetch_sub(v) - v;
456 }
457
operator &=(value_type v)458 BOOST_FORCEINLINE value_type operator&=(value_type v) volatile BOOST_NOEXCEPT
459 {
460 return fetch_and(v) & v;
461 }
462
operator |=(value_type v)463 BOOST_FORCEINLINE value_type operator|=(value_type v) volatile BOOST_NOEXCEPT
464 {
465 return fetch_or(v) | v;
466 }
467
operator ^=(value_type v)468 BOOST_FORCEINLINE value_type operator^=(value_type v) volatile BOOST_NOEXCEPT
469 {
470 return fetch_xor(v) ^ v;
471 }
472
473 BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&))
474 BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&))
475 };
476
477 //! Implementation for bool
478 template< >
479 class base_atomic< bool, int >
480 {
481 public:
482 typedef bool value_type;
483
484 protected:
485 typedef atomics::detail::operations< 1u, false > operations;
486 typedef value_type value_arg_type;
487
488 public:
489 typedef operations::storage_type storage_type;
490
491 protected:
492 operations::aligned_storage_type m_storage;
493
494 public:
base_atomic()495 BOOST_DEFAULTED_FUNCTION(base_atomic(), {})
496 BOOST_CONSTEXPR explicit base_atomic(value_type v) BOOST_NOEXCEPT : m_storage(v) {}
497
498 // Standard methods
store(value_type v,memory_order order=memory_order_seq_cst)499 BOOST_FORCEINLINE void store(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
500 {
501 BOOST_ASSERT(order != memory_order_consume);
502 BOOST_ASSERT(order != memory_order_acquire);
503 BOOST_ASSERT(order != memory_order_acq_rel);
504
505 operations::store(m_storage.value, static_cast< storage_type >(v), order);
506 }
507
load(memory_order order=memory_order_seq_cst) const508 BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT
509 {
510 BOOST_ASSERT(order != memory_order_release);
511 BOOST_ASSERT(order != memory_order_acq_rel);
512
513 return !!operations::load(m_storage.value, order);
514 }
515
exchange(value_type v,memory_order order=memory_order_seq_cst)516 BOOST_FORCEINLINE value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
517 {
518 return !!operations::exchange(m_storage.value, static_cast< storage_type >(v), order);
519 }
520
compare_exchange_strong(value_type & expected,value_type desired,memory_order success_order,memory_order failure_order)521 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
522 {
523 BOOST_ASSERT(failure_order != memory_order_release);
524 BOOST_ASSERT(failure_order != memory_order_acq_rel);
525 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
526
527 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
528 return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order);
529 #else
530 storage_type old_value = static_cast< storage_type >(expected);
531 const bool res = operations::compare_exchange_strong(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order);
532 expected = !!old_value;
533 return res;
534 #endif
535 }
536
compare_exchange_strong(value_type & expected,value_type desired,memory_order order=memory_order_seq_cst)537 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
538 {
539 return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order));
540 }
541
compare_exchange_weak(value_type & expected,value_type desired,memory_order success_order,memory_order failure_order)542 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
543 {
544 BOOST_ASSERT(failure_order != memory_order_release);
545 BOOST_ASSERT(failure_order != memory_order_acq_rel);
546 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
547
548 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
549 return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order);
550 #else
551 storage_type old_value = static_cast< storage_type >(expected);
552 const bool res = operations::compare_exchange_weak(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order);
553 expected = !!old_value;
554 return res;
555 #endif
556 }
557
compare_exchange_weak(value_type & expected,value_type desired,memory_order order=memory_order_seq_cst)558 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
559 {
560 return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order));
561 }
562
563 BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&))
564 BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&))
565 };
566
567
568 //! Implementation for pointers to object types
569 template< typename T >
570 class base_atomic< T*, void* >
571 {
572 public:
573 typedef T* value_type;
574 typedef std::ptrdiff_t difference_type;
575
576 protected:
577 typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations;
578 typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations;
579 typedef value_type value_arg_type;
580
581 public:
582 typedef typename operations::storage_type storage_type;
583
584 protected:
585 typename operations::aligned_storage_type m_storage;
586
587 public:
base_atomic()588 BOOST_DEFAULTED_FUNCTION(base_atomic(), {})
589 BOOST_FORCEINLINE explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< storage_type >(v))
590 {
591 }
592
593 // Standard methods
store(value_type v,memory_order order=memory_order_seq_cst)594 BOOST_FORCEINLINE void store(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
595 {
596 BOOST_ASSERT(order != memory_order_consume);
597 BOOST_ASSERT(order != memory_order_acquire);
598 BOOST_ASSERT(order != memory_order_acq_rel);
599
600 operations::store(m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order);
601 }
602
load(memory_order order=memory_order_seq_cst) const603 BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT
604 {
605 BOOST_ASSERT(order != memory_order_release);
606 BOOST_ASSERT(order != memory_order_acq_rel);
607
608 return atomics::detail::bitwise_cast< value_type >(operations::load(m_storage.value, order));
609 }
610
fetch_add(difference_type v,memory_order order=memory_order_seq_cst)611 BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
612 {
613 return atomics::detail::bitwise_cast< value_type >(operations::fetch_add(m_storage.value, static_cast< storage_type >(v * sizeof(T)), order));
614 }
615
fetch_sub(difference_type v,memory_order order=memory_order_seq_cst)616 BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
617 {
618 return atomics::detail::bitwise_cast< value_type >(operations::fetch_sub(m_storage.value, static_cast< storage_type >(v * sizeof(T)), order));
619 }
620
exchange(value_type v,memory_order order=memory_order_seq_cst)621 BOOST_FORCEINLINE value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
622 {
623 return atomics::detail::bitwise_cast< value_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order));
624 }
625
compare_exchange_strong(value_type & expected,value_type desired,memory_order success_order,memory_order failure_order)626 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
627 {
628 BOOST_ASSERT(failure_order != memory_order_release);
629 BOOST_ASSERT(failure_order != memory_order_acq_rel);
630 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
631
632 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
633 return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
634 #else
635 storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected);
636 const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
637 expected = atomics::detail::bitwise_cast< value_type >(old_value);
638 return res;
639 #endif
640 }
641
compare_exchange_strong(value_type & expected,value_type desired,memory_order order=memory_order_seq_cst)642 BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
643 {
644 return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order));
645 }
646
compare_exchange_weak(value_type & expected,value_type desired,memory_order success_order,memory_order failure_order)647 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
648 {
649 BOOST_ASSERT(failure_order != memory_order_release);
650 BOOST_ASSERT(failure_order != memory_order_acq_rel);
651 BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
652
653 #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
654 return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
655 #else
656 storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected);
657 const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order);
658 expected = atomics::detail::bitwise_cast< value_type >(old_value);
659 return res;
660 #endif
661 }
662
compare_exchange_weak(value_type & expected,value_type desired,memory_order order=memory_order_seq_cst)663 BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
664 {
665 return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order));
666 }
667
668 // Boost.Atomic extensions
opaque_add(difference_type v,memory_order order=memory_order_seq_cst)669 BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
670 {
671 extra_operations::opaque_add(m_storage.value, static_cast< storage_type >(v * sizeof(T)), order);
672 }
673
opaque_sub(difference_type v,memory_order order=memory_order_seq_cst)674 BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
675 {
676 extra_operations::opaque_sub(m_storage.value, static_cast< storage_type >(v * sizeof(T)), order);
677 }
678
add_and_test(difference_type v,memory_order order=memory_order_seq_cst)679 BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
680 {
681 return extra_operations::add_and_test(m_storage.value, static_cast< storage_type >(v * sizeof(T)), order);
682 }
683
sub_and_test(difference_type v,memory_order order=memory_order_seq_cst)684 BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
685 {
686 return extra_operations::sub_and_test(m_storage.value, static_cast< storage_type >(v * sizeof(T)), order);
687 }
688
689 // Operators
operator ++(int)690 BOOST_FORCEINLINE value_type operator++(int) volatile BOOST_NOEXCEPT
691 {
692 return fetch_add(1);
693 }
694
operator ++()695 BOOST_FORCEINLINE value_type operator++() volatile BOOST_NOEXCEPT
696 {
697 return fetch_add(1) + 1;
698 }
699
operator --(int)700 BOOST_FORCEINLINE value_type operator--(int) volatile BOOST_NOEXCEPT
701 {
702 return fetch_sub(1);
703 }
704
operator --()705 BOOST_FORCEINLINE value_type operator--() volatile BOOST_NOEXCEPT
706 {
707 return fetch_sub(1) - 1;
708 }
709
operator +=(difference_type v)710 BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT
711 {
712 return fetch_add(v) + v;
713 }
714
operator -=(difference_type v)715 BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT
716 {
717 return fetch_sub(v) - v;
718 }
719
720 BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&))
721 BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&))
722 };
723
724 } // namespace detail
725
726 template< typename T >
727 class atomic :
728 public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type >
729 {
730 private:
731 typedef atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > base_type;
732 typedef typename base_type::value_arg_type value_arg_type;
733
734 public:
735 typedef typename base_type::value_type value_type;
736 typedef typename base_type::storage_type storage_type;
737
738 public:
739 static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = base_type::operations::is_always_lock_free;
740
741 public:
BOOST_DEFAULTED_FUNCTION(atomic (),BOOST_NOEXCEPT{})742 BOOST_DEFAULTED_FUNCTION(atomic(), BOOST_NOEXCEPT {})
743
744 // NOTE: The constructor is made explicit because gcc 4.7 complains that
745 // operator=(value_arg_type) is considered ambiguous with operator=(atomic const&)
746 // in assignment expressions, even though conversion to atomic<> is less preferred
747 // than conversion to value_arg_type.
748 BOOST_FORCEINLINE explicit BOOST_CONSTEXPR atomic(value_arg_type v) BOOST_NOEXCEPT : base_type(v) {}
749
operator =(value_arg_type v)750 BOOST_FORCEINLINE value_type operator= (value_arg_type v) volatile BOOST_NOEXCEPT
751 {
752 this->store(v);
753 return v;
754 }
755
operator value_type() const756 BOOST_FORCEINLINE operator value_type() const volatile BOOST_NOEXCEPT
757 {
758 return this->load();
759 }
760
is_lock_free() const761 BOOST_FORCEINLINE bool is_lock_free() const volatile BOOST_NOEXCEPT
762 {
763 // C++17 requires all instances of atomic<> return a value consistent with is_always_lock_free here
764 return is_always_lock_free;
765 }
766
storage()767 BOOST_FORCEINLINE storage_type& storage() BOOST_NOEXCEPT { return this->m_storage.value; }
storage()768 BOOST_FORCEINLINE storage_type volatile& storage() volatile BOOST_NOEXCEPT { return this->m_storage.value; }
storage() const769 BOOST_FORCEINLINE storage_type const& storage() const BOOST_NOEXCEPT { return this->m_storage.value; }
storage() const770 BOOST_FORCEINLINE storage_type const volatile& storage() const volatile BOOST_NOEXCEPT { return this->m_storage.value; }
771
772 BOOST_DELETED_FUNCTION(atomic(atomic const&))
773 BOOST_DELETED_FUNCTION(atomic& operator= (atomic const&))
774 BOOST_DELETED_FUNCTION(atomic& operator= (atomic const&) volatile)
775 };
776
777 template< typename T >
778 BOOST_CONSTEXPR_OR_CONST bool atomic< T >::is_always_lock_free;
779
780 typedef atomic< char > atomic_char;
781 typedef atomic< unsigned char > atomic_uchar;
782 typedef atomic< signed char > atomic_schar;
783 typedef atomic< uint8_t > atomic_uint8_t;
784 typedef atomic< int8_t > atomic_int8_t;
785 typedef atomic< unsigned short > atomic_ushort;
786 typedef atomic< short > atomic_short;
787 typedef atomic< uint16_t > atomic_uint16_t;
788 typedef atomic< int16_t > atomic_int16_t;
789 typedef atomic< unsigned int > atomic_uint;
790 typedef atomic< int > atomic_int;
791 typedef atomic< uint32_t > atomic_uint32_t;
792 typedef atomic< int32_t > atomic_int32_t;
793 typedef atomic< unsigned long > atomic_ulong;
794 typedef atomic< long > atomic_long;
795 typedef atomic< uint64_t > atomic_uint64_t;
796 typedef atomic< int64_t > atomic_int64_t;
797 #ifdef BOOST_HAS_LONG_LONG
798 typedef atomic< boost::ulong_long_type > atomic_ullong;
799 typedef atomic< boost::long_long_type > atomic_llong;
800 #endif
801 typedef atomic< void* > atomic_address;
802 typedef atomic< bool > atomic_bool;
803 typedef atomic< wchar_t > atomic_wchar_t;
804 #if !defined(BOOST_NO_CXX11_CHAR16_T)
805 typedef atomic< char16_t > atomic_char16_t;
806 #endif
807 #if !defined(BOOST_NO_CXX11_CHAR32_T)
808 typedef atomic< char32_t > atomic_char32_t;
809 #endif
810
811 typedef atomic< int_least8_t > atomic_int_least8_t;
812 typedef atomic< uint_least8_t > atomic_uint_least8_t;
813 typedef atomic< int_least16_t > atomic_int_least16_t;
814 typedef atomic< uint_least16_t > atomic_uint_least16_t;
815 typedef atomic< int_least32_t > atomic_int_least32_t;
816 typedef atomic< uint_least32_t > atomic_uint_least32_t;
817 typedef atomic< int_least64_t > atomic_int_least64_t;
818 typedef atomic< uint_least64_t > atomic_uint_least64_t;
819 typedef atomic< int_fast8_t > atomic_int_fast8_t;
820 typedef atomic< uint_fast8_t > atomic_uint_fast8_t;
821 typedef atomic< int_fast16_t > atomic_int_fast16_t;
822 typedef atomic< uint_fast16_t > atomic_uint_fast16_t;
823 typedef atomic< int_fast32_t > atomic_int_fast32_t;
824 typedef atomic< uint_fast32_t > atomic_uint_fast32_t;
825 typedef atomic< int_fast64_t > atomic_int_fast64_t;
826 typedef atomic< uint_fast64_t > atomic_uint_fast64_t;
827 typedef atomic< intmax_t > atomic_intmax_t;
828 typedef atomic< uintmax_t > atomic_uintmax_t;
829
830 typedef atomic< std::size_t > atomic_size_t;
831 typedef atomic< std::ptrdiff_t > atomic_ptrdiff_t;
832
833 #if defined(BOOST_HAS_INTPTR_T)
834 typedef atomic< intptr_t > atomic_intptr_t;
835 typedef atomic< uintptr_t > atomic_uintptr_t;
836 #endif
837
838 } // namespace atomics
839 } // namespace boost
840
841 #if defined(BOOST_MSVC)
842 #pragma warning(pop)
843 #endif
844
845 #endif // BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_
846