/*** 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 Generic bitwise (1 << offset) * @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 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); /** * @brief { return *in & (1 << offset); in |= (1 << offset) } * @param in * @param offset Bit index * @return *in & (1 << offset) */ static bool TestAndSet(T *in, const AuUInt8 offset); }; #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)); } #if !defined(AURORA_IS_32BIT) template<> inline auline AuUInt64 AuAtomicUtils::Add(AuUInt64 *in, AuUInt64 addend) { return static_cast(_InterlockedExchangeAdd64(reinterpret_cast(in), static_cast(addend)) + static_cast(addend)); } #endif template<> inline auline AuUInt32 AuAtomicUtils::Add(AuUInt32 *in, AuUInt32 addend) { return static_cast(_InterlockedExchangeAdd(reinterpret_cast(in), static_cast(addend)) + static_cast(addend)); } #if !defined(AURORA_IS_32BIT) template<> inline auline AuInt64 AuAtomicUtils::Add(AuInt64 *in, AuInt64 addend) { return _InterlockedExchangeAdd64(reinterpret_cast(in), static_cast(addend)) + static_cast(addend); } #endif 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 #if !defined(AURORA_IS_32BIT) template<> inline auline AuUInt64 AuAtomicUtils::Set(AuUInt64 *in, AuUInt8 offset) { return _InterlockedOr64(reinterpret_cast(in), AuUInt64(1) << offset); } #endif 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); } #if !defined(AURORA_IS_32BIT) template<> inline auline AuInt64 AuAtomicUtils::Set(AuInt64 *in, AuUInt8 offset) { return _InterlockedOr64(reinterpret_cast(in), AuUInt64(1) << offset); } #endif 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 inline auline bool AuAtomicUtils::TestAndSet(T *in, const AuUInt8 offset) { return AuAtomicUtils::Set(in, offset) & (1 << offset); } #if defined(AURORA_COMPILER_MSVC) && (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)) template<> inline auline bool AuAtomicUtils::TestAndSet(unsigned long *in, const AuUInt8 offset) { return _interlockedbittestandset(reinterpret_cast(in), offset); } template<> inline auline bool AuAtomicUtils::TestAndSet(long *in, const AuUInt8 offset) { return _interlockedbittestandset(reinterpret_cast(in), offset); } template<> inline auline bool AuAtomicUtils::TestAndSet(AuUInt32 *in, const AuUInt8 offset) { return _interlockedbittestandset(reinterpret_cast(in), offset); } template<> inline auline bool AuAtomicUtils::TestAndSet(AuInt32 *in, const AuUInt8 offset) { return _interlockedbittestandset(reinterpret_cast(in), offset); } #if !defined(AURORA_IS_32BIT) template<> inline auline bool AuAtomicUtils::TestAndSet(AuUInt64 *in, const AuUInt8 offset) { return _interlockedbittestandset64(reinterpret_cast(in), offset); } template<> inline auline bool AuAtomicUtils::TestAndSet(AuInt64 *in, const AuUInt8 offset) { return _interlockedbittestandset64(reinterpret_cast(in), offset); } #endif #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); } template auline bool AuAtomicTestAndSet(T *in, AuUInt8 offset) { return AuAtomicUtils::TestAndSet(in, offset); }