xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp (revision f73050e722dd2e484358d03674eb186f3a2f4799)
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() == Iter(a.data()));
53     assert(firstRange.end() == Sent(Iter(a.data())));
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() == Iter(buffer));
64     assert(firstRange.end() == Sent(Iter(buffer + 1)));
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() == Iter(a.data()));
75     assert(firstRange.end() == Sent(Iter(a.data())));
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() == Iter(buffer));
88     assert(firstRange.end() == Sent(Iter(buffer)));
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() == Iter(buffer));
101     assert(firstRange.end() == Sent(Iter(buffer + 1)));
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() == Iter(buffer));
114     assert(firstRange.end() == Sent(Iter(buffer + 1)));
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() == Iter(buffer));
127     assert(firstRange.end() == Sent(Iter(buffer + 3)));
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