|
11 | 11 |
|
12 | 12 | #include <cassert>
|
13 | 13 | #include <cstdint>
|
| 14 | +#include <cstddef> |
| 15 | +#include <type_traits> |
14 | 16 |
|
15 | 17 | #include "test_macros.h"
|
16 | 18 |
|
| 19 | +#if defined(TEST_COMPILER_CLANG) |
| 20 | +# define TEST_ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE |
| 21 | +# define TEST_ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE |
| 22 | +# define TEST_ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE |
| 23 | +# define TEST_ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE |
| 24 | +# define TEST_ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE |
| 25 | +# define TEST_ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE |
| 26 | +#elif defined(TEST_COMPILER_GCC) |
| 27 | +# define TEST_ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE |
| 28 | +# define TEST_ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE |
| 29 | +# define TEST_ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE |
| 30 | +# define TEST_ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE |
| 31 | +# define TEST_ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE |
| 32 | +# define TEST_ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE |
| 33 | +#elif TEST_COMPILER_MSVC |
| 34 | +// This is lifted from STL/stl/inc/atomic on github for the purposes of |
| 35 | +// keeping the tests compiling for MSVC's STL. It's not a perfect solution |
| 36 | +// but at least the tests will keep running. |
| 37 | +// |
| 38 | +// Note MSVC's STL never produces a type that is sometimes lock free, but not always lock free. |
| 39 | +template <class T, size_t Size = sizeof(T)> |
| 40 | +constexpr bool msvc_is_lock_free_macro_value() { |
| 41 | + return (Size <= 8 && (Size & Size - 1) == 0) ? 2 : 0; |
| 42 | +} |
| 43 | +# define TEST_ATOMIC_CHAR_LOCK_FREE ::msvc_is_lock_free_macro_value<char>() |
| 44 | +# define TEST_ATOMIC_SHORT_LOCK_FREE ::msvc_is_lock_free_macro_value<short>() |
| 45 | +# define TEST_ATOMIC_INT_LOCK_FREE ::msvc_is_lock_free_macro_value<int>() |
| 46 | +# define TEST_ATOMIC_LONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long>() |
| 47 | +# define TEST_ATOMIC_LLONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long long>() |
| 48 | +# define TEST_ATOMIC_POINTER_LOCK_FREE ::msvc_is_lock_free_macro_value<void*>() |
| 49 | +#else |
| 50 | +# error "Unknown compiler" |
| 51 | +#endif |
| 52 | +enum class LockFreeStatus { unknown = -1, never = 0, sometimes = 1, always = 2 }; |
| 53 | +#define COMPARE_TYPES(T1, T2) \ |
| 54 | + (sizeof(T1) == sizeof(T2) && alignof(T1) >= alignof(T2)) |
| 55 | + |
| 56 | +template <class T> |
| 57 | +constexpr inline LockFreeStatus get_known_atomic_lock_free_status() { |
| 58 | + return LockFreeStatus{COMPARE_TYPES(T, char) |
| 59 | + ? TEST_ATOMIC_CHAR_LOCK_FREE |
| 60 | + : (COMPARE_TYPES(T, short) |
| 61 | + ? TEST_ATOMIC_SHORT_LOCK_FREE |
| 62 | + : (COMPARE_TYPES(T, int) |
| 63 | + ? TEST_ATOMIC_INT_LOCK_FREE |
| 64 | + : (COMPARE_TYPES(T, long) |
| 65 | + ? TEST_ATOMIC_LONG_LOCK_FREE |
| 66 | + : (COMPARE_TYPES(T, long long) |
| 67 | + ? TEST_ATOMIC_LLONG_LOCK_FREE |
| 68 | + : (COMPARE_TYPES(T, void*) ? TEST_ATOMIC_POINTER_LOCK_FREE |
| 69 | + : -1)))))}; |
| 70 | +} |
| 71 | + |
| 72 | +template <class T> |
| 73 | +constexpr bool is_lock_free_status_known() { |
| 74 | + return get_known_atomic_lock_free_status<T>() != LockFreeStatus::unknown; |
| 75 | +} |
| 76 | + |
| 77 | +static_assert(is_lock_free_status_known<char>(), ""); |
| 78 | +static_assert(is_lock_free_status_known<short>(), ""); |
| 79 | +static_assert(is_lock_free_status_known<int>(), ""); |
| 80 | +static_assert(is_lock_free_status_known<long>(), ""); |
| 81 | +static_assert(is_lock_free_status_known<long long>(), ""); |
| 82 | +static_assert(is_lock_free_status_known<void*>(), ""); |
| 83 | + |
| 84 | + |
| 85 | +// These macros are somewhat suprising to use, since they take the values 0, 1, or 2. |
| 86 | +// To make the tests clearer, get rid of them in preference of AtomicInfo. |
| 87 | +#undef TEST_ATOMIC_CHAR_LOCK_FREE |
| 88 | +#undef TEST_ATOMIC_SHORT_LOCK_FREE |
| 89 | +#undef TEST_ATOMIC_INT_LOCK_FREE |
| 90 | +#undef TEST_ATOMIC_LONG_LOCK_FREE |
| 91 | +#undef TEST_ATOMIC_LLONG_LOCK_FREE |
| 92 | +#undef TEST_ATOMIC_POINTER_LOCK_FREE |
| 93 | + |
17 | 94 | struct UserAtomicType {
|
18 | 95 | int i;
|
19 | 96 |
|
@@ -64,6 +141,17 @@ struct LargeUserAtomicType {
|
64 | 141 | }
|
65 | 142 | };
|
66 | 143 |
|
| 144 | +template <template <class TestArg> class TestFunctor> |
| 145 | +struct TestEachLockFreeKnownIntegralType { |
| 146 | + void operator()() const { |
| 147 | + TestFunctor<char>()(); |
| 148 | + TestFunctor<short>()(); |
| 149 | + TestFunctor<int>()(); |
| 150 | + TestFunctor<long long>()(); |
| 151 | + TestFunctor<void*>()(); |
| 152 | + } |
| 153 | +}; |
| 154 | + |
67 | 155 | template <template <class TestArg> class TestFunctor>
|
68 | 156 | struct TestEachIntegralType {
|
69 | 157 | void operator()() const {
|
|
0 commit comments