/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: auAtomic.hpp Date: 2022-2-1 Author: Reece ***/ #pragma once template struct AuAtomicUtils { /** * @brief Sets bit offset in in * @return original value */ static T Set(T *in, AuUInt8 offset); /** * @brief Adds addend to in * @return updated value */ static T Add(T *in, T addend); /** * @brief Subtracts the minuend from in * @return updated value */ static T Sub(T *in, T minuend); /** * @brief Generic bitwise compare exchange * @param replace replacement value for in if in matches compare * @param compare required reference value * @return original value */ static T CompareExchange(T *in, T replace, T compare); }; #if defined(AURORA_COMPILER_MSVC) template<> inline auline AuUInt64 AuAtomicUtils::CompareExchange(AuUInt64 *in, AuUInt64 replace, AuUInt64 compare) { return static_cast(_InterlockedCompareExchange64(reinterpret_cast(in), static_cast(replace), static_cast(compare))); } template<> inline auline AuUInt32 AuAtomicUtils::CompareExchange(AuUInt32 *in, AuUInt32 replace, AuUInt32 compare) { return static_cast(_InterlockedCompareExchange(reinterpret_cast(in), static_cast(replace), static_cast(compare))); } template<> inline auline AuUInt16 AuAtomicUtils::CompareExchange(AuUInt16 *in, AuUInt16 replace, AuUInt16 compare) { return static_cast(_InterlockedCompareExchange16(reinterpret_cast(in), static_cast(replace), static_cast(compare))); } template<> inline auline AuInt64 AuAtomicUtils::CompareExchange(AuInt64 *in, AuInt64 replace, AuInt64 compare) { return _InterlockedCompareExchange64(reinterpret_cast(in), static_cast(replace), static_cast(compare)); } template<> inline auline AuInt32 AuAtomicUtils::CompareExchange(AuInt32 *in, AuInt32 replace, AuInt32 compare) { return _InterlockedCompareExchange(reinterpret_cast(in), static_cast(replace), static_cast(compare)); } template<> inline auline AuInt16 AuAtomicUtils::CompareExchange(AuInt16 *in, AuInt16 replace, AuInt16 compare) { return _InterlockedCompareExchange16(reinterpret_cast(in), static_cast(replace), static_cast(compare)); } template<> inline auline AuUInt64 AuAtomicUtils::Add(AuUInt64 *in, AuUInt64 addend) { return static_cast(_InterlockedExchangeAdd64(reinterpret_cast(in), static_cast(addend)) + static_cast(addend)); } template<> inline auline AuUInt32 AuAtomicUtils::Add(AuUInt32 *in, AuUInt32 addend) { return static_cast(_InterlockedExchangeAdd(reinterpret_cast(in), static_cast(addend)) + static_cast(addend)); } template<> inline auline AuInt64 AuAtomicUtils::Add(AuInt64 *in, AuInt64 addend) { return _InterlockedExchangeAdd64(reinterpret_cast(in), static_cast(addend)) + static_cast(addend); } template<> inline auline AuInt32 AuAtomicUtils::Add(AuInt32 *in, AuInt32 addend) { return _InterlockedExchangeAdd(reinterpret_cast(in), static_cast(addend)) + static_cast(addend); } // TODO: #if 0 template<> inline auline AuUInt16 AuAtomicUtils::Add(AuUInt16 *in, AuUInt16 addend) { return {}; } #endif template<> inline auline AuUInt64 AuAtomicUtils::Sub(AuUInt64 *in, AuUInt64 minuend) { return Add(in, AuUInt64(0) - minuend); } template<> inline auline AuUInt32 AuAtomicUtils::Sub(AuUInt32 *in, AuUInt32 minuend) { return Add(in, AuUInt32(0) - minuend); } // TODO: #if 0 template<> inline auline AuUInt16 AuAtomicUtils::Sub(AuUInt16 *in, AuUInt16 minuend) { return {}; } #endif template<> inline auline AuUInt64 AuAtomicUtils::Set(AuUInt64 *in, AuUInt8 offset) { return _InterlockedOr64(reinterpret_cast(in), AuUInt64(1) << offset); } template<> inline auline AuUInt32 AuAtomicUtils::Set(AuUInt32 *in, AuUInt8 offset) { return _InterlockedOr(reinterpret_cast(in), 1 << offset); } template<> inline auline AuUInt16 AuAtomicUtils::Set(AuUInt16 *in, AuUInt8 offset) { return _InterlockedOr16(reinterpret_cast(in), 1 << offset); } template<> inline auline AuInt64 AuAtomicUtils::Set(AuInt64 *in, AuUInt8 offset) { return _InterlockedOr64(reinterpret_cast(in), AuUInt64(1) << offset); } template<> inline auline AuInt32 AuAtomicUtils::Set(AuInt32 *in, AuUInt8 offset) { return _InterlockedOr(reinterpret_cast(in), 1 << offset); } template<> inline auline long AuAtomicUtils::Set(long *in, AuUInt8 offset) { return _InterlockedOr(reinterpret_cast(in), 1 << offset); } template<> inline auline unsigned long AuAtomicUtils::Set(unsigned long *in, AuUInt8 offset) { return _InterlockedOr(reinterpret_cast(in), 1 << offset); } template<> inline auline AuInt16 AuAtomicUtils::Set(AuInt16 *in, AuUInt8 offset) { return _InterlockedOr16(reinterpret_cast(in), 1 << offset); } #elif defined(AURORA_COMPILER_CLANG) || defined(AURORA_COMPILER_GCC) template inline auline T AuAtomicUtils::CompareExchange(T *in, T replace, T compare) { return __sync_val_compare_and_swap(in, compare, replace); } template inline auline T AuAtomicUtils::Add(T *in, T addend) { return __sync_add_and_fetch(in, addend); } template inline auline T AuAtomicUtils::Sub(T *in, T minuend) { return __sync_sub_and_fetch(in, minuend); } template inline auline T AuAtomicUtils::Set(T *in, AuUInt8 offset) { return __sync_fetch_and_or(in, T(1) << offset); } #endif template auline T AuAtomicSet(T *in, AuUInt8 offset) { return AuAtomicUtils::Set(in, offset); } template auline T AuAtomicAdd(T *in, T addend) { return AuAtomicUtils::Add(in, addend); } template auline T AuAtomicSub(T *in, T minuend) { return AuAtomicUtils::Sub(in, minuend); } template auline T AuAtomicCompareExchange(T *in, T replace, T compare) { return AuAtomicUtils::CompareExchange(in, replace, compare); }