Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][ranges] P1223R5: find_last #99312

Merged
merged 10 commits into from
Jul 19, 2024
Merged

Conversation

strega-nil
Copy link
Contributor

Implements P1223R5 completely.

Includes an implementation of find_last, find_last_if, and
find_last_if_not.

Note, this is my first contribution to libc++ in a very long time, so please keep that in mind when reviewing!

@strega-nil strega-nil requested a review from a team as a code owner July 17, 2024 12:12
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jul 17, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 17, 2024

@llvm/pr-subscribers-libcxx

Author: nicole mazzuca (strega-nil)

Changes

Implements P1223R5 completely.

Includes an implementation of find_last, find_last_if, and
find_last_if_not.

Note, this is my first contribution to libc++ in a very long time, so please keep that in mind when reviewing!


Patch is 61.68 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/99312.diff

24 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+2)
  • (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1)
  • (modified) libcxx/include/CMakeLists.txt (+3)
  • (modified) libcxx/include/__algorithm/ranges_find_if.h (+2)
  • (added) libcxx/include/__algorithm/ranges_find_last.h (+103)
  • (added) libcxx/include/__algorithm/ranges_find_last_if.h (+106)
  • (added) libcxx/include/__algorithm/ranges_find_last_if_not.h (+70)
  • (modified) libcxx/include/algorithm (+23)
  • (modified) libcxx/include/module.modulemap (+3)
  • (modified) libcxx/include/version (+2)
  • (modified) libcxx/modules/std/algorithm.inc (+1-2)
  • (modified) libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp (+6)
  • (modified) libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp (+8)
  • (modified) libcxx/test/libcxx/diagnostics/algorithm.nodiscard.verify.cpp (+12)
  • (added) libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp (+284)
  • (added) libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp (+233)
  • (added) libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp (+235)
  • (modified) libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp (+5)
  • (modified) libcxx/test/std/algorithms/ranges_robust_against_nonbool.compile.pass.cpp (+4)
  • (modified) libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp (+5)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp (+31)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+31)
  • (modified) libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp (+3)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+5)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 1e347d043ef69..fcffa8d619ab9 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -360,6 +360,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_contains``                              ``202207L``
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_ranges_find_last``                             ``202207L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_iota``                                  *unimplemented*
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_join_with``                             *unimplemented*
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 4f589cd938d7c..ed50498238fd8 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -55,7 +55,7 @@
 "`P0429R9 <https://wg21.link/P0429R9>`__","LWG","A Standard ``flat_map``","July 2022","",""
 "`P1169R4 <https://wg21.link/P1169R4>`__","LWG","``static operator()``","July 2022","|Complete|","16.0"
 "`P1222R4 <https://wg21.link/P1222R4>`__","LWG","A Standard ``flat_set``","July 2022","",""
-"`P1223R5 <https://wg21.link/P1223R5>`__","LWG","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","July 2022","","","|ranges|"
+"`P1223R5 <https://wg21.link/P1223R5>`__","LWG","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","July 2022","|Complete|","19.0","|ranges|"
 "`P1467R9 <https://wg21.link/P1467R9>`__","LWG","Extended ``floating-point`` types and standard names","July 2022","",""
 "`P1642R11 <https://wg21.link/P1642R11>`__","LWG","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","July 2022","",""
 "`P1899R3 <https://wg21.link/P1899R3>`__","LWG","``stride_view``","July 2022","","","|ranges|"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index cd64fe91449c2..824806d562d23 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -97,6 +97,9 @@ set(files
   __algorithm/ranges_find_first_of.h
   __algorithm/ranges_find_if.h
   __algorithm/ranges_find_if_not.h
+  __algorithm/ranges_find_last.h
+  __algorithm/ranges_find_last_if.h
+  __algorithm/ranges_find_last_if_not.h
   __algorithm/ranges_for_each.h
   __algorithm/ranges_for_each_n.h
   __algorithm/ranges_generate.h
diff --git a/libcxx/include/__algorithm/ranges_find_if.h b/libcxx/include/__algorithm/ranges_find_if.h
index 888f9ec3cb2d5..fd2c090af2d6d 100644
--- a/libcxx/include/__algorithm/ranges_find_if.h
+++ b/libcxx/include/__algorithm/ranges_find_if.h
@@ -14,6 +14,8 @@
 #include <__functional/invoke.h>
 #include <__functional/ranges_operations.h>
 #include <__iterator/concepts.h>
+#include <__iterator/next.h>
+#include <__iterator/prev.h>
 #include <__iterator/projected.h>
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
diff --git a/libcxx/include/__algorithm/ranges_find_last.h b/libcxx/include/__algorithm/ranges_find_last.h
new file mode 100644
index 0000000000000..3aba8210660dc
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_find_last.h
@@ -0,0 +1,103 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H
+#define _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H
+
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/next.h>
+#include <__iterator/prev.h>
+#include <__iterator/projected.h>
+#include <__iterator/indirectly_comparable.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+namespace __find_last {
+struct __fn {
+  template <class _Iter, class _Sent, class _Type, class _Proj>
+  _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter>
+  __find_last_impl(_Iter __first, _Sent __last, const _Type& __value, _Proj& __proj) {
+    if (__first == __last) {
+      return subrange<_Iter>(__first, __first);
+    }
+
+    if constexpr (bidirectional_iterator<_Iter>) {
+      auto __last_it = ranges::next(__first, __last);
+      for (auto __it = ranges::prev(__last_it); __it != __first; --__it) {
+        if (std::invoke(__proj, *__it) == __value) {
+          return subrange<_Iter>(std::move(__it), std::move(__last_it));
+        }
+      }
+      if (std::invoke(__proj, *__first) == __value) {
+        return subrange<_Iter>(std::move(__first), std::move(__last_it));
+      }
+      return subrange<_Iter>(__last_it, __last_it);
+    } else {
+      bool __found = false;
+      _Iter __found_it;
+      for (; __first != __last; ++__first) {
+        if (std::invoke(__proj, *__first) == __value) {
+          __found    = true;
+          __found_it = __first;
+        }
+      }
+
+      if (__found) {
+        return subrange<_Iter>(std::move(__found_it), std::move(__first));
+      } else {
+        return subrange<_Iter>(__first, __first);
+      }
+    }
+  }
+
+  template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Type, class _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Type*>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter>
+  operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const {
+    return __find_last_impl(std::move(__first), std::move(__last), __value, __proj);
+  }
+
+  template <forward_range _Range, class _Type, class _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Type*>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range>
+  operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) const {
+    return __find_last_impl(ranges::begin(__range), ranges::end(__range), __value, __proj);
+  }
+};
+} // namespace __find_last
+
+inline namespace __cpo {
+inline constexpr auto find_last = __find_last::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H
diff --git a/libcxx/include/__algorithm/ranges_find_last_if.h b/libcxx/include/__algorithm/ranges_find_last_if.h
new file mode 100644
index 0000000000000..2435672a83b63
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_find_last_if.h
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_H
+#define _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_H
+
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/next.h>
+#include <__iterator/prev.h>
+#include <__iterator/projected.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+
+template <class _Iter, class _Sent, class _Pred, class _Proj>
+_LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter>
+__find_last_if_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
+  if (__first == __last) {
+    return subrange<_Iter>(__first, __first);
+  }
+
+  if constexpr (bidirectional_iterator<_Iter>) {
+    auto __last_it = ranges::next(__first, __last);
+    for (auto __it = ranges::prev(__last_it); __it != __first; --__it) {
+      if (std::invoke(__pred, std::invoke(__proj, *__it))) {
+        return subrange<_Iter>(std::move(__it), std::move(__last_it));
+      }
+    }
+    if (std::invoke(__pred, std::invoke(__proj, *__first))) {
+      return subrange<_Iter>(std::move(__first), std::move(__last_it));
+    }
+    return subrange<_Iter>(__last_it, __last_it);
+  } else {
+    bool __found = false;
+    _Iter __found_it;
+    for (; __first != __last; ++__first) {
+      if (std::invoke(__pred, std::invoke(__proj, *__first))) {
+        __found    = true;
+        __found_it = __first;
+      }
+    }
+
+    if (__found) {
+      return subrange<_Iter>(std::move(__found_it), std::move(__first));
+    } else {
+      return subrange<_Iter>(__first, __first);
+    }
+  }
+}
+
+namespace __find_last_if {
+struct __fn {
+  template <forward_iterator _Iter,
+            sentinel_for<_Iter> _Sent,
+            class _Proj = identity,
+            indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter>
+  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
+    return __find_last_if_impl(std::move(__first), std::move(__last), __pred, __proj);
+  }
+
+  template <forward_range _Range,
+            class _Proj = identity,
+            indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range>
+  operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
+    return __find_last_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
+  }
+};
+} // namespace __find_last_if
+
+inline namespace __cpo {
+inline constexpr auto find_last_if = __find_last_if::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_H
diff --git a/libcxx/include/__algorithm/ranges_find_last_if_not.h b/libcxx/include/__algorithm/ranges_find_last_if_not.h
new file mode 100644
index 0000000000000..4b246c96695c2
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_find_last_if_not.h
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_NOT_H
+#define _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_NOT_H
+
+#include <__algorithm/ranges_find_last_if.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/projected.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+namespace __find_last_if_not {
+struct __fn {
+  template <forward_iterator _Iter,
+            sentinel_for<_Iter> _Sent,
+            class _Proj = identity,
+            indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter>
+  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
+    auto __pred2 = [&__pred](auto&& __e) -> bool { return !std::invoke(__pred, std::forward<decltype(__e)>(__e)); };
+    return ranges::__find_last_if_impl(std::move(__first), std::move(__last), __pred2, __proj);
+  }
+
+  template <forward_range _Range,
+            class _Proj = identity,
+            indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range>
+  operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
+    auto __pred2 = [&__pred](auto&& __e) -> bool { return !std::invoke(__pred, std::forward<decltype(__e)>(__e)); };
+    return ranges::__find_last_if_impl(ranges::begin(__range), ranges::end(__range), __pred2, __proj);
+  }
+};
+} // namespace __find_last_if_not
+
+inline namespace __cpo {
+inline constexpr auto find_last_if_not = __find_last_if_not::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_NOT_H
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index a522a60f1b551..f36e396246a1d 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -101,6 +101,26 @@ namespace ranges {
            indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
     constexpr borrowed_iterator_t<R>
       find_if_not(R&& r, Pred pred, Proj proj = {});                                                      // since C++20
+																																																					//
+  template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
+    constexpr subrange<I> find_last(I first, S last, const T& value, Proj proj = {});
+	template<forward_range R, class T, class Proj = identity>
+		requires
+			indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
+		constexpr borrowed_subrange_t<R> find_last(R&& r, const T& value, Proj proj = {});
+	template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
+           indirect_unary_predicate<projected<I, Proj>> Pred>
+		constexpr subrange<I> find_last_if(I first, S last, Pred pred, Proj proj = {});
+	template<forward_range R, class Proj = identity,
+           indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+		constexpr borrowed_subrange_t<R> find_last_if(R&& r, Pred pred, Proj proj = {});
+	template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
+           indirect_unary_predicate<projected<I, Proj>> Pred>
+		constexpr subrange<I> find_last_if_not(I first, S last, Pred pred, Proj proj = {});
+	template<forward_range R, class Proj = identity,
+           indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+		constexpr borrowed_subrange_t<R> find_last_if_not(R&& r, Pred pred, Proj proj = {});
 
   template<class T, class Proj = identity,
            indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
@@ -1989,6 +2009,9 @@ template <class BidirectionalIterator, class Compare>
 #  include <__algorithm/fold.h>
 #  include <__algorithm/ranges_contains_subrange.h>
 #  include <__algorithm/ranges_ends_with.h>
+#  include <__algorithm/ranges_find_last.h>
+#  include <__algorithm/ranges_find_last_if.h>
+#  include <__algorithm/ranges_find_last_if_not.h>
 #  include <__algorithm/ranges_starts_with.h>
 #endif // _LIBCPP_STD_VER >= 23
 
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index f4aaa14c1c2ee..cbe7d03ebc0a2 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -764,6 +764,9 @@ module std_private_algorithm_ranges_find_end                             [system
 module std_private_algorithm_ranges_find_first_of                        [system] { header "__algorithm/ranges_find_first_of.h" }
 module std_private_algorithm_ranges_find_if                              [system] { header "__algorithm/ranges_find_if.h" }
 module std_private_algorithm_ranges_find_if_not                          [system] { header "__algorithm/ranges_find_if_not.h" }
+module std_private_algorithm_ranges_find_last                            [system] { header "__algorithm/ranges_find_last.h" }
+module std_private_algorithm_ranges_find_last_if                         [system] { header "__algorithm/ranges_find_last_if.h" }
+module std_private_algorithm_ranges_find_last_if_not                     [system] { header "__algorithm/ranges_find_last_if_not.h" }
 module std_private_algorithm_ranges_for_each                             [system] {
   header "__algorithm/ranges_for_each.h"
   export std_private_algorithm_in_fun_result
diff --git a/libcxx/include/version b/libcxx/include/version
index c971336bcb85c..6b3c46f8f7715 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -190,6 +190,7 @@ __cpp_lib_ranges_chunk                                  202202L <ranges>
 __cpp_lib_ranges_chunk_by                               202202L <ranges>
 __cpp_lib_ranges_concat                                 202403L <ranges>
 __cpp_lib_ranges_contains                               202207L <algorithm>
+__cpp_lib_ranges_find_last                              202207L <algorithm>
 __cpp_lib_ranges_iota                                   202202L <numeric>
 __cpp_lib_ranges_join_with                              202202L <ranges>
 __cpp_lib_ranges_repeat                                 202207L <ranges>
@@ -483,6 +484,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # define __cpp_lib_ranges_chunk                         202202L
 # define __cpp_lib_ranges_chunk_by                      202202L
 # define __cpp_lib_ranges_contains                      202207L
+# define __cpp_lib_ranges_find_last                     202207L
 // # define __cpp_lib_ranges_iota                          202202L
 // # define __cpp_lib_ranges_join_with                     202202L
 # define __cpp_lib_ranges_repeat                        202207L
diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc
index e7796bfa26af8..6c7a30330008a 100644
--- a/libcxx/modules/std/algorithm.inc
+++ b/libcxx/modules/std/algorithm.inc
@@ -77,12 +77,11 @@ export namespace std {
     using std::ranges::find_if_not;
   } // namespace ranges
 
+  // [alg.find.last], find last
   namespace ranges {
-#if 0
     using std::ranges::find_last;
     using std::ranges::find_last_if;
     using std::ranges::find_last_if_not;
-#endif
   } // namespace ranges
 
   // [alg.find.end], find end
diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
index 1a6c0d11460c5..3c1cd606c6bff 100644
--- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
@@ -119,6 +119,12 @@ constexpr bool all_the_algorithms()
     (void)std::ranges::find_if(a, UnaryTrue(&copies)); assert(copies == 0);
     (void)std::ranges::find_if_not(first, last, UnaryTrue(&copies)); assert(copies == 0);
     (void)std::ranges::find_if_not(a, UnaryTrue(&copies)); assert(copies == 0);
+#if TEST_STD_VER >= 23
+    (void)std::ranges::find_last_if(first, last, UnaryTrue(&copies)); assert(copies == 0);
+    (void)std::ranges::find_last_if(a, UnaryTrue(&copies)); assert(copies == 0);
+    (void)std::ranges::find_last_if_not(first, last, UnaryTrue(&copies)); assert(copies == 0);
+    (void)std::ranges::find_last_if_not(a, UnaryTrue(&copies)); assert(copies == 0);
+#endif
     (void)std::ranges::for_each(first, last, UnaryVoid(&copies)); assert(copies == 1); copies = 0;
     (void)std::ranges::for_each(a, UnaryVoid(&copies)); assert(copies == 1); copies = 0...
[truncated]

Copy link

github-actions bot commented Jul 17, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Implements [P1223R5][] completely.

Includes an implementation of `find_last`, `find_last_if`, and
`find_last_if_not`.

[P1223R5]: https://wg21.link/p1223r5
@Zingam
Copy link
Contributor

Zingam commented Jul 17, 2024

We usually add a prefix to the title to indicate what a PR relates to, e.g. [libc++][ranges]. BTW I think there is already an open PR but I think it is inactive. We usually ask on Discord to avoid duplicated work
#67270

Please add a release note also.
https://libcxx.llvm.org/ReleaseNotes.html

@strega-nil strega-nil changed the title P1223R5: find_last [libc++][ranges] P1223R5: find_last Jul 17, 2024
@Zingam
Copy link
Contributor

Zingam commented Jul 17, 2024

You should also update the ranges status page: https://libcxx.llvm.org/Status/Ranges.html

@strega-nil
Copy link
Contributor Author

@Zingam

You should also update the ranges status page: https://libcxx.llvm.org/Status/Ranges.html

Isn't this done by updating libcxx/docs/Status/Cxx23Papers.csv?

@Zingam
Copy link
Contributor

Zingam commented Jul 17, 2024

@Zingam

You should also update the ranges status page: https://libcxx.llvm.org/Status/Ranges.html

Isn't this done by updating libcxx/docs/Status/Cxx23Papers.csv?

We have subprojects status pages also.

This is the file for the release notes (LLVM 19): libcxx/docs/ReleaseNotes/19.rst
This is the file for the ranges status page: libcxx/docs/Status/Ranges.rst and the table with the algorithms libcxx/docs/Status/RangesAlgorithms.csv

- add `static` to `operator()`
- update release notes
Copy link
Contributor

@cjdb cjdb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Thanks for this :)

Would you mind adding this to the release notes, please?

I'd also prefer it if we had one find_last.h instead of three files, but this is non-blocking, given precedent. An advantage to doing it in this commit is that the commit history would be more likely to be preserved should we consolidate files at a later point.

@cjdb
Copy link
Contributor

cjdb commented Jul 17, 2024

We usually add a prefix to the title to indicate what a PR relates to, e.g. [libc++][ranges]. BTW I think there is already an open PR but I think it is inactive. We usually ask on Discord to avoid duplicated work #67270

Please add a release note also. https://libcxx.llvm.org/ReleaseNotes.html

That's my fault: I'd forgotten about that PR when suggesting the work to @strega-nil. Having said that, #67270 hasn't been touched in a long while.

@ldionne
Copy link
Member

ldionne commented Jul 18, 2024

@strega-nil I closed #67270 as inactive. Please feel free to take tests and other material from that PR (if you do, please credit the original author of the patch in your commit message). This is now the canonical PR for find_last & friends.

Additionally, make __find_last_impl into one function for all three

Finally, change the tests for find_last to see if people are good with that version
(hopefully, yes, in which case I'll do the rest)
@strega-nil
Copy link
Contributor Author

strega-nil commented Jul 18, 2024

Pinging reviewers for a re-review - I have completed the merge of the files, and I've modified how the find_last test works - if this modification of the test works for y'all, I'll make the same changes to the other tests and say it's shippable :) (after fixing the dang clang-format thing)

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a nice patch! I have a few comments but I don't see any major issues.

libcxx/docs/ReleaseNotes/19.rst Outdated Show resolved Hide resolved
libcxx/include/__algorithm/ranges_find_last.h Outdated Show resolved Hide resolved
libcxx/include/__algorithm/ranges_find_last.h Outdated Show resolved Hide resolved
libcxx/include/__algorithm/ranges_find_last.h Outdated Show resolved Hide resolved
libcxx/include/__algorithm/ranges_find_last.h Outdated Show resolved Hide resolved
libcxx/include/algorithm Outdated Show resolved Hide resolved
@strega-nil
Copy link
Contributor Author

strega-nil commented Jul 19, 2024

@ldionne I think I've fixed all of your comments :)

I'll merge once you've given approval and the tests have gone through.

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the quick turnaround!

@strega-nil strega-nil merged commit 04760bf into llvm:main Jul 19, 2024
55 checks passed
@strega-nil strega-nil deleted the p1223r5_find_last branch July 19, 2024 16:45
sgundapa pushed a commit to sgundapa/upstream_effort that referenced this pull request Jul 23, 2024
Implements [P1223R5][] completely.

Includes an implementation of `find_last`, `find_last_if`, and
`find_last_if_not`.

[P1223R5]: https://wg21.link/p1223r5
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Implements [P1223R5][] completely.

Includes an implementation of `find_last`, `find_last_if`, and
`find_last_if_not`.

[P1223R5]: https://wg21.link/p1223r5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants