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) 2015 Andrey Semashev
7  */
8 /*!
9  * \file   atomic/detail/extra_ops_generic.hpp
10  *
11  * This header contains generic implementation of the extra atomic operations.
12  */
13 
14 #ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_
15 #define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_
16 
17 #include <cstddef>
18 #include <boost/memory_order.hpp>
19 #include <boost/atomic/detail/config.hpp>
20 #include <boost/atomic/detail/storage_type.hpp>
21 #include <boost/atomic/detail/integral_extend.hpp>
22 #include <boost/atomic/detail/extra_operations_fwd.hpp>
23 #include <boost/atomic/capabilities.hpp>
24 
25 #ifdef BOOST_HAS_PRAGMA_ONCE
26 #pragma once
27 #endif
28 
29 #if defined(BOOST_MSVC)
30 #pragma warning(push)
31 // unary minus operator applied to unsigned type, result still unsigned
32 #pragma warning(disable: 4146)
33 #endif
34 
35 namespace boost {
36 namespace atomics {
37 namespace detail {
38 
39 //! Generic implementation of extra operations
40 template< typename Base, std::size_t Size, bool Signed, bool = Base::full_cas_based >
41 struct generic_extra_operations :
42     public Base
43 {
44     typedef Base base_type;
45     typedef typename base_type::storage_type storage_type;
46     typedef typename make_storage_type< Size >::type emulated_storage_type;
47 
fetch_negateboost::atomics::detail::generic_extra_operations48     static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
49     {
50         storage_type old_val;
51         atomics::detail::non_atomic_load(storage, old_val);
52         while (!base_type::compare_exchange_weak(storage, old_val, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)), order, memory_order_relaxed)) {}
53         return old_val;
54     }
55 
negateboost::atomics::detail::generic_extra_operations56     static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
57     {
58         storage_type old_val, new_val;
59         atomics::detail::non_atomic_load(storage, old_val);
60         do
61         {
62             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val));
63         }
64         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
65         return new_val;
66     }
67 
addboost::atomics::detail::generic_extra_operations68     static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
69     {
70         return base_type::fetch_add(storage, v, order) + v;
71     }
72 
subboost::atomics::detail::generic_extra_operations73     static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
74     {
75         return base_type::fetch_sub(storage, v, order) - v;
76     }
77 
bitwise_andboost::atomics::detail::generic_extra_operations78     static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
79     {
80         return base_type::fetch_and(storage, v, order) & v;
81     }
82 
bitwise_orboost::atomics::detail::generic_extra_operations83     static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
84     {
85         return base_type::fetch_or(storage, v, order) | v;
86     }
87 
bitwise_xorboost::atomics::detail::generic_extra_operations88     static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
89     {
90         return base_type::fetch_xor(storage, v, order) ^ v;
91     }
92 
fetch_complementboost::atomics::detail::generic_extra_operations93     static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
94     {
95         return base_type::fetch_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order);
96     }
97 
bitwise_complementboost::atomics::detail::generic_extra_operations98     static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
99     {
100         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u)));
101         return base_type::fetch_xor(storage, mask, order) ^ mask;
102     }
103 
opaque_addboost::atomics::detail::generic_extra_operations104     static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
105     {
106         base_type::fetch_add(storage, v, order);
107     }
108 
opaque_subboost::atomics::detail::generic_extra_operations109     static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
110     {
111         base_type::fetch_sub(storage, v, order);
112     }
113 
opaque_negateboost::atomics::detail::generic_extra_operations114     static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
115     {
116         fetch_negate(storage, order);
117     }
118 
opaque_andboost::atomics::detail::generic_extra_operations119     static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
120     {
121         base_type::fetch_and(storage, v, order);
122     }
123 
opaque_orboost::atomics::detail::generic_extra_operations124     static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
125     {
126         base_type::fetch_or(storage, v, order);
127     }
128 
opaque_xorboost::atomics::detail::generic_extra_operations129     static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
130     {
131         base_type::fetch_xor(storage, v, order);
132     }
133 
opaque_complementboost::atomics::detail::generic_extra_operations134     static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
135     {
136         fetch_complement(storage, order);
137     }
138 
add_and_testboost::atomics::detail::generic_extra_operations139     static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
140     {
141         return !!static_cast< emulated_storage_type >(add(storage, v, order));
142     }
143 
sub_and_testboost::atomics::detail::generic_extra_operations144     static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
145     {
146         return !!static_cast< emulated_storage_type >(sub(storage, v, order));
147     }
148 
negate_and_testboost::atomics::detail::generic_extra_operations149     static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
150     {
151         return !!negate(storage, order);
152     }
153 
and_and_testboost::atomics::detail::generic_extra_operations154     static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
155     {
156         return !!bitwise_and(storage, v, order);
157     }
158 
or_and_testboost::atomics::detail::generic_extra_operations159     static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
160     {
161         return !!bitwise_or(storage, v, order);
162     }
163 
xor_and_testboost::atomics::detail::generic_extra_operations164     static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
165     {
166         return !!bitwise_xor(storage, v, order);
167     }
168 
complement_and_testboost::atomics::detail::generic_extra_operations169     static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
170     {
171         return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order));
172     }
173 
bit_test_and_setboost::atomics::detail::generic_extra_operations174     static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
175     {
176         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
177         storage_type old_val = base_type::fetch_or(storage, mask, order);
178         return !!(old_val & mask);
179     }
180 
bit_test_and_resetboost::atomics::detail::generic_extra_operations181     static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
182     {
183         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
184         storage_type old_val = base_type::fetch_and(storage, ~mask, order);
185         return !!(old_val & mask);
186     }
187 
bit_test_and_complementboost::atomics::detail::generic_extra_operations188     static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
189     {
190         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
191         storage_type old_val = base_type::fetch_xor(storage, mask, order);
192         return !!(old_val & mask);
193     }
194 };
195 
196 //! Specialization for cases when the platform only natively supports CAS
197 template< typename Base, std::size_t Size, bool Signed >
198 struct generic_extra_operations< Base, Size, Signed, true > :
199     public Base
200 {
201     typedef Base base_type;
202     typedef typename base_type::storage_type storage_type;
203     typedef typename make_storage_type< Size >::type emulated_storage_type;
204 
fetch_negateboost::atomics::detail::generic_extra_operations205     static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
206     {
207         storage_type old_val;
208         atomics::detail::non_atomic_load(storage, old_val);
209         while (!base_type::compare_exchange_weak(storage, old_val, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)), order, memory_order_relaxed)) {}
210         return old_val;
211     }
212 
negateboost::atomics::detail::generic_extra_operations213     static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
214     {
215         storage_type old_val, new_val;
216         atomics::detail::non_atomic_load(storage, old_val);
217         do
218         {
219             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val));
220         }
221         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
222         return new_val;
223     }
224 
addboost::atomics::detail::generic_extra_operations225     static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
226     {
227         storage_type old_val, new_val;
228         atomics::detail::non_atomic_load(storage, old_val);
229         do
230         {
231             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val + v));
232         }
233         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
234         return new_val;
235     }
236 
subboost::atomics::detail::generic_extra_operations237     static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
238     {
239         storage_type old_val, new_val;
240         atomics::detail::non_atomic_load(storage, old_val);
241         do
242         {
243             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val - v));
244         }
245         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
246         return new_val;
247     }
248 
bitwise_andboost::atomics::detail::generic_extra_operations249     static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
250     {
251         storage_type old_val, new_val;
252         atomics::detail::non_atomic_load(storage, old_val);
253         do
254         {
255             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val & v));
256         }
257         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
258         return new_val;
259     }
260 
bitwise_orboost::atomics::detail::generic_extra_operations261     static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
262     {
263         storage_type old_val, new_val;
264         atomics::detail::non_atomic_load(storage, old_val);
265         do
266         {
267             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val | v));
268         }
269         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
270         return new_val;
271     }
272 
bitwise_xorboost::atomics::detail::generic_extra_operations273     static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
274     {
275         storage_type old_val, new_val;
276         atomics::detail::non_atomic_load(storage, old_val);
277         do
278         {
279             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val ^ v));
280         }
281         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
282         return new_val;
283     }
284 
fetch_complementboost::atomics::detail::generic_extra_operations285     static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
286     {
287         return base_type::fetch_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order);
288     }
289 
bitwise_complementboost::atomics::detail::generic_extra_operations290     static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
291     {
292         return bitwise_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order);
293     }
294 
opaque_addboost::atomics::detail::generic_extra_operations295     static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
296     {
297         base_type::fetch_add(storage, v, order);
298     }
299 
opaque_subboost::atomics::detail::generic_extra_operations300     static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
301     {
302         base_type::fetch_sub(storage, v, order);
303     }
304 
opaque_negateboost::atomics::detail::generic_extra_operations305     static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
306     {
307         fetch_negate(storage, order);
308     }
309 
opaque_andboost::atomics::detail::generic_extra_operations310     static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
311     {
312         base_type::fetch_and(storage, v, order);
313     }
314 
opaque_orboost::atomics::detail::generic_extra_operations315     static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
316     {
317         base_type::fetch_or(storage, v, order);
318     }
319 
opaque_xorboost::atomics::detail::generic_extra_operations320     static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
321     {
322         base_type::fetch_xor(storage, v, order);
323     }
324 
opaque_complementboost::atomics::detail::generic_extra_operations325     static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
326     {
327         fetch_complement(storage, order);
328     }
329 
add_and_testboost::atomics::detail::generic_extra_operations330     static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
331     {
332         return !!static_cast< emulated_storage_type >(add(storage, v, order));
333     }
334 
sub_and_testboost::atomics::detail::generic_extra_operations335     static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
336     {
337         return !!static_cast< emulated_storage_type >(sub(storage, v, order));
338     }
339 
negate_and_testboost::atomics::detail::generic_extra_operations340     static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
341     {
342         return !!negate(storage, order);
343     }
344 
and_and_testboost::atomics::detail::generic_extra_operations345     static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
346     {
347         return !!bitwise_and(storage, v, order);
348     }
349 
or_and_testboost::atomics::detail::generic_extra_operations350     static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
351     {
352         return !!bitwise_or(storage, v, order);
353     }
354 
xor_and_testboost::atomics::detail::generic_extra_operations355     static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
356     {
357         return !!bitwise_xor(storage, v, order);
358     }
359 
complement_and_testboost::atomics::detail::generic_extra_operations360     static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
361     {
362         return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order));
363     }
364 
bit_test_and_setboost::atomics::detail::generic_extra_operations365     static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
366     {
367         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
368         storage_type old_val = base_type::fetch_or(storage, mask, order);
369         return !!(old_val & mask);
370     }
371 
bit_test_and_resetboost::atomics::detail::generic_extra_operations372     static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
373     {
374         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
375         storage_type old_val = base_type::fetch_and(storage, ~mask, order);
376         return !!(old_val & mask);
377     }
378 
bit_test_and_complementboost::atomics::detail::generic_extra_operations379     static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
380     {
381         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
382         storage_type old_val = base_type::fetch_xor(storage, mask, order);
383         return !!(old_val & mask);
384     }
385 };
386 
387 // Default extra_operations template definition will be used unless specialized for a specific platform
388 template< typename Base, std::size_t Size, bool Signed >
389 struct extra_operations< Base, Size, Signed, true > :
390     public generic_extra_operations< Base, Size, Signed >
391 {
392 };
393 
394 } // namespace detail
395 } // namespace atomics
396 } // namespace boost
397 
398 #if defined(BOOST_MSVC)
399 #pragma warning(pop)
400 #endif
401 
402 #endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_
403