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++] Refactor ranges::{min, max, min_element, max_element} to use std::__min_element #132418

Merged
merged 2 commits into from
Mar 27, 2025

Conversation

winner245
Copy link
Contributor

Previously, ranges::min_element delegated to ranges::__min_element_impl, which duplicated the definition of std::__min_element. This patch updates ranges::min_element to directly call std::__min_element, which allows us to remove the redundant code in ranges::__min_element_impl.

Upon removal of ranges::__min_element_impl, the other ranges algorithms ranges::{min, max, max_element}, which previously delegated to ranges::__min_element_impl, have been updated to call std::__min_element instead.

This refactoring unifies the implementation across these algorithms, ensuring that future optimizations or maintenance work only need to be applied in one place.

@winner245 winner245 marked this pull request as ready for review March 21, 2025 19:56
@winner245 winner245 requested a review from a team as a code owner March 21, 2025 19:56
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2025

@llvm/pr-subscribers-libcxx

Author: Peng Liu (winner245)

Changes

Previously, ranges::min_element delegated to ranges::__min_element_impl, which duplicated the definition of std::__min_element. This patch updates ranges::min_element to directly call std::__min_element, which allows us to remove the redundant code in ranges::__min_element_impl.

Upon removal of ranges::__min_element_impl, the other ranges algorithms ranges::{min, max, max_element}, which previously delegated to ranges::__min_element_impl, have been updated to call std::__min_element instead.

This refactoring unifies the implementation across these algorithms, ensuring that future optimizations or maintenance work only need to be applied in one place.


Full diff: https://github.com/llvm/llvm-project/pull/132418.diff

5 Files Affected:

  • (modified) libcxx/include/__algorithm/min_element.h (+1-1)
  • (modified) libcxx/include/__algorithm/ranges_max.h (+3-3)
  • (modified) libcxx/include/__algorithm/ranges_max_element.h (+3-3)
  • (modified) libcxx/include/__algorithm/ranges_min.h (+3-3)
  • (modified) libcxx/include/__algorithm/ranges_min_element.h (+3-16)
diff --git a/libcxx/include/__algorithm/min_element.h b/libcxx/include/__algorithm/min_element.h
index db996365bf1de..fdab63aefec7e 100644
--- a/libcxx/include/__algorithm/min_element.h
+++ b/libcxx/include/__algorithm/min_element.h
@@ -29,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Comp, class _Iter, class _Sent, class _Proj>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter
-__min_element(_Iter __first, _Sent __last, _Comp __comp, _Proj& __proj) {
+__min_element(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) {
   if (__first == __last)
     return __first;
 
diff --git a/libcxx/include/__algorithm/ranges_max.h b/libcxx/include/__algorithm/ranges_max.h
index f631344422ed5..a8fe13a734f5b 100644
--- a/libcxx/include/__algorithm/ranges_max.h
+++ b/libcxx/include/__algorithm/ranges_max.h
@@ -9,7 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_MAX_H
 #define _LIBCPP___ALGORITHM_RANGES_MAX_H
 
-#include <__algorithm/ranges_min_element.h>
+#include <__algorithm/min_element.h>
 #include <__assert>
 #include <__concepts/copyable.h>
 #include <__config>
@@ -57,7 +57,7 @@ struct __max {
         __il.begin() != __il.end(), "initializer_list must contain at least one element");
 
     auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); };
-    return *ranges::__min_element_impl(__il.begin(), __il.end(), __comp_lhs_rhs_swapped, __proj);
+    return *std::__min_element(__il.begin(), __il.end(), __comp_lhs_rhs_swapped, __proj);
   }
 
   template <input_range _Rp,
@@ -75,7 +75,7 @@ struct __max {
       auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool {
         return std::invoke(__comp, __rhs, __lhs);
       };
-      return *ranges::__min_element_impl(std::move(__first), std::move(__last), __comp_lhs_rhs_swapped, __proj);
+      return *std::__min_element(std::move(__first), std::move(__last), __comp_lhs_rhs_swapped, __proj);
     } else {
       range_value_t<_Rp> __result = *__first;
       while (++__first != __last) {
diff --git a/libcxx/include/__algorithm/ranges_max_element.h b/libcxx/include/__algorithm/ranges_max_element.h
index 869f71ecc8d20..db6d5f6b9c276 100644
--- a/libcxx/include/__algorithm/ranges_max_element.h
+++ b/libcxx/include/__algorithm/ranges_max_element.h
@@ -9,7 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_MAX_ELEMENT_H
 #define _LIBCPP___ALGORITHM_RANGES_MAX_ELEMENT_H
 
-#include <__algorithm/ranges_min_element.h>
+#include <__algorithm/min_element.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__functional/invoke.h>
@@ -40,7 +40,7 @@ struct __max_element {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip
   operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const {
     auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); };
-    return ranges::__min_element_impl(__first, __last, __comp_lhs_rhs_swapped, __proj);
+    return std::__min_element(__first, __last, __comp_lhs_rhs_swapped, __proj);
   }
 
   template <forward_range _Rp,
@@ -49,7 +49,7 @@ struct __max_element {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp>
   operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
     auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); };
-    return ranges::__min_element_impl(ranges::begin(__r), ranges::end(__r), __comp_lhs_rhs_swapped, __proj);
+    return std::__min_element(ranges::begin(__r), ranges::end(__r), __comp_lhs_rhs_swapped, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_min.h b/libcxx/include/__algorithm/ranges_min.h
index 302b5d7975b00..9f1c78eaa9e25 100644
--- a/libcxx/include/__algorithm/ranges_min.h
+++ b/libcxx/include/__algorithm/ranges_min.h
@@ -9,7 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_MIN_H
 #define _LIBCPP___ALGORITHM_RANGES_MIN_H
 
-#include <__algorithm/ranges_min_element.h>
+#include <__algorithm/min_element.h>
 #include <__assert>
 #include <__concepts/copyable.h>
 #include <__config>
@@ -54,7 +54,7 @@ struct __min {
   operator()(initializer_list<_Tp> __il, _Comp __comp = {}, _Proj __proj = {}) const {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         __il.begin() != __il.end(), "initializer_list must contain at least one element");
-    return *ranges::__min_element_impl(__il.begin(), __il.end(), __comp, __proj);
+    return *std::__min_element(__il.begin(), __il.end(), __comp, __proj);
   }
 
   template <input_range _Rp,
@@ -67,7 +67,7 @@ struct __min {
     auto __last  = ranges::end(__r);
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__first != __last, "range must contain at least one element");
     if constexpr (forward_range<_Rp> && !__is_cheap_to_copy<range_value_t<_Rp>>) {
-      return *ranges::__min_element_impl(__first, __last, __comp, __proj);
+      return *std::__min_element(__first, __last, __comp, __proj);
     } else {
       range_value_t<_Rp> __result = *__first;
       while (++__first != __last) {
diff --git a/libcxx/include/__algorithm/ranges_min_element.h b/libcxx/include/__algorithm/ranges_min_element.h
index fb92ae56bcd62..5deb409ccd85e 100644
--- a/libcxx/include/__algorithm/ranges_min_element.h
+++ b/libcxx/include/__algorithm/ranges_min_element.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_MIN_ELEMENT_H
 #define _LIBCPP___ALGORITHM_RANGES_MIN_ELEMENT_H
 
+#include <__algorithm/min_element.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__functional/invoke.h>
@@ -32,20 +33,6 @@ _LIBCPP_PUSH_MACROS
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
-
-// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`.
-template <class _Ip, class _Sp, class _Proj, class _Comp>
-_LIBCPP_HIDE_FROM_ABI constexpr _Ip __min_element_impl(_Ip __first, _Sp __last, _Comp& __comp, _Proj& __proj) {
-  if (__first == __last)
-    return __first;
-
-  _Ip __i = __first;
-  while (++__i != __last)
-    if (std::invoke(__comp, std::invoke(__proj, *__i), std::invoke(__proj, *__first)))
-      __first = __i;
-  return __first;
-}
-
 struct __min_element {
   template <forward_iterator _Ip,
             sentinel_for<_Ip> _Sp,
@@ -53,7 +40,7 @@ struct __min_element {
             indirect_strict_weak_order<projected<_Ip, _Proj>> _Comp = ranges::less>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip
   operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const {
-    return ranges::__min_element_impl(__first, __last, __comp, __proj);
+    return std::__min_element(__first, __last, __comp, __proj);
   }
 
   template <forward_range _Rp,
@@ -61,7 +48,7 @@ struct __min_element {
             indirect_strict_weak_order<projected<iterator_t<_Rp>, _Proj>> _Comp = ranges::less>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp>
   operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
-    return ranges::__min_element_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+    return std::__min_element(ranges::begin(__r), ranges::end(__r), __comp, __proj);
   }
 };
 

@ldionne ldionne merged commit 8fdfe3f into llvm:main Mar 27, 2025
88 checks passed
@winner245 winner245 deleted the min_element branch March 27, 2025 15:22
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.

3 participants