-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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
[libcxx] patch for implementing ranges::find_last #67270
Changes from all commits
ceb7f40
1a65a7e
8b8662a
50b159a
f733b23
d0fe8a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 <__algorithm/ranges_find_last_if.h> | ||
#include <__config> | ||
#include <__functional/identity.h> | ||
#include <__functional/ranges_operations.h> | ||
#include <__iterator/concepts.h> | ||
#include <__iterator/projected.h> | ||
#include <__ranges/access.h> | ||
#include <__ranges/concepts.h> | ||
#include <__ranges/dangling.h> | ||
#include <__utility/forward.h> | ||
#include <__utility/move.h> | ||
|
||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
# pragma GCC system_header | ||
#endif | ||
|
||
#if _LIBCPP_STD_VER >= 23 | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
namespace ranges { | ||
namespace __find_last { | ||
struct __fn { | ||
template <forward_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, class _Proj = identity> | ||
requires indirect_binary_predicate < ranges::equal_to, projected<_Ip, _Proj>, | ||
const _Tp* > _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Ip> | ||
operator()(_Ip __first, _Sp __last, const _Tp& __value, _Proj __proj = {}) const { | ||
auto __pred = [&](auto&& __e) { return std::forward<decltype(__e)>(__e) == __value; }; | ||
return ranges::__find_last_if_impl(std::move(__first), std::move(__last), __pred, __proj); | ||
} | ||
|
||
template <forward_range _Rp, class _Tp, class _Proj = identity> | ||
requires indirect_binary_predicate < ranges::equal_to, projected<iterator_t<_Rp>, _Proj>, | ||
const _Tp* > _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Rp> | ||
operator()(_Rp&& __r, const _Tp& __value, _Proj __proj = {}) const { | ||
auto __pred = [&](auto&& __e) { return std::forward<decltype(__e)>(__e) == __value; }; | ||
return ranges::__find_last_if_impl(ranges::begin(__r), ranges::end(__r), __pred, __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 | ||
|
||
#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 <__concepts/assignable.h> | ||
#include <__config> | ||
#include <__functional/identity.h> | ||
#include <__functional/invoke.h> | ||
#include <__iterator/concepts.h> | ||
#include <__iterator/next.h> | ||
#include <__iterator/projected.h> | ||
#include <__ranges/access.h> | ||
#include <__ranges/concepts.h> | ||
#include <__ranges/dangling.h> | ||
#include <__ranges/range_adaptor.h> | ||
#include <__ranges/subrange.h> | ||
#include <__utility/move.h> | ||
|
||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
# pragma GCC system_header | ||
#endif | ||
|
||
#if _LIBCPP_STD_VER >= 23 | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
namespace ranges { | ||
|
||
template <class _Ip, class _Sp, class _Pred, class _Proj> | ||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Ip> | ||
__find_last_if_impl(_Ip __first, _Sp __last, _Pred&& __pred, _Proj&& __proj) { | ||
if constexpr (common_range<_Ip> && bidirectional_range<_Ip>) { | ||
// Optimized for common_range and bidirectional_range | ||
_Ip __original_last = __last; // Save the original value of __last | ||
while (__first != __last) { | ||
--__last; | ||
if (std::invoke(__pred, std::invoke(__proj, *__last))) { | ||
return {__last, __original_last}; // Directly return the result | ||
} | ||
} | ||
return {__last, __original_last}; | ||
} else if constexpr (bidirectional_iterator<_Ip> && assignable_from<_Ip&, _Sp&>) { | ||
// For non-common but bidirectional ranges | ||
_Ip __result = ranges::next(__first, __last); | ||
Comment on lines
+49
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make sure
|
||
_Ip __original_last = __result; | ||
while (__first != __result) { | ||
--__result; | ||
if (std::invoke(__pred, std::invoke(__proj, *__result))) { | ||
return {__result, __original_last}; | ||
} | ||
} | ||
return {__result, __original_last}; | ||
} else { | ||
// Code for the non-bidirectional case | ||
_Ip __original_first = __first; | ||
_Ip __result = __first; | ||
while (__first != __last) { | ||
if (std::invoke(__pred, std::invoke(__proj, *__first))) { | ||
__result = __first; | ||
} | ||
++__first; | ||
} | ||
return {__result, __original_first}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
} | ||
|
||
namespace __find_last_if { | ||
struct __fn { | ||
template <forward_range _Rp, | ||
class _Proj = identity, | ||
indirect_unary_predicate<projected<iterator_t<_Rp>, _Proj>> _Pred> | ||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Rp> | ||
operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { | ||
return ranges::__find_last_if_impl(ranges::begin(__r), ranges::end(__r), __pred, __proj); | ||
} | ||
|
||
template <forward_iterator _Ip, | ||
sentinel_for<_Ip> _Sp, | ||
class _Proj = identity, | ||
indirect_unary_predicate<projected<_Ip, _Proj>> _Pred> | ||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Ip> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add tests for the |
||
operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const { | ||
return ranges::__find_last_if_impl(std::move(__first), std::move(__last), __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 | ||
|
||
#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#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 <__iterator/concepts.h> | ||
#include <__iterator/projected.h> | ||
#include <__ranges/access.h> | ||
#include <__ranges/concepts.h> | ||
#include <__ranges/dangling.h> | ||
#include <__utility/forward.h> | ||
#include <__utility/move.h> | ||
|
||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
# pragma GCC system_header | ||
#endif | ||
|
||
#if _LIBCPP_STD_VER >= 23 | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
namespace ranges { | ||
namespace __find_last_if_not { | ||
struct __fn { | ||
static constexpr auto __make_negate_pred = [](auto&& __pred) { | ||
return [&__pred](auto&& __e) { return !std::invoke(__pred, std::forward<decltype(__e)>(__e)); }; | ||
}; | ||
|
||
template <forward_iterator _Ip, | ||
sentinel_for<_Ip> _Sp, | ||
class _Proj = identity, | ||
indirect_unary_predicate<projected<_Ip, _Proj>> _Pred> | ||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Ip> | ||
operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const { | ||
auto __negate_pred = __make_negate_pred(__pred); | ||
return ranges::__find_last_if_impl(std::move(__first), std::move(__last), __negate_pred, __proj); | ||
} | ||
|
||
template <forward_range _Rp, | ||
class _Proj = identity, | ||
indirect_unary_predicate<projected<iterator_t<_Rp>, _Proj>> _Pred> | ||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Rp> | ||
operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { | ||
auto __negate_pred = __make_negate_pred(__pred); | ||
return ranges::__find_last_if_impl(ranges::begin(__r), ranges::end(__r), __negate_pred, __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 | ||
|
||
#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_IF_NOT_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is incorrect. since here you passed in iterator and sentinel, not the range itself, so they will never be
common_range
orbidirectional_range
. I think your second branch almost covers it except that instead of directly copying the last, it copies the first then assigns it to the last. If we want to keep this branch, I think the correct check is to check iterator and sentinel are the same type and the iterator models bidi iterator