tenno 0.1.0
Loading...
Searching...
No Matches
atomic.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#pragma once
7
8#include <tenno/mutex.hpp>
9
10namespace tenno
11{
12
18template <typename T> class atomic;
19
20/* general case */
21template <typename T> class atomic
22{
23public:
27 using value_type = T;
28 const bool is_always_lock_free = false;
29
30 atomic() noexcept = default;
31 ~atomic() noexcept = default;
32 atomic(const atomic &) = delete;
33 atomic &operator=(const atomic &) = delete;
34 atomic &operator=(const atomic &) volatile = delete;
35
36 inline bool is_lock_free() const noexcept
37 {
38 return this->is_always_lock_free;
39 }
40
41 inline void store(T desired) noexcept
42 {
43 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
44 this->_value = desired;
45 }
46
47 inline T load() noexcept
48 {
49 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
50 return this->_value;
51 }
52
53 operator T() noexcept
54 {
55 return this->load();
56 }
57
64 inline T exchange(T desired) noexcept
65 {
66 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
67 T old = this->_value;
68 this->_value = desired;
69 return old;
70 }
71
78 inline bool compare_exchange_weak(const T &expected, T desired) noexcept
79 {
80 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
81 if (this->_value == expected)
82 {
83 this->_value = desired;
84 return true;
85 }
86 return false;
87 }
88
96 inline bool compare_exchange_strong(const T &expected, T desired) noexcept
97 {
98 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
99 if (this->_value == expected)
100 {
101 this->_value = desired;
102 return true;
103 }
104 return false;
105 }
106
107 // TODO
108 // - wait
109 // - notify_one
110 // - notify_all
111
112private:
113 T _value;
114 tenno::mutex _mutex;
115};
116
117/* general pointer */
118template <typename U> class atomic<U *>
119{
120public:
121 using value_type = U *;
122 const bool is_always_lock_free = false;
123
124 atomic() noexcept = default;
125 ~atomic() noexcept = default;
126 atomic(const atomic &) = delete;
127 atomic &operator=(const atomic &) = delete;
128 atomic &operator=(const atomic &) volatile = delete;
129
130 inline bool is_lock_free() const noexcept
131 {
132 return this->is_always_lock_free;
133 }
134
135 inline void store(U *desired) noexcept
136 {
137 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
138 this->_value = desired;
139 }
140
141 inline U load() noexcept
142 {
143 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
144 return *this->_value;
145 }
146
147 operator U() noexcept
148 {
149 return this->load();
150 }
151
152 inline U exchange(U *desired) noexcept
153 {
154 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
155 U old = *this->_value;
156 this->_value = desired;
157 return old;
158 }
159
166 inline bool compare_exchange_weak(const U *expected, U *desired) noexcept
167 {
168 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
169 if (this->_value != nullptr && *this->_value == *expected)
170 {
171 *this->_value = *desired;
172 return true;
173 }
174 return false;
175 }
176
177 inline bool compare_exchange_strong(const U *expected, U *desired) noexcept
178 {
179 tenno::lock_guard<tenno::mutex> lock(this->_mutex);
180 if (this->_value != nullptr && *this->_value == *expected)
181 {
182 *this->_value = *desired;
183 return true;
184 }
185 return false;
186 }
187
188private:
189 U *_value;
190 tenno::mutex _mutex;
191};
192
193/* int specialization */
194template <> class atomic<int>
195{
196public:
197 using value_type = int;
198 const bool is_always_lock_free = true;
199
200 atomic() noexcept = default;
201 ~atomic() noexcept = default;
202 atomic(const atomic &) = delete;
203 atomic &operator=(const atomic &) = delete;
204 atomic &operator=(const atomic &) volatile = delete;
205
206 inline bool is_lock_free() const noexcept
207 {
208 return this->is_always_lock_free;
209 }
210
211 inline void store(int desired) noexcept
212 {
213 asm volatile("lock xchg %0, %1" : "+m"(this->_value), "+r"(desired));
214 }
215
216 inline int load() noexcept
217 {
218 int out = 0;
219 asm volatile("lock add %1, %0" : "+m"(out), "+r"(this->_value));
220 return out;
221 }
222
223 operator int() noexcept
224 {
225 return this->load();
226 }
227
228 inline int exchange(int desired) noexcept
229 {
230 asm volatile("lock xchg %0, %1" : "+m"(this->_value), "+r"(desired));
231 return desired;
232 }
233
234 inline bool compare_exchange_weak(int &expected, int desired) noexcept
235 {
236 bool success;
237 asm volatile("lock cmpxchg %[desired], %[target]\n\t"
238 "sete %[success]\n\t"
239 : [success] "=r"(success), "=m"(this->_value)
240 : [target] "m"(this->_value),
241 "a"(expected), [desired] "r"(desired)
242 : "memory", "cc");
243 return success;
244 }
245
246 inline bool compare_exchange_strong(int &expected, int desired) noexcept
247 {
248 bool success = false;
249 while (!success)
250 {
251 asm volatile("lock cmpxchg %[desired], %[target]\n\t"
252 "sete %[success]\n\t"
253 : [success] "=r"(success), "=m"(this->_value)
254 : [target] "m"(this->_value),
255 "a"(expected), [desired] "r"(desired)
256 : "memory", "cc");
257 }
258 return true;
259 }
260
261private:
262 int _value;
263};
264
265/* char specialization */
266
267template <> class atomic<char>
268{
269public:
270 using value_type = char;
271 const bool is_always_lock_free = true;
272
273 atomic() noexcept = default;
274 ~atomic() noexcept = default;
275 atomic(const atomic &) = delete;
276 atomic &operator=(const atomic &) = delete;
277 atomic &operator=(const atomic &) volatile = delete;
278
279 inline bool is_lock_free() const noexcept
280 {
281 return this->is_always_lock_free;
282 }
283
284 inline void store(char desired) noexcept
285 {
286 asm volatile("lock xchg %0, %1" : "+m"(this->_value), "+r"(desired));
287 }
288
289 inline char load() noexcept
290 {
291 char out = 0;
292 asm volatile("lock add %1, %0" : "+m"(out), "+r"(this->_value));
293 return out;
294 }
295
296 operator char() noexcept
297 {
298 return this->load();
299 }
300
301 inline char exchange(char desired) noexcept
302 {
303 asm volatile("lock xchg %0, %1" : "+m"(this->_value), "+r"(desired));
304 return desired;
305 }
306
307 inline bool compare_exchange_weak(char &expected, char desired) noexcept
308 {
309 bool success;
310 asm volatile("lock cmpxchg %[desired], %[target]\n\t"
311 "sete %[success]\n\t"
312 : [success] "=r"(success), "=m"(this->_value)
313 : [target] "m"(this->_value),
314 "a"(expected), [desired] "r"(desired)
315 : "memory", "cc");
316 return success;
317 }
318
319 inline bool compare_exchange_strong(char &expected, char desired) noexcept
320 {
321 bool success = false;
322 while (!success)
323 {
324 asm volatile("lock cmpxchg %[desired], %[target]\n\t"
325 "sete %[success]\n\t"
326 : [success] "=r"(success), "=m"(this->_value)
327 : [target] "m"(this->_value),
328 "a"(expected), [desired] "r"(desired)
329 : "memory", "cc");
330 }
331 return true;
332 }
333
334private:
335 char _value;
336};
337
338/* long specialization */
339
340template <> class atomic<long>
341{
342public:
343 using value_type = long;
344 const bool is_always_lock_free = true;
345
346 atomic() noexcept = default;
347 ~atomic() noexcept = default;
348 atomic(const atomic &) = delete;
349 atomic &operator=(const atomic &) = delete;
350 atomic &operator=(const atomic &) volatile = delete;
351
352 inline bool is_lock_free() const noexcept
353 {
354 return this->is_always_lock_free;
355 }
356
357 inline void store(long desired) noexcept
358 {
359 asm volatile("lock xchg %0, %1" : "+m"(this->_value), "+r"(desired));
360 }
361
362 inline long load() noexcept
363 {
364 long out = 0;
365 asm volatile("lock add %1, %0" : "+m"(out), "+r"(this->_value));
366 return out;
367 }
368
369 operator long() noexcept
370 {
371 return this->load();
372 }
373
374 inline long exchange(long desired) noexcept
375 {
376 asm volatile("lock xchg %0, %1" : "+m"(this->_value), "+r"(desired));
377 return desired;
378 }
379
380 inline bool compare_exchange_weak(long &expected, long desired) noexcept
381 {
382 bool success;
383 asm volatile("lock cmpxchg %[desired], %[target]\n\t"
384 "sete %[success]\n\t"
385 : [success] "=r"(success), "=m"(this->_value)
386 : [target] "m"(this->_value),
387 "a"(expected), [desired] "r"(desired)
388 : "memory", "cc");
389 return success;
390 }
391
392 inline bool compare_exchange_strong(long &expected, long desired) noexcept
393 {
394 bool success = false;
395 while (!success)
396 {
397 asm volatile("lock cmpxchg %[desired], %[target]\n\t"
398 "sete %[success]\n\t"
399 : [success] "=r"(success), "=m"(this->_value)
400 : [target] "m"(this->_value),
401 "a"(expected), [desired] "r"(desired)
402 : "memory", "cc");
403 }
404 return true;
405 }
406
407private:
408 long _value;
409};
410
411} // namespace tenno
U exchange(U *desired) noexcept
Definition atomic.hpp:152
atomic() noexcept=default
bool compare_exchange_strong(const U *expected, U *desired) noexcept
Definition atomic.hpp:177
U load() noexcept
Definition atomic.hpp:141
void store(U *desired) noexcept
Definition atomic.hpp:135
bool compare_exchange_weak(const U *expected, U *desired) noexcept
Compare and exchange the value of the atomic object.
Definition atomic.hpp:166
atomic() noexcept=default
char load() noexcept
Definition atomic.hpp:289
char exchange(char desired) noexcept
Definition atomic.hpp:301
bool compare_exchange_weak(char &expected, char desired) noexcept
Definition atomic.hpp:307
bool compare_exchange_strong(char &expected, char desired) noexcept
Definition atomic.hpp:319
void store(char desired) noexcept
Definition atomic.hpp:284
int exchange(int desired) noexcept
Definition atomic.hpp:228
bool compare_exchange_strong(int &expected, int desired) noexcept
Definition atomic.hpp:246
bool compare_exchange_weak(int &expected, int desired) noexcept
Definition atomic.hpp:234
int load() noexcept
Definition atomic.hpp:216
atomic() noexcept=default
void store(int desired) noexcept
Definition atomic.hpp:211
long load() noexcept
Definition atomic.hpp:362
long exchange(long desired) noexcept
Definition atomic.hpp:374
bool compare_exchange_strong(long &expected, long desired) noexcept
Definition atomic.hpp:392
atomic() noexcept=default
void store(long desired) noexcept
Definition atomic.hpp:357
bool compare_exchange_weak(long &expected, long desired) noexcept
Definition atomic.hpp:380
The atomic class template provides operations on atomic types.
Definition atomic.hpp:22
void store(T desired) noexcept
Definition atomic.hpp:41
bool compare_exchange_weak(const T &expected, T desired) noexcept
Compare and exchange the value of the atomic object.
Definition atomic.hpp:78
T exchange(T desired) noexcept
Exchange the value stored in the atomic object with a new value.
Definition atomic.hpp:64
const bool is_always_lock_free
Definition atomic.hpp:28
atomic() noexcept=default
bool compare_exchange_strong(const T &expected, T desired) noexcept
Compare and exchange the value of the atomic object.
Definition atomic.hpp:96
bool is_lock_free() const noexcept
Definition atomic.hpp:36
T value_type
The type of the atomic object.
Definition atomic.hpp:27
T load() noexcept
Definition atomic.hpp:47
An expected value.
Definition expected.hpp:38
A simple lock guard implementation.
Definition mutex.hpp:126
A simple mutex implementation.
Definition mutex.hpp:15