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 { |
31 | 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 | |
37 | constexpr auto always = [](auto v) { return [v](auto&&...) { return v; }; }; |
38 | |
39 | template <class Iter> |
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 | |
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 | |
178 | int main(int, char**) { |
179 | test(); |
180 | static_assert(test()); |
181 | return 0; |
182 | } |
183 | |