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_traits.hpp>
21 #include <boost/atomic/detail/integral_conversions.hpp>
22 #include <boost/atomic/detail/extra_operations_fwd.hpp>
23 #include <boost/atomic/detail/header.hpp>
24 
25 #ifdef BOOST_HAS_PRAGMA_ONCE
26 #pragma once
27 #endif
28 
29 namespace boost {
30 namespace atomics {
31 namespace detail {
32 
33 //! Generic implementation of extra operations
34 template< typename Base, std::size_t Size, bool Signed, bool = Base::full_cas_based >
35 struct extra_operations_generic :
36     public Base
37 {
38     typedef Base base_type;
39     typedef typename base_type::storage_type storage_type;
40     typedef typename storage_traits< Size >::type emulated_storage_type;
41 
fetch_negateboost::atomics::detail::extra_operations_generic42     static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
43     {
44         storage_type old_val;
45         atomics::detail::non_atomic_load(storage, old_val);
46         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)) {}
47         return old_val;
48     }
49 
negateboost::atomics::detail::extra_operations_generic50     static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
51     {
52         storage_type old_val, new_val;
53         atomics::detail::non_atomic_load(storage, old_val);
54         do
55         {
56             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val));
57         }
58         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
59         return new_val;
60     }
61 
addboost::atomics::detail::extra_operations_generic62     static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
63     {
64         return base_type::fetch_add(storage, v, order) + v;
65     }
66 
subboost::atomics::detail::extra_operations_generic67     static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
68     {
69         return base_type::fetch_sub(storage, v, order) - v;
70     }
71 
bitwise_andboost::atomics::detail::extra_operations_generic72     static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
73     {
74         return base_type::fetch_and(storage, v, order) & v;
75     }
76 
bitwise_orboost::atomics::detail::extra_operations_generic77     static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
78     {
79         return base_type::fetch_or(storage, v, order) | v;
80     }
81 
bitwise_xorboost::atomics::detail::extra_operations_generic82     static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
83     {
84         return base_type::fetch_xor(storage, v, order) ^ v;
85     }
86 
fetch_complementboost::atomics::detail::extra_operations_generic87     static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
88     {
89         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);
90     }
91 
bitwise_complementboost::atomics::detail::extra_operations_generic92     static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
93     {
94         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u)));
95         return base_type::fetch_xor(storage, mask, order) ^ mask;
96     }
97 
opaque_addboost::atomics::detail::extra_operations_generic98     static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
99     {
100         base_type::fetch_add(storage, v, order);
101     }
102 
opaque_subboost::atomics::detail::extra_operations_generic103     static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
104     {
105         base_type::fetch_sub(storage, v, order);
106     }
107 
opaque_negateboost::atomics::detail::extra_operations_generic108     static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
109     {
110         fetch_negate(storage, order);
111     }
112 
opaque_andboost::atomics::detail::extra_operations_generic113     static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
114     {
115         base_type::fetch_and(storage, v, order);
116     }
117 
opaque_orboost::atomics::detail::extra_operations_generic118     static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
119     {
120         base_type::fetch_or(storage, v, order);
121     }
122 
opaque_xorboost::atomics::detail::extra_operations_generic123     static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
124     {
125         base_type::fetch_xor(storage, v, order);
126     }
127 
opaque_complementboost::atomics::detail::extra_operations_generic128     static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
129     {
130         fetch_complement(storage, order);
131     }
132 
add_and_testboost::atomics::detail::extra_operations_generic133     static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
134     {
135         return !!static_cast< emulated_storage_type >(add(storage, v, order));
136     }
137 
sub_and_testboost::atomics::detail::extra_operations_generic138     static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
139     {
140         return !!static_cast< emulated_storage_type >(sub(storage, v, order));
141     }
142 
negate_and_testboost::atomics::detail::extra_operations_generic143     static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
144     {
145         return !!negate(storage, order);
146     }
147 
and_and_testboost::atomics::detail::extra_operations_generic148     static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
149     {
150         return !!bitwise_and(storage, v, order);
151     }
152 
or_and_testboost::atomics::detail::extra_operations_generic153     static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
154     {
155         return !!bitwise_or(storage, v, order);
156     }
157 
xor_and_testboost::atomics::detail::extra_operations_generic158     static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
159     {
160         return !!bitwise_xor(storage, v, order);
161     }
162 
complement_and_testboost::atomics::detail::extra_operations_generic163     static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
164     {
165         return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order));
166     }
167 
bit_test_and_setboost::atomics::detail::extra_operations_generic168     static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
169     {
170         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
171         storage_type old_val = base_type::fetch_or(storage, mask, order);
172         return !!(old_val & mask);
173     }
174 
bit_test_and_resetboost::atomics::detail::extra_operations_generic175     static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
176     {
177         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
178         storage_type old_val = base_type::fetch_and(storage, ~mask, order);
179         return !!(old_val & mask);
180     }
181 
bit_test_and_complementboost::atomics::detail::extra_operations_generic182     static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
183     {
184         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
185         storage_type old_val = base_type::fetch_xor(storage, mask, order);
186         return !!(old_val & mask);
187     }
188 };
189 
190 //! Specialization for cases when the platform only natively supports CAS
191 template< typename Base, std::size_t Size, bool Signed >
192 struct extra_operations_generic< Base, Size, Signed, true > :
193     public Base
194 {
195     typedef Base base_type;
196     typedef typename base_type::storage_type storage_type;
197     typedef typename storage_traits< Size >::type emulated_storage_type;
198 
fetch_negateboost::atomics::detail::extra_operations_generic199     static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
200     {
201         storage_type old_val;
202         atomics::detail::non_atomic_load(storage, old_val);
203         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)) {}
204         return old_val;
205     }
206 
negateboost::atomics::detail::extra_operations_generic207     static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
208     {
209         storage_type old_val, new_val;
210         atomics::detail::non_atomic_load(storage, old_val);
211         do
212         {
213             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val));
214         }
215         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
216         return new_val;
217     }
218 
addboost::atomics::detail::extra_operations_generic219     static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
220     {
221         storage_type old_val, new_val;
222         atomics::detail::non_atomic_load(storage, old_val);
223         do
224         {
225             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val + v));
226         }
227         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
228         return new_val;
229     }
230 
subboost::atomics::detail::extra_operations_generic231     static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
232     {
233         storage_type old_val, new_val;
234         atomics::detail::non_atomic_load(storage, old_val);
235         do
236         {
237             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val - v));
238         }
239         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
240         return new_val;
241     }
242 
bitwise_andboost::atomics::detail::extra_operations_generic243     static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
244     {
245         storage_type old_val, new_val;
246         atomics::detail::non_atomic_load(storage, old_val);
247         do
248         {
249             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val & v));
250         }
251         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
252         return new_val;
253     }
254 
bitwise_orboost::atomics::detail::extra_operations_generic255     static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
256     {
257         storage_type old_val, new_val;
258         atomics::detail::non_atomic_load(storage, old_val);
259         do
260         {
261             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val | v));
262         }
263         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
264         return new_val;
265     }
266 
bitwise_xorboost::atomics::detail::extra_operations_generic267     static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
268     {
269         storage_type old_val, new_val;
270         atomics::detail::non_atomic_load(storage, old_val);
271         do
272         {
273             new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val ^ v));
274         }
275         while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed));
276         return new_val;
277     }
278 
fetch_complementboost::atomics::detail::extra_operations_generic279     static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
280     {
281         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);
282     }
283 
bitwise_complementboost::atomics::detail::extra_operations_generic284     static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
285     {
286         return bitwise_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order);
287     }
288 
opaque_addboost::atomics::detail::extra_operations_generic289     static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
290     {
291         base_type::fetch_add(storage, v, order);
292     }
293 
opaque_subboost::atomics::detail::extra_operations_generic294     static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
295     {
296         base_type::fetch_sub(storage, v, order);
297     }
298 
opaque_negateboost::atomics::detail::extra_operations_generic299     static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
300     {
301         fetch_negate(storage, order);
302     }
303 
opaque_andboost::atomics::detail::extra_operations_generic304     static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
305     {
306         base_type::fetch_and(storage, v, order);
307     }
308 
opaque_orboost::atomics::detail::extra_operations_generic309     static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
310     {
311         base_type::fetch_or(storage, v, order);
312     }
313 
opaque_xorboost::atomics::detail::extra_operations_generic314     static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
315     {
316         base_type::fetch_xor(storage, v, order);
317     }
318 
opaque_complementboost::atomics::detail::extra_operations_generic319     static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
320     {
321         fetch_complement(storage, order);
322     }
323 
add_and_testboost::atomics::detail::extra_operations_generic324     static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
325     {
326         return !!static_cast< emulated_storage_type >(add(storage, v, order));
327     }
328 
sub_and_testboost::atomics::detail::extra_operations_generic329     static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
330     {
331         return !!static_cast< emulated_storage_type >(sub(storage, v, order));
332     }
333 
negate_and_testboost::atomics::detail::extra_operations_generic334     static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
335     {
336         return !!negate(storage, order);
337     }
338 
and_and_testboost::atomics::detail::extra_operations_generic339     static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
340     {
341         return !!bitwise_and(storage, v, order);
342     }
343 
or_and_testboost::atomics::detail::extra_operations_generic344     static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
345     {
346         return !!bitwise_or(storage, v, order);
347     }
348 
xor_and_testboost::atomics::detail::extra_operations_generic349     static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
350     {
351         return !!bitwise_xor(storage, v, order);
352     }
353 
complement_and_testboost::atomics::detail::extra_operations_generic354     static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
355     {
356         return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order));
357     }
358 
bit_test_and_setboost::atomics::detail::extra_operations_generic359     static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
360     {
361         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
362         storage_type old_val = base_type::fetch_or(storage, mask, order);
363         return !!(old_val & mask);
364     }
365 
bit_test_and_resetboost::atomics::detail::extra_operations_generic366     static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
367     {
368         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
369         storage_type old_val = base_type::fetch_and(storage, ~mask, order);
370         return !!(old_val & mask);
371     }
372 
bit_test_and_complementboost::atomics::detail::extra_operations_generic373     static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
374     {
375         const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number));
376         storage_type old_val = base_type::fetch_xor(storage, mask, order);
377         return !!(old_val & mask);
378     }
379 };
380 
381 // Default extra_operations template definition will be used unless specialized for a specific platform
382 template< typename Base, std::size_t Size, bool Signed >
383 struct extra_operations< Base, Size, Signed, true > :
384     public extra_operations_generic< Base, Size, Signed >
385 {
386 };
387 
388 } // namespace detail
389 } // namespace atomics
390 } // namespace boost
391 
392 #include <boost/atomic/detail/footer.hpp>
393 
394 #endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_
395