Skip to content

Commit 101d1e9

Browse files
committed
[libc++] Implement ranges::find_end, ranges::search{, _n}
Reviewed By: var-const, #libc, huixie90 Spies: thakis, h-vetinari, huixie90, libcxx-commits, mgorny Differential Revision: https://reviews.llvm.org/D124079
1 parent 9d24eba commit 101d1e9

File tree

22 files changed

+1834
-168
lines changed

22 files changed

+1834
-168
lines changed

libcxx/docs/Status/RangesAlgorithms.csv

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ Search,max_element,Nikolas Klauser,`D117523 <https://llvm.org/D117523>`_,✅
2323
Search,minmax_element,Nikolas Klauser,`D120637 <https://llvm.org/D120637>`_,✅
2424
Search,count,Nikolas Klauser,`D121523 <https://llvm.org/D121523>`_,✅
2525
Search,count_if,Nikolas Klauser,`D121523 <https://llvm.org/D121523>`_,✅
26-
Search,search,Nikolas Klauser,`D124079 <https://llvm.org/D124079>`_,Under review
27-
Search,search_n,Nikolas Klauser,`D124079 <https://llvm.org/D124079>`_,Under review
28-
Search,find_end,Nikolas Klauser,`D124079 <https://llvm.org/D124079>`_,Under review
26+
Search,search,Nikolas Klauser,`D124079 <https://llvm.org/D124079>`_,
27+
Search,search_n,Nikolas Klauser,`D124079 <https://llvm.org/D124079>`_,
28+
Search,find_end,Nikolas Klauser,`D124079 <https://llvm.org/D124079>`_,
2929
Read-only,is_partitioned,Nikolas Klauser,`D124440 <https://llvm.org/D124440>`_,✅
3030
Read-only,is_sorted,Nikolas Klauser,`D125608 <https://llvm.org/D125608>`_,✅
3131
Read-only,is_sorted_until,Nikolas Klauser,`D125608 <https://llvm.org/D125608>`_,✅

libcxx/include/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ set(files
8383
__algorithm/ranges_fill.h
8484
__algorithm/ranges_fill_n.h
8585
__algorithm/ranges_find.h
86+
__algorithm/ranges_find_end.h
8687
__algorithm/ranges_find_first_of.h
8788
__algorithm/ranges_find_if.h
8889
__algorithm/ranges_find_if_not.h
@@ -129,6 +130,8 @@ set(files
129130
__algorithm/ranges_reverse.h
130131
__algorithm/ranges_reverse_copy.h
131132
__algorithm/ranges_rotate_copy.h
133+
__algorithm/ranges_search.h
134+
__algorithm/ranges_search_n.h
132135
__algorithm/ranges_set_difference.h
133136
__algorithm/ranges_set_intersection.h
134137
__algorithm/ranges_set_union.h

libcxx/include/__algorithm/find_end.h

Lines changed: 130 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,44 +11,69 @@
1111
#define _LIBCPP___ALGORITHM_FIND_END_OF_H
1212

1313
#include <__algorithm/comp.h>
14+
#include <__algorithm/iterator_operations.h>
15+
#include <__algorithm/search.h>
1416
#include <__config>
17+
#include <__functional/identity.h>
18+
#include <__iterator/advance.h>
1519
#include <__iterator/iterator_traits.h>
20+
#include <__iterator/next.h>
21+
#include <__iterator/reverse_iterator.h>
22+
#include <__utility/pair.h>
23+
#include <type_traits>
1624

1725
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1826
# pragma GCC system_header
1927
#endif
2028

2129
_LIBCPP_BEGIN_NAMESPACE_STD
2230

23-
template <class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2>
24-
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator1 __find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
25-
_ForwardIterator2 __first2, _ForwardIterator2 __last2,
26-
_BinaryPredicate __pred, forward_iterator_tag,
27-
forward_iterator_tag) {
31+
template <
32+
class _AlgPolicy,
33+
class _Iter1,
34+
class _Sent1,
35+
class _Iter2,
36+
class _Sent2,
37+
class _Pred,
38+
class _Proj1,
39+
class _Proj2>
40+
_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_AFTER_CXX11 pair<_Iter1, _Iter1> __find_end_impl(
41+
_Iter1 __first1,
42+
_Sent1 __last1,
43+
_Iter2 __first2,
44+
_Sent2 __last2,
45+
_Pred& __pred,
46+
_Proj1& __proj1,
47+
_Proj2& __proj2,
48+
forward_iterator_tag,
49+
forward_iterator_tag) {
2850
// modeled after search algorithm
29-
_ForwardIterator1 __r = __last1; // __last1 is the "default" answer
51+
_Iter1 __match_first = _IterOps<_AlgPolicy>::next(__first1, __last1); // __last1 is the "default" answer
52+
_Iter1 __match_last = __match_first;
3053
if (__first2 == __last2)
31-
return __r;
54+
return pair<_Iter1, _Iter1>(__match_last, __match_last);
3255
while (true) {
3356
while (true) {
34-
if (__first1 == __last1) // if source exhausted return last correct answer
35-
return __r; // (or __last1 if never found)
36-
if (__pred(*__first1, *__first2))
57+
if (__first1 == __last1) // if source exhausted return last correct answer (or __last1 if never found)
58+
return pair<_Iter1, _Iter1>(__match_first, __match_last);
59+
if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
3760
break;
3861
++__first1;
3962
}
4063
// *__first1 matches *__first2, now match elements after here
41-
_ForwardIterator1 __m1 = __first1;
42-
_ForwardIterator2 __m2 = __first2;
64+
_Iter1 __m1 = __first1;
65+
_Iter2 __m2 = __first2;
4366
while (true) {
4467
if (++__m2 == __last2) { // Pattern exhaused, record answer and search for another one
45-
__r = __first1;
68+
__match_first = __first1;
69+
__match_last = ++__m1;
4670
++__first1;
4771
break;
4872
}
4973
if (++__m1 == __last1) // Source exhausted, return last answer
50-
return __r;
51-
if (!__pred(*__m1, *__m2)) // mismatch, restart with a new __first
74+
return pair<_Iter1, _Iter1>(__match_first, __match_last);
75+
// mismatch, restart with a new __first
76+
if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2)))
5277
{
5378
++__first1;
5479
break;
@@ -57,92 +82,146 @@ _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator1 __find_end(_ForwardIterator1 __f
5782
}
5883
}
5984

60-
template <class _BinaryPredicate, class _BidirectionalIterator1, class _BidirectionalIterator2>
61-
_LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator1 __find_end(
62-
_BidirectionalIterator1 __first1, _BidirectionalIterator1 __last1, _BidirectionalIterator2 __first2,
63-
_BidirectionalIterator2 __last2, _BinaryPredicate __pred, bidirectional_iterator_tag, bidirectional_iterator_tag) {
85+
template <
86+
class _IterOps,
87+
class _Pred,
88+
class _Iter1,
89+
class _Sent1,
90+
class _Iter2,
91+
class _Sent2,
92+
class _Proj1,
93+
class _Proj2>
94+
_LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter1 __find_end(
95+
_Iter1 __first1,
96+
_Sent1 __sent1,
97+
_Iter2 __first2,
98+
_Sent2 __sent2,
99+
_Pred& __pred,
100+
_Proj1& __proj1,
101+
_Proj2& __proj2,
102+
bidirectional_iterator_tag,
103+
bidirectional_iterator_tag) {
104+
auto __last1 = _IterOps::next(__first1, __sent1);
105+
auto __last2 = _IterOps::next(__first2, __sent2);
64106
// modeled after search algorithm (in reverse)
65107
if (__first2 == __last2)
66108
return __last1; // Everything matches an empty sequence
67-
_BidirectionalIterator1 __l1 = __last1;
68-
_BidirectionalIterator2 __l2 = __last2;
109+
_Iter1 __l1 = __last1;
110+
_Iter2 __l2 = __last2;
69111
--__l2;
70112
while (true) {
71113
// Find last element in sequence 1 that matchs *(__last2-1), with a mininum of loop checks
72114
while (true) {
73115
if (__first1 == __l1) // return __last1 if no element matches *__first2
74116
return __last1;
75-
if (__pred(*--__l1, *__l2))
117+
if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2)))
76118
break;
77119
}
78120
// *__l1 matches *__l2, now match elements before here
79-
_BidirectionalIterator1 __m1 = __l1;
80-
_BidirectionalIterator2 __m2 = __l2;
121+
_Iter1 __m1 = __l1;
122+
_Iter2 __m2 = __l2;
81123
while (true) {
82124
if (__m2 == __first2) // If pattern exhausted, __m1 is the answer (works for 1 element pattern)
83125
return __m1;
84126
if (__m1 == __first1) // Otherwise if source exhaused, pattern not found
85127
return __last1;
86-
if (!__pred(*--__m1, *--__m2)) // if there is a mismatch, restart with a new __l1
128+
129+
// if there is a mismatch, restart with a new __l1
130+
if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(__proj2, *--__m2)))
87131
{
88132
break;
89133
} // else there is a match, check next elements
90134
}
91135
}
92136
}
93137

94-
template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>
95-
_LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator1 __find_end(
96-
_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
97-
_RandomAccessIterator2 __last2, _BinaryPredicate __pred, random_access_iterator_tag, random_access_iterator_tag) {
98-
typedef typename iterator_traits<_RandomAccessIterator1>::difference_type _D1;
99-
typedef typename iterator_traits<_RandomAccessIterator2>::difference_type _D2;
138+
template <
139+
class _AlgPolicy,
140+
class _Pred,
141+
class _Iter1,
142+
class _Sent1,
143+
class _Iter2,
144+
class _Sent2,
145+
class _Proj1,
146+
class _Proj2>
147+
_LIBCPP_CONSTEXPR_AFTER_CXX11 _Iter1 __find_end(
148+
_Iter1 __first1,
149+
_Sent1 __sent1,
150+
_Iter2 __first2,
151+
_Sent2 __sent2,
152+
_Pred& __pred,
153+
_Proj1& __proj1,
154+
_Proj2& __proj2,
155+
random_access_iterator_tag,
156+
random_access_iterator_tag) {
157+
typedef typename iterator_traits<_Iter1>::difference_type _D1;
158+
auto __last1 = _IterOps<_AlgPolicy>::next(__first1, __sent1);
159+
auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __sent2);
100160
// Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern
101-
_D2 __len2 = __last2 - __first2;
161+
auto __len2 = __last2 - __first2;
102162
if (__len2 == 0)
103163
return __last1;
104-
_D1 __len1 = __last1 - __first1;
164+
auto __len1 = __last1 - __first1;
105165
if (__len1 < __len2)
106166
return __last1;
107-
const _RandomAccessIterator1 __s = __first1 + _D1(__len2 - 1); // End of pattern match can't go before here
108-
_RandomAccessIterator1 __l1 = __last1;
109-
_RandomAccessIterator2 __l2 = __last2;
167+
const _Iter1 __s = __first1 + _D1(__len2 - 1); // End of pattern match can't go before here
168+
_Iter1 __l1 = __last1;
169+
_Iter2 __l2 = __last2;
110170
--__l2;
111171
while (true) {
112172
while (true) {
113173
if (__s == __l1)
114174
return __last1;
115-
if (__pred(*--__l1, *__l2))
175+
if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2)))
116176
break;
117177
}
118-
_RandomAccessIterator1 __m1 = __l1;
119-
_RandomAccessIterator2 __m2 = __l2;
178+
_Iter1 __m1 = __l1;
179+
_Iter2 __m2 = __l2;
120180
while (true) {
121181
if (__m2 == __first2)
122182
return __m1;
123183
// no need to check range on __m1 because __s guarantees we have enough source
124-
if (!__pred(*--__m1, *--__m2)) {
184+
if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(*--__m2))) {
125185
break;
126186
}
127187
}
128188
}
129189
}
130190

131191
template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
132-
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator1
133-
find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2,
134-
_BinaryPredicate __pred) {
135-
return _VSTD::__find_end<_BinaryPredicate&>(
136-
__first1, __last1, __first2, __last2, __pred, typename iterator_traits<_ForwardIterator1>::iterator_category(),
137-
typename iterator_traits<_ForwardIterator2>::iterator_category());
192+
_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
193+
_ForwardIterator1 __find_end_classic(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
194+
_ForwardIterator2 __first2, _ForwardIterator2 __last2,
195+
_BinaryPredicate& __pred) {
196+
auto __proj = __identity();
197+
return std::__find_end_impl<_ClassicAlgPolicy>(
198+
__first1,
199+
__last1,
200+
__first2,
201+
__last2,
202+
__pred,
203+
__proj,
204+
__proj,
205+
typename iterator_traits<_ForwardIterator1>::iterator_category(),
206+
typename iterator_traits<_ForwardIterator2>::iterator_category())
207+
.first;
208+
}
209+
210+
template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
211+
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
212+
_ForwardIterator1 find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
213+
_ForwardIterator2 __first2, _ForwardIterator2 __last2,
214+
_BinaryPredicate __pred) {
215+
return std::__find_end_classic(__first1, __last1, __first2, __last2, __pred);
138216
}
139217

140218
template <class _ForwardIterator1, class _ForwardIterator2>
141-
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator1
142-
find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) {
143-
typedef typename iterator_traits<_ForwardIterator1>::value_type __v1;
144-
typedef typename iterator_traits<_ForwardIterator2>::value_type __v2;
145-
return _VSTD::find_end(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>());
219+
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
220+
_ForwardIterator1 find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
221+
_ForwardIterator2 __first2, _ForwardIterator2 __last2) {
222+
using __v1 = typename iterator_traits<_ForwardIterator1>::value_type;
223+
using __v2 = typename iterator_traits<_ForwardIterator2>::value_type;
224+
return std::find_end(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>());
146225
}
147226

148227
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__algorithm/iterator_operations.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct _IterOps<_RangeAlgPolicy> {
3939
static constexpr auto __iter_move = ranges::iter_move;
4040
static constexpr auto iter_swap = ranges::iter_swap;
4141
static constexpr auto next = ranges::next;
42+
static constexpr auto __advance_to = ranges::advance;
4243
};
4344
#endif
4445

@@ -82,6 +83,11 @@ struct _IterOps<_ClassicAlgPolicy> {
8283
_Iterator next(_Iterator, _Iterator __last) {
8384
return __last;
8485
}
86+
87+
template <class _Iter>
88+
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 void __advance_to(_Iter& __first, _Iter __last) {
89+
__first = __last;
90+
}
8591
};
8692

8793
_LIBCPP_END_NAMESPACE_STD

0 commit comments

Comments
 (0)