Skip to content

Commit 04dbf7a

Browse files
[libc++][ranges] Avoid using distance in ranges::contains_subrange (#87155)
Both `std::distance` or `ranges::distance` are inefficient for non-sized ranges. Also, calculating the range using `int` type is seriously problematic. This patch avoids using `distance` and calculation of the length of non-sized ranges. Fixes #86833.
1 parent c45861f commit 04dbf7a

File tree

2 files changed

+10
-8
lines changed

2 files changed

+10
-8
lines changed

libcxx/include/__algorithm/ranges_contains_subrange.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
#include <__functional/ranges_operations.h>
1616
#include <__functional/reference_wrapper.h>
1717
#include <__iterator/concepts.h>
18-
#include <__iterator/distance.h>
1918
#include <__iterator/indirectly_comparable.h>
2019
#include <__iterator/projected.h>
2120
#include <__ranges/access.h>
2221
#include <__ranges/concepts.h>
22+
#include <__ranges/size.h>
2323
#include <__ranges/subrange.h>
2424
#include <__utility/move.h>
2525

@@ -53,8 +53,7 @@ struct __fn {
5353
_Pred __pred = {},
5454
_Proj1 __proj1 = {},
5555
_Proj2 __proj2 = {}) {
56-
auto __n2 = ranges::distance(__first2, __last2);
57-
if (__n2 == 0)
56+
if (__first2 == __last2)
5857
return true;
5958

6059
auto __ret = ranges::search(
@@ -70,14 +69,13 @@ struct __fn {
7069
requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2>
7170
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool static
7271
operator()(_Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) {
73-
auto __n2 = 0;
7472
if constexpr (sized_range<_Range2>) {
75-
__n2 = ranges::size(__range2);
73+
if (ranges::size(__range2) == 0)
74+
return true;
7675
} else {
77-
__n2 = std::distance(cbegin(__range2), cend(__range2));
76+
if (ranges::begin(__range2) == ranges::end(__range2))
77+
return true;
7878
}
79-
if (__n2 == 0)
80-
return true;
8179

8280
auto __ret = ranges::search(__range1, __range2, __pred, std::ref(__proj1), std::ref(__proj2));
8381
return __ret.empty() == false;

libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains_subrange.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ constexpr bool test() {
309309
});
310310
});
311311

312+
assert(std::ranges::contains_subrange(
313+
std::views::iota(0, 5), std::views::iota(0, 5) | std::views::filter([](int) { return true; })));
314+
assert(!std::ranges::contains_subrange(std::views::iota(0ULL, 42ULL), std::views::iota(0ULL, 1ULL << 32)));
315+
312316
return true;
313317
}
314318

0 commit comments

Comments
 (0)