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) 2018 Andrey Semashev
7  */
8 /*!
9  * \file   atomic/detail/extra_ops_emulated.hpp
10  *
11  * This header contains emulated (lock-based) implementation of the extra atomic operations.
12  */
13 
14 #ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_
15 #define BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_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/extra_operations_fwd.hpp>
22 #include <boost/atomic/detail/lockpool.hpp>
23 
24 #ifdef BOOST_HAS_PRAGMA_ONCE
25 #pragma once
26 #endif
27 
28 #if defined(BOOST_MSVC)
29 #pragma warning(push)
30 // unary minus operator applied to unsigned type, result still unsigned
31 #pragma warning(disable: 4146)
32 #endif
33 
34 namespace boost {
35 namespace atomics {
36 namespace detail {
37 
38 //! Generic implementation of extra operations
39 template< typename Base, std::size_t Size, bool Signed >
40 struct emulated_extra_operations :
41     public Base
42 {
43     typedef Base base_type;
44     typedef typename base_type::storage_type storage_type;
45 
fetch_negateboost::atomics::detail::emulated_extra_operations46     static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
47     {
48         storage_type& s = const_cast< storage_type& >(storage);
49         lockpool::scoped_lock lock(&storage);
50         storage_type old_val = s;
51         s = static_cast< storage_type >(-old_val);
52         return old_val;
53     }
54 
negateboost::atomics::detail::emulated_extra_operations55     static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
56     {
57         storage_type& s = const_cast< storage_type& >(storage);
58         lockpool::scoped_lock lock(&storage);
59         storage_type new_val = static_cast< storage_type >(-s);
60         s = new_val;
61         return new_val;
62     }
63 
addboost::atomics::detail::emulated_extra_operations64     static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
65     {
66         storage_type& s = const_cast< storage_type& >(storage);
67         lockpool::scoped_lock lock(&storage);
68         storage_type new_val = s;
69         new_val += v;
70         s = new_val;
71         return new_val;
72     }
73 
subboost::atomics::detail::emulated_extra_operations74     static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
75     {
76         storage_type& s = const_cast< storage_type& >(storage);
77         lockpool::scoped_lock lock(&storage);
78         storage_type new_val = s;
79         new_val -= v;
80         s = new_val;
81         return new_val;
82     }
83 
bitwise_andboost::atomics::detail::emulated_extra_operations84     static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
85     {
86         storage_type& s = const_cast< storage_type& >(storage);
87         lockpool::scoped_lock lock(&storage);
88         storage_type new_val = s;
89         new_val &= v;
90         s = new_val;
91         return new_val;
92     }
93 
bitwise_orboost::atomics::detail::emulated_extra_operations94     static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
95     {
96         storage_type& s = const_cast< storage_type& >(storage);
97         lockpool::scoped_lock lock(&storage);
98         storage_type new_val = s;
99         new_val |= v;
100         s = new_val;
101         return new_val;
102     }
103 
bitwise_xorboost::atomics::detail::emulated_extra_operations104     static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
105     {
106         storage_type& s = const_cast< storage_type& >(storage);
107         lockpool::scoped_lock lock(&storage);
108         storage_type new_val = s;
109         new_val ^= v;
110         s = new_val;
111         return new_val;
112     }
113 
fetch_complementboost::atomics::detail::emulated_extra_operations114     static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
115     {
116         storage_type& s = const_cast< storage_type& >(storage);
117         lockpool::scoped_lock lock(&storage);
118         storage_type old_val = s;
119         s = static_cast< storage_type >(~old_val);
120         return old_val;
121     }
122 
bitwise_complementboost::atomics::detail::emulated_extra_operations123     static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
124     {
125         storage_type& s = const_cast< storage_type& >(storage);
126         lockpool::scoped_lock lock(&storage);
127         storage_type new_val = static_cast< storage_type >(~s);
128         s = new_val;
129         return new_val;
130     }
131 
opaque_addboost::atomics::detail::emulated_extra_operations132     static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
133     {
134         Base::fetch_add(storage, v, order);
135     }
136 
opaque_subboost::atomics::detail::emulated_extra_operations137     static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
138     {
139         Base::fetch_sub(storage, v, order);
140     }
141 
opaque_negateboost::atomics::detail::emulated_extra_operations142     static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
143     {
144         fetch_negate(storage, order);
145     }
146 
opaque_andboost::atomics::detail::emulated_extra_operations147     static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
148     {
149         Base::fetch_and(storage, v, order);
150     }
151 
opaque_orboost::atomics::detail::emulated_extra_operations152     static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
153     {
154         Base::fetch_or(storage, v, order);
155     }
156 
opaque_xorboost::atomics::detail::emulated_extra_operations157     static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
158     {
159         Base::fetch_xor(storage, v, order);
160     }
161 
opaque_complementboost::atomics::detail::emulated_extra_operations162     static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
163     {
164         fetch_complement(storage, order);
165     }
166 
add_and_testboost::atomics::detail::emulated_extra_operations167     static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
168     {
169         return !!add(storage, v, order);
170     }
171 
sub_and_testboost::atomics::detail::emulated_extra_operations172     static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
173     {
174         return !!sub(storage, v, order);
175     }
176 
negate_and_testboost::atomics::detail::emulated_extra_operations177     static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
178     {
179         return !!negate(storage, order);
180     }
181 
and_and_testboost::atomics::detail::emulated_extra_operations182     static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
183     {
184         return !!bitwise_and(storage, v, order);
185     }
186 
or_and_testboost::atomics::detail::emulated_extra_operations187     static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
188     {
189         return !!bitwise_or(storage, v, order);
190     }
191 
xor_and_testboost::atomics::detail::emulated_extra_operations192     static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
193     {
194         return !!bitwise_xor(storage, v, order);
195     }
196 
complement_and_testboost::atomics::detail::emulated_extra_operations197     static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
198     {
199         return !!bitwise_complement(storage, order);
200     }
201 
bit_test_and_setboost::atomics::detail::emulated_extra_operations202     static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
203     {
204         storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number);
205         storage_type old_val = Base::fetch_or(storage, mask, order);
206         return !!(old_val & mask);
207     }
208 
bit_test_and_resetboost::atomics::detail::emulated_extra_operations209     static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
210     {
211         storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number);
212         storage_type old_val = Base::fetch_and(storage, ~mask, order);
213         return !!(old_val & mask);
214     }
215 
bit_test_and_complementboost::atomics::detail::emulated_extra_operations216     static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT
217     {
218         storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number);
219         storage_type old_val = Base::fetch_xor(storage, mask, order);
220         return !!(old_val & mask);
221     }
222 };
223 
224 template< typename Base, std::size_t Size, bool Signed >
225 struct extra_operations< Base, Size, Signed, false > :
226     public emulated_extra_operations< Base, Size, Signed >
227 {
228 };
229 
230 } // namespace detail
231 } // namespace atomics
232 } // namespace boost
233 
234 #if defined(BOOST_MSVC)
235 #pragma warning(pop)
236 #endif
237 
238 #endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_
239