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
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_contains`` ``202207L``
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_find_last`` ``202207L``
strega-nil marked this conversation as resolved.
Show resolved Hide resolved
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_iota`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_join_with`` *unimplemented*
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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|"
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/__algorithm/ranges_find_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
strega-nil marked this conversation as resolved.
Show resolved Hide resolved
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
Expand Down
103 changes: 103 additions & 0 deletions libcxx/include/__algorithm/ranges_find_last.h
Original file line number Diff line number Diff line change
@@ -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/indirectly_comparable.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 {
namespace __find_last {
struct __fn {
template <class _Iter, class _Sent, class _Type, class _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter>
strega-nil marked this conversation as resolved.
Show resolved Hide resolved
__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 {
strega-nil marked this conversation as resolved.
Show resolved Hide resolved
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
106 changes: 106 additions & 0 deletions libcxx/include/__algorithm/ranges_find_last_if.h
Original file line number Diff line number Diff line change
@@ -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>
strega-nil marked this conversation as resolved.
Show resolved Hide resolved
__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
70 changes: 70 additions & 0 deletions libcxx/include/__algorithm/ranges_find_last_if_not.h
Original file line number Diff line number Diff line change
@@ -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)); };
cjdb marked this conversation as resolved.
Show resolved Hide resolved
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
23 changes: 23 additions & 0 deletions libcxx/include/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions libcxx/modules/std/algorithm.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading