]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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) 2020 Andrey Semashev | |
7 | */ | |
8 | /*! | |
9 | * \file atomic/detail/atomic_ref_template.hpp | |
10 | * | |
11 | * This header contains interface definition of \c atomic_ref template. | |
12 | */ | |
13 | ||
14 | #ifndef BOOST_ATOMIC_DETAIL_ATOMIC_REF_TEMPLATE_HPP_INCLUDED_ | |
15 | #define BOOST_ATOMIC_DETAIL_ATOMIC_REF_TEMPLATE_HPP_INCLUDED_ | |
16 | ||
17 | #include <cstddef> | |
18 | #include <boost/cstdint.hpp> | |
19 | #include <boost/assert.hpp> | |
20 | #include <boost/static_assert.hpp> | |
21 | #include <boost/memory_order.hpp> | |
22 | #include <boost/atomic/detail/config.hpp> | |
23 | #include <boost/atomic/detail/intptr.hpp> | |
24 | #include <boost/atomic/detail/classify.hpp> | |
25 | #include <boost/atomic/detail/addressof.hpp> | |
26 | #include <boost/atomic/detail/storage_traits.hpp> | |
27 | #include <boost/atomic/detail/bitwise_cast.hpp> | |
28 | #include <boost/atomic/detail/integral_conversions.hpp> | |
29 | #include <boost/atomic/detail/operations.hpp> | |
30 | #include <boost/atomic/detail/extra_operations.hpp> | |
31 | #include <boost/atomic/detail/memory_order_utils.hpp> | |
32 | #include <boost/atomic/detail/type_traits/is_signed.hpp> | |
33 | #include <boost/atomic/detail/type_traits/is_trivially_copyable.hpp> | |
34 | #include <boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp> | |
35 | #include <boost/atomic/detail/type_traits/alignment_of.hpp> | |
36 | #include <boost/atomic/detail/type_traits/conditional.hpp> | |
37 | #include <boost/atomic/detail/type_traits/integral_constant.hpp> | |
38 | #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) | |
39 | #include <boost/atomic/detail/bitwise_fp_cast.hpp> | |
40 | #include <boost/atomic/detail/fp_operations.hpp> | |
41 | #include <boost/atomic/detail/extra_fp_operations.hpp> | |
42 | #endif | |
43 | ||
44 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
45 | #pragma once | |
46 | #endif | |
47 | ||
48 | #if defined(BOOST_MSVC) | |
49 | #pragma warning(push) | |
50 | // 'boost::atomics::atomic_ref<T>' : multiple assignment operators specified | |
51 | #pragma warning(disable: 4522) | |
52 | #endif | |
53 | ||
54 | /* | |
55 | * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, | |
56 | * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. | |
57 | */ | |
58 | ||
59 | namespace boost { | |
60 | namespace atomics { | |
61 | namespace detail { | |
62 | ||
63 | template< typename T, bool IsSigned > | |
64 | struct is_atomic_ref_lock_free | |
65 | { | |
66 | typedef T value_type; | |
67 | typedef atomics::detail::operations< sizeof(value_type), IsSigned > operations; | |
68 | typedef typename operations::storage_type storage_type; | |
69 | ||
70 | static BOOST_CONSTEXPR_OR_CONST bool value = sizeof(value_type) == sizeof(storage_type) && operations::is_always_lock_free; | |
71 | }; | |
72 | ||
73 | template< typename T, bool IsSigned > | |
74 | class base_atomic_ref_common | |
75 | { | |
76 | public: | |
77 | typedef T value_type; | |
78 | ||
79 | protected: | |
80 | typedef typename atomics::detail::conditional< | |
81 | atomics::detail::is_atomic_ref_lock_free< T, IsSigned >::value, | |
82 | atomics::detail::operations< sizeof(value_type), IsSigned >, | |
83 | atomics::detail::emulated_operations< sizeof(value_type), atomics::detail::alignment_of< value_type >::value, IsSigned > | |
84 | >::type operations; | |
85 | typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; | |
86 | typedef typename operations::storage_type storage_type; | |
87 | ||
88 | public: | |
89 | static BOOST_CONSTEXPR_OR_CONST std::size_t required_alignment = atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment ? operations::storage_alignment : atomics::detail::alignment_of< value_type >::value; | |
90 | static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = operations::is_always_lock_free; | |
91 | ||
92 | protected: | |
93 | value_type* m_value; | |
94 | ||
95 | public: | |
96 | BOOST_FORCEINLINE explicit base_atomic_ref_common(value_type& v) BOOST_NOEXCEPT : m_value(atomics::detail::addressof(v)) | |
97 | { | |
98 | } | |
99 | ||
100 | protected: | |
101 | BOOST_FORCEINLINE storage_type& storage() const BOOST_NOEXCEPT | |
102 | { | |
103 | return *reinterpret_cast< storage_type* >(m_value); | |
104 | } | |
105 | }; | |
106 | ||
107 | #if defined(BOOST_NO_CXX17_INLINE_VARIABLES) | |
108 | template< typename T, bool IsSigned > | |
109 | BOOST_CONSTEXPR_OR_CONST std::size_t base_atomic_ref_common< T, IsSigned >::required_alignment; | |
110 | template< typename T, bool IsSigned > | |
111 | BOOST_CONSTEXPR_OR_CONST bool base_atomic_ref_common< T, IsSigned >::is_always_lock_free; | |
112 | #endif | |
113 | ||
114 | ||
115 | template< typename T, typename Kind > | |
116 | class base_atomic_ref; | |
117 | ||
118 | //! General template. Implementation for user-defined types, such as structs and enums, and pointers to non-object types | |
119 | template< typename T > | |
120 | class base_atomic_ref< T, void > : | |
121 | public base_atomic_ref_common< T, false > | |
122 | { | |
123 | private: | |
124 | typedef base_atomic_ref_common< T, false > base_type; | |
125 | ||
126 | public: | |
127 | typedef typename base_type::value_type value_type; | |
128 | ||
129 | protected: | |
130 | typedef typename base_type::operations operations; | |
131 | typedef typename base_type::storage_type storage_type; | |
132 | typedef typename base_type::value_arg_type value_arg_type; | |
133 | ||
134 | private: | |
135 | typedef atomics::detail::integral_constant< bool, atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment > use_bitwise_cast; | |
136 | ||
137 | public: | |
138 | BOOST_DEFAULTED_FUNCTION(base_atomic_ref(base_atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) | |
139 | BOOST_FORCEINLINE explicit base_atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) | |
140 | { | |
141 | } | |
142 | ||
143 | BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
144 | { | |
145 | BOOST_ASSERT(order != memory_order_consume); | |
146 | BOOST_ASSERT(order != memory_order_acquire); | |
147 | BOOST_ASSERT(order != memory_order_acq_rel); | |
148 | ||
149 | operations::store(this->storage(), atomics::detail::bitwise_cast< storage_type >(v), order); | |
150 | } | |
151 | ||
152 | BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
153 | { | |
154 | BOOST_ASSERT(order != memory_order_release); | |
155 | BOOST_ASSERT(order != memory_order_acq_rel); | |
156 | ||
157 | return atomics::detail::bitwise_cast< value_type >(operations::load(this->storage(), order)); | |
158 | } | |
159 | ||
160 | BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
161 | { | |
162 | return atomics::detail::bitwise_cast< value_type >(operations::exchange(this->storage(), atomics::detail::bitwise_cast< storage_type >(v), order)); | |
163 | } | |
164 | ||
165 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) const BOOST_NOEXCEPT | |
166 | { | |
167 | BOOST_ASSERT(failure_order != memory_order_release); | |
168 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
169 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
170 | ||
171 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
172 | } | |
173 | ||
174 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
175 | { | |
176 | return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
177 | } | |
178 | ||
179 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) const BOOST_NOEXCEPT | |
180 | { | |
181 | BOOST_ASSERT(failure_order != memory_order_release); | |
182 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
183 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
184 | ||
185 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
186 | } | |
187 | ||
188 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
189 | { | |
190 | return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
191 | } | |
192 | ||
193 | BOOST_DELETED_FUNCTION(base_atomic_ref& operator=(base_atomic_ref const&)) | |
194 | ||
195 | private: | |
196 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
197 | { | |
198 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
199 | return operations::compare_exchange_strong(this->storage(), reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); | |
200 | #else | |
201 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
202 | #endif | |
203 | } | |
204 | ||
205 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
206 | { | |
207 | storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected); | |
208 | const bool res = operations::compare_exchange_strong(this->storage(), old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); | |
209 | expected = atomics::detail::bitwise_cast< value_type >(old_value); | |
210 | return res; | |
211 | } | |
212 | ||
213 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
214 | { | |
215 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
216 | return operations::compare_exchange_weak(this->storage(), reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); | |
217 | #else | |
218 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
219 | #endif | |
220 | } | |
221 | ||
222 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
223 | { | |
224 | storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected); | |
225 | const bool res = operations::compare_exchange_weak(this->storage(), old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); | |
226 | expected = atomics::detail::bitwise_cast< value_type >(old_value); | |
227 | return res; | |
228 | } | |
229 | }; | |
230 | ||
231 | ||
232 | //! Implementation for integers | |
233 | template< typename T > | |
234 | class base_atomic_ref< T, int > : | |
235 | public base_atomic_ref_common< T, atomics::detail::is_signed< T >::value > | |
236 | { | |
237 | private: | |
238 | typedef base_atomic_ref_common< T, atomics::detail::is_signed< T >::value > base_type; | |
239 | ||
240 | public: | |
241 | typedef typename base_type::value_type value_type; | |
242 | typedef typename base_type::value_type difference_type; | |
243 | ||
244 | protected: | |
245 | typedef typename base_type::operations operations; | |
246 | typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; | |
247 | typedef typename base_type::storage_type storage_type; | |
248 | typedef value_type value_arg_type; | |
249 | ||
250 | private: | |
251 | typedef atomics::detail::integral_constant< bool, atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment > use_bitwise_cast; | |
252 | ||
253 | public: | |
254 | BOOST_DEFAULTED_FUNCTION(base_atomic_ref(base_atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) | |
255 | BOOST_FORCEINLINE explicit base_atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) | |
256 | { | |
257 | } | |
258 | ||
259 | // Standard methods | |
260 | BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
261 | { | |
262 | BOOST_ASSERT(order != memory_order_consume); | |
263 | BOOST_ASSERT(order != memory_order_acquire); | |
264 | BOOST_ASSERT(order != memory_order_acq_rel); | |
265 | ||
266 | operations::store(this->storage(), static_cast< storage_type >(v), order); | |
267 | } | |
268 | ||
269 | BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
270 | { | |
271 | BOOST_ASSERT(order != memory_order_release); | |
272 | BOOST_ASSERT(order != memory_order_acq_rel); | |
273 | ||
274 | return atomics::detail::integral_truncate< value_type >(operations::load(this->storage(), order)); | |
275 | } | |
276 | ||
277 | BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
278 | { | |
279 | return atomics::detail::integral_truncate< value_type >(operations::fetch_add(this->storage(), static_cast< storage_type >(v), order)); | |
280 | } | |
281 | ||
282 | BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
283 | { | |
284 | return atomics::detail::integral_truncate< value_type >(operations::fetch_sub(this->storage(), static_cast< storage_type >(v), order)); | |
285 | } | |
286 | ||
287 | BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
288 | { | |
289 | return atomics::detail::integral_truncate< value_type >(operations::exchange(this->storage(), static_cast< storage_type >(v), order)); | |
290 | } | |
291 | ||
292 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
293 | { | |
294 | BOOST_ASSERT(failure_order != memory_order_release); | |
295 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
296 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
297 | ||
298 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
299 | } | |
300 | ||
301 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
302 | { | |
303 | return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
304 | } | |
305 | ||
306 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
307 | { | |
308 | BOOST_ASSERT(failure_order != memory_order_release); | |
309 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
310 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
311 | ||
312 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
313 | } | |
314 | ||
315 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
316 | { | |
317 | return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
318 | } | |
319 | ||
320 | BOOST_FORCEINLINE value_type fetch_and(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
321 | { | |
322 | return atomics::detail::integral_truncate< value_type >(operations::fetch_and(this->storage(), static_cast< storage_type >(v), order)); | |
323 | } | |
324 | ||
325 | BOOST_FORCEINLINE value_type fetch_or(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
326 | { | |
327 | return atomics::detail::integral_truncate< value_type >(operations::fetch_or(this->storage(), static_cast< storage_type >(v), order)); | |
328 | } | |
329 | ||
330 | BOOST_FORCEINLINE value_type fetch_xor(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
331 | { | |
332 | return atomics::detail::integral_truncate< value_type >(operations::fetch_xor(this->storage(), static_cast< storage_type >(v), order)); | |
333 | } | |
334 | ||
335 | // Boost.Atomic extensions | |
336 | BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
337 | { | |
338 | return atomics::detail::integral_truncate< value_type >(extra_operations::fetch_negate(this->storage(), order)); | |
339 | } | |
340 | ||
341 | BOOST_FORCEINLINE value_type fetch_complement(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
342 | { | |
343 | return atomics::detail::integral_truncate< value_type >(extra_operations::fetch_complement(this->storage(), order)); | |
344 | } | |
345 | ||
346 | BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
347 | { | |
348 | return atomics::detail::integral_truncate< value_type >(extra_operations::add(this->storage(), static_cast< storage_type >(v), order)); | |
349 | } | |
350 | ||
351 | BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
352 | { | |
353 | return atomics::detail::integral_truncate< value_type >(extra_operations::sub(this->storage(), static_cast< storage_type >(v), order)); | |
354 | } | |
355 | ||
356 | BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
357 | { | |
358 | return atomics::detail::integral_truncate< value_type >(extra_operations::negate(this->storage(), order)); | |
359 | } | |
360 | ||
361 | BOOST_FORCEINLINE value_type bitwise_and(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
362 | { | |
363 | return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_and(this->storage(), static_cast< storage_type >(v), order)); | |
364 | } | |
365 | ||
366 | BOOST_FORCEINLINE value_type bitwise_or(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
367 | { | |
368 | return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_or(this->storage(), static_cast< storage_type >(v), order)); | |
369 | } | |
370 | ||
371 | BOOST_FORCEINLINE value_type bitwise_xor(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
372 | { | |
373 | return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_xor(this->storage(), static_cast< storage_type >(v), order)); | |
374 | } | |
375 | ||
376 | BOOST_FORCEINLINE value_type bitwise_complement(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
377 | { | |
378 | return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_complement(this->storage(), order)); | |
379 | } | |
380 | ||
381 | BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
382 | { | |
383 | extra_operations::opaque_add(this->storage(), static_cast< storage_type >(v), order); | |
384 | } | |
385 | ||
386 | BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
387 | { | |
388 | extra_operations::opaque_sub(this->storage(), static_cast< storage_type >(v), order); | |
389 | } | |
390 | ||
391 | BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
392 | { | |
393 | extra_operations::opaque_negate(this->storage(), order); | |
394 | } | |
395 | ||
396 | BOOST_FORCEINLINE void opaque_and(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
397 | { | |
398 | extra_operations::opaque_and(this->storage(), static_cast< storage_type >(v), order); | |
399 | } | |
400 | ||
401 | BOOST_FORCEINLINE void opaque_or(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
402 | { | |
403 | extra_operations::opaque_or(this->storage(), static_cast< storage_type >(v), order); | |
404 | } | |
405 | ||
406 | BOOST_FORCEINLINE void opaque_xor(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
407 | { | |
408 | extra_operations::opaque_xor(this->storage(), static_cast< storage_type >(v), order); | |
409 | } | |
410 | ||
411 | BOOST_FORCEINLINE void opaque_complement(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
412 | { | |
413 | extra_operations::opaque_complement(this->storage(), order); | |
414 | } | |
415 | ||
416 | BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
417 | { | |
418 | return extra_operations::add_and_test(this->storage(), static_cast< storage_type >(v), order); | |
419 | } | |
420 | ||
421 | BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
422 | { | |
423 | return extra_operations::sub_and_test(this->storage(), static_cast< storage_type >(v), order); | |
424 | } | |
425 | ||
426 | BOOST_FORCEINLINE bool negate_and_test(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
427 | { | |
428 | return extra_operations::negate_and_test(this->storage(), order); | |
429 | } | |
430 | ||
431 | BOOST_FORCEINLINE bool and_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
432 | { | |
433 | return extra_operations::and_and_test(this->storage(), static_cast< storage_type >(v), order); | |
434 | } | |
435 | ||
436 | BOOST_FORCEINLINE bool or_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
437 | { | |
438 | return extra_operations::or_and_test(this->storage(), static_cast< storage_type >(v), order); | |
439 | } | |
440 | ||
441 | BOOST_FORCEINLINE bool xor_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
442 | { | |
443 | return extra_operations::xor_and_test(this->storage(), static_cast< storage_type >(v), order); | |
444 | } | |
445 | ||
446 | BOOST_FORCEINLINE bool complement_and_test(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
447 | { | |
448 | return extra_operations::complement_and_test(this->storage(), order); | |
449 | } | |
450 | ||
451 | BOOST_FORCEINLINE bool bit_test_and_set(unsigned int bit_number, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
452 | { | |
453 | BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); | |
454 | return extra_operations::bit_test_and_set(this->storage(), bit_number, order); | |
455 | } | |
456 | ||
457 | BOOST_FORCEINLINE bool bit_test_and_reset(unsigned int bit_number, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
458 | { | |
459 | BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); | |
460 | return extra_operations::bit_test_and_reset(this->storage(), bit_number, order); | |
461 | } | |
462 | ||
463 | BOOST_FORCEINLINE bool bit_test_and_complement(unsigned int bit_number, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
464 | { | |
465 | BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); | |
466 | return extra_operations::bit_test_and_complement(this->storage(), bit_number, order); | |
467 | } | |
468 | ||
469 | // Operators | |
470 | BOOST_FORCEINLINE value_type operator++(int) BOOST_NOEXCEPT | |
471 | { | |
472 | return fetch_add(1); | |
473 | } | |
474 | ||
475 | BOOST_FORCEINLINE value_type operator++() BOOST_NOEXCEPT | |
476 | { | |
477 | return add(1); | |
478 | } | |
479 | ||
480 | BOOST_FORCEINLINE value_type operator--(int) BOOST_NOEXCEPT | |
481 | { | |
482 | return fetch_sub(1); | |
483 | } | |
484 | ||
485 | BOOST_FORCEINLINE value_type operator--() BOOST_NOEXCEPT | |
486 | { | |
487 | return sub(1); | |
488 | } | |
489 | ||
490 | BOOST_FORCEINLINE value_type operator+=(difference_type v) BOOST_NOEXCEPT | |
491 | { | |
492 | return add(v); | |
493 | } | |
494 | ||
495 | BOOST_FORCEINLINE value_type operator-=(difference_type v) BOOST_NOEXCEPT | |
496 | { | |
497 | return sub(v); | |
498 | } | |
499 | ||
500 | BOOST_FORCEINLINE value_type operator&=(value_type v) BOOST_NOEXCEPT | |
501 | { | |
502 | return bitwise_and(v); | |
503 | } | |
504 | ||
505 | BOOST_FORCEINLINE value_type operator|=(value_type v) BOOST_NOEXCEPT | |
506 | { | |
507 | return bitwise_or(v); | |
508 | } | |
509 | ||
510 | BOOST_FORCEINLINE value_type operator^=(value_type v) BOOST_NOEXCEPT | |
511 | { | |
512 | return bitwise_xor(v); | |
513 | } | |
514 | ||
515 | BOOST_DELETED_FUNCTION(base_atomic_ref& operator=(base_atomic_ref const&)) | |
516 | ||
517 | private: | |
518 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
519 | { | |
520 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
521 | return operations::compare_exchange_strong(this->storage(), reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); | |
522 | #else | |
523 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
524 | #endif | |
525 | } | |
526 | ||
527 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
528 | { | |
529 | storage_type old_value = static_cast< storage_type >(expected); | |
530 | const bool res = operations::compare_exchange_strong(this->storage(), old_value, static_cast< storage_type >(desired), success_order, failure_order); | |
531 | expected = atomics::detail::integral_truncate< value_type >(old_value); | |
532 | return res; | |
533 | } | |
534 | ||
535 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
536 | { | |
537 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
538 | return operations::compare_exchange_weak(this->storage(), reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); | |
539 | #else | |
540 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
541 | #endif | |
542 | } | |
543 | ||
544 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
545 | { | |
546 | storage_type old_value = static_cast< storage_type >(expected); | |
547 | const bool res = operations::compare_exchange_weak(this->storage(), old_value, static_cast< storage_type >(desired), success_order, failure_order); | |
548 | expected = atomics::detail::integral_truncate< value_type >(old_value); | |
549 | return res; | |
550 | } | |
551 | }; | |
552 | ||
553 | //! Implementation for bool | |
554 | template< > | |
555 | class base_atomic_ref< bool, int > : | |
556 | public base_atomic_ref_common< bool, false > | |
557 | { | |
558 | private: | |
559 | typedef base_atomic_ref_common< bool, false > base_type; | |
560 | ||
561 | public: | |
562 | typedef bool value_type; | |
563 | ||
564 | protected: | |
565 | typedef base_type::operations operations; | |
566 | typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; | |
567 | typedef base_type::storage_type storage_type; | |
568 | typedef value_type value_arg_type; | |
569 | ||
570 | private: | |
571 | typedef atomics::detail::integral_constant< bool, atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment > use_bitwise_cast; | |
572 | ||
573 | public: | |
574 | BOOST_DEFAULTED_FUNCTION(base_atomic_ref(base_atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) | |
575 | BOOST_FORCEINLINE explicit base_atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) | |
576 | { | |
577 | } | |
578 | ||
579 | // Standard methods | |
580 | BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
581 | { | |
582 | BOOST_ASSERT(order != memory_order_consume); | |
583 | BOOST_ASSERT(order != memory_order_acquire); | |
584 | BOOST_ASSERT(order != memory_order_acq_rel); | |
585 | ||
586 | operations::store(this->storage(), static_cast< storage_type >(v), order); | |
587 | } | |
588 | ||
589 | BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
590 | { | |
591 | BOOST_ASSERT(order != memory_order_release); | |
592 | BOOST_ASSERT(order != memory_order_acq_rel); | |
593 | ||
594 | return !!operations::load(this->storage(), order); | |
595 | } | |
596 | ||
597 | BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
598 | { | |
599 | return !!operations::exchange(this->storage(), static_cast< storage_type >(v), order); | |
600 | } | |
601 | ||
602 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
603 | { | |
604 | BOOST_ASSERT(failure_order != memory_order_release); | |
605 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
606 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
607 | ||
608 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
609 | } | |
610 | ||
611 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
612 | { | |
613 | return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
614 | } | |
615 | ||
616 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
617 | { | |
618 | BOOST_ASSERT(failure_order != memory_order_release); | |
619 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
620 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
621 | ||
622 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
623 | } | |
624 | ||
625 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
626 | { | |
627 | return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
628 | } | |
629 | ||
630 | BOOST_DELETED_FUNCTION(base_atomic_ref& operator=(base_atomic_ref const&)) | |
631 | ||
632 | private: | |
633 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
634 | { | |
635 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
636 | return operations::compare_exchange_strong(this->storage(), reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); | |
637 | #else | |
638 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
639 | #endif | |
640 | } | |
641 | ||
642 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
643 | { | |
644 | storage_type old_value = static_cast< storage_type >(expected); | |
645 | const bool res = operations::compare_exchange_strong(this->storage(), old_value, static_cast< storage_type >(desired), success_order, failure_order); | |
646 | expected = !!old_value; | |
647 | return res; | |
648 | } | |
649 | ||
650 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
651 | { | |
652 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
653 | return operations::compare_exchange_weak(this->storage(), reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); | |
654 | #else | |
655 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
656 | #endif | |
657 | } | |
658 | ||
659 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
660 | { | |
661 | storage_type old_value = static_cast< storage_type >(expected); | |
662 | const bool res = operations::compare_exchange_weak(this->storage(), old_value, static_cast< storage_type >(desired), success_order, failure_order); | |
663 | expected = !!old_value; | |
664 | return res; | |
665 | } | |
666 | }; | |
667 | ||
668 | ||
669 | #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) | |
670 | ||
671 | //! Implementation for floating point types | |
672 | template< typename T > | |
673 | class base_atomic_ref< T, float > : | |
674 | public base_atomic_ref_common< T, false > | |
675 | { | |
676 | private: | |
677 | typedef base_atomic_ref_common< T, false > base_type; | |
678 | ||
679 | public: | |
680 | typedef typename base_type::value_type value_type; | |
681 | typedef typename base_type::value_type difference_type; | |
682 | ||
683 | protected: | |
684 | typedef typename base_type::operations operations; | |
685 | typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; | |
686 | typedef atomics::detail::fp_operations< extra_operations, value_type, operations::storage_size > fp_operations; | |
687 | typedef atomics::detail::extra_fp_operations< fp_operations, value_type, operations::storage_size > extra_fp_operations; | |
688 | typedef typename base_type::storage_type storage_type; | |
689 | typedef value_type value_arg_type; | |
690 | ||
691 | private: | |
692 | typedef atomics::detail::integral_constant< bool, atomics::detail::value_sizeof< value_type >::value != sizeof(storage_type) > has_padding_bits; | |
693 | typedef atomics::detail::integral_constant< bool, has_padding_bits::value || atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment > use_bitwise_cast; | |
694 | ||
695 | public: | |
696 | BOOST_DEFAULTED_FUNCTION(base_atomic_ref(base_atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) | |
697 | BOOST_FORCEINLINE explicit base_atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) | |
698 | { | |
699 | this->clear_padding_bits(has_padding_bits()); | |
700 | } | |
701 | ||
702 | BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
703 | { | |
704 | BOOST_ASSERT(order != memory_order_consume); | |
705 | BOOST_ASSERT(order != memory_order_acquire); | |
706 | BOOST_ASSERT(order != memory_order_acq_rel); | |
707 | ||
708 | operations::store(this->storage(), atomics::detail::bitwise_fp_cast< storage_type >(v), order); | |
709 | } | |
710 | ||
711 | BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
712 | { | |
713 | BOOST_ASSERT(order != memory_order_release); | |
714 | BOOST_ASSERT(order != memory_order_acq_rel); | |
715 | ||
716 | return atomics::detail::bitwise_fp_cast< value_type >(operations::load(this->storage(), order)); | |
717 | } | |
718 | ||
719 | BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
720 | { | |
721 | return fp_operations::fetch_add(this->storage(), v, order); | |
722 | } | |
723 | ||
724 | BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
725 | { | |
726 | return fp_operations::fetch_sub(this->storage(), v, order); | |
727 | } | |
728 | ||
729 | BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
730 | { | |
731 | return atomics::detail::bitwise_fp_cast< value_type >(operations::exchange(this->storage(), atomics::detail::bitwise_fp_cast< storage_type >(v), order)); | |
732 | } | |
733 | ||
734 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
735 | { | |
736 | BOOST_ASSERT(failure_order != memory_order_release); | |
737 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
738 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
739 | ||
740 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
741 | } | |
742 | ||
743 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
744 | { | |
745 | return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
746 | } | |
747 | ||
748 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
749 | { | |
750 | BOOST_ASSERT(failure_order != memory_order_release); | |
751 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
752 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
753 | ||
754 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
755 | } | |
756 | ||
757 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
758 | { | |
759 | return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
760 | } | |
761 | ||
762 | // Boost.Atomic extensions | |
763 | BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
764 | { | |
765 | return extra_fp_operations::fetch_negate(this->storage(), order); | |
766 | } | |
767 | ||
768 | BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
769 | { | |
770 | return extra_fp_operations::add(this->storage(), v, order); | |
771 | } | |
772 | ||
773 | BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
774 | { | |
775 | return extra_fp_operations::sub(this->storage(), v, order); | |
776 | } | |
777 | ||
778 | BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
779 | { | |
780 | return extra_fp_operations::negate(this->storage(), order); | |
781 | } | |
782 | ||
783 | BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
784 | { | |
785 | extra_fp_operations::opaque_add(this->storage(), v, order); | |
786 | } | |
787 | ||
788 | BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
789 | { | |
790 | extra_fp_operations::opaque_sub(this->storage(), v, order); | |
791 | } | |
792 | ||
793 | BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
794 | { | |
795 | extra_fp_operations::opaque_negate(this->storage(), order); | |
796 | } | |
797 | ||
798 | // Operators | |
799 | BOOST_FORCEINLINE value_type operator+=(difference_type v) BOOST_NOEXCEPT | |
800 | { | |
801 | return add(v); | |
802 | } | |
803 | ||
804 | BOOST_FORCEINLINE value_type operator-=(difference_type v) BOOST_NOEXCEPT | |
805 | { | |
806 | return sub(v); | |
807 | } | |
808 | ||
809 | BOOST_DELETED_FUNCTION(base_atomic_ref& operator=(base_atomic_ref const&)) | |
810 | ||
811 | private: | |
812 | BOOST_FORCEINLINE void clear_padding_bits(atomics::detail::false_type) const BOOST_NOEXCEPT | |
813 | { | |
814 | } | |
815 | ||
816 | BOOST_FORCEINLINE void clear_padding_bits(atomics::detail::true_type) const BOOST_NOEXCEPT | |
817 | { | |
818 | storage_type old_value = operations::load(this->storage(), boost::memory_order_relaxed); | |
819 | while (true) | |
820 | { | |
821 | storage_type new_value = old_value; | |
822 | atomics::detail::clear_tail_padding_bits< atomics::detail::value_sizeof< value_type >::value >(new_value); | |
823 | bool res = operations::compare_exchange_weak(this->storage(), old_value, new_value, boost::memory_order_relaxed, boost::memory_order_relaxed); | |
824 | if (BOOST_LIKELY(res)) | |
825 | break; | |
826 | } | |
827 | } | |
828 | ||
829 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
830 | { | |
831 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
832 | return operations::compare_exchange_strong(this->storage(), reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); | |
833 | #else | |
834 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
835 | #endif | |
836 | } | |
837 | ||
838 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
839 | { | |
840 | storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected); | |
841 | const bool res = operations::compare_exchange_strong(this->storage(), old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); | |
842 | expected = atomics::detail::bitwise_fp_cast< value_type >(old_value); | |
843 | return res; | |
844 | } | |
845 | ||
846 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
847 | { | |
848 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
849 | return operations::compare_exchange_weak(this->storage(), reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); | |
850 | #else | |
851 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
852 | #endif | |
853 | } | |
854 | ||
855 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
856 | { | |
857 | storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected); | |
858 | const bool res = operations::compare_exchange_weak(this->storage(), old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); | |
859 | expected = atomics::detail::bitwise_fp_cast< value_type >(old_value); | |
860 | return res; | |
861 | } | |
862 | }; | |
863 | ||
864 | #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT) | |
865 | ||
866 | ||
867 | //! Implementation for pointers to object types | |
868 | template< typename T > | |
869 | class base_atomic_ref< T*, void* > : | |
870 | public base_atomic_ref_common< T*, false > | |
871 | { | |
872 | private: | |
873 | typedef base_atomic_ref_common< T*, false > base_type; | |
874 | ||
875 | public: | |
876 | typedef typename base_type::value_type value_type; | |
877 | typedef std::ptrdiff_t difference_type; | |
878 | ||
879 | protected: | |
880 | typedef typename base_type::operations operations; | |
881 | typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; | |
882 | typedef typename base_type::storage_type storage_type; | |
883 | typedef value_type value_arg_type; | |
884 | ||
885 | private: | |
886 | typedef atomics::detail::integral_constant< bool, atomics::detail::alignment_of< value_type >::value <= operations::storage_alignment > use_bitwise_cast; | |
887 | ||
888 | // uintptr_storage_type is the minimal storage type that is enough to store pointers. The actual storage_type theoretically may be larger, | |
889 | // if the target architecture only supports atomic ops on larger data. Typically, though, they are the same type. | |
890 | typedef atomics::detail::uintptr_t uintptr_storage_type; | |
891 | ||
892 | public: | |
893 | BOOST_DEFAULTED_FUNCTION(base_atomic_ref(base_atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) | |
894 | BOOST_FORCEINLINE explicit base_atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) | |
895 | { | |
896 | } | |
897 | ||
898 | // Standard methods | |
899 | BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
900 | { | |
901 | BOOST_ASSERT(order != memory_order_consume); | |
902 | BOOST_ASSERT(order != memory_order_acquire); | |
903 | BOOST_ASSERT(order != memory_order_acq_rel); | |
904 | ||
905 | operations::store(this->storage(), atomics::detail::bitwise_cast< uintptr_storage_type >(v), order); | |
906 | } | |
907 | ||
908 | BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const BOOST_NOEXCEPT | |
909 | { | |
910 | BOOST_ASSERT(order != memory_order_release); | |
911 | BOOST_ASSERT(order != memory_order_acq_rel); | |
912 | ||
913 | return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::load(this->storage(), order))); | |
914 | } | |
915 | ||
916 | BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
917 | { | |
918 | return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::fetch_add(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order))); | |
919 | } | |
920 | ||
921 | BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
922 | { | |
923 | return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::fetch_sub(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order))); | |
924 | } | |
925 | ||
926 | BOOST_FORCEINLINE value_type exchange(value_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
927 | { | |
928 | return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::exchange(this->storage(), atomics::detail::bitwise_cast< uintptr_storage_type >(v), order))); | |
929 | } | |
930 | ||
931 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
932 | { | |
933 | BOOST_ASSERT(failure_order != memory_order_release); | |
934 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
935 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
936 | ||
937 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
938 | } | |
939 | ||
940 | BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
941 | { | |
942 | return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
943 | } | |
944 | ||
945 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
946 | { | |
947 | BOOST_ASSERT(failure_order != memory_order_release); | |
948 | BOOST_ASSERT(failure_order != memory_order_acq_rel); | |
949 | BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); | |
950 | ||
951 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, use_bitwise_cast()); | |
952 | } | |
953 | ||
954 | BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
955 | { | |
956 | return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); | |
957 | } | |
958 | ||
959 | // Boost.Atomic extensions | |
960 | BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
961 | { | |
962 | return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(extra_operations::add(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order))); | |
963 | } | |
964 | ||
965 | BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
966 | { | |
967 | return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(extra_operations::sub(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order))); | |
968 | } | |
969 | ||
970 | BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
971 | { | |
972 | extra_operations::opaque_add(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order); | |
973 | } | |
974 | ||
975 | BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
976 | { | |
977 | extra_operations::opaque_sub(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order); | |
978 | } | |
979 | ||
980 | BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
981 | { | |
982 | return extra_operations::add_and_test(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order); | |
983 | } | |
984 | ||
985 | BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) BOOST_NOEXCEPT | |
986 | { | |
987 | return extra_operations::sub_and_test(this->storage(), static_cast< uintptr_storage_type >(v * sizeof(T)), order); | |
988 | } | |
989 | ||
990 | // Operators | |
991 | BOOST_FORCEINLINE value_type operator++(int) BOOST_NOEXCEPT | |
992 | { | |
993 | return fetch_add(1); | |
994 | } | |
995 | ||
996 | BOOST_FORCEINLINE value_type operator++() BOOST_NOEXCEPT | |
997 | { | |
998 | return add(1); | |
999 | } | |
1000 | ||
1001 | BOOST_FORCEINLINE value_type operator--(int) BOOST_NOEXCEPT | |
1002 | { | |
1003 | return fetch_sub(1); | |
1004 | } | |
1005 | ||
1006 | BOOST_FORCEINLINE value_type operator--() BOOST_NOEXCEPT | |
1007 | { | |
1008 | return sub(1); | |
1009 | } | |
1010 | ||
1011 | BOOST_FORCEINLINE value_type operator+=(difference_type v) BOOST_NOEXCEPT | |
1012 | { | |
1013 | return add(v); | |
1014 | } | |
1015 | ||
1016 | BOOST_FORCEINLINE value_type operator-=(difference_type v) BOOST_NOEXCEPT | |
1017 | { | |
1018 | return sub(v); | |
1019 | } | |
1020 | ||
1021 | BOOST_DELETED_FUNCTION(base_atomic_ref& operator=(base_atomic_ref const&)) | |
1022 | ||
1023 | private: | |
1024 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
1025 | { | |
1026 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
1027 | return operations::compare_exchange_strong(this->storage(), reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); | |
1028 | #else | |
1029 | return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
1030 | #endif | |
1031 | } | |
1032 | ||
1033 | BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
1034 | { | |
1035 | storage_type old_value = atomics::detail::bitwise_cast< uintptr_storage_type >(expected); | |
1036 | const bool res = operations::compare_exchange_strong(this->storage(), old_value, atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); | |
1037 | expected = atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(old_value)); | |
1038 | return res; | |
1039 | } | |
1040 | ||
1041 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) const BOOST_NOEXCEPT | |
1042 | { | |
1043 | #if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) | |
1044 | return operations::compare_exchange_weak(this->storage(), reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); | |
1045 | #else | |
1046 | return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::true_type()); | |
1047 | #endif | |
1048 | } | |
1049 | ||
1050 | BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) const BOOST_NOEXCEPT | |
1051 | { | |
1052 | storage_type old_value = atomics::detail::bitwise_cast< uintptr_storage_type >(expected); | |
1053 | const bool res = operations::compare_exchange_weak(this->storage(), old_value, atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); | |
1054 | expected = atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(old_value)); | |
1055 | return res; | |
1056 | } | |
1057 | }; | |
1058 | ||
1059 | } // namespace detail | |
1060 | ||
1061 | template< typename T > | |
1062 | class atomic_ref : | |
1063 | public atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type > | |
1064 | { | |
1065 | private: | |
1066 | typedef atomics::detail::base_atomic_ref< T, typename atomics::detail::classify< T >::type > base_type; | |
1067 | typedef typename base_type::value_arg_type value_arg_type; | |
1068 | ||
1069 | public: | |
1070 | typedef typename base_type::value_type value_type; | |
1071 | ||
1072 | BOOST_STATIC_ASSERT_MSG(sizeof(value_type) > 0u, "boost::atomic_ref<T> requires T to be a complete type"); | |
1073 | #if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_IS_TRIVIALLY_COPYABLE) | |
1074 | BOOST_STATIC_ASSERT_MSG(atomics::detail::is_trivially_copyable< value_type >::value, "boost::atomic_ref<T> requires T to be a trivially copyable type"); | |
1075 | #endif | |
1076 | ||
1077 | private: | |
1078 | typedef typename base_type::storage_type storage_type; | |
1079 | ||
1080 | public: | |
1081 | BOOST_DEFAULTED_FUNCTION(atomic_ref(atomic_ref const& that) BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL : base_type(static_cast< base_type const& >(that)) {}) | |
1082 | BOOST_FORCEINLINE explicit atomic_ref(value_type& v) BOOST_NOEXCEPT : base_type(v) | |
1083 | { | |
1084 | // Check that referenced object alignment satisfies required alignment | |
1085 | BOOST_ASSERT((((atomics::detail::uintptr_t)this->m_value) & (base_type::required_alignment - 1u)) == 0u); | |
1086 | } | |
1087 | ||
1088 | BOOST_FORCEINLINE value_type operator= (value_arg_type v) BOOST_NOEXCEPT | |
1089 | { | |
1090 | this->store(v); | |
1091 | return v; | |
1092 | } | |
1093 | ||
1094 | BOOST_FORCEINLINE operator value_type() const BOOST_NOEXCEPT | |
1095 | { | |
1096 | return this->load(); | |
1097 | } | |
1098 | ||
1099 | BOOST_FORCEINLINE bool is_lock_free() const BOOST_NOEXCEPT | |
1100 | { | |
1101 | // C++20 specifies that is_lock_free returns true if operations on *all* objects of the atomic_ref<T> type are lock-free. | |
1102 | // This does not allow to return true or false depending on the referenced object runtime alignment. Currently, Boost.Atomic | |
1103 | // follows this specification, although we may support runtime alignment checking in the future. | |
1104 | return base_type::is_always_lock_free; | |
1105 | } | |
1106 | ||
1107 | BOOST_FORCEINLINE value_type& value() const BOOST_NOEXCEPT { return *this->m_value; } | |
1108 | ||
1109 | BOOST_DELETED_FUNCTION(atomic_ref& operator= (atomic_ref const&)) | |
1110 | }; | |
1111 | ||
1112 | } // namespace atomics | |
1113 | } // namespace boost | |
1114 | ||
1115 | #if defined(BOOST_MSVC) | |
1116 | #pragma warning(pop) | |
1117 | #endif | |
1118 | ||
1119 | #endif // BOOST_ATOMIC_DETAIL_ATOMIC_REF_TEMPLATE_HPP_INCLUDED_ |