Skip to content

Commit a6b846a

Browse files
authored
[libc++][ranges] Implement ranges::contains_subrange (#66963)
1 parent bf3d5db commit a6b846a

File tree

12 files changed

+450
-5
lines changed

12 files changed

+450
-5
lines changed

libcxx/docs/Status/RangesAlgorithms.csv

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ C++20,all C++20 algorithms,N/A,N/A,✅
33
C++23,`find_last <https://wg21.link/P1223R5>`_,Unassigned,No patch yet,Not started
44
C++23,`find_last_if <https://wg21.link/P1223R5>`_,Unassigned,No patch yet,Not started
55
C++23,`find_last_if_not <https://wg21.link/P1223R5>`_,Unassigned,No patch yet,Not started
6-
C++23,`starts_with <https://wg21.link/P1659R3>`_,Zijun Zhao,`D150735 <https://llvm.org/D150735>`_,
7-
C++23,`ends_with <https://wg21.link/P1659R3>`_,Zijun Zhao,No patch yet,In Progress
6+
C++23,`starts_with <https://wg21.link/P1659R3>`_,Zijun Zhao,`D150735 <https://llvm.org/D150735>`_,Complete
7+
C++23,`ends_with <https://wg21.link/P1659R3>`_,Zijun Zhao, `D150831 <https://llvm.org/D150831>`_,Complete
88
C++23,`shift_left <https://wg21.link/p2440r1>`_,Unassigned,No patch yet,Not started
99
C++23,`shift_right <https://wg21.link/p2440r1>`_,Unassigned,No patch yet,Not started
1010
C++23,`iota (algorithm) <https://wg21.link/p2440r1>`_,Unassigned,No patch yet,Not started
1111
C++23,`fold <https://wg21.link/p2322r5>`_,Unassigned,No patch yet,Not started
12-
C++23,`contains <https://wg21.link/p2302r2>`_,Zijun Zhao,No patch yet,In Progress
12+
C++23,`contains <https://wg21.link/p2302r2>`_,Zijun Zhao, `#65148 <https://github.com/llvm/llvm-project/pull/65148>`_,Complete
1313
C++23,`fold_left_with_iter <https://wg21.link/p2322r6>`_,Christopher Di Bella,N/A,Complete
1414
C++23,`fold_left <https://wg21.link/p2322r6>`_,Christopher Di Bella,N/A,Complete
1515
C++23,`fold_left_first_with_iter <https://wg21.link/p2322r6>`_,Christopher Di Bella,N/A,In progress

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ set(files
110110
__algorithm/ranges_binary_search.h
111111
__algorithm/ranges_clamp.h
112112
__algorithm/ranges_contains.h
113+
__algorithm/ranges_contains_subrange.h
113114
__algorithm/ranges_copy.h
114115
__algorithm/ranges_copy_backward.h
115116
__algorithm/ranges_copy_if.h
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//===----------------------------------------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H
10+
#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H
11+
12+
#include <__algorithm/ranges_search.h>
13+
#include <__config>
14+
#include <__functional/identity.h>
15+
#include <__functional/ranges_operations.h>
16+
#include <__functional/reference_wrapper.h>
17+
#include <__iterator/concepts.h>
18+
#include <__iterator/distance.h>
19+
#include <__iterator/indirectly_comparable.h>
20+
#include <__iterator/projected.h>
21+
#include <__ranges/access.h>
22+
#include <__ranges/concepts.h>
23+
#include <__ranges/subrange.h>
24+
#include <__utility/move.h>
25+
26+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27+
# pragma GCC system_header
28+
#endif
29+
30+
_LIBCPP_PUSH_MACROS
31+
#include <__undef_macros>
32+
33+
#if _LIBCPP_STD_VER >= 23
34+
35+
_LIBCPP_BEGIN_NAMESPACE_STD
36+
37+
namespace ranges {
38+
namespace __contains_subrange {
39+
struct __fn {
40+
template <forward_iterator _Iter1,
41+
sentinel_for<_Iter1> _Sent1,
42+
forward_iterator _Iter2,
43+
sentinel_for<_Iter2> _Sent2,
44+
class _Pred = ranges::equal_to,
45+
class _Proj1 = identity,
46+
class _Proj2 = identity>
47+
requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
48+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool static operator()(
49+
_Iter1 __first1,
50+
_Sent1 __last1,
51+
_Iter2 __first2,
52+
_Sent2 __last2,
53+
_Pred __pred = {},
54+
_Proj1 __proj1 = {},
55+
_Proj2 __proj2 = {}) {
56+
auto __n2 = ranges::distance(__first2, __last2);
57+
if (__n2 == 0)
58+
return true;
59+
60+
auto __ret = ranges::search(
61+
std::move(__first1), __last1, std::move(__first2), __last2, __pred, std::ref(__proj1), std::ref(__proj2));
62+
return __ret.empty() == false;
63+
}
64+
65+
template <forward_range _Range1,
66+
forward_range _Range2,
67+
class _Pred = ranges::equal_to,
68+
class _Proj1 = identity,
69+
class _Proj2 = identity>
70+
requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2>
71+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool static
72+
operator()(_Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) {
73+
auto __n2 = 0;
74+
if constexpr (sized_range<_Range2>) {
75+
__n2 = ranges::size(__range2);
76+
} else {
77+
__n2 = std::distance(cbegin(__range2), cend(__range2));
78+
}
79+
if (__n2 == 0)
80+
return true;
81+
82+
auto __ret = ranges::search(__range1, __range2, __pred, std::ref(__proj1), std::ref(__proj2));
83+
return __ret.empty() == false;
84+
}
85+
};
86+
} // namespace __contains_subrange
87+
88+
inline namespace __cpo {
89+
inline constexpr auto contains_subrange = __contains_subrange::__fn{};
90+
} // namespace __cpo
91+
} // namespace ranges
92+
93+
_LIBCPP_END_NAMESPACE_STD
94+
95+
#endif // _LIBCPP_STD_VER >= 23
96+
97+
_LIBCPP_POP_MACROS
98+
99+
#endif // _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H

libcxx/include/algorithm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,19 @@ namespace ranges {
217217
constexpr ranges::minmax_element_result<borrowed_iterator_t<R>>
218218
minmax_element(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
219219
220+
template<forward_iterator I1, sentinel_for<I1> S1,
221+
forward_iterator I2, sentinel_for<I2> S2,
222+
class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
223+
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
224+
constexpr bool contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2,
225+
Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23
226+
227+
template<forward_range R1, forward_range R2,
228+
class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
229+
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
230+
constexpr bool contains_subrange(R1&& r1, R2&& r2, Pred pred = {},
231+
Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23
232+
220233
template<class I, class O>
221234
using copy_result = in_out_result<I, O>; // since C++20
222235
@@ -1875,6 +1888,7 @@ template <class BidirectionalIterator, class Compare>
18751888
#include <__algorithm/ranges_binary_search.h>
18761889
#include <__algorithm/ranges_clamp.h>
18771890
#include <__algorithm/ranges_contains.h>
1891+
#include <__algorithm/ranges_contains_subrange.h>
18781892
#include <__algorithm/ranges_copy.h>
18791893
#include <__algorithm/ranges_copy_backward.h>
18801894
#include <__algorithm/ranges_copy_if.h>

libcxx/include/libcxx.imp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
{ include: [ "<__algorithm/ranges_binary_search.h>", "private", "<algorithm>", "public" ] },
111111
{ include: [ "<__algorithm/ranges_clamp.h>", "private", "<algorithm>", "public" ] },
112112
{ include: [ "<__algorithm/ranges_contains.h>", "private", "<algorithm>", "public" ] },
113+
{ include: [ "<__algorithm/ranges_contains_subrange.h>", "private", "<algorithm>", "public" ] },
113114
{ include: [ "<__algorithm/ranges_copy.h>", "private", "<algorithm>", "public" ] },
114115
{ include: [ "<__algorithm/ranges_copy_backward.h>", "private", "<algorithm>", "public" ] },
115116
{ include: [ "<__algorithm/ranges_copy_if.h>", "private", "<algorithm>", "public" ] },

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ module std_private_algorithm_ranges_clamp [system
778778
export std_private_functional_ranges_operations
779779
}
780780
module std_private_algorithm_ranges_contains [system] { header "__algorithm/ranges_contains.h" }
781+
module std_private_algorithm_ranges_contains_subrange [system] { header "__algorithm/ranges_contains_subrange.h" }
781782
module std_private_algorithm_ranges_copy [system] {
782783
header "__algorithm/ranges_copy.h"
783784
export std_private_algorithm_in_out_result

libcxx/modules/std/algorithm.inc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ export namespace std {
4646
// [alg.contains], contains
4747
namespace ranges {
4848
using std::ranges::contains;
49-
#if 0
5049
using std::ranges::contains_subrange;
51-
#endif
5250
} // namespace ranges
5351
#endif // _LIBCPP_STD_VER >= 23
5452

libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ constexpr bool all_the_algorithms()
8686
assert(copies == 0);
8787
(void)std::ranges::contains(a, value, Proj(&copies));
8888
assert(copies == 0);
89+
(void)std::ranges::contains_subrange(first, last, first2, last2, Equal(), Proj(&copies), Proj(&copies));
90+
assert(copies == 0);
91+
(void)std::ranges::contains_subrange(a, b, Equal(), Proj(&copies), Proj(&copies));
92+
assert(copies == 0);
8993
#endif
9094
(void)std::ranges::count(first, last, value, Proj(&copies)); assert(copies == 0);
9195
(void)std::ranges::count(a, value, Proj(&copies)); assert(copies == 0);

libcxx/test/libcxx/diagnostics/ranges.nodiscard_extensions.compile.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ void test() {
3333
#if TEST_STD_VER >= 23
3434
std::ranges::contains(range, 1);
3535
std::ranges::contains(iter, iter, 1);
36+
std::ranges::contains_subrange(range, range);
37+
std::ranges::contains_subrange(iter, iter, iter, iter);
3638
#endif
3739
std::ranges::count_if(range, pred);
3840
std::ranges::count_if(iter, iter, pred);

libcxx/test/libcxx/diagnostics/ranges.nodiscard_extensions.verify.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ void test() {
9595
// expected-warning@-1{{ignoring return value of function declared with 'nodiscard' attribute}}
9696
std::ranges::contains(iter, iter, 1);
9797
// expected-warning@-1{{ignoring return value of function declared with 'nodiscard' attribute}}
98+
std::ranges::contains_subrange(range, range);
99+
// expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}}
100+
std::ranges::contains_subrange(iter, iter, iter, iter);
101+
// expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}}
98102
std::ranges::fold_left(range, 0, std::plus());
99103
// expected-warning@-1{{ignoring return value of function declared with 'nodiscard' attribute}}
100104
std::ranges::fold_left(iter, iter, 0, std::plus());

0 commit comments

Comments
 (0)