ORIGINAL
Loading...
Searching...
No Matches
atomic.h
1#ifndef ORIGINAL_ATOMIC_H
2#define ORIGINAL_ATOMIC_H
3
4#include <type_traits>
5#include <cstring>
6#include "optional.h"
7#include "config.h"
8#include "mutex.h"
9
10namespace original {
11#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
12
13 // ==================== Memory Order Enumeration ====================
14
25 enum class memOrder {
26 RELAXED = __ATOMIC_RELAXED,
27 ACQUIRE = __ATOMIC_ACQUIRE,
28 RELEASE = __ATOMIC_RELEASE,
29 ACQ_REL = __ATOMIC_ACQ_REL,
30 SEQ_CST = __ATOMIC_SEQ_CST,
31 };
32
33 // ==================== Forward Declarations ====================
34
35 template<typename TYPE, bool USE_LOCK>
36 class atomicImpl;
37
46 template<typename TYPE>
47 using atomic = atomicImpl<
48 TYPE,
49 !( std::is_trivially_copyable_v<TYPE> &&
50 std::is_trivially_destructible_v<TYPE> &&
51 __atomic_always_lock_free(sizeof(TYPE), nullptr) )
52 >;
53
54 // ==================== Lock-Free Implementation ====================
55
63 template<typename TYPE>
64 class atomicImpl<TYPE, false> {
65 alignas(TYPE) byte data_[sizeof(TYPE)];
66
70 atomicImpl();
71
77 explicit atomicImpl(TYPE value, memOrder order = SEQ_CST);
78
79 public:
80 // Memory ordering constants for convenience
81 static constexpr auto RELAXED = memOrder::RELAXED;
82 static constexpr auto ACQUIRE = memOrder::ACQUIRE;
83 static constexpr auto RELEASE = memOrder::RELEASE;
84 static constexpr auto ACQ_REL = memOrder::ACQ_REL;
85 static constexpr auto SEQ_CST = memOrder::SEQ_CST;
86
87 // Disable copying and moving
88 atomicImpl(const atomicImpl&) = delete;
89 atomicImpl(atomicImpl&&) = delete;
90 atomicImpl& operator=(const atomicImpl&) = delete;
91 atomicImpl& operator=(atomicImpl&&) = delete;
92
97 static constexpr bool isLockFree() noexcept;
98
104 void store(TYPE value, memOrder order = SEQ_CST);
105
111 TYPE load(memOrder order = SEQ_CST) const noexcept;
112
117 TYPE operator*() const noexcept;
118
123 explicit operator TYPE() const noexcept;
124
129 void operator=(TYPE value) noexcept;
130
136 atomicImpl& operator+=(TYPE value) noexcept;
137
143 atomicImpl& operator-=(TYPE value) noexcept;
144
151 TYPE exchange(TYPE value, memOrder order = SEQ_CST) noexcept;
152
160 bool exchangeCmp(TYPE& expected, TYPE desired, memOrder order = SEQ_CST) noexcept;
161
163 ~atomicImpl() = default;
164
165 // Friend factory functions
166 template<typename T>
167 friend auto makeAtomic();
168
169 template<typename T>
170 friend auto makeAtomic(T value);
171 };
172
173 // ==================== Mutex-Based Implementation ====================
174
182 template<typename TYPE>
183 class atomicImpl<TYPE, true> {
184 mutable pMutex mutex_;
185 alternative<TYPE> data_;
186
190 atomicImpl() = default;
191
197 explicit atomicImpl(TYPE value, memOrder order = RELEASE);
198
199 public:
200 // Memory ordering constants (for API compatibility)
201 static constexpr auto RELAXED = memOrder::RELAXED;
202 static constexpr auto ACQUIRE = memOrder::ACQUIRE;
203 static constexpr auto RELEASE = memOrder::RELEASE;
204 static constexpr auto ACQ_REL = memOrder::ACQ_REL;
205 static constexpr auto SEQ_CST = memOrder::SEQ_CST;
206
207 // Disable copying and moving
208 atomicImpl(const atomicImpl&) = delete;
209 atomicImpl(atomicImpl&&) = delete;
210 atomicImpl& operator=(const atomicImpl&) = delete;
211 atomicImpl& operator=(atomicImpl&&) = delete;
212
217 static constexpr bool isLockFree() noexcept;
218
224 void store(TYPE value, memOrder order = SEQ_CST);
225
231 TYPE load(memOrder order = SEQ_CST) const noexcept;
232
237 TYPE operator*() const noexcept;
238
243 explicit operator TYPE() const noexcept;
244
249 void operator=(TYPE value) noexcept;
250
256 atomicImpl& operator+=(TYPE value) noexcept;
257
263 atomicImpl& operator-=(TYPE value) noexcept;
264
271 TYPE exchange(const TYPE& value, memOrder order = SEQ_CST) noexcept;
272
280 bool exchangeCmp(TYPE& expected, const TYPE& desired, memOrder order = SEQ_CST) noexcept;
281
283 ~atomicImpl() = default;
284
285 // Friend factory functions
286 template<typename T>
287 friend auto makeAtomic();
288
289 template<typename T>
290 friend auto makeAtomic(T value);
291 };
292
293 // ==================== Factory Functions ====================
294
300 template<typename TYPE>
301 auto makeAtomic();
302
309 template<typename TYPE>
310 auto makeAtomic(TYPE value);
311
312} // namespace original
313
314template <typename TYPE>
315original::atomicImpl<TYPE, false>::atomicImpl() {
316 std::memset(this->data_, byte{}, sizeof(TYPE));
317}
318
319template <typename TYPE>
320original::atomicImpl<TYPE, false>::atomicImpl(TYPE value, memOrder order) {
321 __atomic_store(reinterpret_cast<TYPE*>(this->data_), &value, static_cast<integer>(order));
322}
323
324template <typename TYPE>
325constexpr bool original::atomicImpl<TYPE, false>::isLockFree() noexcept {
326 return true;
327}
328
329template <typename TYPE>
330void original::atomicImpl<TYPE, false>::store(TYPE value, memOrder order) {
331 __atomic_store(reinterpret_cast<TYPE*>(this->data_), &value, static_cast<integer>(order));
332}
333
334template <typename TYPE>
335TYPE original::atomicImpl<TYPE, false>::load(memOrder order) const noexcept {
336 TYPE result;
337 __atomic_load(reinterpret_cast<const TYPE*>(this->data_), &result, static_cast<integer>(order));
338 return result;
339}
340
341template <typename TYPE>
343{
344 return this->load();
345}
346
347template <typename TYPE>
349{
350 return this->load();
351}
352
353template <typename TYPE>
354void original::atomicImpl<TYPE, false>::operator=(TYPE value) noexcept
355{
356 this->store(std::move(value));
357}
358
359template <typename TYPE>
361{
362 __atomic_fetch_add(reinterpret_cast<TYPE*>(this->data_), value, static_cast<integer>(memOrder::SEQ_CST));
363 return *this;
364}
365
366template <typename TYPE>
368{
369 __atomic_fetch_sub(reinterpret_cast<TYPE*>(this->data_), value, static_cast<integer>(memOrder::SEQ_CST));
370 return *this;
371}
372
373template <typename TYPE>
374TYPE original::atomicImpl<TYPE, false>::exchange(TYPE value, memOrder order) noexcept {
375 TYPE result;
376 __atomic_exchange(reinterpret_cast<TYPE*>(this->data_), &value,
377 &result, static_cast<integer>(order));
378 return result;
379}
380
381template <typename TYPE>
382bool original::atomicImpl<TYPE, false>::exchangeCmp(TYPE& expected, TYPE desired, memOrder order) noexcept
383{
384 return __atomic_compare_exchange_n(reinterpret_cast<TYPE*>(this->data_),
385 &expected, std::move(desired), false,
386 static_cast<integer>(order), static_cast<integer>(order));
387}
388
389template <typename TYPE>
391 uniqueLock lock{this->mutex_};
392 this->data_.set(value);
393}
394
395template <typename TYPE>
396constexpr bool original::atomicImpl<TYPE, true>::isLockFree() noexcept {
397 return false;
398}
399
400template <typename TYPE>
401void original::atomicImpl<TYPE, true>::store(TYPE value, memOrder) {
402 uniqueLock lock{this->mutex_};
403 this->data_.set(value);
404}
405
406template <typename TYPE>
407TYPE original::atomicImpl<TYPE, true>::load(memOrder) const noexcept {
408 uniqueLock lock{this->mutex_};
409 return *this->data_;
410}
411
412template <typename TYPE>
414{
415 return this->load();
416}
417
418template <typename TYPE>
420{
421 return this->load();
422}
423
424template <typename TYPE>
425void original::atomicImpl<TYPE, true>::operator=(TYPE value) noexcept
426{
427 this->store(std::move(value));
428}
429
430template <typename TYPE>
432{
433 uniqueLock lock{this->mutex_};
434 TYPE result = *this->data_ + value;
435 this->data_.set(result);
436 return *this;
437}
438
439template <typename TYPE>
441{
442 uniqueLock lock{this->mutex_};
443 TYPE result = *this->data_ - value;
444 this->data_.set(result);
445 return *this;
446}
447
448template <typename TYPE>
449TYPE original::atomicImpl<TYPE, true>::exchange(const TYPE& value, memOrder) noexcept {
450 uniqueLock lock{this->mutex_};
451 TYPE result = *this->data_;
452 this->data_.set(value);
453 return result;
454}
455
456template <typename TYPE>
457bool original::atomicImpl<TYPE, true>::exchangeCmp(TYPE& expected, const TYPE& desired, memOrder) noexcept {
458 uniqueLock lock{this->mutex_};
459 if (*this->data_ == expected) {
460 this->data_.set(desired);
461 return true;
462 }
463 expected = *this->data_;
464 return false;
465}
466
467template<typename TYPE>
469{
470 return atomic<TYPE>{};
471}
472
473template<typename TYPE>
474auto original::makeAtomic(TYPE value)
475{
476 return atomic<TYPE>{std::move(value)};
477}
478#endif
479#endif
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
ownerPtr & operator=(const ownerPtr &other)=delete
Copy assignment prohibited.
Platform-independent type definitions and compiler/platform detection.
std::int64_t integer
64-bit signed integer type for arithmetic operations
Definition config.h:254
Cross-platform mutex and lock management utilities.
Main namespace for the project Original.
Definition algorithms.h:21
Type-safe optional value container.