[libc++] Implement P1901R2: owner_hash and owner_equal for shared_ptr/weak_ptr#210551
[libc++] Implement P1901R2: owner_hash and owner_equal for shared_ptr/weak_ptr#210551firedog1234 wants to merge 3 commits into
Conversation
|
@llvm/pr-subscribers-libcxx Author: Avi Patel (firedog1234) ChangesSummaryImplements P1901R2 (C++26), adding ownership-based hashing and equality support for This change:
Fixes #105372. Test Plan
AcknowledgementsClaude assisted with test development and documentation. Patch is 27.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/210551.diff 17 Files Affected:
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 6bf2f35fb4212..8a26828240de4 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -526,7 +526,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_senders`` *unimplemented*
---------------------------------------------------------- -----------------
- ``__cpp_lib_smart_ptr_owner_equality`` *unimplemented*
+ ``__cpp_lib_smart_ptr_owner_equality`` ``202306L``
---------------------------------------------------------- -----------------
``__cpp_lib_span_at`` ``202311L``
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 1213e8f43c8cd..1dee9843c9c55 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -55,6 +55,7 @@ Implemented Papers
- P3369R0: constexpr for ``uninitialized_default_construct`` (`Github <https://llvm.org/PR118380>`__)
- P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github <https://llvm.org/PR118379>`__)
- P4206R0: Revert string support in ``std::constant_wrapper`` (`Github <https://llvm.org/PR203338>`__)
+- P1901R2: Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers (`Github <https://llvm.org/PR105372>`__)
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index efc98495d1d5c..98135f198110c 100644
--- a/libcxx/docs/Status/Cxx26Papers.csv
+++ b/libcxx/docs/Status/Cxx26Papers.csv
@@ -12,7 +12,7 @@
"`P2338R4 <https://wg21.link/P2338R4>`__","Freestanding Library: Character primitives and the C library","2023-06 (Varna)","","","`#105369 <https://github.com/llvm/llvm-project/issues/105369>`__",""
"`P2013R5 <https://wg21.link/P2013R5>`__","Freestanding Language: Optional ``::operator new``","2023-06 (Varna)","","","`#105370 <https://github.com/llvm/llvm-project/issues/105370>`__",""
"`P2363R5 <https://wg21.link/P2363R5>`__","Extending associative containers with the remaining heterogeneous overloads","2023-06 (Varna)","","","`#105371 <https://github.com/llvm/llvm-project/issues/105371>`__",""
-"`P1901R2 <https://wg21.link/P1901R2>`__","Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers","2023-06 (Varna)","","","`#105372 <https://github.com/llvm/llvm-project/issues/105372>`__",""
+"`P1901R2 <https://wg21.link/P1901R2>`__","Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers","2023-06 (Varna)","|Complete|","23","`#105372 <https://github.com/llvm/llvm-project/issues/105372>`__",""
"`P1885R12 <https://wg21.link/P1885R12>`__","Naming Text Encodings to Demystify Them","2023-06 (Varna)","|Complete|","23","`#105373 <https://github.com/llvm/llvm-project/issues/105373>`__",""
"`P0792R14 <https://wg21.link/P0792R14>`__","``function_ref``: a type-erased callable reference","2023-06 (Varna)","","","`#105376 <https://github.com/llvm/llvm-project/issues/105376>`__",""
"`P2874R2 <https://wg21.link/P2874R2>`__","P2874R2: Mandating Annex D Require No More","2023-06 (Varna)","|Complete|","12","`#105377 <https://github.com/llvm/llvm-project/issues/105377>`__",""
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index ebd542ba14d01..0770f2a8e383d 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -18,6 +18,7 @@
#include <__cstddef/ptrdiff_t.h>
#include <__exception/exception.h>
#include <__functional/binary_function.h>
+#include <__functional/hash.h>
#include <__functional/operations.h>
#include <__functional/reference_wrapper.h>
#include <__fwd/ostream.h>
@@ -555,6 +556,22 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr {
_LIBCPP_HIDE_FROM_ABI bool __owner_equivalent(const shared_ptr& __p) const { return __cntrl_ == __p.__cntrl_; }
+#if _LIBCPP_STD_VER >= 26
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t owner_hash() const _NOEXCEPT {
+ return std::hash<__shared_weak_count*>()(__cntrl_);
+ }
+
+ template <class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(shared_ptr<_Up> const& __p) const _NOEXCEPT {
+ return __cntrl_ == __p.__cntrl_;
+ }
+
+ template <class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(weak_ptr<_Up> const& __p) const _NOEXCEPT {
+ return __cntrl_ == __p.__cntrl_;
+ }
+#endif
+
#if _LIBCPP_STD_VER >= 17
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __add_lvalue_reference_t<element_type> operator[](ptrdiff_t __i) const {
static_assert(is_array<_Tp>::value, "std::shared_ptr<T>::operator[] is only valid when T is an array type.");
@@ -1244,6 +1261,22 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI weak_ptr {
return __cntrl_ < __r.__cntrl_;
}
+#if _LIBCPP_STD_VER >= 26
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t owner_hash() const _NOEXCEPT {
+ return std::hash<__shared_weak_count*>()(__cntrl_);
+ }
+
+ template <class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(shared_ptr<_Up> const& __p) const _NOEXCEPT {
+ return __cntrl_ == __p.__cntrl_;
+ }
+
+ template <class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_equal(weak_ptr<_Up> const& __p) const _NOEXCEPT {
+ return __cntrl_ == __p.__cntrl_;
+ }
+#endif
+
template <class _Up>
friend class weak_ptr;
template <class _Up>
@@ -1317,6 +1350,44 @@ struct owner_less<void> {
};
#endif
+#if _LIBCPP_STD_VER >= 26
+struct owner_hash {
+ template <class _Tp>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(shared_ptr<_Tp> const& __p) const _NOEXCEPT {
+ return __p.owner_hash();
+ }
+ template <class _Tp>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(weak_ptr<_Tp> const& __p) const _NOEXCEPT {
+ return __p.owner_hash();
+ }
+ typedef void is_transparent;
+};
+
+struct owner_equal {
+ template <class _Tp, class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(shared_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) const _NOEXCEPT {
+ return __x.owner_equal(__y);
+ }
+ template <class _Tp, class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(shared_ptr<_Tp> const& __x, weak_ptr<_Up> const& __y) const _NOEXCEPT {
+ return __x.owner_equal(__y);
+ }
+ template <class _Tp, class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(weak_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) const _NOEXCEPT {
+ return __x.owner_equal(__y);
+ }
+ template <class _Tp, class _Up>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool
+ operator()(weak_ptr<_Tp> const& __x, weak_ptr<_Up> const& __y) const _NOEXCEPT {
+ return __x.owner_equal(__y);
+ }
+ typedef void is_transparent;
+};
+#endif
+
template <class _Tp>
class enable_shared_from_this {
mutable weak_ptr<_Tp> __weak_this_;
diff --git a/libcxx/include/memory b/libcxx/include/memory
index d5d48ed9a9e6d..03636ddb839b0 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -633,6 +633,9 @@ public:
explicit operator bool() const noexcept;
template<class U> bool owner_before(shared_ptr<U> const& b) const noexcept;
template<class U> bool owner_before(weak_ptr<U> const& b) const noexcept;
+ size_t owner_hash() const noexcept; // C++26
+ template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26
+ template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26
};
template<class T>
@@ -771,6 +774,9 @@ public:
shared_ptr<T> lock() const noexcept;
template<class U> bool owner_before(shared_ptr<U> const& b) const noexcept;
template<class U> bool owner_before(weak_ptr<U> const& b) const noexcept;
+ size_t owner_hash() const noexcept; // C++26
+ template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26
+ template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26
};
template<class T>
@@ -817,6 +823,32 @@ struct owner_less<void>
typedef void is_transparent;
};
+// class owner_hash: // C++26
+struct owner_hash
+{
+ template <class _Tp>
+ size_t operator()(shared_ptr<_Tp> const& __p) const noexcept;
+ template <class _Tp>
+ size_t operator()(weak_ptr<_Tp> const& __p) const noexcept;
+
+ typedef void is_transparent;
+};
+
+// class owner_equal: // C++26
+struct owner_equal
+{
+ template <class _Tp, class _Up>
+ bool operator()(shared_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) const noexcept;
+ template <class _Tp, class _Up>
+ bool operator()(shared_ptr<_Tp> const& __x, weak_ptr<_Up> const& __y) const noexcept;
+ template <class _Tp, class _Up>
+ bool operator()( weak_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) const noexcept;
+ template <class _Tp, class _Up>
+ bool operator()( weak_ptr<_Tp> const& __x, weak_ptr<_Up> const& __y) const noexcept;
+
+ typedef void is_transparent;
+};
+
template<class T>
class enable_shared_from_this
{
diff --git a/libcxx/include/version b/libcxx/include/version
index 4a6b01093641d..31b5cc4048e18 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -628,7 +628,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_saturation_arithmetic 202603L
// # define __cpp_lib_senders 202406L
-// # define __cpp_lib_smart_ptr_owner_equality 202306L
+# define __cpp_lib_smart_ptr_owner_equality 202306L
# define __cpp_lib_span_at 202311L
# define __cpp_lib_sstream_from_string_view 202306L
# define __cpp_lib_string_subview 202506L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
index c58357a463ffd..dc14ff766ac5c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
@@ -648,17 +648,11 @@
# error "__cpp_lib_smart_ptr_for_overwrite should have the value 202002L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
-# endif
-# if __cpp_lib_smart_ptr_owner_equality != 202306L
-# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_smart_ptr_owner_equality
+# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
+# endif
+# if __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
# endif
# ifndef __cpp_lib_to_address
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index f2d74cc99d864..11b181a66c518 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -8024,17 +8024,11 @@
# error "__cpp_lib_smart_ptr_for_overwrite should have the value 202002L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
-# endif
-# if __cpp_lib_smart_ptr_owner_equality != 202306L
-# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_smart_ptr_owner_equality
-# error "__cpp_lib_smart_ptr_owner_equality should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_smart_ptr_owner_equality
+# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26"
+# endif
+# if __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26"
# endif
# ifndef __cpp_lib_source_location
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp
new file mode 100644
index 0000000000000..0f8c6935ef811
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_shared_ptr.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <memory>
+
+// shared_ptr
+
+// template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept;
+
+#include <memory>
+#include <cassert>
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::shared_ptr<int> p3(new int);
+ const std::shared_ptr<void> empty1;
+ const std::shared_ptr<long> empty2;
+
+ assert(p1.owner_equal(p2));
+ assert(p2.owner_equal(p1));
+ assert(!p1.owner_equal(p3));
+ assert(!p3.owner_equal(p1));
+
+ assert(empty1.owner_equal(empty2));
+ assert(!p1.owner_equal(empty1));
+
+ ASSERT_SAME_TYPE(decltype(p1.owner_equal(p2)), bool);
+ ASSERT_NOEXCEPT(p1.owner_equal(p2));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp
new file mode 100644
index 0000000000000..6ac9f57e07a05
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_equal_weak_ptr.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <memory>
+
+// shared_ptr
+
+// template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept;
+
+#include <memory>
+#include <cassert>
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::shared_ptr<int> p3(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<int> w3(p3);
+ const std::shared_ptr<void> empty_sp;
+ const std::weak_ptr<long> empty_wp;
+
+ assert(p1.owner_equal(w1));
+ assert(p2.owner_equal(w1));
+ assert(!p1.owner_equal(w3));
+ assert(!p3.owner_equal(w1));
+
+ assert(empty_sp.owner_equal(empty_wp));
+
+ ASSERT_SAME_TYPE(decltype(p1.owner_equal(w1)), bool);
+ ASSERT_NOEXCEPT(p1.owner_equal(w1));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp
new file mode 100644
index 0000000000000..57967b9369fe3
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/owner_hash.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <memory>
+
+// shared_ptr
+
+// size_t owner_hash() const noexcept;
+
+#include <memory>
+#include <cassert>
+#include <cstddef>
+#include "test_macros.h"
+
+struct Pair {
+ int a;
+ int b;
+};
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::weak_ptr<int> w1(p1);
+
+ assert(p1.owner_hash() == p2.owner_hash());
+ assert(p1.owner_hash() == w1.owner_hash());
+
+ const std::shared_ptr<Pair> sp(new Pair{1, 2});
+ const std::shared_ptr<int> alias(sp, &sp->b);
+ assert(static_cast<void*>(sp.get()) != static_cast<void*>(alias.get()));
+ assert(sp.owner_hash() == alias.owner_hash());
+
+ ASSERT_SAME_TYPE(decltype(p1.owner_hash()), std::size_t);
+ ASSERT_NOEXCEPT(p1.owner_hash());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp
new file mode 100644
index 0000000000000..1c6c9e8bd5d67
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.ownerequal/owner_equal.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <memory>
+
+// struct owner_equal
+// {
+// template<class T, class U>
+// bool operator()(shared_ptr<T> const&, shared_ptr<U> const&) const noexcept;
+// template<class T, class U>
+// bool operator()(shared_ptr<T> const&, weak_ptr<U> const&) const noexcept;
+// template<class T, class U>
+// bool operator()(weak_ptr<T> const&, shared_ptr<U> const&) const noexcept;
+// template<class T, class U>
+// bool operator()(weak_ptr<T> const&, weak_ptr<U> const&) const noexcept;
+//
+// typedef unspecified is_transparent;
+// };
+
+#include <memory>
+#include <cassert>
+#include <type_traits>
+#include <unordered_set>
+#include "test_macros.h"
+
+int main(int, char**) {
+ const std::shared_ptr<int> p1(new int);
+ const std::shared_ptr<int> p2 = p1;
+ const std::shared_ptr<int> p3(new int);
+ const std::weak_ptr<int> w1(p1);
+ const std::weak_ptr<int> w3(p3);
+
+ std::owner_equal oe;
+
+ assert(oe(p1, p2));
+ assert(oe(p1, w1));
+ assert(oe(w1, p1));
+ assert(oe(w1, w1));
+
+ assert(!oe(p1, p3));
+ assert(!oe(p1, w3));
+ assert(!oe(w1, p3));
+ assert(!oe(w1, w3));
+
+ ASSERT_SAME_TYPE(decltype(oe(p1, p2)), bool);
+ ASSERT_NOEXCEPT(oe(p1, p2));
+ ASSERT_NOEXCEPT(oe(p1, w1));
+ ASSERT_NOEXCEPT(oe(w1, p1));
+ ASSERT_NOEXCEPT(oe(w1, w1));
+
+ static_assert(std::is_same<std::owner_equal::is_transparent, void>::value, "");
+
+ {
+ std::unordered_set<std::weak_p...
[truncated]
|
|
@frederick-vs-ja Would you be able to review this implementation? Thanks. |
| - P3369R0: constexpr for ``uninitialized_default_construct`` (`Github <https://llvm.org/PR118380>`__) | ||
| - P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github <https://llvm.org/PR118379>`__) | ||
| - P4206R0: Revert string support in ``std::constant_wrapper`` (`Github <https://llvm.org/PR203338>`__) | ||
| - P1901R2: Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers (`Github <https://llvm.org/PR105372>`__) |
There was a problem hiding this comment.
This line should be added to 24.rst because we won't backport this to LLVM 23.
| template <class _Tp> | ||
| size_t operator()(weak_ptr<_Tp> const& __p) const noexcept; | ||
|
|
||
| typedef void is_transparent; |
There was a problem hiding this comment.
| typedef void is_transparent; | |
| using is_transparent = unspecified; |
The standard doesn't specify the actual type. See [util.smartptr.owner.hash] and [util.smartptr.owner.equal].
There was a problem hiding this comment.
The synopsis should be copied from the standard preferably.
|
Ah, we should also modify |
|
Got it. Thanks for the review! i'll add updates. |
| size_t owner_hash() const noexcept; // C++26 | ||
| template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26 | ||
| template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26 |
There was a problem hiding this comment.
| size_t owner_hash() const noexcept; // C++26 | |
| template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26 | |
| template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26 | |
| size_t owner_hash() const noexcept; // C++26 | |
| template<class U> bool owner_equal(shared_ptr<U> const& b) const noexcept; // C++26 | |
| template<class U> bool owner_equal(weak_ptr<U> const& b) const noexcept; // C++26 |
Nit: please ident. Also bellow.
| template <class _Tp> | ||
| size_t operator()(weak_ptr<_Tp> const& __p) const noexcept; | ||
|
|
||
| typedef void is_transparent; |
There was a problem hiding this comment.
The synopsis should be copied from the standard preferably.
| #include <memory> | ||
| #include <cassert> | ||
| #include "test_macros.h" |
There was a problem hiding this comment.
| #include <memory> | |
| #include <cassert> | |
| #include "test_macros.h" | |
| #include <cassert> | |
| #include <memory> | |
| #include "test_macros.h" |
#include's should be sorted and grouped manually. Here and bellow.
| assert(p1.owner_equal(p2)); | ||
| assert(p2.owner_equal(p1)); | ||
| assert(!p1.owner_equal(p3)); | ||
| assert(!p3.owner_equal(p1)); | ||
|
|
||
| assert(empty1.owner_equal(empty2)); | ||
| assert(!p1.owner_equal(empty1)); | ||
|
|
||
| ASSERT_SAME_TYPE(decltype(p1.owner_equal(p2)), bool); | ||
| ASSERT_NOEXCEPT(p1.owner_equal(p2)); |
There was a problem hiding this comment.
Nit: The above is correct but in newer test when possible we prefer to use the non-macro versions. For example the following patterns:
| assert(p1.owner_equal(p2)); | |
| assert(p2.owner_equal(p1)); | |
| assert(!p1.owner_equal(p3)); | |
| assert(!p3.owner_equal(p1)); | |
| assert(empty1.owner_equal(empty2)); | |
| assert(!p1.owner_equal(empty1)); | |
| ASSERT_SAME_TYPE(decltype(p1.owner_equal(p2)), bool); | |
| ASSERT_NOEXCEPT(p1.owner_equal(p2)); | |
| std::same_as<bool> decltype(auto) result = p1.owner(p2); | |
| assert(result)); | |
| static_assert(noexcept(p1.owner_equal(p2))); | |
| ...etc... |
There is no specific order required but you can order them for easier reading.
|
Thanks guys for the review! I pushed updates in a new commit. |
Summary
Implements P1901R2 (C++26), adding ownership-based hashing and equality support for
std::shared_ptrandstd::weak_ptr.This change:
shared_ptr::owner_hash()/weak_ptr::owner_hash()shared_ptr::owner_equal()/weak_ptr::owner_equal()std::owner_hashandstd::owner_equalstd::weak_ptrto be used as keys in unordered associative containersFixes #105372.
Test Plan
util.smartptr.shared.obs/util.smartptr.weak.obs/util.smartptr.ownerhash/util.smartptr.ownerequal/Acknowledgements
Claude assisted with test development and documentation.