1#ifndef ORIGINAL_ATOMIC_H
2#define ORIGINAL_ATOMIC_H
11#ifdef ORIGINAL_COMPILER_GCC
26 RELAXED = __ATOMIC_RELAXED,
27 ACQUIRE = __ATOMIC_ACQUIRE,
28 RELEASE = __ATOMIC_RELEASE,
29 ACQ_REL = __ATOMIC_ACQ_REL,
30 SEQ_CST = __ATOMIC_SEQ_CST,
35 template<
typename TYPE,
bool USE_LOCK>
46 template<
typename TYPE>
47 using atomic = atomicImpl<
49 !( std::is_trivially_copyable_v<TYPE> &&
50 std::is_trivially_destructible_v<TYPE> &&
51 __atomic_always_lock_free(
sizeof(TYPE),
nullptr) )
63 template<
typename TYPE>
64 class atomicImpl<TYPE, false> {
65 alignas(TYPE)
byte data_[
sizeof(TYPE)];
77 explicit atomicImpl(TYPE value, memOrder order = SEQ_CST);
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;
88 atomicImpl(
const atomicImpl&) =
delete;
89 atomicImpl(atomicImpl&&) =
delete;
90 atomicImpl& operator=(
const atomicImpl&) =
delete;
91 atomicImpl& operator=(atomicImpl&&) =
delete;
97 static constexpr bool isLockFree() noexcept;
104 void store(TYPE value, memOrder order = SEQ_CST);
111 TYPE load(memOrder order = SEQ_CST) const noexcept;
117 TYPE operator*() const noexcept;
123 explicit operator TYPE() const noexcept;
129 void operator=(TYPE value) noexcept;
136 atomicImpl& operator+=(TYPE value) noexcept;
143 atomicImpl& operator-=(TYPE value) noexcept;
151 TYPE exchange(TYPE value, memOrder order = SEQ_CST) noexcept;
160 bool exchangeCmp(TYPE& expected, TYPE desired, memOrder order = SEQ_CST) noexcept;
163 ~atomicImpl() = default;
167 friend auto makeAtomic();
170 friend auto makeAtomic(T value);
182 template<typename TYPE>
183 class atomicImpl<TYPE, true> {
184 mutable pMutex mutex_;
185 alternative<TYPE> data_;
190 atomicImpl() =
default;
197 explicit atomicImpl(TYPE value, memOrder order = RELEASE);
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;
208 atomicImpl(
const atomicImpl&) =
delete;
209 atomicImpl(atomicImpl&&) =
delete;
210 atomicImpl& operator=(
const atomicImpl&) =
delete;
211 atomicImpl& operator=(atomicImpl&&) =
delete;
217 static constexpr bool isLockFree() noexcept;
224 void store(TYPE value, memOrder order = SEQ_CST);
231 TYPE load(memOrder order = SEQ_CST) const noexcept;
237 TYPE operator*() const noexcept;
243 explicit operator TYPE() const noexcept;
249 void operator=(TYPE value) noexcept;
256 atomicImpl& operator+=(TYPE value) noexcept;
263 atomicImpl& operator-=(TYPE value) noexcept;
271 TYPE exchange(const TYPE& value, memOrder order = SEQ_CST) noexcept;
280 bool exchangeCmp(TYPE& expected, const TYPE& desired, memOrder order = SEQ_CST) noexcept;
283 ~atomicImpl() = default;
287 friend auto makeAtomic();
290 friend auto makeAtomic(T value);
300 template<typename TYPE>
309 template<typename TYPE>
310 auto makeAtomic(TYPE value);
314template <typename TYPE>
315original::atomicImpl<TYPE, false>::atomicImpl() {
316 std::memset(this->data_,
byte{},
sizeof(TYPE));
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));
324template <
typename TYPE>
325constexpr bool original::atomicImpl<TYPE, false>::isLockFree() noexcept {
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));
334template <
typename TYPE>
335TYPE original::atomicImpl<TYPE, false>::load(memOrder order)
const noexcept {
337 __atomic_load(
reinterpret_cast<const TYPE*
>(this->data_), &result,
static_cast<integer>(order));
341template <
typename TYPE>
342TYPE original::atomicImpl<TYPE, false>::operator*() const noexcept
347template <
typename TYPE>
348original::atomicImpl<TYPE, false>::operator TYPE() const noexcept
353template <
typename TYPE>
354void original::atomicImpl<TYPE, false>::operator=(TYPE value)
noexcept
356 this->store(std::move(value));
359template <
typename TYPE>
360original::atomicImpl<TYPE, false>& original::atomicImpl<TYPE, false>::operator+=(TYPE value)
noexcept
362 __atomic_fetch_add(
reinterpret_cast<TYPE*
>(this->data_), value,
static_cast<integer>(memOrder::SEQ_CST));
366template <
typename TYPE>
367original::atomicImpl<TYPE, false>& original::atomicImpl<TYPE, false>::operator-=(TYPE value)
noexcept
369 __atomic_fetch_sub(
reinterpret_cast<TYPE*
>(this->data_), value,
static_cast<integer>(memOrder::SEQ_CST));
373template <
typename TYPE>
374TYPE original::atomicImpl<TYPE, false>::exchange(TYPE value, memOrder order)
noexcept {
376 __atomic_exchange(
reinterpret_cast<TYPE*
>(this->data_), &value,
377 &result,
static_cast<integer>(order));
381template <
typename TYPE>
382bool original::atomicImpl<TYPE, false>::exchangeCmp(TYPE& expected, TYPE desired, memOrder order)
noexcept
384 return __atomic_compare_exchange_n(
reinterpret_cast<TYPE*
>(this->data_),
385 &expected, std::move(desired),
false,
389template <
typename TYPE>
390original::atomicImpl<TYPE, true>::atomicImpl(TYPE value, memOrder) {
391 uniqueLock lock{this->mutex_};
392 this->data_.set(value);
395template <
typename TYPE>
396constexpr bool original::atomicImpl<TYPE, true>::isLockFree() noexcept {
400template <
typename TYPE>
401void original::atomicImpl<TYPE, true>::store(TYPE value, memOrder) {
402 uniqueLock lock{this->mutex_};
403 this->data_.set(value);
406template <
typename TYPE>
407TYPE original::atomicImpl<TYPE, true>::load(memOrder)
const noexcept {
408 uniqueLock lock{this->mutex_};
412template <
typename TYPE>
413TYPE original::atomicImpl<TYPE, true>::operator*() const noexcept
418template <
typename TYPE>
419original::atomicImpl<TYPE, true>::operator TYPE() const noexcept
424template <
typename TYPE>
425void original::atomicImpl<TYPE, true>::operator=(TYPE value)
noexcept
427 this->store(std::move(value));
430template <
typename TYPE>
431original::atomicImpl<TYPE, true>& original::atomicImpl<TYPE, true>::operator+=(TYPE value)
noexcept
433 uniqueLock lock{this->mutex_};
434 TYPE result = *this->data_ + value;
435 this->data_.set(result);
439template <
typename TYPE>
440original::atomicImpl<TYPE, true>& original::atomicImpl<TYPE, true>::operator-=(TYPE value)
noexcept
442 uniqueLock lock{this->mutex_};
443 TYPE result = *this->data_ - value;
444 this->data_.set(result);
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);
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);
463 expected = *this->data_;
467template<
typename TYPE>
468auto original::makeAtomic()
470 return atomic<TYPE>{};
473template<
typename TYPE>
474auto original::makeAtomic(TYPE value)
476 return atomic<TYPE>{std::move(value)};
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.