xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.drop.while/begin.pass.cpp (revision 594fa1474f0c96da864257c0cda31b9b8381cd15)
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