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