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