libstdc++: complete P0493R5 with pointer support

Previous implementations of fetch_min/max only supported integers, not
handling pointers. To complete the paper, we need to implement support
for pointers as well. This patch adds the missing functionality and
test cases.

libstdc++-v3/ChangeLog:

	* include/bits/atomic_base.h (__atomic_base<_PTp*>::fetch_min,
	__atomic_base<_PTp*>::fetch_max,
	__atomic_ref<_Pt, false, false, true>::fetch_min,
	__atomic_ref<_Pt, false, false, true>::fetch_max): Define new
	functions.
	* include/std/atomic (atomic<_Tp*>::fetch_min,
	atomic<_Tp*>::fetch_max): Likewise.
	(atomic_fetch_min_explicit, atomic_fetch_max_explicit,
	atomic_fetch_min, atomic_fetch_max): Change parameter from
	__atomic_base<_ITp>* to atomic<_Tp>*.
	* testsuite/29_atomics/atomic/pointer_fetch_minmax.cc: New test.
	* testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc: New
	test.
This commit is contained in:
Yuao Ma
2026-02-25 20:44:07 +08:00
parent f059aa93d3
commit 0772974fec
4 changed files with 212 additions and 32 deletions

View File

@@ -983,6 +983,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
fetch_sub(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return __atomic_fetch_sub(&_M_p, _S_type_size(__d), int(__m)); }
#if __glibcxx_atomic_min_max
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_min(__pointer_type __p,
memory_order __m = memory_order_seq_cst) noexcept
{ return __atomic_impl::__fetch_min(&_M_p, __p, __m); }
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_min(__pointer_type __p,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return __atomic_impl::__fetch_min(&_M_p, __p, __m); }
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_max(__pointer_type __p,
memory_order __m = memory_order_seq_cst) noexcept
{ return __atomic_impl::__fetch_max(&_M_p, __p, __m); }
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_max(__pointer_type __p,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return __atomic_impl::__fetch_max(&_M_p, __p, __m); }
#endif
};
namespace __atomic_impl
@@ -1976,6 +1998,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) const noexcept
{ return __atomic_impl::fetch_sub(this->_M_ptr, _S_type_size(__d), __m); }
#if __glibcxx_atomic_min_max
_GLIBCXX_ALWAYS_INLINE value_type
fetch_min(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
{ return __atomic_impl::__fetch_min(this->_M_ptr, __i, __m); }
_GLIBCXX_ALWAYS_INLINE value_type
fetch_max(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
{ return __atomic_impl::__fetch_max(this->_M_ptr, __i, __m); }
#endif
value_type
operator++(int) const noexcept
{ return fetch_add(1); }

View File

@@ -718,6 +718,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
return _M_b.fetch_sub(__d, __m);
}
#if __glibcxx_atomic_min_max
__pointer_type
fetch_min(__pointer_type __p,
memory_order __m = memory_order_seq_cst) noexcept
{ return _M_b.fetch_min(__p, __m); }
__pointer_type
fetch_min(__pointer_type __p,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_b.fetch_min(__p, __m); }
__pointer_type
fetch_max(__pointer_type __p,
memory_order __m = memory_order_seq_cst) noexcept
{ return _M_b.fetch_max(__p, __m); }
__pointer_type
fetch_max(__pointer_type __p,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_b.fetch_max(__p, __m); }
#endif
};
@@ -1574,31 +1596,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __a->fetch_xor(__i, __m); }
#ifdef __cpp_lib_atomic_min_max
template<typename _ITp>
inline _ITp
atomic_fetch_min_explicit(__atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i,
template<typename _Tp>
inline _Tp
atomic_fetch_min_explicit(atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_min(__i, __m); }
template<typename _ITp>
inline _ITp
atomic_fetch_min_explicit(volatile __atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i,
template<typename _Tp>
inline _Tp
atomic_fetch_min_explicit(volatile atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_min(__i, __m); }
template<typename _ITp>
inline _ITp
atomic_fetch_max_explicit(__atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i,
template<typename _Tp>
inline _Tp
atomic_fetch_max_explicit(atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_max(__i, __m); }
template<typename _ITp>
inline _ITp
atomic_fetch_max_explicit(volatile __atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i,
template<typename _Tp>
inline _Tp
atomic_fetch_max_explicit(volatile atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i,
memory_order __m) noexcept
{ return __a->fetch_max(__i, __m); }
#endif
@@ -1664,28 +1686,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
#ifdef __cpp_lib_atomic_min_max
template<typename _ITp>
inline _ITp
atomic_fetch_min(__atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i) noexcept
template<typename _Tp>
inline _Tp
atomic_fetch_min(atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); }
template<typename _ITp>
inline _ITp
atomic_fetch_min(volatile __atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i) noexcept
template<typename _Tp>
inline _Tp
atomic_fetch_min(volatile atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_min_explicit(__a, __i, memory_order_seq_cst); }
template<typename _ITp>
inline _ITp
atomic_fetch_max(__atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i) noexcept
template<typename _Tp>
inline _Tp
atomic_fetch_max(atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
template<typename _ITp>
inline _ITp
atomic_fetch_max(volatile __atomic_base<_ITp>* __a,
__atomic_val_t<_ITp> __i) noexcept
template<typename _Tp>
inline _Tp
atomic_fetch_max(volatile atomic<_Tp>* __a,
__atomic_val_t<_Tp> __i) noexcept
{ return atomic_fetch_max_explicit(__a, __i, memory_order_seq_cst); }
#endif

View File

@@ -0,0 +1,53 @@
// { dg-do run { target c++26 } }
// { dg-require-atomic-cmpxchg-word "" }
// { dg-add-options libatomic }
#include <atomic>
#include <testsuite_hooks.h>
void test01() {
long arr[10] = {};
const auto mo = std::memory_order_relaxed;
std::atomic<long *> a(arr);
auto v = atomic_fetch_max(&a, arr + 5);
VERIFY(v == arr);
VERIFY(a == arr + 5);
v = atomic_fetch_max_explicit(&a, arr + 2, mo);
VERIFY(v == arr + 5);
VERIFY(a == arr + 5);
v = atomic_fetch_min(&a, arr + 3);
VERIFY(v == arr + 5);
VERIFY(a == arr + 3);
v = atomic_fetch_min_explicit(&a, arr + 5, mo);
VERIFY(v == arr + 3);
VERIFY(a == arr + 3);
}
void test02() {
char arr[10] = {};
const auto mo = std::memory_order_relaxed;
std::atomic<char *> a(arr);
auto v = atomic_fetch_max(&a, arr + 5);
VERIFY(v == arr);
VERIFY(a == arr + 5);
v = atomic_fetch_max_explicit(&a, arr + 2, mo);
VERIFY(v == arr + 5);
VERIFY(a == arr + 5);
v = atomic_fetch_min(&a, arr + 3);
VERIFY(v == arr + 5);
VERIFY(a == arr + 3);
v = atomic_fetch_min_explicit(&a, arr + 5, mo);
VERIFY(v == arr + 3);
VERIFY(a == arr + 3);
}
int main() {
test01();
test02();
}

View File

@@ -0,0 +1,71 @@
// { dg-do run { target c++26 } }
// { dg-require-atomic-cmpxchg-word "" }
// { dg-add-options libatomic }
#include <atomic>
#include <testsuite_hooks.h>
void test01() {
long arr[10] = {};
long *value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<long *> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<long *>::is_always_lock_free)
VERIFY(ok);
a = arr;
auto v = a.fetch_max(arr + 5);
VERIFY(v == arr);
VERIFY(a == arr + 5);
v = a.fetch_max(arr + 2, mo);
VERIFY(v == arr + 5);
VERIFY(a == arr + 5);
v = a.fetch_min(arr + 3);
VERIFY(v == arr + 5);
VERIFY(a == arr + 3);
v = a.fetch_min(arr + 5, mo);
VERIFY(v == arr + 3);
VERIFY(a == arr + 3);
}
VERIFY(value == arr + 3);
}
void test02() {
char arr[10] = {};
char *value;
{
const auto mo = std::memory_order_relaxed;
std::atomic_ref<char *> a(value);
bool ok = a.is_lock_free();
if constexpr (std::atomic_ref<char *>::is_always_lock_free)
VERIFY(ok);
a = arr;
auto v = a.fetch_max(arr + 5);
VERIFY(v == arr);
VERIFY(a == arr + 5);
v = a.fetch_max(arr + 2, mo);
VERIFY(v == arr + 5);
VERIFY(a == arr + 5);
v = a.fetch_min(arr + 3);
VERIFY(v == arr + 5);
VERIFY(a == arr + 3);
v = a.fetch_min(arr + 5, mo);
VERIFY(v == arr + 3);
VERIFY(a == arr + 3);
}
VERIFY(value == arr + 3);
}
int main() {
test01();
test02();
}