14#ifndef IOX2_BB_ATOMIC_HPP
15#define IOX2_BB_ATOMIC_HPP
35 using enable_if_integral_t = std::enable_if_t<std::is_same<T, U>::value && std::is_integral<U>::value,
T>;
38 using enable_if_pointer_t = std::enable_if_t<std::is_same<T, U>::value && std::is_pointer<U>::value,
T>;
41 using enable_if_integral_or_pointer_t =
42 std::enable_if_t<std::is_same<T, U>::value && (std::is_integral<U>::value || std::is_pointer<U>::value),
T>;
45#if __cplusplus >= 201703L
47 std::atomic<T>::is_always_lock_free,
48 "The 'iox2::legacy::Atomic' must work across process boundaries and must therefore be always lock-free!");
57#if __cplusplus < 201703L
58 if (!std::atomic_is_lock_free(&m_value)) {
59 std::cerr <<
"The 'iox2::legacy::Atomic' must work across process boundaries and must therefore be always "
100 return m_value.operator
T();
105 return m_value.operator
T();
110 return m_value.is_lock_free();
115 return m_value.is_lock_free();
119 void store(
T value, std::memory_order
order = std::memory_order_seq_cst)
noexcept {
120 m_value.store(value,
order);
124 void store(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
125 m_value.store(value,
order);
129 T load(std::memory_order
order = std::memory_order_seq_cst)
const noexcept {
130 return m_value.load(
order);
134 T load(std::memory_order
order = std::memory_order_seq_cst)
const volatile noexcept {
135 return m_value.load(
order);
141 return m_value.exchange(value,
order);
146 T exchange(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
147 return m_value.exchange(value,
order);
165 std::memory_order
failure)
volatile noexcept {
183 std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
201 std::memory_order
failure)
volatile noexcept {
217 std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
223 template <
typename U = T>
224 enable_if_integral_t<U>
fetch_add(
T value, std::memory_order
order = std::memory_order_seq_cst)
noexcept {
225 return m_value.fetch_add(value,
order);
230 template <
typename U = T>
231 enable_if_integral_t<U>
fetch_add(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
232 return m_value.fetch_add(value,
order);
237 template <
typename U = T>
239 std::memory_order
order = std::memory_order_seq_cst)
noexcept {
240 return m_value.fetch_add(value,
order);
245 template <
typename U = T>
247 std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
248 return m_value.fetch_add(value,
order);
253 template <
typename U = T>
254 enable_if_integral_t<U>
fetch_sub(
T value, std::memory_order
order = std::memory_order_seq_cst)
noexcept {
255 return m_value.fetch_sub(value,
order);
260 template <
typename U = T>
261 enable_if_integral_t<U>
fetch_sub(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
262 return m_value.fetch_sub(value,
order);
267 template <
typename U = T>
269 std::memory_order
order = std::memory_order_seq_cst)
noexcept {
270 return m_value.fetch_sub(value,
order);
275 template <
typename U = T>
277 std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
278 return m_value.fetch_sub(value,
order);
283 template <
typename U = T>
285 return m_value.operator+=(value);
290 template <
typename U = T>
292 return m_value.operator+=(value);
297 template <
typename U = T>
299 return m_value.operator-=(value);
304 template <
typename U = T>
306 return m_value.operator-=(value);
311 template <
typename U = T>
312 enable_if_pointer_t<U>
operator+=(std::ptrdiff_t value)
noexcept {
313 return m_value.operator+=(value);
318 template <
typename U = T>
319 enable_if_pointer_t<U>
operator+=(std::ptrdiff_t value)
volatile noexcept {
320 return m_value.operator+=(value);
325 template <
typename U = T>
326 enable_if_pointer_t<U>
operator-=(std::ptrdiff_t value)
noexcept {
327 return m_value.operator-=(value);
332 template <
typename U = T>
333 enable_if_pointer_t<U>
operator-=(std::ptrdiff_t value)
volatile noexcept {
334 return m_value.operator-=(value);
338 template <
typename U = T>
340 return m_value.operator++();
344 template <
typename U = T>
346 return m_value.operator++();
350 template <
typename U = T>
351 enable_if_integral_or_pointer_t<U>
operator++(
int)
noexcept {
352 return m_value.operator++(0);
356 template <
typename U = T>
357 enable_if_integral_or_pointer_t<U>
operator++(
int)
volatile noexcept {
358 return m_value.operator++(0);
362 template <
typename U = T>
364 return m_value.operator--();
368 template <
typename U = T>
370 return m_value.operator--();
374 template <
typename U = T>
375 enable_if_integral_or_pointer_t<U>
operator--(
int)
noexcept {
376 return m_value.operator--(0);
380 template <
typename U = T>
381 enable_if_integral_or_pointer_t<U>
operator--(
int)
volatile noexcept {
382 return m_value.operator--(0);
387 template <
typename U = T>
388 enable_if_integral_t<U>
fetch_and(
T value, std::memory_order
order = std::memory_order_seq_cst)
noexcept {
389 return m_value.fetch_and(value,
order);
394 template <
typename U = T>
395 enable_if_integral_t<U>
fetch_and(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
396 return m_value.fetch_and(value,
order);
401 template <
typename U = T>
402 enable_if_integral_t<U>
fetch_or(
T value, std::memory_order
order = std::memory_order_seq_cst)
noexcept {
403 return m_value.fetch_or(value,
order);
408 template <
typename U = T>
409 enable_if_integral_t<U>
fetch_or(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
410 return m_value.fetch_or(value,
order);
415 template <
typename U = T>
416 enable_if_integral_t<U>
fetch_xor(
T value, std::memory_order
order = std::memory_order_seq_cst)
noexcept {
417 return m_value.fetch_xor(value,
order);
422 template <
typename U = T>
423 enable_if_integral_t<U>
fetch_xor(
T value, std::memory_order
order = std::memory_order_seq_cst)
volatile noexcept {
424 return m_value.fetch_xor(value,
order);
429 template <
typename U = T>
431 return m_value.operator&=(value);
436 template <
typename U = T>
438 return m_value.operator&=(value);
443 template <
typename U = T>
445 return m_value.operator|=(value);
450 template <
typename U = T>
452 return m_value.operator|=(value);
457 template <
typename U = T>
459 return m_value.operator^=(value);
464 template <
typename U = T>
466 return m_value.operator^=(value);
470 std::atomic<T> m_value;
A thin wrapper for a 'std::atomic' which ensures that all atomic operations are always lock-free in o...
enable_if_integral_or_pointer_t< U > operator--(int) noexcept
Atomic post-decrement operator, equivalent to 'return fetch_sub(1)'.
enable_if_pointer_t< U > operator-=(std::ptrdiff_t value) noexcept
Atomically substracts the given difference to the stored pointer value and returns the resulting new ...
enable_if_integral_t< U > fetch_xor(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically performs a bitwise 'XOR' operation to the stored value with the given memory order and ret...
enable_if_integral_t< U > operator^=(T value) volatile noexcept
Atomically performs a bitwise 'OR' operation to the stored value and returns the resulting value,...
enable_if_integral_t< U > fetch_add(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically adds the given value to the stored value with the given memory order and returns the previ...
void store(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically stores the given value with the given memory order.
enable_if_integral_t< U > operator-=(T value) volatile noexcept
Atomically substracts the given value to the stored value and returns the resulting value....
enable_if_integral_t< U > operator+=(T value) volatile noexcept
Atomically adds the given value to the stored value and returns the resulting value....
enable_if_integral_or_pointer_t< U > operator++() noexcept
Atomic pre-increment operator, equivalent to 'return fetch_add(1) + 1'.
T load(std::memory_order order=std::memory_order_seq_cst) const noexcept
Atomically loads and returns the stored value.
enable_if_integral_or_pointer_t< U > operator++(int) noexcept
Atomic post-increment operator, equivalent to 'return fetch_add(1)'.
T load(std::memory_order order=std::memory_order_seq_cst) const volatile noexcept
Atomically loads and returns the stored value.
enable_if_integral_t< U > operator|=(T value) noexcept
Atomically performs a bitwise 'OR' operation to the stored value and returns the resulting value,...
bool compare_exchange_weak(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
enable_if_integral_t< U > fetch_sub(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically substracts the given value to the stored value with the given memory order and returns the...
enable_if_integral_or_pointer_t< U > operator++(int) volatile noexcept
Atomic post-increment operator, equivalent to 'return fetch_add(1)'.
bool compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
enable_if_integral_t< U > operator&=(T value) noexcept
Atomically performs a bitwise 'AND' operation to the stored value and returns the resulting value,...
Atomic(const Atomic &other)=delete
Similar to the std::atomic, the 'iox2::legacy::Atomic' is not copy constructible.
T exchange(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically exchanges the given value with the stored value using the given memory order and returns t...
enable_if_integral_t< U > fetch_or(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically performs a bitwise 'OR' operation to the stored value with the given memory order and retu...
bool compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
void store(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically stores the given value with the given memory order.
bool is_lock_free() const volatile noexcept
Return true if all operations on an object of this type are lock-free.
enable_if_integral_t< U > operator-=(T value) noexcept
Atomically substracts the given value to the stored value and returns the resulting value....
constexpr Atomic() noexcept
Constructs a new 'iox2::legacy::Atomic' with a default value.
enable_if_integral_t< U > fetch_and(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically performs a bitwise 'AND' operation to the stored value with the given memory order and ret...
Atomic & operator=(Atomic &&rhs) noexcept=default
enable_if_integral_t< U > operator|=(T value) volatile noexcept
Atomically performs a bitwise 'OR' operation to the stored value and returns the resulting value,...
T operator=(T value) volatile noexcept
Atomically assigns the given value to the 'iox2::legacy::Atomic' and returns the given value....
bool compare_exchange_weak(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
bool compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) volatile noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
T exchange(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically exchanges the given value with the stored value using the given memory order and returns t...
enable_if_pointer_t< U > fetch_sub(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
enable_if_integral_t< U > operator&=(T value) volatile noexcept
Atomically performs a bitwise 'AND' operation to the stored value and returns the resulting value,...
bool is_lock_free() const noexcept
Return true if all operations on an object of this type are lock-free.
enable_if_pointer_t< U > operator+=(std::ptrdiff_t value) noexcept
Atomically adds the given difference to the stored pointer value and returns the resulting new pointe...
enable_if_integral_or_pointer_t< U > operator--(int) volatile noexcept
Atomic post-decrement operator, equivalent to 'return fetch_sub(1)'.
enable_if_integral_t< U > fetch_sub(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically substracts the given value to the stored value with the given memory order and returns the...
enable_if_integral_t< U > fetch_or(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically performs a bitwise 'OR' operation to the stored value with the given memory order and retu...
bool compare_exchange_strong(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
enable_if_pointer_t< U > operator-=(std::ptrdiff_t value) volatile noexcept
Atomically substracts the given difference to the stored pointer value and returns the resulting new ...
Atomic(Atomic &&rhs) noexcept=default
enable_if_pointer_t< U > operator+=(std::ptrdiff_t value) volatile noexcept
Atomically adds the given difference to the stored pointer value and returns the resulting new pointe...
enable_if_pointer_t< U > fetch_add(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) noexcept
enable_if_integral_t< U > fetch_xor(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically performs a bitwise 'XOR' operation to the stored value with the given memory order and ret...
enable_if_integral_t< U > fetch_add(T value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Atomically adds the given value to the stored value with the given memory order and returns the previ...
constexpr Atomic(T value) noexcept
Constructs a new 'iox2::legacy::Atomic' with the given value.
enable_if_integral_t< U > operator^=(T value) noexcept
Atomically performs a bitwise 'OR' operation to the stored value and returns the resulting value,...
enable_if_integral_or_pointer_t< U > operator--() volatile noexcept
Atomic pre-decrement operator, equivalent to 'return fetch_sub(1) - 1'.
enable_if_integral_or_pointer_t< U > operator++() volatile noexcept
Atomic pre-increment operator, equivalent to 'return fetch_add(1) + 1'.
Atomic & operator=(const Atomic &)=delete
Similar to the std::atomic, the 'iox2::legacy::Atomic' is not copy assignable.
bool compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) volatile noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
enable_if_integral_or_pointer_t< U > operator--() noexcept
Atomic pre-decrement operator, equivalent to 'return fetch_sub(1) - 1'.
bool compare_exchange_strong(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Performs an atomic CAS operation on the stored value with the given desired value and the given memor...
enable_if_integral_t< U > fetch_and(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically performs a bitwise 'AND' operation to the stored value with the given memory order and ret...
enable_if_pointer_t< U > fetch_sub(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) noexcept
enable_if_integral_t< U > operator+=(T value) noexcept
Atomically adds the given value to the stored value and returns the resulting value....
enable_if_pointer_t< U > fetch_add(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
T operator=(T value) noexcept
Atomically assigns the given value to the 'iox2::legacy::Atomic' and returns the given value....
Implementation of the C++23 expected class which can contain an error or a success value.
std::atomic_flag AtomicFlag
An alias to the std::atomic_flag.
constexpr bool always_false_v
Helper value to bind a static_assert to a type.
helper struct to create an expected which is signalling success more easily