1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H
10 #define _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H
12 #include <__algorithm/ranges_equal.h>
13 #include <__algorithm/ranges_starts_with.h>
15 #include <__functional/identity.h>
16 #include <__functional/ranges_operations.h>
17 #include <__functional/reference_wrapper.h>
18 #include <__iterator/advance.h>
19 #include <__iterator/concepts.h>
20 #include <__iterator/distance.h>
21 #include <__iterator/indirectly_comparable.h>
22 #include <__iterator/reverse_iterator.h>
23 #include <__ranges/access.h>
24 #include <__ranges/concepts.h>
25 #include <__ranges/size.h>
26 #include <__utility/move.h>
28 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
29 # pragma GCC system_header
33 #include <__undef_macros>
35 #if _LIBCPP_STD_VER >= 23
37 _LIBCPP_BEGIN_NAMESPACE_STD
41 template <class _Iter1
, class _Sent1
, class _Iter2
, class _Sent2
, class _Pred
, class _Proj1
, class _Proj2
>
42 _LIBCPP_HIDE_FROM_ABI
static constexpr bool __ends_with_fn_impl_bidirectional(
50 auto __rbegin1
= std::make_reverse_iterator(__last1
);
51 auto __rend1
= std::make_reverse_iterator(__first1
);
52 auto __rbegin2
= std::make_reverse_iterator(__last2
);
53 auto __rend2
= std::make_reverse_iterator(__first2
);
54 return ranges::starts_with(
55 __rbegin1
, __rend1
, __rbegin2
, __rend2
, std::ref(__pred
), std::ref(__proj1
), std::ref(__proj2
));
58 template <class _Iter1
, class _Sent1
, class _Iter2
, class _Sent2
, class _Pred
, class _Proj1
, class _Proj2
>
59 _LIBCPP_HIDE_FROM_ABI
static constexpr bool __ends_with_fn_impl(
67 if constexpr (std::bidirectional_iterator
<_Sent1
> && std::bidirectional_iterator
<_Sent2
> &&
68 (!std::random_access_iterator
<_Sent1
>) && (!std::random_access_iterator
<_Sent2
>)) {
69 return __ends_with_fn_impl_bidirectional(__first1
, __last1
, __first2
, __last2
, __pred
, __proj1
, __proj2
);
72 auto __n1
= ranges::distance(__first1
, __last1
);
73 auto __n2
= ranges::distance(__first2
, __last2
);
79 return __ends_with_fn_impl_with_offset(
91 template <class _Iter1
,
99 static _LIBCPP_HIDE_FROM_ABI
constexpr bool __ends_with_fn_impl_with_offset(
108 if constexpr (std::bidirectional_iterator
<_Sent1
> && std::bidirectional_iterator
<_Sent2
> &&
109 !std::random_access_iterator
<_Sent1
> && !std::random_access_iterator
<_Sent2
>) {
110 return __ends_with_fn_impl_bidirectional(
111 std::move(__first1
), std::move(__last1
), std::move(__first2
), std::move(__last2
), __pred
, __proj1
, __proj2
);
114 ranges::advance(__first1
, __offset
);
115 return ranges::equal(
126 template <input_iterator _Iter1
,
127 sentinel_for
<_Iter1
> _Sent1
,
128 input_iterator _Iter2
,
129 sentinel_for
<_Iter2
> _Sent2
,
130 class _Pred
= ranges::equal_to
,
131 class _Proj1
= identity
,
132 class _Proj2
= identity
>
133 requires(forward_iterator
<_Iter1
> || sized_sentinel_for
<_Sent1
, _Iter1
>) &&
134 (forward_iterator
<_Iter2
> || sized_sentinel_for
<_Sent2
, _Iter2
>) &&
135 indirectly_comparable
<_Iter1
, _Iter2
, _Pred
, _Proj1
, _Proj2
>
136 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI
constexpr bool operator()(
143 _Proj2 __proj2
= {}) const {
144 return __ends_with_fn_impl(
145 std::move(__first1
), std::move(__last1
), std::move(__first2
), std::move(__last2
), __pred
, __proj1
, __proj2
);
148 template <input_range _Range1
,
150 class _Pred
= ranges::equal_to
,
151 class _Proj1
= identity
,
152 class _Proj2
= identity
>
153 requires(forward_range
<_Range1
> || sized_range
<_Range1
>) && (forward_range
<_Range2
> || sized_range
<_Range2
>) &&
154 indirectly_comparable
<iterator_t
<_Range1
>, iterator_t
<_Range2
>, _Pred
, _Proj1
, _Proj2
>
155 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI
constexpr bool operator()(
156 _Range1
&& __range1
, _Range2
&& __range2
, _Pred __pred
= {}, _Proj1 __proj1
= {}, _Proj2 __proj2
= {}) const {
157 if constexpr (sized_range
<_Range1
> && sized_range
<_Range2
>) {
158 auto __n1
= ranges::size(__range1
);
159 auto __n2
= ranges::size(__range2
);
164 auto __offset
= __n1
- __n2
;
166 return __ends_with_fn_impl_with_offset(
167 ranges::begin(__range1
),
168 ranges::end(__range1
),
169 ranges::begin(__range2
),
170 ranges::end(__range2
),
177 return __ends_with_fn_impl(
178 ranges::begin(__range1
),
179 ranges::end(__range1
),
180 ranges::begin(__range2
),
181 ranges::end(__range2
),
189 inline namespace __cpo
{
190 inline constexpr auto ends_with
= __ends_with
{};
192 } // namespace ranges
194 _LIBCPP_END_NAMESPACE_STD
196 #endif // _LIBCPP_STD_VER >= 23
200 #endif // _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H