YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
atomic.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <type_traits>
7
8namespace yaclib::detail {
9
11
12void SetAtomicWeakFailFrequency(std::uint32_t k);
13
14template <typename Impl, typename T>
15class AtomicBase : public AtomicWait<Impl, T> {
17
18 public:
19 using Base::Base;
20 using Base::is_always_lock_free;
21 using Base::is_lock_free;
22
23 T operator=(T desired) noexcept {
24 YACLIB_INJECT_FAULT(auto r = Impl::operator=(desired));
25 return r;
26 }
27 T operator=(T desired) volatile noexcept {
28 YACLIB_INJECT_FAULT(auto r = Impl::operator=(desired));
29 return r;
30 }
31
32 void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
33 YACLIB_INJECT_FAULT(Impl::store(desired, order));
34 }
35 void store(T desired, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
36 YACLIB_INJECT_FAULT(Impl::store(desired, order));
37 }
38
39 T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
40 YACLIB_INJECT_FAULT(auto r = Impl::load(order));
41 return r;
42 }
43 T load(std::memory_order order = std::memory_order_seq_cst) const volatile noexcept {
44 YACLIB_INJECT_FAULT(auto r = Impl::load(order));
45 return r;
46 }
47
48 operator T() const noexcept {
49 return load();
50 }
51 operator T() const volatile noexcept {
52 // YACLIB_INJECT_FAULT(auto r = Impl::operator T()());
53 return load();
54 }
55
56 T exchange(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
57 YACLIB_INJECT_FAULT(auto r = Impl::exchange(desired, order));
58 return r;
59 }
60 T exchange(T desired, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
61 YACLIB_INJECT_FAULT(auto r = Impl::exchange(desired, order));
62 return r;
63 }
64
65 bool compare_exchange_weak(T& expected, T desired, std::memory_order success, std::memory_order failure) noexcept {
68 return false;
69 }
70 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_weak(expected, desired, success, failure));
71 return r;
72 }
73 bool compare_exchange_weak(T& expected, T desired, std::memory_order success,
74 std::memory_order failure) volatile noexcept {
77 return false;
78 }
79 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_weak(expected, desired, success, failure));
80 return r;
81 }
82 bool compare_exchange_weak(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
85 return false;
86 }
87 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_weak(expected, desired, order));
88 return r;
89 }
91 std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
94 return false;
95 }
96 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_weak(expected, desired, order));
97 return r;
98 }
99 bool compare_exchange_strong(T& expected, T desired, std::memory_order success, std::memory_order failure) noexcept {
100 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_strong(expected, desired, success, failure));
101 return r;
102 }
103 bool compare_exchange_strong(T& expected, T desired, std::memory_order success,
104 std::memory_order failure) volatile noexcept {
105 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_strong(expected, desired, success, failure));
106 return r;
107 }
108 bool compare_exchange_strong(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
109 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_strong(expected, desired, order));
110 return r;
111 }
113 std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
114 YACLIB_INJECT_FAULT(auto r = Impl::compare_exchange_strong(expected, desired, order));
115 return r;
116 }
117};
118
119template <typename Impl, typename T, bool IsFloating = std::is_floating_point_v<T>>
120class AtomicFloatingBase : public AtomicBase<Impl, T> {
122
123 public:
124 using Base::Base;
125};
126
127template <typename Impl, typename T>
128class AtomicFloatingBase<Impl, T, true> : public AtomicBase<Impl, T> {
130
131 public:
132 using Base::Base;
133
134 T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
135 YACLIB_INJECT_FAULT(auto r = Impl::fetch_add(arg, order));
136 return r;
137 }
138 T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
139 YACLIB_INJECT_FAULT(auto r = Impl::fetch_add(arg, order));
140 return r;
141 }
142
143 T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
144 YACLIB_INJECT_FAULT(auto r = Impl::fetch_sub(arg, order));
145 return r;
146 }
147 T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
148 YACLIB_INJECT_FAULT(auto r = Impl::fetch_sub(arg, order));
149 return r;
150 }
151
152 T operator+=(T arg) noexcept {
153 YACLIB_INJECT_FAULT(auto r = Impl::operator+=(arg));
154 return r;
155 }
156 T operator+=(T arg) volatile noexcept {
157 YACLIB_INJECT_FAULT(auto r = Impl::operator+=(arg));
158 return r;
159 }
160
161 T operator-=(T arg) noexcept {
162 YACLIB_INJECT_FAULT(auto r = Impl::operator-=(arg));
163 return r;
164 }
165 T operator-=(T arg) volatile noexcept {
166 YACLIB_INJECT_FAULT(auto r = Impl::operator-=(arg));
167 return r;
168 }
169};
170
171template <typename Impl, typename T, bool IsIntegral = std::is_integral_v<T> && !std::is_same_v<T, bool>>
172class AtomicIntegralBase : public AtomicFloatingBase<Impl, T> {
174
175 public:
176 using Base::Base;
177};
178
179template <typename Impl, typename T>
180class AtomicIntegralBase<Impl, T, true> : public AtomicFloatingBase<Impl, T, true> {
182
183 public:
184 using Base::Base;
185
186 T fetch_and(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
187 YACLIB_INJECT_FAULT(auto r = Impl::fetch_and(arg, order));
188 return r;
189 }
190 T fetch_and(T arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
191 YACLIB_INJECT_FAULT(auto r = Impl::fetch_and(arg, order));
192 return r;
193 }
194
195 T fetch_or(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
196 YACLIB_INJECT_FAULT(auto r = Impl::fetch_or(arg, order));
197 return r;
198 }
199 T fetch_or(T arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
200 YACLIB_INJECT_FAULT(auto r = Impl::fetch_or(arg, order));
201 return r;
202 }
203
204 T fetch_xor(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
205 YACLIB_INJECT_FAULT(auto r = Impl::fetch_xor(arg, order));
206 return r;
207 }
208 T fetch_xor(T arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
209 YACLIB_INJECT_FAULT(auto r = Impl::fetch_xor(arg, order));
210 return r;
211 }
212
214 YACLIB_INJECT_FAULT(auto r = ++static_cast<Impl&>(*this));
215 return r;
216 }
218 YACLIB_INJECT_FAULT(auto r = ++static_cast<Impl&>(*this));
219 return r;
220 }
221
222 T operator++(int) noexcept {
223 YACLIB_INJECT_FAULT(auto r = static_cast<Impl&>(*this)++);
224 return r;
225 }
226 T operator++(int) volatile noexcept {
227 YACLIB_INJECT_FAULT(auto r = static_cast<Impl&>(*this)++);
228 return r;
229 }
230
232 YACLIB_INJECT_FAULT(auto r = --static_cast<Impl&>(*this));
233 return r;
234 }
236 YACLIB_INJECT_FAULT(auto r = --static_cast<Impl&>(*this));
237 return r;
238 }
239
240 T operator--(int) noexcept {
241 YACLIB_INJECT_FAULT(auto r = static_cast<Impl&>(*this)--);
242 return r;
243 }
244 T operator--(int) volatile noexcept {
245 YACLIB_INJECT_FAULT(auto r = static_cast<Impl&>(*this)--);
246 return r;
247 }
248
249 T operator&=(T arg) noexcept {
250 YACLIB_INJECT_FAULT(auto r = Impl::operator&=(arg));
251 return r;
252 }
253 T operator&=(T arg) volatile noexcept {
254 YACLIB_INJECT_FAULT(auto r = Impl::operator&=(arg));
255 return r;
256 }
257
258 T operator|=(T arg) noexcept {
259 YACLIB_INJECT_FAULT(auto r = Impl::operator|=(arg));
260 return r;
261 }
262 T operator|=(T arg) volatile noexcept {
263 YACLIB_INJECT_FAULT(auto r = Impl::operator|=(arg));
264 return r;
265 }
266
267 T operator^=(T arg) noexcept {
268 YACLIB_INJECT_FAULT(auto r = Impl::operator^=(arg));
269 return r;
270 }
271 T operator^=(T arg) volatile noexcept {
272 YACLIB_INJECT_FAULT(auto r = Impl::operator^=(arg));
273 return r;
274 }
275};
276
277template <typename Impl, typename T>
278class Atomic : public AtomicIntegralBase<Impl, T> {
280
281 public:
282 using Base::Base;
283};
284
285template <typename Impl, typename U>
286class Atomic<Impl, U*> : public AtomicBase<Impl, U*> {
288
289 public:
290 using Base::Base;
291
292 U* fetch_add(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
293 YACLIB_INJECT_FAULT(auto* r = Impl::fetch_add(arg, order));
294 return r;
295 }
296 U* fetch_add(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
297 YACLIB_INJECT_FAULT(auto* r = Impl::fetch_add(arg, order));
298 return r;
299 }
300
301 U* fetch_sub(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
302 YACLIB_INJECT_FAULT(auto* r = Impl::fetch_sub(arg, order));
303 return r;
304 }
305 U* fetch_sub(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
306 YACLIB_INJECT_FAULT(auto* r = Impl::fetch_sub(arg, order));
307 return r;
308 }
309
311 YACLIB_INJECT_FAULT(auto* r = ++static_cast<Impl&>(*this));
312 return r;
313 }
315 YACLIB_INJECT_FAULT(auto* r = ++static_cast<Impl&>(*this));
316 return r;
317 }
318
319 U* operator++(int) noexcept {
320 YACLIB_INJECT_FAULT(auto* r = static_cast<Impl&>(*this)++);
321 return r;
322 }
323 U* operator++(int) volatile noexcept {
324 YACLIB_INJECT_FAULT(auto* r = static_cast<Impl&>(*this)++);
325 return r;
326 }
327
329 YACLIB_INJECT_FAULT(auto* r = --static_cast<Impl&>(*this));
330 return r;
331 }
333 YACLIB_INJECT_FAULT(auto* r = --static_cast<Impl&>(*this));
334 return r;
335 }
336
337 U* operator--(int) noexcept {
338 YACLIB_INJECT_FAULT(auto* r = static_cast<Impl&>(*this)--);
339 return r;
340 }
341 U* operator--(int) volatile noexcept {
342 YACLIB_INJECT_FAULT(auto* r = static_cast<Impl&>(*this)--);
343 return r;
344 }
345
346 U* operator+=(std::ptrdiff_t arg) noexcept {
347 YACLIB_INJECT_FAULT(auto* r = Impl::operator+=(arg));
348 return r;
349 }
350 U* operator+=(std::ptrdiff_t arg) volatile noexcept {
351 YACLIB_INJECT_FAULT(auto* r = Impl::operator+=(arg));
352 return r;
353 }
354
355 U* operator-=(std::ptrdiff_t arg) noexcept {
356 YACLIB_INJECT_FAULT(auto* r = Impl::operator-=(arg));
357 return r;
358 }
359 U* operator-=(std::ptrdiff_t arg) volatile noexcept {
360 YACLIB_INJECT_FAULT(auto* r = Impl::operator-=(arg));
361 return r;
362 }
363};
364
365// TODO(myannyax) Implement
366// template <typename Impl, typename U>
367// class Atomic<Impl, std::shared_ptr<U>>;
368//
369// template <typename Impl, typename U>
370// class Atomic<Impl, std::weak_ptr<U>>;
371
372} // namespace yaclib::detail
void store(T desired, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:35
bool compare_exchange_strong(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:108
bool compare_exchange_weak(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:82
T operator=(T desired) noexcept
Definition atomic.hpp:23
bool compare_exchange_strong(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:112
T exchange(T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:56
T operator=(T desired) volatile noexcept
Definition atomic.hpp:27
T exchange(T desired, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:60
bool compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) volatile noexcept
Definition atomic.hpp:103
bool compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept
Definition atomic.hpp:99
bool compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) volatile noexcept
Definition atomic.hpp:73
bool compare_exchange_weak(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:90
T load(std::memory_order order=std::memory_order_seq_cst) const noexcept
Definition atomic.hpp:39
bool compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept
Definition atomic.hpp:65
void store(T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:32
T load(std::memory_order order=std::memory_order_seq_cst) const volatile noexcept
Definition atomic.hpp:43
T fetch_sub(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:143
T fetch_add(T arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:138
T fetch_add(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:134
T fetch_sub(T arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:147
T fetch_xor(T arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:208
T fetch_and(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:186
T fetch_or(T arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:199
T fetch_and(T arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:190
T fetch_or(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:195
T fetch_xor(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:204
U * operator+=(std::ptrdiff_t arg) noexcept
Definition atomic.hpp:346
U * fetch_add(std::ptrdiff_t arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:296
U * operator++(int) volatile noexcept
Definition atomic.hpp:323
U * operator++() volatile noexcept
Definition atomic.hpp:314
U * operator--() volatile noexcept
Definition atomic.hpp:332
U * operator--(int) volatile noexcept
Definition atomic.hpp:341
U * operator-=(std::ptrdiff_t arg) volatile noexcept
Definition atomic.hpp:359
U * fetch_sub(std::ptrdiff_t arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:301
U * operator+=(std::ptrdiff_t arg) volatile noexcept
Definition atomic.hpp:350
U * operator-=(std::ptrdiff_t arg) noexcept
Definition atomic.hpp:355
U * fetch_add(std::ptrdiff_t arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition atomic.hpp:292
U * fetch_sub(std::ptrdiff_t arg, std::memory_order order=std::memory_order_seq_cst) volatile noexcept
Definition atomic.hpp:305
#define YACLIB_INJECT_FAULT(statement)
Definition inject.hpp:20
void SetAtomicWeakFailFrequency(std::uint32_t k)
Definition atomic.cpp:16
bool ShouldFailAtomicWeak()
Definition atomic.cpp:11
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25