#ifndef ATOMIC_HELPERS_H
#define ATOMIC_HELPERS_H
#include <cassert>
#include <cstdint>
#include <cstddef>
#include <type_traits>
#include "test_macros.h"
#if defined(TEST_COMPILER_CLANG)
# define TEST_ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
# define TEST_ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
# define TEST_ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
# define TEST_ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
# define TEST_ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
# define TEST_ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
#elif defined(TEST_COMPILER_GCC)
# define TEST_ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
# define TEST_ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
# define TEST_ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
# define TEST_ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
# define TEST_ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
# define TEST_ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
#elif TEST_COMPILER_MSVC
template <class T, size_t Size = sizeof(T)>
constexpr bool msvc_is_lock_free_macro_value() {
return (Size <= 8 && (Size & Size - 1) == 0) ? 2 : 0;
}
# define TEST_ATOMIC_CHAR_LOCK_FREE ::msvc_is_lock_free_macro_value<char>()
# define TEST_ATOMIC_SHORT_LOCK_FREE ::msvc_is_lock_free_macro_value<short>()
# define TEST_ATOMIC_INT_LOCK_FREE ::msvc_is_lock_free_macro_value<int>()
# define TEST_ATOMIC_LONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long>()
# define TEST_ATOMIC_LLONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long long>()
# define TEST_ATOMIC_POINTER_LOCK_FREE ::msvc_is_lock_free_macro_value<void*>()
#else
# error "Unknown compiler"
#endif
#ifdef TEST_COMPILER_CLANG
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wc++11-extensions"
#endif
enum class LockFreeStatus : int { unknown = -1, never = 0, sometimes = 1, always = 2 };
#define COMPARE_TYPES(T, FundamentalT) (sizeof(T) == sizeof(FundamentalT) && TEST_ALIGNOF(T) >= sizeof(T))
template <class T>
struct LockFreeStatusInfo {
static const LockFreeStatus value = LockFreeStatus(
COMPARE_TYPES(T, char)
? TEST_ATOMIC_CHAR_LOCK_FREE
: (COMPARE_TYPES(T, short)
? TEST_ATOMIC_SHORT_LOCK_FREE
: (COMPARE_TYPES(T, int)
? TEST_ATOMIC_INT_LOCK_FREE
: (COMPARE_TYPES(T, long)
? TEST_ATOMIC_LONG_LOCK_FREE
: (COMPARE_TYPES(T, long long)
? TEST_ATOMIC_LLONG_LOCK_FREE
: (COMPARE_TYPES(T, void*) ? TEST_ATOMIC_POINTER_LOCK_FREE : -1))))));
static const bool status_known = LockFreeStatusInfo::value != LockFreeStatus::unknown;
};
#undef COMPARE_TYPES
#if TEST_STD_VER >= 11
static_assert(LockFreeStatusInfo<char>::status_known, "");
static_assert(LockFreeStatusInfo<short>::status_known, "");
static_assert(LockFreeStatusInfo<int>::status_known, "");
static_assert(LockFreeStatusInfo<long>::status_known, "");
static_assert(LockFreeStatusInfo<void*>::status_known, "");
static_assert(alignof(long long) == sizeof(long long) ? LockFreeStatusInfo<long long>::status_known : true, "");
static_assert(LockFreeStatusInfo<char>::value == LockFreeStatus::always, "");
static_assert(LockFreeStatusInfo<short>::value == LockFreeStatus::always, "");
static_assert(LockFreeStatusInfo<int>::value == LockFreeStatus::always, "");
#endif
#undef TEST_ATOMIC_CHAR_LOCK_FREE
#undef TEST_ATOMIC_SHORT_LOCK_FREE
#undef TEST_ATOMIC_INT_LOCK_FREE
#undef TEST_ATOMIC_LONG_LOCK_FREE
#undef TEST_ATOMIC_LLONG_LOCK_FREE
#undef TEST_ATOMIC_POINTER_LOCK_FREE
#ifdef TEST_COMPILER_CLANG
# pragma clang diagnostic pop
#endif
struct UserAtomicType {
int i;
explicit UserAtomicType(int d = 0) TEST_NOEXCEPT : i(d) {}
friend bool operator==(const UserAtomicType& x, const UserAtomicType& y) { return x.i == y.i; }
};
Enable these once we have P0528
struct WeirdUserAtomicType
{
char i, j, k; // the 3 chars of doom
explicit WeirdUserAtomicType(int d = 0) TEST_NOEXCEPT : i(d) {}
friend bool operator==(const WeirdUserAtomicType& x, const WeirdUserAtomicType& y)
{ return x.i == y.i; }
};
struct PaddedUserAtomicType
{
char i; int j; // probably lock-free?
explicit PaddedUserAtomicType(int d = 0) TEST_NOEXCEPT : i(d) {}
friend bool operator==(const PaddedUserAtomicType& x, const PaddedUserAtomicType& y)
{ return x.i == y.i; }
};
*/
struct LargeUserAtomicType {
int a[128];
LargeUserAtomicType(int d = 0) TEST_NOEXCEPT {
for (auto&& e : a)
e = d++;
}
friend bool operator==(LargeUserAtomicType const& x, LargeUserAtomicType const& y) TEST_NOEXCEPT {
for (int i = 0; i < 128; ++i)
if (x.a[i] != y.a[i])
return false;
return true;
}
};
template <template <class TestArg> class TestFunctor>
struct TestEachIntegralType {
void operator()() const {
TestFunctor<char>()();
TestFunctor<signed char>()();
TestFunctor<unsigned char>()();
TestFunctor<short>()();
TestFunctor<unsigned short>()();
TestFunctor<int>()();
TestFunctor<unsigned int>()();
TestFunctor<long>()();
TestFunctor<unsigned long>()();
TestFunctor<long long>()();
TestFunctor<unsigned long long>()();
TestFunctor<wchar_t>()();
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
TestFunctor<char8_t>()();
#endif
TestFunctor<char16_t>()();
TestFunctor<char32_t>()();
TestFunctor<std::int8_t>()();
TestFunctor<std::uint8_t>()();
TestFunctor<std::int16_t>()();
TestFunctor<std::uint16_t>()();
TestFunctor<std::int32_t>()();
TestFunctor<std::uint32_t>()();
TestFunctor<std::int64_t>()();
TestFunctor<std::uint64_t>()();
}
};
template <template <class TestArg> class TestFunctor>
struct TestEachFloatingPointType {
void operator()() const {
TestFunctor<float>()();
TestFunctor<double>()();
TestFunctor<long double>()();
}
};
template <template <class TestArg> class TestFunctor>
struct TestEachPointerType {
void operator()() const {
TestFunctor<int*>()();
TestFunctor<const int*>()();
}
};
template <template <class TestArg> class TestFunctor>
struct TestEachAtomicType {
void operator()() const {
TestEachIntegralType<TestFunctor>()();
TestEachPointerType<TestFunctor>()();
TestFunctor<UserAtomicType>()();
Note: These aren't going to be lock-free,
so some libatomic.a is necessary.
*/
TestFunctor<LargeUserAtomicType>()();
Enable these once we have P0528
TestFunctor<PaddedUserAtomicType>()();
TestFunctor<WeirdUserAtomicType>()();
*/
TestFunctor<float>()();
TestFunctor<double>()();
}
};
#endif