]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: complete P0493R5 with pointer support
authorYuao Ma <c8ef@outlook.com>
Wed, 25 Feb 2026 12:44:07 +0000 (20:44 +0800)
committerYuao Ma <c8ef@outlook.com>
Thu, 26 Feb 2026 13:11:07 +0000 (21:11 +0800)
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.

libstdc++-v3/include/bits/atomic_base.h
libstdc++-v3/include/std/atomic
libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc [new file with mode: 0644]
libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc [new file with mode: 0644]

index 79c1b31ccc419b586dc5453a019e097ac207232d..6c5b83a08182eb29e1c69b963e3ce15769dd8015 100644 (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); }
index 306667e3c633870726bfa028cb89cbe8e8cd49ed..3ec218afa096228cc1faa74125b246ddab7a99cc 100644 (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
 
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic/pointer_fetch_minmax.cc
new file mode 100644 (file)
index 0000000..aca0c31
--- /dev/null
@@ -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();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer_fetch_minmax.cc
new file mode 100644 (file)
index 0000000..25eef63
--- /dev/null
@@ -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();
+}