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