[libcxx-commits] [libcxx] [WIP][libc++] Implement find_first_of in terms of find_if or find (PR #207276)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 2 13:48:50 PDT 2026


https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/207276

This allows taking advantage of optimizations in find_if and find in that algorithm.

Closes #129319

>From b636d2308702c846194c588d4040e0c0635fbd1d Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 2 Jul 2026 16:47:46 -0400
Subject: [PATCH] [WIP][libc++] Implement find_first_of in terms of find_if or
 find

This allows taking advantage of optimizations in find_if and find
in that algorithm.

Closes #129319
---
 libcxx/include/__algorithm/find_first_of.h    | 36 +++++++++++++++----
 .../__algorithm/ranges_find_first_of.h        |  1 +
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/__algorithm/find_first_of.h b/libcxx/include/__algorithm/find_first_of.h
index 45ec133154371..c6f4bdb0874a0 100644
--- a/libcxx/include/__algorithm/find_first_of.h
+++ b/libcxx/include/__algorithm/find_first_of.h
@@ -11,7 +11,11 @@
 #define _LIBCPP___ALGORITHM_FIND_FIRST_OF_H
 
 #include <__algorithm/comp.h>
+#include <__algorithm/find.h>
+#include <__algorithm/find_if.h>
 #include <__config>
+#include <__iterator/iterator_traits.h>
+#include <__type_traits/desugars_to.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -20,16 +24,36 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1 __find_first_of_ce(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1 __find_first_of(
     _ForwardIterator1 __first1,
     _ForwardIterator1 __last1,
     _ForwardIterator2 __first2,
     _ForwardIterator2 __last2,
     _BinaryPredicate&& __pred) {
-  for (; __first1 != __last1; ++__first1)
-    for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
-      if (__pred(*__first1, *__j))
+  for (; __first1 != __last1; ++__first1) {
+#ifndef _LIBCPP_CXX03_LANG
+
+    using _Ref1 = typename iterator_traits<_ForwardIterator1>::reference;
+    using _Ref2 = typename iterator_traits<_ForwardIterator2>::reference;
+
+    if constexpr (__desugars_to<__equal_tag, _BinaryPredicate, _Ref1, _Ref2>) {
+      _ForwardIterator2 __found = std::find(__first2, __last2, *__first1);
+      if (__found != __last2)
         return __first1;
+    } else {
+      _ForwardIterator2 __found = std::find_if(__first2, __last2, [&](auto&& __x) { return __pred(*__first1, __x); });
+      if (__found != __last2)
+        return __first1;
+    }
+
+#else
+
+    _ForwardIterator2 __found = std::find_if(__first2, __last2, [&](auto&& __x) { return __pred(*__first1, __x); });
+    if (__found != __last2)
+      return __first1;
+
+#endif
+  }
   return __last1;
 }
 
@@ -40,13 +64,13 @@ template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredica
     _ForwardIterator2 __first2,
     _ForwardIterator2 __last2,
     _BinaryPredicate __pred) {
-  return std::__find_first_of_ce(__first1, __last1, __first2, __last2, __pred);
+  return std::__find_first_of(__first1, __last1, __first2, __last2, __pred);
 }
 
 template <class _ForwardIterator1, class _ForwardIterator2>
 [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 find_first_of(
     _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) {
-  return std::__find_first_of_ce(__first1, __last1, __first2, __last2, __equal_to());
+  return std::__find_first_of(__first1, __last1, __first2, __last2, __equal_to());
 }
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/ranges_find_first_of.h b/libcxx/include/__algorithm/ranges_find_first_of.h
index 102e16dd7a55b..62e4fbbff6738 100644
--- a/libcxx/include/__algorithm/ranges_find_first_of.h
+++ b/libcxx/include/__algorithm/ranges_find_first_of.h
@@ -42,6 +42,7 @@ struct __find_first_of {
       _Pred& __pred,
       _Proj1& __proj1,
       _Proj2& __proj2) {
+    // TODO: also implement this via __find_first_of (requires projection support?)
     for (; __first1 != __last1; ++__first1) {
       for (auto __j = __first2; __j != __last2; ++__j) {
         if (std::invoke(__pred, std::invoke(__proj1, *__first1), std::invoke(__proj2, *__j)))



More information about the libcxx-commits mailing list