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 | static_assert(HasBegin<std::ranges::split_view<View, View>>); |
31 | static_assert(!HasBegin<const std::ranges::split_view<View, View>>); |
32 | |
33 | template <template <class> class MakeIter> |
34 | constexpr void testOne() { |
35 | constexpr auto make_subrange = []<class T, std::size_t N>(T(&buffer)[N]) { |
36 | using Iter = MakeIter<T*>; |
37 | using Sent = sentinel_wrapper<Iter>; |
38 | return std::ranges::subrange<Iter, Sent>{Iter{buffer}, Sent{Iter{buffer + N}}}; |
39 | }; |
40 | |
41 | using Iter = MakeIter<int*>; |
42 | using Sent = sentinel_wrapper<Iter>; |
43 | using Range = std::ranges::subrange<Iter, Sent>; |
44 | |
45 | // empty view |
46 | { |
47 | std::array<int, 0> a; |
48 | Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}}; |
49 | std::ranges::split_view sv{std::move(range), 1}; |
50 | auto it = sv.begin(); |
51 | auto firstRange = *it; |
52 | assert(firstRange.begin() == range.begin()); |
53 | assert(firstRange.end() == range.end()); |
54 | } |
55 | |
56 | // empty pattern |
57 | { |
58 | int buffer[] = {1, 2, 3}; |
59 | auto range = make_subrange(buffer); |
60 | std::ranges::split_view sv{std::move(range), std::views::empty<int>}; |
61 | auto it = sv.begin(); |
62 | auto firstRange = *it; |
63 | assert(firstRange.begin() == range.begin()); |
64 | assert(firstRange.end() == std::next(range.begin())); |
65 | } |
66 | |
67 | // empty view and empty pattern |
68 | { |
69 | std::array<int, 0> a; |
70 | Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}}; |
71 | std::ranges::split_view sv{std::move(range), std::views::empty<int>}; |
72 | auto it = sv.begin(); |
73 | auto firstRange = *it; |
74 | assert(firstRange.begin() == range.begin()); |
75 | assert(firstRange.end() == range.end()); |
76 | } |
77 | |
78 | // pattern found at the beginning |
79 | { |
80 | int buffer[] = {1, 2, 3}; |
81 | auto range = make_subrange(buffer); |
82 | int pattern[] = {1, 2}; |
83 | std::ranges::split_view sv{range, pattern}; |
84 | |
85 | auto it = sv.begin(); |
86 | auto firstRange = *it; |
87 | assert(firstRange.begin() == range.begin()); |
88 | assert(firstRange.end() == range.begin()); |
89 | } |
90 | |
91 | // pattern found in the middle |
92 | { |
93 | int buffer[] = {1, 2, 3, 4}; |
94 | auto range = make_subrange(buffer); |
95 | int pattern[] = {2, 3}; |
96 | std::ranges::split_view sv{range, pattern}; |
97 | |
98 | auto it = sv.begin(); |
99 | auto firstRange = *it; |
100 | assert(firstRange.begin() == range.begin()); |
101 | assert(firstRange.end() == std::next(range.begin())); |
102 | } |
103 | |
104 | // pattern found at the end |
105 | { |
106 | int buffer[] = {1, 2, 3}; |
107 | auto range = make_subrange(buffer); |
108 | int pattern[] = {2, 3}; |
109 | std::ranges::split_view sv{range, pattern}; |
110 | |
111 | auto it = sv.begin(); |
112 | auto firstRange = *it; |
113 | assert(firstRange.begin() == range.begin()); |
114 | assert(firstRange.end() == std::next(range.begin())); |
115 | } |
116 | |
117 | // pattern not found |
118 | { |
119 | int buffer[] = {1, 2, 3}; |
120 | auto range = make_subrange(buffer); |
121 | int pattern[] = {1, 3}; |
122 | std::ranges::split_view sv{range, pattern}; |
123 | |
124 | auto it = sv.begin(); |
125 | auto firstRange = *it; |
126 | assert(firstRange.begin() == range.begin()); |
127 | assert(firstRange.end() == range.end()); |
128 | } |
129 | |
130 | // Make sure that we cache the result of begin() on subsequent calls |
131 | { |
132 | struct Foo { |
133 | int& equalsCalledTimes; |
134 | |
135 | constexpr bool operator==(const Foo&) const { |
136 | ++equalsCalledTimes; |
137 | return true; |
138 | } |
139 | }; |
140 | |
141 | int equalsCalledTimes = 0; |
142 | Foo buffer[] = {Foo{equalsCalledTimes}, Foo{equalsCalledTimes}}; |
143 | auto range = make_subrange(buffer); |
144 | |
145 | std::ranges::split_view sv{range, Foo{equalsCalledTimes}}; |
146 | |
147 | assert(equalsCalledTimes == 0); |
148 | |
149 | [[maybe_unused]] auto it1 = sv.begin(); |
150 | auto calledTimesAfterFirstBegin = equalsCalledTimes; |
151 | assert(calledTimesAfterFirstBegin != 0); |
152 | |
153 | for (int i = 0; i < 10; ++i) { |
154 | [[maybe_unused]] auto it2 = sv.begin(); |
155 | assert(equalsCalledTimes == calledTimesAfterFirstBegin); |
156 | } |
157 | } |
158 | } |
159 | |
160 | constexpr bool test() { |
161 | testOne<forward_iterator>(); |
162 | testOne<bidirectional_iterator>(); |
163 | testOne<random_access_iterator>(); |
164 | testOne<contiguous_iterator>(); |
165 | testOne<std::type_identity_t>(); |
166 | return true; |
167 | } |
168 | |
169 | int main(int, char**) { |
170 | test(); |
171 | static_assert(test()); |
172 | return 0; |
173 | } |
174 | |