iceoryx2
C++ Language Bindings
Loading...
Searching...
No Matches
atomic.hpp
Go to the documentation of this file.
1// Copyright (c) 2024 by ekxide IO GmbH. All rights reserved.
2// Copyright (c) 2025 Contributors to the Eclipse Foundation
3//
4// See the NOTICE file(s) distributed with this work for additional
5// information regarding copyright ownership.
6//
7// This program and the accompanying materials are made available under the
8// terms of the Apache Software License 2.0 which is available at
9// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
10// which is available at https://opensource.org/licenses/MIT.
11//
12// SPDX-License-Identifier: Apache-2.0 OR MIT
13
14#ifndef IOX2_BB_ATOMIC_HPP
15#define IOX2_BB_ATOMIC_HPP
16
17#include <atomic>
18#include <cstdlib>
19#include <iostream>
20#include <type_traits>
21
22namespace iox2 {
23namespace legacy {
24namespace concurrent {
26using AtomicFlag = std::atomic_flag;
27
31template <typename T>
32class Atomic {
33 private:
34 template <typename U>
35 using enable_if_integral_t = std::enable_if_t<std::is_same<T, U>::value && std::is_integral<U>::value, T>;
36
37 template <typename U>
38 using enable_if_pointer_t = std::enable_if_t<std::is_same<T, U>::value && std::is_pointer<U>::value, T>;
39
40 template <typename U>
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>;
43
44 public:
45#if __cplusplus >= 201703L
46 static_assert(
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!");
49
51 static constexpr bool is_always_lock_free = std::atomic<T>::is_always_lock_free;
52#endif
53
55 constexpr Atomic() noexcept
56 : m_value { T() } {
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 "
60 "lock-free!"
61 << std::endl;
62 std::abort();
63 }
64#endif
65 }
66
68 explicit constexpr Atomic(T value) noexcept
69 : m_value { value } {
70 }
71
73 Atomic(const Atomic& other) = delete;
75 Atomic& operator=(const Atomic&) = delete;
76
77 Atomic(Atomic&& rhs) noexcept = default;
78 Atomic& operator=(Atomic&& rhs) noexcept = default;
79
80 ~Atomic() = default;
81
84 // NOLINTNEXTLINE(cppcoreguidelines-c-copy-assignment-signature) This mimics the std::atomic copy assignment operator
85 T operator=(T value) noexcept {
86 m_value = value;
87 return value;
88 }
89
92 // NOLINTNEXTLINE(cppcoreguidelines-c-copy-assignment-signature) This mimics the std::atomic copy assignment operator
93 T operator=(T value) volatile noexcept {
94 m_value = value;
95 return value;
96 }
97
99 explicit operator T() const noexcept {
100 return m_value.operator T();
101 }
102
104 explicit operator T() const volatile noexcept {
105 return m_value.operator T();
106 }
107
110 return m_value.is_lock_free();
111 }
112
115 return m_value.is_lock_free();
116 }
117
119 void store(T value, std::memory_order order = std::memory_order_seq_cst) noexcept {
120 m_value.store(value, order);
121 }
122
124 void store(T value, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
125 m_value.store(value, order);
126 }
127
129 T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
130 return m_value.load(order);
131 }
132
134 T load(std::memory_order order = std::memory_order_seq_cst) const volatile noexcept {
135 return m_value.load(order);
136 }
137
140 T exchange(T value, std::memory_order order = std::memory_order_seq_cst) noexcept {
141 return m_value.exchange(value, order);
142 }
143
146 T exchange(T value, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
147 return m_value.exchange(value, order);
148 }
149
154 bool compare_exchange_weak(T& expected, T desired, std::memory_order success, std::memory_order failure) noexcept {
155 return m_value.compare_exchange_weak(expected, desired, success, failure);
156 }
157
163 T desired,
164 std::memory_order success,
165 std::memory_order failure) volatile noexcept {
166 return m_value.compare_exchange_weak(expected, desired, success, failure);
167 }
168
173 bool compare_exchange_weak(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
174 return m_value.compare_exchange_weak(expected, desired, order);
175 }
176
182 T desired,
183 std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
184 return m_value.compare_exchange_weak(expected, desired, order);
185 }
186
190 bool
191 compare_exchange_strong(T& expected, T desired, std::memory_order success, std::memory_order failure) noexcept {
192 return m_value.compare_exchange_strong(expected, desired, success, failure);
193 }
194
199 T desired,
200 std::memory_order success,
201 std::memory_order failure) volatile noexcept {
202 return m_value.compare_exchange_strong(expected, desired, success, failure);
203 }
204
208 bool compare_exchange_strong(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
209 return m_value.compare_exchange_strong(expected, desired, order);
210 }
211
216 T desired,
217 std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
218 return m_value.compare_exchange_strong(expected, desired, order);
219 }
220
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);
226 }
227
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);
233 }
234
237 template <typename U = T>
238 enable_if_pointer_t<U> fetch_add(std::ptrdiff_t value,
239 std::memory_order order = std::memory_order_seq_cst) noexcept {
240 return m_value.fetch_add(value, order);
241 }
242
245 template <typename U = T>
246 enable_if_pointer_t<U> fetch_add(std::ptrdiff_t value,
247 std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
248 return m_value.fetch_add(value, order);
249 }
250
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);
256 }
257
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);
263 }
264
267 template <typename U = T>
268 enable_if_pointer_t<U> fetch_sub(std::ptrdiff_t value,
269 std::memory_order order = std::memory_order_seq_cst) noexcept {
270 return m_value.fetch_sub(value, order);
271 }
272
275 template <typename U = T>
276 enable_if_pointer_t<U> fetch_sub(std::ptrdiff_t value,
277 std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
278 return m_value.fetch_sub(value, order);
279 }
280
283 template <typename U = T>
284 enable_if_integral_t<U> operator+=(T value) noexcept {
285 return m_value.operator+=(value);
286 }
287
290 template <typename U = T>
291 enable_if_integral_t<U> operator+=(T value) volatile noexcept {
292 return m_value.operator+=(value);
293 }
294
297 template <typename U = T>
298 enable_if_integral_t<U> operator-=(T value) noexcept {
299 return m_value.operator-=(value);
300 }
301
304 template <typename U = T>
305 enable_if_integral_t<U> operator-=(T value) volatile noexcept {
306 return m_value.operator-=(value);
307 }
308
311 template <typename U = T>
312 enable_if_pointer_t<U> operator+=(std::ptrdiff_t value) noexcept {
313 return m_value.operator+=(value);
314 }
315
318 template <typename U = T>
319 enable_if_pointer_t<U> operator+=(std::ptrdiff_t value) volatile noexcept {
320 return m_value.operator+=(value);
321 }
322
325 template <typename U = T>
326 enable_if_pointer_t<U> operator-=(std::ptrdiff_t value) noexcept {
327 return m_value.operator-=(value);
328 }
329
332 template <typename U = T>
333 enable_if_pointer_t<U> operator-=(std::ptrdiff_t value) volatile noexcept {
334 return m_value.operator-=(value);
335 }
336
338 template <typename U = T>
339 enable_if_integral_or_pointer_t<U> operator++() noexcept {
340 return m_value.operator++();
341 }
342
344 template <typename U = T>
345 enable_if_integral_or_pointer_t<U> operator++() volatile noexcept {
346 return m_value.operator++();
347 }
348
350 template <typename U = T>
351 enable_if_integral_or_pointer_t<U> operator++(int) noexcept {
352 return m_value.operator++(0);
353 }
354
356 template <typename U = T>
357 enable_if_integral_or_pointer_t<U> operator++(int) volatile noexcept {
358 return m_value.operator++(0);
359 }
360
362 template <typename U = T>
363 enable_if_integral_or_pointer_t<U> operator--() noexcept {
364 return m_value.operator--();
365 }
366
368 template <typename U = T>
369 enable_if_integral_or_pointer_t<U> operator--() volatile noexcept {
370 return m_value.operator--();
371 }
372
374 template <typename U = T>
375 enable_if_integral_or_pointer_t<U> operator--(int) noexcept {
376 return m_value.operator--(0);
377 }
378
380 template <typename U = T>
381 enable_if_integral_or_pointer_t<U> operator--(int) volatile noexcept {
382 return m_value.operator--(0);
383 }
384
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);
390 }
391
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);
397 }
398
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);
404 }
405
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);
411 }
412
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);
418 }
419
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);
425 }
426
429 template <typename U = T>
430 enable_if_integral_t<U> operator&=(T value) noexcept {
431 return m_value.operator&=(value);
432 }
433
436 template <typename U = T>
437 enable_if_integral_t<U> operator&=(T value) volatile noexcept {
438 return m_value.operator&=(value);
439 }
440
443 template <typename U = T>
444 enable_if_integral_t<U> operator|=(T value) noexcept {
445 return m_value.operator|=(value);
446 }
447
450 template <typename U = T>
451 enable_if_integral_t<U> operator|=(T value) volatile noexcept {
452 return m_value.operator|=(value);
453 }
454
457 template <typename U = T>
458 enable_if_integral_t<U> operator^=(T value) noexcept {
459 return m_value.operator^=(value);
460 }
461
464 template <typename U = T>
465 enable_if_integral_t<U> operator^=(T value) volatile noexcept {
466 return m_value.operator^=(value);
467 }
468
469 private:
470 std::atomic<T> m_value;
471};
472} // namespace concurrent
473} // namespace legacy
474} // namespace iox2
475
476#endif // IOX2_BB_ATOMIC_HPP
A thin wrapper for a 'std::atomic' which ensures that all atomic operations are always lock-free in o...
Definition atomic.hpp:32
enable_if_integral_or_pointer_t< U > operator--(int) noexcept
Atomic post-decrement operator, equivalent to 'return fetch_sub(1)'.
Definition atomic.hpp:375
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 ...
Definition atomic.hpp:326
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...
Definition atomic.hpp:423
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,...
Definition atomic.hpp:465
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...
Definition atomic.hpp:224
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.
Definition atomic.hpp:124
enable_if_integral_t< U > operator-=(T value) volatile noexcept
Atomically substracts the given value to the stored value and returns the resulting value....
Definition atomic.hpp:305
enable_if_integral_t< U > operator+=(T value) volatile noexcept
Atomically adds the given value to the stored value and returns the resulting value....
Definition atomic.hpp:291
enable_if_integral_or_pointer_t< U > operator++() noexcept
Atomic pre-increment operator, equivalent to 'return fetch_add(1) + 1'.
Definition atomic.hpp:339
T load(std::memory_order order=std::memory_order_seq_cst) const noexcept
Atomically loads and returns the stored value.
Definition atomic.hpp:129
enable_if_integral_or_pointer_t< U > operator++(int) noexcept
Atomic post-increment operator, equivalent to 'return fetch_add(1)'.
Definition atomic.hpp:351
T load(std::memory_order order=std::memory_order_seq_cst) const volatile noexcept
Atomically loads and returns the stored value.
Definition atomic.hpp:134
enable_if_integral_t< U > operator|=(T value) noexcept
Atomically performs a bitwise 'OR' operation to the stored value and returns the resulting value,...
Definition atomic.hpp:444
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...
Definition atomic.hpp:173
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...
Definition atomic.hpp:254
enable_if_integral_or_pointer_t< U > operator++(int) volatile noexcept
Atomic post-increment operator, equivalent to 'return fetch_add(1)'.
Definition atomic.hpp:357
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...
Definition atomic.hpp:154
enable_if_integral_t< U > operator&=(T value) noexcept
Atomically performs a bitwise 'AND' operation to the stored value and returns the resulting value,...
Definition atomic.hpp:430
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...
Definition atomic.hpp:146
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...
Definition atomic.hpp:402
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...
Definition atomic.hpp:191
void store(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Atomically stores the given value with the given memory order.
Definition atomic.hpp:119
bool is_lock_free() const volatile noexcept
Return true if all operations on an object of this type are lock-free.
Definition atomic.hpp:114
enable_if_integral_t< U > operator-=(T value) noexcept
Atomically substracts the given value to the stored value and returns the resulting value....
Definition atomic.hpp:298
constexpr Atomic() noexcept
Constructs a new 'iox2::legacy::Atomic' with a default value.
Definition atomic.hpp:55
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...
Definition atomic.hpp:395
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,...
Definition atomic.hpp:451
T operator=(T value) volatile noexcept
Atomically assigns the given value to the 'iox2::legacy::Atomic' and returns the given value....
Definition atomic.hpp:93
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...
Definition atomic.hpp:181
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...
Definition atomic.hpp:198
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...
Definition atomic.hpp:140
enable_if_pointer_t< U > fetch_sub(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:276
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,...
Definition atomic.hpp:437
bool is_lock_free() const noexcept
Return true if all operations on an object of this type are lock-free.
Definition atomic.hpp:109
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...
Definition atomic.hpp:312
enable_if_integral_or_pointer_t< U > operator--(int) volatile noexcept
Atomic post-decrement operator, equivalent to 'return fetch_sub(1)'.
Definition atomic.hpp:381
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...
Definition atomic.hpp:261
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...
Definition atomic.hpp:409
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...
Definition atomic.hpp:215
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 ...
Definition atomic.hpp:333
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...
Definition atomic.hpp:319
enable_if_pointer_t< U > fetch_add(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:238
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...
Definition atomic.hpp:416
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...
Definition atomic.hpp:231
constexpr Atomic(T value) noexcept
Constructs a new 'iox2::legacy::Atomic' with the given value.
Definition atomic.hpp:68
enable_if_integral_t< U > operator^=(T value) noexcept
Atomically performs a bitwise 'OR' operation to the stored value and returns the resulting value,...
Definition atomic.hpp:458
enable_if_integral_or_pointer_t< U > operator--() volatile noexcept
Atomic pre-decrement operator, equivalent to 'return fetch_sub(1) - 1'.
Definition atomic.hpp:369
enable_if_integral_or_pointer_t< U > operator++() volatile noexcept
Atomic pre-increment operator, equivalent to 'return fetch_add(1) + 1'.
Definition atomic.hpp:345
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...
Definition atomic.hpp:162
enable_if_integral_or_pointer_t< U > operator--() noexcept
Atomic pre-decrement operator, equivalent to 'return fetch_sub(1) - 1'.
Definition atomic.hpp:363
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...
Definition atomic.hpp:208
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...
Definition atomic.hpp:388
enable_if_pointer_t< U > fetch_sub(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:268
enable_if_integral_t< U > operator+=(T value) noexcept
Atomically adds the given value to the stored value and returns the resulting value....
Definition atomic.hpp:284
enable_if_pointer_t< U > fetch_add(std::ptrdiff_t value, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:246
T operator=(T value) noexcept
Atomically assigns the given value to the 'iox2::legacy::Atomic' and returns the given value....
Definition atomic.hpp:85
Implementation of the C++23 expected class which can contain an error or a success value.
Definition expected.hpp:150
std::atomic_flag AtomicFlag
An alias to the std::atomic_flag.
Definition atomic.hpp:26
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