1*594fa147SHui Xie //===----------------------------------------------------------------------===//
2*594fa147SHui Xie //
3*594fa147SHui Xie // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*594fa147SHui Xie // See https://llvm.org/LICENSE.txt for license information.
5*594fa147SHui Xie // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*594fa147SHui Xie //
7*594fa147SHui Xie //===----------------------------------------------------------------------===//
8*594fa147SHui Xie
9*594fa147SHui Xie // UNSUPPORTED: c++03, c++11, c++14, c++17
10*594fa147SHui Xie
11*594fa147SHui Xie // constexpr auto begin();
12*594fa147SHui Xie
13*594fa147SHui Xie #include <array>
14*594fa147SHui Xie #include <cassert>
15*594fa147SHui Xie #include <ranges>
16*594fa147SHui Xie #include <type_traits>
17*594fa147SHui Xie #include <utility>
18*594fa147SHui Xie
19*594fa147SHui Xie #include "test_iterators.h"
20*594fa147SHui Xie
21*594fa147SHui Xie struct View : std::ranges::view_base {
22*594fa147SHui Xie int* begin() const;
23*594fa147SHui Xie int* end() const;
24*594fa147SHui Xie };
25*594fa147SHui Xie
26*594fa147SHui Xie // Test that begin is not const
27*594fa147SHui Xie template <class T>
28*594fa147SHui Xie concept HasBegin = requires(T t) { t.begin(); };
29*594fa147SHui Xie
30*594fa147SHui Xie struct Pred {
operator ()Pred31*594fa147SHui Xie constexpr bool operator()(int i) const { return i < 3; }
32*594fa147SHui Xie };
33*594fa147SHui Xie
34*594fa147SHui Xie static_assert(HasBegin<std::ranges::drop_while_view<View, Pred>>);
35*594fa147SHui Xie static_assert(!HasBegin<const std::ranges::drop_while_view<View, Pred>>);
36*594fa147SHui Xie
__anon3e24633c0202(auto&&...) 37*594fa147SHui Xie constexpr auto always = [](auto v) { return [v](auto&&...) { return v; }; };
38*594fa147SHui Xie
39*594fa147SHui Xie template <class Iter>
testOne()40*594fa147SHui Xie constexpr void testOne() {
41*594fa147SHui Xie using Sent = sentinel_wrapper<Iter>;
42*594fa147SHui Xie using Range = std::ranges::subrange<Iter, Sent>;
43*594fa147SHui Xie constexpr auto make_subrange = []<std::size_t N>(int(&buffer)[N]) {
44*594fa147SHui Xie return Range{Iter{buffer}, Sent{Iter{buffer + N}}};
45*594fa147SHui Xie };
46*594fa147SHui Xie
47*594fa147SHui Xie // empty
48*594fa147SHui Xie {
49*594fa147SHui Xie std::array<int, 0> a;
50*594fa147SHui Xie Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}};
51*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), always(false)};
52*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
53*594fa147SHui Xie assert(base(it) == a.data() + a.size());
54*594fa147SHui Xie }
55*594fa147SHui Xie
56*594fa147SHui Xie // 1 element not dropped
57*594fa147SHui Xie {
58*594fa147SHui Xie int buffer[] = {1};
59*594fa147SHui Xie auto range = make_subrange(buffer);
60*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), always(false)};
61*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
62*594fa147SHui Xie assert(base(it) == buffer);
63*594fa147SHui Xie }
64*594fa147SHui Xie
65*594fa147SHui Xie // 1 element dropped
66*594fa147SHui Xie {
67*594fa147SHui Xie int buffer[] = {1};
68*594fa147SHui Xie auto range = make_subrange(buffer);
69*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), always(true)};
70*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
71*594fa147SHui Xie assert(base(it) == buffer + 1);
72*594fa147SHui Xie }
73*594fa147SHui Xie
74*594fa147SHui Xie // multiple elements. no element dropped
75*594fa147SHui Xie {
76*594fa147SHui Xie int buffer[] = {1, 2, 3, 4, 5};
77*594fa147SHui Xie auto range = make_subrange(buffer);
78*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), always(false)};
79*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
80*594fa147SHui Xie assert(base(it) == buffer);
81*594fa147SHui Xie }
82*594fa147SHui Xie
83*594fa147SHui Xie // multiple elements. all elements dropped
84*594fa147SHui Xie {
85*594fa147SHui Xie int buffer[] = {1, 2, 3, 4, 5};
86*594fa147SHui Xie auto range = make_subrange(buffer);
87*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), always(true)};
88*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
89*594fa147SHui Xie assert(base(it) == buffer + 5);
90*594fa147SHui Xie }
91*594fa147SHui Xie
92*594fa147SHui Xie // multiple elements. some elements dropped
93*594fa147SHui Xie {
94*594fa147SHui Xie int buffer[] = {1, 2, 3, 2, 1};
95*594fa147SHui Xie auto range = make_subrange(buffer);
96*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), [](int i) { return i < 3; }};
97*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
98*594fa147SHui Xie assert(base(it) == buffer + 2);
99*594fa147SHui Xie }
100*594fa147SHui Xie
101*594fa147SHui Xie // Make sure we do not make a copy of the predicate when we call begin()
102*594fa147SHui Xie {
103*594fa147SHui Xie struct TrackingPred {
104*594fa147SHui Xie constexpr explicit TrackingPred(bool* moved, bool* copied) : moved_(moved), copied_(copied) {}
105*594fa147SHui Xie constexpr TrackingPred(TrackingPred const& other) : moved_(other.moved_), copied_(other.copied_) {
106*594fa147SHui Xie *copied_ = true;
107*594fa147SHui Xie }
108*594fa147SHui Xie constexpr TrackingPred(TrackingPred&& other) : moved_(other.moved_), copied_(other.copied_) { *moved_ = true; }
109*594fa147SHui Xie TrackingPred& operator=(TrackingPred const&) = default;
110*594fa147SHui Xie TrackingPred& operator=(TrackingPred&&) = default;
111*594fa147SHui Xie
112*594fa147SHui Xie constexpr bool operator()(int i) const { return i < 3; }
113*594fa147SHui Xie bool* moved_;
114*594fa147SHui Xie bool* copied_;
115*594fa147SHui Xie };
116*594fa147SHui Xie
117*594fa147SHui Xie int buffer[] = {1, 2, 3, 2, 1};
118*594fa147SHui Xie bool moved = false, copied = false;
119*594fa147SHui Xie auto range = make_subrange(buffer);
120*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), TrackingPred(&moved, &copied)};
121*594fa147SHui Xie moved = false;
122*594fa147SHui Xie copied = false;
123*594fa147SHui Xie [[maybe_unused]] auto it = dwv.begin();
124*594fa147SHui Xie assert(!moved);
125*594fa147SHui Xie assert(!copied);
126*594fa147SHui Xie }
127*594fa147SHui Xie
128*594fa147SHui Xie // Test with a non-const predicate
129*594fa147SHui Xie {
130*594fa147SHui Xie int buffer[] = {1, 2, 3, 2, 1};
131*594fa147SHui Xie auto range = make_subrange(buffer);
132*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), [](int i) mutable { return i < 3; }};
133*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
134*594fa147SHui Xie assert(base(it) == buffer + 2);
135*594fa147SHui Xie }
136*594fa147SHui Xie
137*594fa147SHui Xie // Test with a predicate that takes by non-const reference
138*594fa147SHui Xie {
139*594fa147SHui Xie int buffer[] = {1, 2, 3, 2, 1};
140*594fa147SHui Xie auto range = make_subrange(buffer);
141*594fa147SHui Xie std::ranges::drop_while_view dwv{std::move(range), [](int& i) { return i < 3; }};
142*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
143*594fa147SHui Xie assert(base(it) == buffer + 2);
144*594fa147SHui Xie }
145*594fa147SHui Xie
146*594fa147SHui Xie if constexpr (std::forward_iterator<Iter>) {
147*594fa147SHui Xie // Make sure that we cache the result of begin() on subsequent calls
148*594fa147SHui Xie {
149*594fa147SHui Xie int buffer[] = {1, 2, 3, 2, 1};
150*594fa147SHui Xie auto range = make_subrange(buffer);
151*594fa147SHui Xie
152*594fa147SHui Xie int called = 0;
153*594fa147SHui Xie auto pred = [&](int i) {
154*594fa147SHui Xie ++called;
155*594fa147SHui Xie return i < 3;
156*594fa147SHui Xie };
157*594fa147SHui Xie std::ranges::drop_while_view dwv{range, pred};
158*594fa147SHui Xie for (auto i = 0; i < 10; ++i) {
159*594fa147SHui Xie std::same_as<Iter> decltype(auto) it = dwv.begin();
160*594fa147SHui Xie assert(base(it) == buffer + 2);
161*594fa147SHui Xie assert(called == 3);
162*594fa147SHui Xie }
163*594fa147SHui Xie }
164*594fa147SHui Xie }
165*594fa147SHui Xie }
166*594fa147SHui Xie
test()167*594fa147SHui Xie constexpr bool test() {
168*594fa147SHui Xie testOne<cpp17_input_iterator<int*>>();
169*594fa147SHui Xie testOne<cpp20_input_iterator<int*>>();
170*594fa147SHui Xie testOne<forward_iterator<int*>>();
171*594fa147SHui Xie testOne<bidirectional_iterator<int*>>();
172*594fa147SHui Xie testOne<random_access_iterator<int*>>();
173*594fa147SHui Xie testOne<contiguous_iterator<int*>>();
174*594fa147SHui Xie testOne<int*>();
175*594fa147SHui Xie return true;
176*594fa147SHui Xie }
177*594fa147SHui Xie
main(int,char **)178*594fa147SHui Xie int main(int, char**) {
179*594fa147SHui Xie test();
180*594fa147SHui Xie static_assert(test());
181*594fa147SHui Xie return 0;
182*594fa147SHui Xie }
183