[libcxx-commits] [libcxx] [libc++] Add __is_transparently_comparable_v optimizations for set and multiset [Issue 187105] (PR #189735)

Michael Levine via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 9 21:58:09 PDT 2026


https://github.com/levinem updated https://github.com/llvm/llvm-project/pull/189735

>From 508f88ced34aa636b9bf3ee66ec71d5f984e4f20 Mon Sep 17 00:00:00 2001
From: mlevine55 <mlevine55 at bloomberg.net>
Date: Thu, 26 Mar 2026 12:11:29 -0400
Subject: [PATCH 1/3] added __is_transparently_comparable_v optimizations for
 multimap and for some map functions

Signed-off-by: mlevine55 <mlevine55 at bloomberg.net>
---
 libcxx/include/map                            |  52 ++++--
 ...kup_with_transparently_comparable.pass.cpp | 150 ++++++++++++++++++
 2 files changed, 189 insertions(+), 13 deletions(-)
 create mode 100644 libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp

diff --git a/libcxx/include/map b/libcxx/include/map
index b7031aeb51c7a..09db3982db526 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -1331,7 +1331,9 @@ public:
     return __tree_.__count_unique(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
     return __tree_.__count_multi(__k);
   }
@@ -1403,11 +1405,15 @@ public:
     return __tree_.__equal_range_unique(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
     return __tree_.__equal_range_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
     return __tree_.__equal_range_multi(__k);
   }
@@ -1917,11 +1923,15 @@ public:
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); }
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
     return __tree_.find(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
     return __tree_.find(__k);
   }
@@ -1931,7 +1941,9 @@ public:
     return __tree_.__count_multi(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
     return __tree_.__count_multi(__k);
   }
@@ -1939,7 +1951,9 @@ public:
 
 #  if _LIBCPP_STD_VER >= 20
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
     return find(__k) != end();
   }
@@ -1954,12 +1968,16 @@ public:
   }
 
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
     return __tree_.__lower_bound_multi(__k);
   }
 
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
     return __tree_.__lower_bound_multi(__k);
   }
@@ -1974,11 +1992,15 @@ public:
   }
 
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
     return __tree_.__upper_bound_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
     return __tree_.__upper_bound_multi(__k);
   }
@@ -1991,11 +2013,15 @@ public:
     return __tree_.__equal_range_multi(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
     return __tree_.__equal_range_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
     return __tree_.__equal_range_multi(__k);
   }
diff --git a/libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp b/libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp
new file mode 100644
index 0000000000000..24bba0b571633
--- /dev/null
+++ b/libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp
@@ -0,0 +1,150 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// Make sure that lookup operations on ordered associative containers are
+// transparent when they can, even when not using a comparator that advertises
+// itself as transparent (e.g. std::less<>). This is a libc++ QoI extension.
+//
+// At the moment, we only implement this optimization when the key stored in
+// the container is std::string, so the tests are written with that assumption.
+
+#include <cassert>
+#include <functional>
+#include <map>
+#include <set>
+#include <string>
+
+#include "count_new.h"
+#include "test_macros.h"
+
+template <class Container>
+void test() {
+  // Use a string longer than the SSO so that construction must allocate.
+  const char* key = "long-string-to-exceed-SSO-buffer";
+
+  // find
+  {
+    Container c;
+    globalMemCounter.reset();
+    (void)c.find(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+  {
+    Container const c;
+    globalMemCounter.reset();
+    (void)c.find(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+
+  // count
+  {
+    Container c;
+    globalMemCounter.reset();
+    (void)c.count(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+  {
+    Container const c;
+    globalMemCounter.reset();
+    (void)c.count(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+
+#if TEST_STD_VER >= 20
+  // contains
+  {
+    Container c;
+    globalMemCounter.reset();
+    (void)c.contains(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+  {
+    Container const c;
+    globalMemCounter.reset();
+    (void)c.contains(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+#endif
+
+  // lower_bound
+  {
+    Container c;
+    globalMemCounter.reset();
+    (void)c.lower_bound(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+  {
+    Container const c;
+    globalMemCounter.reset();
+    (void)c.lower_bound(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+
+  // upper_bound
+  {
+    Container c;
+    globalMemCounter.reset();
+    (void)c.upper_bound(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+  {
+    Container const c;
+    globalMemCounter.reset();
+    (void)c.upper_bound(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+
+  // equal_range
+  {
+    Container c;
+    globalMemCounter.reset();
+    (void)c.equal_range(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+  {
+    Container const c;
+    globalMemCounter.reset();
+    (void)c.equal_range(key);
+    assert(globalMemCounter.checkNewCalledEq(0));
+  }
+}
+
+int main(int, char**) {
+  test<std::map<std::string, int>>();
+  test<std::multimap<std::string, int>>();
+  // TODO: Implement the optimization for set and multiset
+  // test<std::set<std::string>>();
+  // test<std::multiset<std::string>>();
+
+  test<std::map<std::string, int, std::greater<std::string>>>();
+  test<std::multimap<std::string, int, std::greater<std::string>>>();
+  // test<std::set<std::string, std::greater<std::string>>>();
+  // test<std::multiset<std::string, std::greater<std::string>>>();
+
+  {
+    // std::map only: map::at
+    std::map<std::string, int> c;
+    char const* key = "long-string-to-exceed-SSO-buffer";
+    c[key]          = 1;
+    {
+      globalMemCounter.reset();
+      (void)c.at(key);
+      assert(globalMemCounter.checkNewCalledEq(0));
+    }
+    {
+      const std::map<std::string, int>& cc = c;
+      globalMemCounter.reset();
+      (void)cc.at(key);
+      assert(globalMemCounter.checkNewCalledEq(0));
+    }
+  }
+
+  return 0;
+}

>From 7c98d24204f4e9ab78495459b5cdcc5962264d25 Mon Sep 17 00:00:00 2001
From: mlevine55 <mlevine55 at bloomberg.net>
Date: Thu, 26 Mar 2026 13:23:14 -0400
Subject: [PATCH 2/3] copy of a different pr's test setup that can be expanded
 in that test file directly

Signed-off-by: mlevine55 <mlevine55 at bloomberg.net>
---
 ...kup_with_transparently_comparable.pass.cpp | 150 ------------------
 1 file changed, 150 deletions(-)
 delete mode 100644 libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp

diff --git a/libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp b/libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp
deleted file mode 100644
index 24bba0b571633..0000000000000
--- a/libcxx/test/libcxx/containers/associative/lookup_with_transparently_comparable.pass.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-
-// Make sure that lookup operations on ordered associative containers are
-// transparent when they can, even when not using a comparator that advertises
-// itself as transparent (e.g. std::less<>). This is a libc++ QoI extension.
-//
-// At the moment, we only implement this optimization when the key stored in
-// the container is std::string, so the tests are written with that assumption.
-
-#include <cassert>
-#include <functional>
-#include <map>
-#include <set>
-#include <string>
-
-#include "count_new.h"
-#include "test_macros.h"
-
-template <class Container>
-void test() {
-  // Use a string longer than the SSO so that construction must allocate.
-  const char* key = "long-string-to-exceed-SSO-buffer";
-
-  // find
-  {
-    Container c;
-    globalMemCounter.reset();
-    (void)c.find(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-  {
-    Container const c;
-    globalMemCounter.reset();
-    (void)c.find(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-
-  // count
-  {
-    Container c;
-    globalMemCounter.reset();
-    (void)c.count(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-  {
-    Container const c;
-    globalMemCounter.reset();
-    (void)c.count(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-
-#if TEST_STD_VER >= 20
-  // contains
-  {
-    Container c;
-    globalMemCounter.reset();
-    (void)c.contains(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-  {
-    Container const c;
-    globalMemCounter.reset();
-    (void)c.contains(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-#endif
-
-  // lower_bound
-  {
-    Container c;
-    globalMemCounter.reset();
-    (void)c.lower_bound(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-  {
-    Container const c;
-    globalMemCounter.reset();
-    (void)c.lower_bound(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-
-  // upper_bound
-  {
-    Container c;
-    globalMemCounter.reset();
-    (void)c.upper_bound(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-  {
-    Container const c;
-    globalMemCounter.reset();
-    (void)c.upper_bound(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-
-  // equal_range
-  {
-    Container c;
-    globalMemCounter.reset();
-    (void)c.equal_range(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-  {
-    Container const c;
-    globalMemCounter.reset();
-    (void)c.equal_range(key);
-    assert(globalMemCounter.checkNewCalledEq(0));
-  }
-}
-
-int main(int, char**) {
-  test<std::map<std::string, int>>();
-  test<std::multimap<std::string, int>>();
-  // TODO: Implement the optimization for set and multiset
-  // test<std::set<std::string>>();
-  // test<std::multiset<std::string>>();
-
-  test<std::map<std::string, int, std::greater<std::string>>>();
-  test<std::multimap<std::string, int, std::greater<std::string>>>();
-  // test<std::set<std::string, std::greater<std::string>>>();
-  // test<std::multiset<std::string, std::greater<std::string>>>();
-
-  {
-    // std::map only: map::at
-    std::map<std::string, int> c;
-    char const* key = "long-string-to-exceed-SSO-buffer";
-    c[key]          = 1;
-    {
-      globalMemCounter.reset();
-      (void)c.at(key);
-      assert(globalMemCounter.checkNewCalledEq(0));
-    }
-    {
-      const std::map<std::string, int>& cc = c;
-      globalMemCounter.reset();
-      (void)cc.at(key);
-      assert(globalMemCounter.checkNewCalledEq(0));
-    }
-  }
-
-  return 0;
-}

>From 1fdca3169109098032e24a1ab3e7991ffaf896c1 Mon Sep 17 00:00:00 2001
From: mlevine55 <mlevine55 at bloomberg.net>
Date: Tue, 31 Mar 2026 14:31:47 -0400
Subject: [PATCH 3/3] set and multiset optimizations

Signed-off-by: mlevine55 <mlevine55 at bloomberg.net>
---
 libcxx/include/set | 80 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 60 insertions(+), 20 deletions(-)

diff --git a/libcxx/include/set b/libcxx/include/set
index 695b6c87e3984..ff1de085c1d8b 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -825,11 +825,15 @@ public:
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); }
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
     return __tree_.find(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
     return __tree_.find(__k);
   }
@@ -839,7 +843,9 @@ public:
     return __tree_.__count_unique(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
     return __tree_.__count_multi(__k);
   }
@@ -847,7 +853,9 @@ public:
 
 #  if _LIBCPP_STD_VER >= 20
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
     return find(__k) != end();
   }
@@ -864,12 +872,16 @@ public:
   // The transparent versions of the lookup functions use the _multi version, since a non-element key is allowed to
   // match multiple elements.
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
     return __tree_.__lower_bound_multi(__k);
   }
 
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
     return __tree_.__lower_bound_multi(__k);
   }
@@ -884,11 +896,15 @@ public:
   }
 
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
     return __tree_.__upper_bound_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
     return __tree_.__upper_bound_multi(__k);
   }
@@ -901,11 +917,15 @@ public:
     return __tree_.__equal_range_unique(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
     return __tree_.__equal_range_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
     return __tree_.__equal_range_multi(__k);
   }
@@ -1302,11 +1322,15 @@ public:
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); }
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
     return __tree_.find(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
     return __tree_.find(__k);
   }
@@ -1316,7 +1340,9 @@ public:
     return __tree_.__count_multi(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
     return __tree_.__count_multi(__k);
   }
@@ -1324,7 +1350,9 @@ public:
 
 #  if _LIBCPP_STD_VER >= 20
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
     return find(__k) != end();
   }
@@ -1339,12 +1367,16 @@ public:
   }
 
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
     return __tree_.__lower_bound_multi(__k);
   }
 
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
     return __tree_.__lower_bound_multi(__k);
   }
@@ -1359,11 +1391,15 @@ public:
   }
 
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
     return __tree_.__upper_bound_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
     return __tree_.__upper_bound_multi(__k);
   }
@@ -1376,11 +1412,15 @@ public:
     return __tree_.__equal_range_multi(__k);
   }
 #  if _LIBCPP_STD_VER >= 14
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
     return __tree_.__equal_range_multi(__k);
   }
-  template <typename _K2, class _Comp = _Compare, enable_if_t<__is_transparent_v<_Comp>, int> = 0>
+  template <typename _K2,
+            class _Comp = _Compare,
+            enable_if_t<__is_transparent_v<_Comp> || __is_transparently_comparable_v<_Comp, key_type, _K2>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
     return __tree_.__equal_range_multi(__k);
   }



More information about the libcxx-commits mailing list