New structs and member functions added to C++26 by P1901R2.
libstdc++-v3/ChangeLog:
PR libstdc++/117403
* include/bits/shared_ptr.h (shared_ptr::owner_equal)
(shared_ptr::owner_hash, weak_ptr::owner_equal)
(weak_ptr::owner_hash): Define new member functions.
* include/bits/shared_ptr_base.h (owner_equal, owner_hash):
Define new structs.
* include/bits/version.def (smart_ptr_owner_equality): Define.
* include/bits/version.h: Regenerate.
* include/std/memory: Added define for
__glibcxx_want_smart_ptr_owner_equality.
* testsuite/20_util/owner_equal/version.cc: New test.
* testsuite/20_util/owner_equal/cmp.cc: New test.
* testsuite/20_util/owner_equal/noexcept.cc: New test.
* testsuite/20_util/owner_hash/cmp.cc: New test.
* testsuite/20_util/owner_hash/noexcept.cc: New test.
* testsuite/20_util/shared_ptr/observers/owner_equal.cc: New
test.
* testsuite/20_util/shared_ptr/observers/owner_hash.cc:
New test.
* testsuite/20_util/weak_ptr/observers/owner_equal.cc: New test.
* testsuite/20_util/weak_ptr/observers/owner_hash.cc: New test.
Signed-off-by: Paul Keir <paul.keir@uws.ac.uk>
: public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>>
{ };
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+
+ /**
+ * @brief Provides ownership-based hashing.
+ * @headerfile memory
+ * @since C++26
+ */
+ struct owner_hash
+ {
+ template<typename _Tp>
+ size_t
+ operator()(const shared_ptr<_Tp>& __s) const noexcept
+ { return __s.owner_hash(); }
+
+ template<typename _Tp>
+ size_t
+ operator()(const weak_ptr<_Tp>& __s) const noexcept
+ { return __s.owner_hash(); }
+
+ using is_transparent = void;
+ };
+
+ /**
+ * @brief Provides ownership-based mixed equality comparisons of
+ * shared and weak pointers.
+ * @headerfile memory
+ * @since C++26
+ */
+ struct owner_equal
+ {
+ template<typename _Tp1, typename _Tp2>
+ bool
+ operator()(const shared_ptr<_Tp1>& __lhs,
+ const shared_ptr<_Tp2>& __rhs) const noexcept
+ { return __lhs.owner_equal(__rhs); }
+
+ template<typename _Tp1, typename _Tp2>
+ bool
+ operator()(const shared_ptr<_Tp1>& __lhs,
+ const weak_ptr<_Tp2>& __rhs) const noexcept
+ { return __lhs.owner_equal(__rhs); }
+
+ template<typename _Tp1, typename _Tp2>
+ bool
+ operator()(const weak_ptr<_Tp1>& __lhs,
+ const shared_ptr<_Tp2>& __rhs) const noexcept
+ { return __lhs.owner_equal(__rhs); }
+
+ template<typename _Tp1, typename _Tp2>
+ bool
+ operator()(const weak_ptr<_Tp1>& __lhs,
+ const weak_ptr<_Tp2>& __rhs) const noexcept
+ { return __lhs.owner_equal(__rhs); }
+
+ using is_transparent = void;
+ };
+#endif
+
/**
* @brief Base class allowing use of the member function `shared_from_this`.
* @headerfile memory
_M_less(const __weak_count<_Lp>& __rhs) const noexcept
{ return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+ size_t
+ _M_owner_hash() const noexcept
+ { return std::hash<_Sp_counted_base<_Lp>*>()(this->_M_pi); }
+#endif
+
// Friend function injected into enclosing namespace and found by ADL
friend inline bool
operator==(const __shared_count& __a, const __shared_count& __b) noexcept
_M_less(const __shared_count<_Lp>& __rhs) const noexcept
{ return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+ size_t
+ _M_owner_hash() const noexcept
+ { return std::hash<_Sp_counted_base<_Lp>*>()(this->_M_pi); }
+#endif
+
// Friend function injected into enclosing namespace and found by ADL
friend inline bool
operator==(const __weak_count& __a, const __weak_count& __b) noexcept
{ return _M_refcount._M_less(__rhs._M_refcount); }
/// @}
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+ size_t owner_hash() const noexcept { return _M_refcount._M_owner_hash(); }
+
+ template<typename _Tp1>
+ bool
+ owner_equal(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept
+ { return _M_refcount == __rhs._M_refcount; }
+
+ template<typename _Tp1>
+ bool
+ owner_equal(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept
+ { return _M_refcount == __rhs._M_refcount; }
+#endif
+
protected:
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept
{ return _M_refcount._M_less(__rhs._M_refcount); }
+#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26
+ size_t owner_hash() const noexcept { return _M_refcount._M_owner_hash(); }
+
+ template<typename _Tp1>
+ bool
+ owner_equal(const __shared_ptr<_Tp1, _Lp> & __rhs) const noexcept
+ { return _M_refcount == __rhs._M_refcount; }
+
+ template<typename _Tp1>
+ bool
+ owner_equal(const __weak_ptr<_Tp1, _Lp> & __rhs) const noexcept
+ { return _M_refcount == __rhs._M_refcount; }
+#endif
+
void
reset() noexcept
{ __weak_ptr().swap(*this); }
};
};
+ftms = {
+ name = smart_ptr_owner_equality;
+ values = {
+ v = 202306;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
ftms = {
name = sstream_from_string_view;
values = {
#endif /* !defined(__cpp_lib_polymorphic) && defined(__glibcxx_want_polymorphic) */
#undef __glibcxx_want_polymorphic
+#if !defined(__cpp_lib_smart_ptr_owner_equality)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_smart_ptr_owner_equality 202306L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_smart_ptr_owner_equality)
+# define __cpp_lib_smart_ptr_owner_equality 202306L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_smart_ptr_owner_equality) && defined(__glibcxx_want_smart_ptr_owner_equality) */
+#undef __glibcxx_want_smart_ptr_owner_equality
+
#if !defined(__cpp_lib_sstream_from_string_view)
# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
# define __glibcxx_sstream_from_string_view 202306L
#define __glibcxx_want_smart_ptr_for_overwrite
#define __glibcxx_want_to_address
#define __glibcxx_want_transparent_operators
+#define __glibcxx_want_smart_ptr_owner_equality
#include <bits/version.h>
#if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED
--- /dev/null
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.6 Struct owner_equal [util.smartptr.owner.equal]
+
+#include <memory>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+struct A { };
+
+struct B { A a[2]; };
+
+int
+test01()
+{
+ // test empty shared_ptr owners compare equivalent
+ std::owner_equal eq;
+ std::shared_ptr<A> p1;
+ std::shared_ptr<A> p2;
+ VERIFY( eq(p1, p2) && eq(p2, p1) );
+ std::weak_ptr<A> p3;
+ VERIFY( eq(p1, p3) && eq(p3, p1) );
+ VERIFY( eq(p1, p3) && eq(p3, p1) );
+ return 0;
+}
+
+
+// Construction from pointer
+int
+test02()
+{
+ std::owner_equal eq;
+
+ std::shared_ptr<A> empty;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( !eq(empty, a1) && !eq(a1, empty) );
+
+ std::shared_ptr<A> a2(new A);
+ VERIFY( !eq(a1, a2) && !eq(a2, a1) );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( eq(a1, w1) && eq(w1, a1) );
+
+ std::weak_ptr<A> w2(a2);
+ VERIFY( !eq(w1, w2) && !eq(w2, w1) );
+
+ a1.reset();
+ VERIFY( eq(empty, a1) && eq(a1, empty) );
+ VERIFY( !eq(a1, w1) && !eq(w1, a1) );
+
+ a2.reset();
+ VERIFY( eq(a2, a1) && eq(a1, a2) );
+
+ return 0;
+}
+
+// aliasing
+int
+test03()
+{
+ std::owner_equal eq;
+
+ std::shared_ptr<B> b(new B);
+ std::shared_ptr<A> a0(b, &b->a[0]);
+ std::shared_ptr<A> a1(b, &b->a[1]);
+ // values are different but owners are equivalent:
+ VERIFY( a0 < a1 && eq(a0, a1) && eq(b, a0) && eq(b, a1) );
+
+ std::weak_ptr<A> w0(a0);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( eq(w0, w1) && eq(w1, w0) );
+ VERIFY( eq(a0, w1) && eq(w1, a0) );
+ VERIFY( eq(w0, a1) && eq(a1, w0) );
+
+ return 0;
+}
+
+// as binary predicate
+int
+test04()
+{
+ std::owner_equal eq;
+
+ std::shared_ptr<B> b(new B);
+ std::shared_ptr<A> a0(b, &b->a[0]);
+ std::shared_ptr<A> a1(b, &b->a[1]);
+ std::shared_ptr<A> c(new A);
+ std::weak_ptr<A> a[3]{a0, a1, c};
+ std::weak_ptr<A>* p = std::unique(a, a+3, eq);
+ VERIFY( p == &a[2] );
+
+ return 0;
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ return 0;
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.6 Struct owner_equal [util.smartptr.owner.equal]
+
+#include <memory>
+
+#ifndef __cpp_lib_smart_ptr_owner_equality
+# error "Feature-test macro for smart ptr owner equality missing in <memory>"
+#elif __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "Feature-test macro for smart ptr owner equality has wrong value in <memory>"
+#endif
+
+const std::owner_equal eq;
+const std::shared_ptr<int> si;
+const std::weak_ptr<int> wi;
+static_assert( noexcept(!eq(si, si)) );
+static_assert( noexcept(!eq(si, wi)) );
+static_assert( noexcept(!eq(wi, si)) );
+static_assert( noexcept(!eq(wi, wi)) );
+static_assert( noexcept(!eq(si, wi)) );
+static_assert( noexcept(!eq(wi, si)) );
+const std::shared_ptr<long> sl;
+const std::weak_ptr<char> wc;
+static_assert( noexcept(!eq(si, si)) );
+static_assert( noexcept(!eq(si, sl)) );
+static_assert( noexcept(!eq(sl, si)) );
+static_assert( noexcept(!eq(si, wc)) );
+static_assert( noexcept(!eq(wc, si)) );
+static_assert( noexcept(!eq(wc, wi)) );
--- /dev/null
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 17.3.2 Header <version> synopsis [version.syn]
+
+#include <version>
+
+#ifndef __cpp_lib_smart_ptr_owner_equality
+# error "Feature-test macro for smart ptr owner equality missing in <version>"
+#elif __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "Feature-test macro for smart ptr owner equality has wrong value in <version>"
+#endif
+
--- /dev/null
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.5 Struct owner_hash [util.smartptr.owner.hash]
+
+#include <memory>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+struct A { };
+
+struct B { A a[2]; };
+
+int
+test01()
+{
+ // test empty shared_ptr hashes compare equivalent
+ std::owner_hash oh;
+ std::shared_ptr<A> p1;
+ std::shared_ptr<A> p2;
+ VERIFY( oh(p1) == oh(p2) );
+ std::weak_ptr<A> p3;
+ VERIFY( oh(p1) == oh(p3) );
+ VERIFY( oh(p1) == oh(p3) );
+ return 0;
+}
+
+
+// Construction from pointer
+int
+test02()
+{
+ std::owner_hash oh;
+
+ std::shared_ptr<A> empty;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( oh(empty) != oh(a1) );
+
+ std::shared_ptr<A> a2(new A);
+ VERIFY( oh(a1) != oh(a2) );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( oh(a1) == oh(w1) );
+
+ std::weak_ptr<A> w2(a2);
+ VERIFY( oh(w1) != oh(w2) );
+
+ a1.reset();
+ VERIFY( oh(empty) == oh(a1) );
+ VERIFY( oh(a1) != oh(w1) );
+
+ a2.reset();
+ VERIFY( oh(a2) == oh(a1) );
+
+ return 0;
+}
+
+// aliasing
+int
+test03()
+{
+ std::owner_hash oh;
+
+ std::shared_ptr<B> b(new B);
+ std::shared_ptr<A> a0(b, &b->a[0]);
+ std::shared_ptr<A> a1(b, &b->a[1]);
+ // values are different but owners are ohuivalent:
+ VERIFY( a0 < a1 && oh(a0) == oh(a1) && oh(b) == oh(a0) && oh(b) == oh(a1) );
+
+ std::weak_ptr<A> w0(a0);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( oh(w0) == oh(w1) );
+ VERIFY( oh(a0) == oh(w1) );
+ VERIFY( oh(w0) == oh(a1) );
+
+ return 0;
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.5 Struct owner_hash [util.smartptr.owner.hash]
+
+#include <memory>
+
+const std::owner_hash oh;
+const std::shared_ptr<int> si;
+const std::weak_ptr<int> wi;
+static_assert( noexcept(!oh(si)) );
+static_assert( noexcept(!oh(wi)) );
+const std::shared_ptr<long> sl;
+const std::weak_ptr<char> wc;
+static_assert( noexcept(!oh(sl)) );
+static_assert( noexcept(!oh(wc)) );
--- /dev/null
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.2.6 shared_ptr observers [util.smartptr.shared.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A
+{
+ int i;
+ virtual ~A() { }
+};
+
+struct B : A
+{
+};
+
+void
+test01()
+{
+ // test empty shared_ptr owners compare equivalent
+ std::shared_ptr<A> p1;
+ std::shared_ptr<B> p2;
+ VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+}
+
+
+// Construction from pointer
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( !a1.owner_equal(a0) && !a0.owner_equal(a1) );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( !a1.owner_equal(b1) && !b1.owner_equal(a1) );
+
+ std::shared_ptr<A> a2(a1);
+ VERIFY( a1.owner_equal(a2) && a2.owner_equal(a1) );
+ a2 = b1;
+ VERIFY( b1.owner_equal(a2) && a2.owner_equal(b1) );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_equal(w1) && w1.owner_equal(a1) );
+ std::weak_ptr<A> w2(a2);
+ VERIFY( b1.owner_equal(w2) && w2.owner_equal(b1) );
+
+ static_assert( noexcept(a1.owner_equal(a0)) );
+ static_assert( noexcept(a1.owner_equal(b1)) );
+ static_assert( noexcept(b1.owner_equal(a1)) );
+ static_assert( noexcept(a1.owner_equal(w1)) );
+ static_assert( noexcept(b1.owner_equal(w1)) );
+}
+
+// Aliasing
+void
+test03()
+{
+ std::shared_ptr<A> p1(new A());
+ std::shared_ptr<int> p2(p1, &p1->i);
+ VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
--- /dev/null
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.2.6 shared_ptr observers [util.smartptr.shared.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A
+{
+ int i;
+ virtual ~A() { }
+};
+
+struct B : A
+{
+};
+
+void
+test01()
+{
+ // test empty shared_ptr hashes compare equivalent
+ std::shared_ptr<A> p1;
+ std::shared_ptr<B> p2;
+ VERIFY( p1.owner_hash() == p2.owner_hash() );
+}
+
+
+// Construction from pointer
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( a1.owner_hash() != a0.owner_hash() );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( a1.owner_hash() != b1.owner_hash() );
+
+ std::shared_ptr<A> a2(a1);
+ VERIFY( a1.owner_hash() == a2.owner_hash() );
+ a2 = b1;
+ VERIFY( b1.owner_hash() == a2.owner_hash() );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_hash() == w1.owner_hash() );
+ std::weak_ptr<A> w2(a2);
+ VERIFY( b1.owner_hash() == w2.owner_hash() );
+
+ static_assert( noexcept(a1.owner_hash()) );
+ static_assert( noexcept(b1.owner_hash()) );
+}
+
+// Aliasing
+void
+test03()
+{
+ std::shared_ptr<A> p1(new A());
+ std::shared_ptr<int> p2(p1, &p1->i);
+ VERIFY( p1.owner_hash() == p2.owner_hash() );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
--- /dev/null
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.3.6 weak_ptr observers [util.smartptr.weak.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A { };
+struct B { };
+
+void
+test01()
+{
+ // test empty weak_ptr owners compare equivalent
+ std::weak_ptr<A> p1;
+ std::weak_ptr<B> p2;
+ VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+
+ std::shared_ptr<B> p3;
+ VERIFY( p1.owner_equal(p3) && p3.owner_equal(p1) );
+
+ static_assert( noexcept(p1.owner_equal(p1)) );
+ static_assert( noexcept(p1.owner_equal(p2)) );
+ static_assert( noexcept(p1.owner_equal(p3)) );
+ static_assert( noexcept(p2.owner_equal(p1)) );
+}
+
+
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+ std::weak_ptr<A> w0(a0);
+
+ std::shared_ptr<A> a1(new A);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_equal(w1) && w1.owner_equal(a1) );
+ VERIFY( !w1.owner_equal(w0) && !w0.owner_equal(w1) );
+ VERIFY( !w1.owner_equal(a0) && !a0.owner_equal(w1) );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( !w1.owner_equal(b1) && !b1.owner_equal(w1) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ return 0;
+}
--- /dev/null
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.3.6 weak_ptr observers [util.smartptr.weak.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A { };
+struct B { };
+
+void
+test01()
+{
+ // test empty weak_ptr hashes compare equivalent
+ std::weak_ptr<A> p1;
+ std::weak_ptr<B> p2;
+ VERIFY( p1.owner_hash() == p2.owner_hash() );
+
+ std::shared_ptr<B> p3;
+ VERIFY( p1.owner_hash() == p3.owner_hash() );
+
+ static_assert( noexcept(p1.owner_hash()) );
+ static_assert( noexcept(p2.owner_hash()) );
+}
+
+
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+ std::weak_ptr<A> w0(a0);
+
+ std::shared_ptr<A> a1(new A);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_hash() == w1.owner_hash() );
+ VERIFY( w1.owner_hash() != w0.owner_hash() );
+ VERIFY( w1.owner_hash() != a0.owner_hash() );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( w1.owner_hash() != b1.owner_hash() );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ return 0;
+}