2022-04-01 04:06:53 +00:00
|
|
|
/***
|
|
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
|
|
|
|
File: auAtomic.hpp
|
|
|
|
Date: 2022-2-1
|
|
|
|
Author: Reece
|
|
|
|
***/
|
|
|
|
#pragma once
|
|
|
|
|
2023-08-23 19:02:09 +00:00
|
|
|
#if defined(AURORA_COMPILER_CLANG)
|
|
|
|
#include <stdatomic.h>
|
|
|
|
#endif
|
|
|
|
|
2023-08-28 14:25:46 +00:00
|
|
|
// Defines:
|
|
|
|
// AuAtomicCompareExchange (no weak variants yet)
|
|
|
|
// -
|
|
|
|
// AuAtomicTestAndSet
|
|
|
|
// AuAtomicClearU8Lock
|
|
|
|
// AuAtomicSet
|
|
|
|
// AuAtomicUnset (ret: bool)
|
|
|
|
// AuAtomicAndUnsetBit (ret: T)
|
|
|
|
// -
|
|
|
|
// AuAtomicLoadWeak (tbd)
|
|
|
|
// (no weak store) (tbd)
|
|
|
|
// -
|
|
|
|
// AuAtomicLoad
|
|
|
|
// AuAtomicStore
|
|
|
|
// -
|
|
|
|
// AuAtomicOrSetBit
|
|
|
|
// AuAtomicOr
|
|
|
|
// AuAtomicAnd
|
|
|
|
// AuAtomicAdd
|
|
|
|
// AuAtomicSub
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
template <class T>
|
|
|
|
struct AuAtomicUtils
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @brief Generic bitwise (1 << offset)
|
|
|
|
* @return original value
|
|
|
|
* @warning T is bound by platform and compiler constraints
|
|
|
|
*/
|
|
|
|
static T Set(T *in, AuUInt8 offset);
|
|
|
|
|
2022-09-27 15:37:42 +00:00
|
|
|
/**
|
2023-03-22 21:21:47 +00:00
|
|
|
* @brief
|
|
|
|
* @param in
|
|
|
|
* @param orValue
|
|
|
|
* @return original value
|
2022-09-27 15:37:42 +00:00
|
|
|
*/
|
|
|
|
static T Or(T *in, T orValue);
|
|
|
|
|
2023-03-22 21:21:47 +00:00
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
* @param in
|
|
|
|
* @param andValue
|
|
|
|
* @return original value
|
|
|
|
*/
|
|
|
|
static T And(T *in, T andValue);
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
/**
|
|
|
|
* @brief Adds addend to in
|
|
|
|
* @return updated value
|
|
|
|
* @warning T is bound by platform and compiler constraints
|
|
|
|
*/
|
|
|
|
static T Add(T *in, T addend);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Subtracts the minuend from in
|
|
|
|
* @return updated value
|
|
|
|
* @warning T is bound by platform and compiler constraints
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
* @warning T is bound by platform and compiler constraints
|
|
|
|
*/
|
|
|
|
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)
|
|
|
|
* @warning T is bound by platform and compiler constraints
|
|
|
|
*/
|
|
|
|
static bool TestAndSet(T *in, const AuUInt8 offset);
|
2023-08-23 19:02:09 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
static T Load(T *in);
|
|
|
|
|
|
|
|
//
|
|
|
|
static void Store(T *in, T value);
|
|
|
|
|
|
|
|
//
|
|
|
|
static void ClearU8Lock(T *in);
|
2023-08-28 14:25:46 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
static T LoadWeak(T *in);
|
2022-04-01 04:06:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#if defined(AURORA_COMPILER_MSVC)
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt64 AuAtomicUtils<AuUInt64>::CompareExchange(AuUInt64 *in, AuUInt64 replace, AuUInt64 compare)
|
|
|
|
{
|
|
|
|
return static_cast<AuUInt64>(_InterlockedCompareExchange64(reinterpret_cast<long long volatile *>(in), static_cast<long long>(replace), static_cast<long long>(compare)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt32 AuAtomicUtils<AuUInt32>::CompareExchange(AuUInt32 *in, AuUInt32 replace, AuUInt32 compare)
|
|
|
|
{
|
|
|
|
return static_cast<AuUInt32>(_InterlockedCompareExchange(reinterpret_cast<long volatile *>(in), static_cast<long>(replace), static_cast<long>(compare)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt16 AuAtomicUtils<AuUInt16>::CompareExchange(AuUInt16 *in, AuUInt16 replace, AuUInt16 compare)
|
|
|
|
{
|
|
|
|
return static_cast<AuUInt16>(_InterlockedCompareExchange16(reinterpret_cast<short volatile *>(in), static_cast<short>(replace), static_cast<short>(compare)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt64 AuAtomicUtils<AuInt64>::CompareExchange(AuInt64 *in, AuInt64 replace, AuInt64 compare)
|
|
|
|
{
|
|
|
|
return _InterlockedCompareExchange64(reinterpret_cast<long long volatile *>(in), static_cast<long long>(replace), static_cast<long long>(compare));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt32 AuAtomicUtils<AuInt32>::CompareExchange(AuInt32 *in, AuInt32 replace, AuInt32 compare)
|
|
|
|
{
|
|
|
|
return _InterlockedCompareExchange(reinterpret_cast<long volatile *>(in), static_cast<long>(replace), static_cast<long>(compare));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt16 AuAtomicUtils<AuInt16>::CompareExchange(AuInt16 *in, AuInt16 replace, AuInt16 compare)
|
|
|
|
{
|
|
|
|
return _InterlockedCompareExchange16(reinterpret_cast<short volatile *>(in), static_cast<short>(replace), static_cast<short>(compare));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt64 AuAtomicUtils<AuUInt64>::Add(AuUInt64 *in, AuUInt64 addend)
|
|
|
|
{
|
|
|
|
return static_cast<AuUInt64>(_InterlockedExchangeAdd64(reinterpret_cast<long long volatile *>(in), static_cast<long long>(addend)) + static_cast<long long>(addend));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt32 AuAtomicUtils<AuUInt32>::Add(AuUInt32 *in, AuUInt32 addend)
|
|
|
|
{
|
|
|
|
return static_cast<AuUInt32>(_InterlockedExchangeAdd(reinterpret_cast<long volatile *>(in), static_cast<long>(addend)) + static_cast<long>(addend));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
|
|
|
inline auline AuInt64 AuAtomicUtils<AuInt64>::Add(AuInt64 *in, AuInt64 addend)
|
|
|
|
{
|
|
|
|
return _InterlockedExchangeAdd64(reinterpret_cast<long long volatile *>(in), static_cast<long long>(addend)) + static_cast<long long>(addend);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt32 AuAtomicUtils<AuInt32>::Add(AuInt32 *in, AuInt32 addend)
|
|
|
|
{
|
|
|
|
return _InterlockedExchangeAdd(reinterpret_cast<long volatile *>(in), static_cast<long>(addend)) + static_cast<long>(addend);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
#if 0
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt16 AuAtomicUtils<AuUInt16>::Add(AuUInt16 *in, AuUInt16 addend)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt64 AuAtomicUtils<AuUInt64>::Sub(AuUInt64 *in, AuUInt64 minuend)
|
|
|
|
{
|
|
|
|
return Add(in, AuUInt64(0) - minuend);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt32 AuAtomicUtils<AuUInt32>::Sub(AuUInt32 *in, AuUInt32 minuend)
|
|
|
|
{
|
|
|
|
return Add(in, AuUInt32(0) - minuend);
|
|
|
|
}
|
|
|
|
|
2022-11-17 23:26:48 +00:00
|
|
|
template <>
|
|
|
|
inline auline AuInt64 AuAtomicUtils<AuInt64>::Sub(AuInt64 *in, AuInt64 minuend)
|
|
|
|
{
|
|
|
|
return Add(in, AuInt64(0) - minuend);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt32 AuAtomicUtils<AuInt32>::Sub(AuInt32 *in, AuInt32 minuend)
|
|
|
|
{
|
|
|
|
return Add(in, AuInt32(0) - minuend);
|
|
|
|
}
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
// TODO:
|
|
|
|
#if 0
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt16 AuAtomicUtils<AuUInt16>::Sub(AuUInt16 *in, AuUInt16 minuend)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline AuUInt64 AuAtomicUtils<AuUInt64>::Or(AuUInt64 *in, AuUInt64 orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr64(reinterpret_cast<long long volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline AuUInt32 AuAtomicUtils<AuUInt32>::Or(AuUInt32 *in, AuUInt32 orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr(reinterpret_cast<long volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline AuUInt16 AuAtomicUtils<AuUInt16>::Or(AuUInt16 *in, AuUInt16 orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr16(reinterpret_cast<short volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline AuInt64 AuAtomicUtils<AuInt64>::Or(AuInt64 *in, AuInt64 orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr64(reinterpret_cast<long long volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline AuInt32 AuAtomicUtils<AuInt32>::Or(AuInt32 *in, AuInt32 orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr(reinterpret_cast<long volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline long AuAtomicUtils<long>::Or(long *in, long orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr(reinterpret_cast<long volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline unsigned long AuAtomicUtils<unsigned long>::Or(unsigned long *in, unsigned long orValue)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return _InterlockedOr(reinterpret_cast<long volatile *>(in), orValue);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
2022-09-27 15:37:42 +00:00
|
|
|
inline auline AuInt16 AuAtomicUtils<AuInt16>::Or(AuInt16 *in, AuInt16 orValue)
|
|
|
|
{
|
|
|
|
return _InterlockedOr16(reinterpret_cast<short volatile *>(in), orValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::Set(T *in, AuUInt8 offset)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-09-27 15:37:42 +00:00
|
|
|
return AuAtomicUtils<T>::Or(in, T(1) << offset);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-22 21:21:47 +00:00
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt64 AuAtomicUtils<AuUInt64>::And(AuUInt64 *in, AuUInt64 AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd64(reinterpret_cast<long long volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt32 AuAtomicUtils<AuUInt32>::And(AuUInt32 *in, AuUInt32 AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd(reinterpret_cast<long volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuUInt16 AuAtomicUtils<AuUInt16>::And(AuUInt16 *in, AuUInt16 AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd16(reinterpret_cast<short volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
|
|
|
inline auline AuInt64 AuAtomicUtils<AuInt64>::And(AuInt64 *in, AuInt64 AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd64(reinterpret_cast<long long volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt32 AuAtomicUtils<AuInt32>::And(AuInt32 *in, AuInt32 AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd(reinterpret_cast<long volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline long AuAtomicUtils<long>::And(long *in, long AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd(reinterpret_cast<long volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline unsigned long AuAtomicUtils<unsigned long>::And(unsigned long *in, unsigned long AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd(reinterpret_cast<long volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline AuInt16 AuAtomicUtils<AuInt16>::And(AuInt16 *in, AuInt16 AndValue)
|
|
|
|
{
|
|
|
|
return _InterlockedAnd16(reinterpret_cast<short volatile *>(in), AndValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
#elif defined(AURORA_COMPILER_CLANG) || defined(AURORA_COMPILER_GCC)
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::CompareExchange(T *in, T replace, T compare)
|
|
|
|
{
|
|
|
|
return __sync_val_compare_and_swap(in, compare, replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::Add(T *in, T addend)
|
|
|
|
{
|
|
|
|
return __sync_add_and_fetch(in, addend);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::Sub(T *in, T minuend)
|
|
|
|
{
|
|
|
|
return __sync_sub_and_fetch(in, minuend);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::Set(T *in, AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return __sync_fetch_and_or(in, T(1) << offset);
|
|
|
|
}
|
|
|
|
|
2022-09-27 15:37:42 +00:00
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::Or(T *in, T value)
|
|
|
|
{
|
|
|
|
return __sync_fetch_and_or(in, value);
|
|
|
|
}
|
|
|
|
|
2023-03-22 21:21:47 +00:00
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::And(T *in, T value)
|
|
|
|
{
|
|
|
|
return __sync_fetch_and_and(in, value);
|
|
|
|
}
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
#endif
|
|
|
|
|
2023-08-28 14:25:46 +00:00
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::LoadWeak(T *in)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::Load(in);
|
|
|
|
}
|
|
|
|
|
2023-08-23 19:02:09 +00:00
|
|
|
#if defined(AURORA_COMPILER_CLANG)
|
|
|
|
#define ATOMIC_PREFIX_HAX(name) __c11_ ## name
|
|
|
|
#else
|
|
|
|
#define ATOMIC_PREFIX_HAX(name) __ ## name ## _explicit
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline T AuAtomicUtils<T>::Load(T *in)
|
|
|
|
{
|
|
|
|
#if defined(AURORA_COMPILER_MSVC) && (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
2023-08-24 20:49:26 +00:00
|
|
|
::_ReadWriteBarrier(); // compile-time only! we use this to prevent optimizations. x86/64 does not care so long as we're aligned.
|
2023-08-23 19:02:09 +00:00
|
|
|
return *in;
|
|
|
|
#elif defined(AURORA_COMPILER_MSVC)
|
2023-08-24 20:49:26 +00:00
|
|
|
::MemoryBarrier(); // works on all legacy MSVC targets including AMD64, IA64, and POWER
|
2023-08-23 19:02:09 +00:00
|
|
|
return *in;
|
|
|
|
#else
|
2023-08-24 20:49:26 +00:00
|
|
|
|
|
|
|
#if defined(AURORA_COMPILER_CLANG)
|
|
|
|
#if !(defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
|
|
|
__sync_synchronize(); // brute force on unknown archs. gcc-like compilers will accept this
|
|
|
|
#endif
|
2023-08-23 19:02:09 +00:00
|
|
|
if constexpr (AuIsSame_v<AuUInt8, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_uint_fast8_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt8, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_int_fast8_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt16, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_uint_fast16_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt16, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_int_fast16_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt32, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_uint_fast32_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt32, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_int_fast32_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
2023-08-28 14:25:46 +00:00
|
|
|
else if constexpr (AuIsSame_v<AuUInt64, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_uint_fast64_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt64, T>)
|
|
|
|
{
|
|
|
|
return ATOMIC_PREFIX_HAX(atomic_load)((atomic_int_fast64_t *)in, __ATOMIC_ACQUIRE);
|
|
|
|
}
|
2023-08-23 19:02:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
static_assert(AuIsVoid_v<T>, "T");
|
|
|
|
}
|
2023-08-24 20:49:26 +00:00
|
|
|
#else
|
|
|
|
return __sync_val_compare_and_swap(*in, 0, 0);
|
|
|
|
#endif
|
|
|
|
#endif
|
2023-08-23 19:02:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline auline void AuAtomicUtils<T>::Store(T *in, T val)
|
|
|
|
{
|
|
|
|
#if defined(AURORA_COMPILER_MSVC) && (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
|
|
|
*in = val;
|
|
|
|
#elif defined(AURORA_COMPILER_MSVC)
|
2023-08-28 14:25:46 +00:00
|
|
|
#if 0
|
|
|
|
* in = val;
|
2023-08-24 20:49:26 +00:00
|
|
|
::MemoryBarrier();
|
2023-08-28 14:25:46 +00:00
|
|
|
#else
|
|
|
|
if constexpr (AuIsSame_v<AuUInt8, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange8((CHAR volatile *)in, (CHAR)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt8, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange8((CHAR volatile *)in, (CHAR)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt16, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange16((SHORT volatile *)in, (SHORT)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt16, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange16((SHORT volatile *)in, (SHORT)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt32, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange32((LONG32 volatile *)in, (LONG32)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt32, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange32((LONG32 volatile *)in, (LONG32)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt64, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange64((LONG64 volatile *)in, (LONG64)val);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt64, T>)
|
|
|
|
{
|
|
|
|
::InterlockedExchange64((LONG64 volatile *)in, (LONG64)val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
static_assert(AuIsVoid_v<T>, "T");
|
|
|
|
}
|
|
|
|
#endif
|
2023-08-23 19:02:09 +00:00
|
|
|
#else
|
|
|
|
if constexpr (AuIsSame_v<AuUInt8, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_uint_fast8_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt8, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_int_fast8_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt16, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_uint_fast16_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt16, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_int_fast16_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuUInt32, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_uint_fast32_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt32, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_int_fast32_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
2023-08-28 14:25:46 +00:00
|
|
|
else if constexpr (AuIsSame_v<AuUInt64, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_uint_fast64_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
|
|
|
else if constexpr (AuIsSame_v<AuInt64, T>)
|
|
|
|
{
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_int_fast64_t *)in, val, __ATOMIC_RELEASE);
|
|
|
|
}
|
2023-08-23 19:02:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
static_assert(AuIsVoid_v<T>, "T");
|
|
|
|
}
|
2023-08-24 20:49:26 +00:00
|
|
|
#if !(defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
|
|
|
__sync_synchronize();
|
|
|
|
#endif
|
2023-08-23 19:02:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline
|
|
|
|
void AuAtomicUtils<AuUInt8>::ClearU8Lock(AuUInt8 *in)
|
|
|
|
{
|
|
|
|
#if defined(AURORA_COMPILER_MSVC) && (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
|
|
|
*in = 0;
|
|
|
|
::_ReadWriteBarrier();
|
|
|
|
#elif defined(AURORA_COMPILER_MSVC)
|
2023-08-24 20:49:26 +00:00
|
|
|
// i think this will work on aarch64 and most risc architectures
|
2023-08-23 19:02:09 +00:00
|
|
|
InterlockedAndRelease((volatile LONG *)in, ~0xFF);
|
|
|
|
#else
|
|
|
|
ATOMIC_PREFIX_HAX(atomic_store)((atomic_uint_fast8_t *)in, 0, __ATOMIC_RELEASE);
|
2023-08-24 20:49:26 +00:00
|
|
|
#if !(defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
|
|
|
__sync_synchronize();
|
|
|
|
#endif
|
2023-08-23 19:02:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline
|
|
|
|
void AuAtomicUtils<AuUInt32>::ClearU8Lock(AuUInt32 *in)
|
|
|
|
{
|
|
|
|
#if defined(AU_CPU_ENDIAN_LITTLE)
|
|
|
|
AuAtomicUtils<AuUInt8>::ClearU8Lock((AuUInt8 *)in);
|
|
|
|
#else
|
|
|
|
AuAtomicUtils<AuUInt8>::ClearU8Lock(((AuUInt8 *)in) + 3);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
template <class T>
|
|
|
|
inline auline bool AuAtomicUtils<T>::TestAndSet(T *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::Set(in, offset) & (1 << offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(AURORA_COMPILER_MSVC) && (defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86))
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline bool AuAtomicUtils<unsigned long>::TestAndSet(unsigned long *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return _interlockedbittestandset(reinterpret_cast<volatile long *>(in), offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline bool AuAtomicUtils<long>::TestAndSet(long *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return _interlockedbittestandset(reinterpret_cast<volatile long *>(in), offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline bool AuAtomicUtils<AuUInt32>::TestAndSet(AuUInt32 *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return _interlockedbittestandset(reinterpret_cast<volatile long *>(in), offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline bool AuAtomicUtils<AuInt32>::TestAndSet(AuInt32 *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return _interlockedbittestandset(reinterpret_cast<volatile long *>(in), offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(AURORA_IS_32BIT)
|
|
|
|
template <>
|
|
|
|
inline auline bool AuAtomicUtils<AuUInt64>::TestAndSet(AuUInt64 *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return _interlockedbittestandset64(reinterpret_cast<volatile long long *>(in), offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline auline bool AuAtomicUtils<AuInt64>::TestAndSet(AuInt64 *in, const AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return _interlockedbittestandset64(reinterpret_cast<volatile long long *>(in), offset);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2023-08-23 19:02:09 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
void AuAtomicStore(T *in, T value)
|
|
|
|
{
|
|
|
|
AuAtomicUtils<T>::Store(in, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicLoad(T *in)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::Load(in);
|
|
|
|
}
|
|
|
|
|
2023-08-28 14:25:46 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicLoadWeak(T *in)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::LoadWeak(in);
|
|
|
|
}
|
|
|
|
|
2023-08-23 19:02:09 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
void AuAtomicClearU8Lock(T *in)
|
|
|
|
{
|
|
|
|
AuAtomicUtils<T>::ClearU8Lock(in);
|
|
|
|
}
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
template <class T>
|
2022-09-27 15:37:42 +00:00
|
|
|
auline
|
2023-03-27 04:44:29 +00:00
|
|
|
T AuAtomicOrSetBit(T *in, AuUInt8 offset)
|
2022-04-01 04:06:53 +00:00
|
|
|
{
|
2022-11-17 23:26:48 +00:00
|
|
|
return AuAtomicUtils<T>::Set(in, offset);
|
2022-09-27 15:37:42 +00:00
|
|
|
}
|
|
|
|
|
2023-03-27 04:44:29 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
bool AuAtomicSet(T *in, AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return AuAtomicOrSetBit(in, offset) & (T(1) << offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicAndUnsetBit(T *in, AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::And(in, ~(T(1) << T(offset)));
|
|
|
|
}
|
|
|
|
|
2023-03-22 21:21:47 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
bool AuAtomicUnset(T *in, AuUInt8 offset)
|
|
|
|
{
|
2023-03-27 04:44:29 +00:00
|
|
|
auto uBit = T(1) << T(offset);
|
|
|
|
return AuAtomicUtils<T>::And(in, ~(uBit)) & uBit;
|
2023-03-22 21:21:47 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 15:37:42 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicOr(T *in, T value)
|
|
|
|
{
|
2022-11-17 23:26:48 +00:00
|
|
|
return AuAtomicUtils<T>::Or(in, value);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-22 21:21:47 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicAnd(T *in, T value)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::And(in, value);
|
|
|
|
}
|
|
|
|
|
2022-04-01 04:06:53 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicAdd(T *in, T addend)
|
|
|
|
{
|
2022-11-17 23:26:48 +00:00
|
|
|
return AuAtomicUtils<T>::Add(in, addend);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicSub(T *in, T minuend)
|
|
|
|
{
|
2022-11-17 23:26:48 +00:00
|
|
|
return AuAtomicUtils<T>::Sub(in, minuend);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicCompareExchange(T *in, T replace, T compare)
|
|
|
|
{
|
2022-11-17 23:26:48 +00:00
|
|
|
return AuAtomicUtils<T>::CompareExchange(in, replace, compare);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
bool AuAtomicTestAndSet(T *in, AuUInt8 offset)
|
|
|
|
{
|
2022-11-17 23:26:48 +00:00
|
|
|
return AuAtomicUtils<T>::TestAndSet(in, offset);
|
|
|
|
}
|
|
|
|
|
2023-08-23 19:02:09 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
void AuAtomicStore(volatile T *in, T value)
|
|
|
|
{
|
|
|
|
AuAtomicUtils<T>::Store((T *)in, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicLoad(volatile T *in)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::Load((T *)in);
|
|
|
|
}
|
|
|
|
|
2023-08-28 14:25:46 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicLoadWeak(volatile T *in)
|
|
|
|
{
|
|
|
|
return AuAtomicUtils<T>::LoadWeak((T *)in);
|
|
|
|
}
|
|
|
|
|
2023-08-23 19:02:09 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
void AuAtomicClearU8Lock(volatile T *in)
|
|
|
|
{
|
|
|
|
AuAtomicUtils<T>::ClearU8Lock((T *)in);
|
|
|
|
}
|
|
|
|
|
2022-11-17 23:26:48 +00:00
|
|
|
template <class T>
|
|
|
|
auline
|
2023-04-01 05:44:37 +00:00
|
|
|
T AuAtomicOrSetBit(volatile T *in, AuUInt8 offset)
|
2022-11-17 23:26:48 +00:00
|
|
|
{
|
2023-04-01 05:44:37 +00:00
|
|
|
return AuAtomicOrSetBit((T *)in, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
bool AuAtomicSet(volatile T *in, AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return AuAtomicSet((T *)in, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicAndUnsetBit(volatile T *in, AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return AuAtomicAndUnsetBit((T *)in, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
bool AuAtomicUnset(volatile T *in, AuUInt8 offset)
|
|
|
|
{
|
|
|
|
return AuAtomicUnset((T *)in, offset);
|
2022-11-17 23:26:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicOr(volatile T *in, T value)
|
|
|
|
{
|
2023-04-01 05:44:37 +00:00
|
|
|
return AuAtomicOr((T *)in, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicAnd(volatile T *in, T value)
|
|
|
|
{
|
|
|
|
return AuAtomicAnd((T *)in, value);
|
2022-11-17 23:26:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicAdd(volatile T *in, T addend)
|
|
|
|
{
|
2023-03-11 14:24:48 +00:00
|
|
|
return AuAtomicUtils<T>::Add((T *)(in), addend);
|
2022-11-17 23:26:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicSub(volatile T *in, T minuend)
|
|
|
|
{
|
2023-03-11 14:24:48 +00:00
|
|
|
return AuAtomicUtils<T>::Sub((T *)(in), minuend);
|
2022-11-17 23:26:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
T AuAtomicCompareExchange(volatile T *in, T replace, T compare)
|
|
|
|
{
|
2023-03-11 14:24:48 +00:00
|
|
|
return AuAtomicUtils<T>::CompareExchange((T *)(in), replace, compare);
|
2022-11-17 23:26:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
auline
|
|
|
|
bool AuAtomicTestAndSet(volatile T *in, AuUInt8 offset)
|
|
|
|
{
|
2023-03-11 14:24:48 +00:00
|
|
|
return AuAtomicUtils<T>::TestAndSet((T *)(in), offset);
|
2022-04-01 04:06:53 +00:00
|
|
|
}
|