Skip to content

Commit d56c6db

Browse files
<atomic>: Add member difference_type to atomic<void*> and its friends (#4689)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 7c25aef commit d56c6db

File tree

3 files changed

+121
-10
lines changed

3 files changed

+121
-10
lines changed

stl/inc/atomic

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,14 +2122,24 @@ struct _Atomic_pointer<_Ty&> : _Atomic_storage<_Ty&> {
21222122
}
21232123
};
21242124

2125+
template <class _Ty>
2126+
struct _Atomic_nonobject_pointer : _Atomic_storage<_Ty> {
2127+
using _Base = _Atomic_storage<_Ty>;
2128+
using difference_type = ptrdiff_t;
2129+
2130+
using _Base::_Base;
2131+
};
2132+
21252133
#define ATOMIC_VAR_INIT(_Value) \
21262134
{ _Value }
21272135

21282136
template <class _TVal, class _Ty = _TVal>
21292137
using _Choose_atomic_base2_t =
21302138
typename _Select<is_integral_v<_TVal> && !is_same_v<bool, _TVal>>::template _Apply<_Atomic_integral_facade<_Ty>,
2131-
typename _Select<is_pointer_v<_TVal> && is_object_v<remove_pointer_t<_TVal>>>::template _Apply<
2132-
_Atomic_pointer<_Ty>, _Atomic_storage<_Ty>>>;
2139+
typename _Select<is_pointer_v<_TVal>>::template _Apply<
2140+
typename _Select<is_object_v<remove_pointer_t<_TVal>>>::template _Apply<_Atomic_pointer<_Ty>,
2141+
_Atomic_nonobject_pointer<_Ty>>,
2142+
_Atomic_storage<_Ty>>>;
21332143

21342144
#if _HAS_CXX20
21352145
template <class _TVal, class _Ty = _TVal>

tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <atomic>
1010
#include <cassert>
11+
#include <cstddef>
1112
#include <cstdint>
1213
#include <cstdlib>
1314
#include <cstring>
@@ -20,14 +21,18 @@ using namespace std;
2021

2122
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
2223

23-
// N3797 29.6.5 [atomics.types.operations.req]/21:
24-
// bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile noexcept;
25-
// bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) noexcept;
26-
// bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile
27-
// noexcept; bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst)
28-
// noexcept; When only one memory_order argument is supplied, the value of success is order, and the value of failure is
29-
// order except that a value of memory_order_acq_rel shall be replaced by the value memory_order_acquire and a value of
30-
// memory_order_release shall be replaced by the value memory_order_relaxed.
24+
// N4981 [atomics.types.operations]/23:
25+
// bool compare_exchange_weak(T& expected, T desired,
26+
// memory_order order = memory_order::seq_cst) volatile noexcept;
27+
// bool compare_exchange_weak(T& expected, T desired,
28+
// memory_order order = memory_order::seq_cst) noexcept;
29+
// bool compare_exchange_strong(T& expected, T desired,
30+
// memory_order order = memory_order::seq_cst) volatile noexcept;
31+
// bool compare_exchange_strong(T& expected, T desired,
32+
// memory_order order = memory_order::seq_cst) noexcept;
33+
// When only one memory_order argument is supplied, the value of success is order, and the value of failure is order
34+
// except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and a value of
35+
// memory_order::release shall be replaced by the value memory_order::relaxed.
3136

3237
template <typename T>
3338
void test(T t) {
@@ -553,6 +558,57 @@ void test_double_identical_results() {
553558
#endif // _HAS_CXX20
554559
}
555560

561+
// Also test GH-4688 "<atomic>: atomic_ref<void*> and atomic<void*> lack difference_type"
562+
template <class, class = void>
563+
constexpr bool atomic_has_member_difference_type = false;
564+
template <class T>
565+
constexpr bool atomic_has_member_difference_type<T, void_t<typename atomic<T>::difference_type>> = true;
566+
567+
STATIC_ASSERT(is_same_v<atomic<signed char>::difference_type, signed char>);
568+
STATIC_ASSERT(is_same_v<atomic<short>::difference_type, short>);
569+
STATIC_ASSERT(is_same_v<atomic<int>::difference_type, int>);
570+
STATIC_ASSERT(is_same_v<atomic<long>::difference_type, long>);
571+
STATIC_ASSERT(is_same_v<atomic<long long>::difference_type, long long>);
572+
STATIC_ASSERT(is_same_v<atomic<unsigned char>::difference_type, unsigned char>);
573+
STATIC_ASSERT(is_same_v<atomic<unsigned short>::difference_type, unsigned short>);
574+
STATIC_ASSERT(is_same_v<atomic<unsigned int>::difference_type, unsigned int>);
575+
STATIC_ASSERT(is_same_v<atomic<unsigned long>::difference_type, unsigned long>);
576+
STATIC_ASSERT(is_same_v<atomic<unsigned long long>::difference_type, unsigned long long>);
577+
STATIC_ASSERT(is_same_v<atomic<char>::difference_type, char>);
578+
#ifdef __cpp_char8_t
579+
STATIC_ASSERT(is_same_v<atomic<char8_t>::difference_type, char8_t>);
580+
#endif // defined(__cpp_char8_t)
581+
STATIC_ASSERT(is_same_v<atomic<char16_t>::difference_type, char16_t>);
582+
STATIC_ASSERT(is_same_v<atomic<char32_t>::difference_type, char32_t>);
583+
STATIC_ASSERT(is_same_v<atomic<wchar_t>::difference_type, wchar_t>);
584+
585+
#if _HAS_CXX20 // P0020R6 Floating Point Atomic
586+
STATIC_ASSERT(is_same_v<atomic<float>::difference_type, float>);
587+
STATIC_ASSERT(is_same_v<atomic<double>::difference_type, double>);
588+
STATIC_ASSERT(is_same_v<atomic<long double>::difference_type, long double>);
589+
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
590+
STATIC_ASSERT(!atomic_has_member_difference_type<float>);
591+
STATIC_ASSERT(!atomic_has_member_difference_type<double>);
592+
STATIC_ASSERT(!atomic_has_member_difference_type<long double>);
593+
#endif // ^^^ !_HAS_CXX20 ^^^
594+
595+
STATIC_ASSERT(is_same_v<atomic<int*>::difference_type, ptrdiff_t>);
596+
STATIC_ASSERT(is_same_v<atomic<bool*>::difference_type, ptrdiff_t>);
597+
STATIC_ASSERT(is_same_v<atomic<const int*>::difference_type, ptrdiff_t>);
598+
STATIC_ASSERT(is_same_v<atomic<volatile bool*>::difference_type, ptrdiff_t>);
599+
600+
STATIC_ASSERT(is_same_v<atomic<void*>::difference_type, ptrdiff_t>);
601+
STATIC_ASSERT(is_same_v<atomic<const void*>::difference_type, ptrdiff_t>);
602+
STATIC_ASSERT(is_same_v<atomic<volatile void*>::difference_type, ptrdiff_t>);
603+
STATIC_ASSERT(is_same_v<atomic<const volatile void*>::difference_type, ptrdiff_t>);
604+
STATIC_ASSERT(is_same_v<atomic<void (*)()>::difference_type, ptrdiff_t>);
605+
606+
STATIC_ASSERT(!atomic_has_member_difference_type<bool>);
607+
STATIC_ASSERT(!atomic_has_member_difference_type<nullptr_t>);
608+
STATIC_ASSERT(!atomic_has_member_difference_type<Bytes<4>>);
609+
STATIC_ASSERT(!atomic_has_member_difference_type<Bytes<8>>);
610+
STATIC_ASSERT(!atomic_has_member_difference_type<Bytes<12>>);
611+
556612
int main() {
557613
X x = {1729};
558614
test(x);

tests/std/tests/P0019R8_atomic_ref/test.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,51 @@ struct int128 {
4040
}
4141
};
4242

43+
// Also test GH-4688 "<atomic>: atomic_ref<void*> and atomic<void*> lack difference_type"
44+
template <class T>
45+
constexpr bool atomic_ref_has_member_difference_type = requires { typename std::atomic_ref<T>::difference_type; };
46+
47+
static_assert(std::is_same_v<std::atomic_ref<signed char>::difference_type, signed char>);
48+
static_assert(std::is_same_v<std::atomic_ref<short>::difference_type, short>);
49+
static_assert(std::is_same_v<std::atomic_ref<int>::difference_type, int>);
50+
static_assert(std::is_same_v<std::atomic_ref<long>::difference_type, long>);
51+
static_assert(std::is_same_v<std::atomic_ref<long long>::difference_type, long long>);
52+
static_assert(std::is_same_v<std::atomic_ref<unsigned char>::difference_type, unsigned char>);
53+
static_assert(std::is_same_v<std::atomic_ref<unsigned short>::difference_type, unsigned short>);
54+
static_assert(std::is_same_v<std::atomic_ref<unsigned int>::difference_type, unsigned int>);
55+
static_assert(std::is_same_v<std::atomic_ref<unsigned long>::difference_type, unsigned long>);
56+
static_assert(std::is_same_v<std::atomic_ref<unsigned long long>::difference_type, unsigned long long>);
57+
static_assert(std::is_same_v<std::atomic_ref<char>::difference_type, char>);
58+
#ifdef __cpp_char8_t
59+
static_assert(std::is_same_v<std::atomic_ref<char8_t>::difference_type, char8_t>);
60+
#endif // defined(__cpp_char8_t)
61+
static_assert(std::is_same_v<std::atomic_ref<char16_t>::difference_type, char16_t>);
62+
static_assert(std::is_same_v<std::atomic_ref<char32_t>::difference_type, char32_t>);
63+
static_assert(std::is_same_v<std::atomic_ref<wchar_t>::difference_type, wchar_t>);
64+
65+
static_assert(std::is_same_v<std::atomic_ref<float>::difference_type, float>);
66+
static_assert(std::is_same_v<std::atomic_ref<double>::difference_type, double>);
67+
static_assert(std::is_same_v<std::atomic_ref<long double>::difference_type, long double>);
68+
69+
static_assert(std::is_same_v<std::atomic_ref<int*>::difference_type, std::ptrdiff_t>);
70+
static_assert(std::is_same_v<std::atomic_ref<bool*>::difference_type, std::ptrdiff_t>);
71+
static_assert(std::is_same_v<std::atomic_ref<const int*>::difference_type, std::ptrdiff_t>);
72+
static_assert(std::is_same_v<std::atomic_ref<volatile bool*>::difference_type, std::ptrdiff_t>);
73+
static_assert(std::is_same_v<std::atomic_ref<bigint*>::difference_type, std::ptrdiff_t>);
74+
static_assert(std::is_same_v<std::atomic_ref<const volatile int128*>::difference_type, std::ptrdiff_t>);
75+
76+
static_assert(std::is_same_v<std::atomic_ref<void*>::difference_type, std::ptrdiff_t>);
77+
static_assert(std::is_same_v<std::atomic_ref<const void*>::difference_type, std::ptrdiff_t>);
78+
static_assert(std::is_same_v<std::atomic_ref<volatile void*>::difference_type, std::ptrdiff_t>);
79+
static_assert(std::is_same_v<std::atomic_ref<const volatile void*>::difference_type, std::ptrdiff_t>);
80+
static_assert(std::is_same_v<std::atomic_ref<void (*)()>::difference_type, std::ptrdiff_t>);
81+
static_assert(std::is_same_v<std::atomic_ref<bigint (*)(int128)>::difference_type, std::ptrdiff_t>);
82+
83+
static_assert(!atomic_ref_has_member_difference_type<bool>);
84+
static_assert(!atomic_ref_has_member_difference_type<std::nullptr_t>);
85+
static_assert(!atomic_ref_has_member_difference_type<bigint>);
86+
static_assert(!atomic_ref_has_member_difference_type<int128>);
87+
4388

4489
// code reuse of ../P1135R6_atomic_flag_test/test.cpp
4590

0 commit comments

Comments
 (0)