xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp (revision f73050e722dd2e484358d03674eb186f3a2f4799)
1a2b3ab8fSHui //===----------------------------------------------------------------------===//
2a2b3ab8fSHui //
3a2b3ab8fSHui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a2b3ab8fSHui // See https://llvm.org/LICENSE.txt for license information.
5a2b3ab8fSHui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a2b3ab8fSHui //
7a2b3ab8fSHui //===----------------------------------------------------------------------===//
8a2b3ab8fSHui 
9a2b3ab8fSHui // UNSUPPORTED: c++03, c++11, c++14, c++17
10a2b3ab8fSHui 
11a2b3ab8fSHui // constexpr auto begin();
12a2b3ab8fSHui 
13a2b3ab8fSHui #include <array>
14a2b3ab8fSHui #include <cassert>
15a2b3ab8fSHui #include <ranges>
16a2b3ab8fSHui #include <type_traits>
17a2b3ab8fSHui #include <utility>
18a2b3ab8fSHui 
19a2b3ab8fSHui #include "test_iterators.h"
20a2b3ab8fSHui 
21a2b3ab8fSHui struct View : std::ranges::view_base {
22a2b3ab8fSHui   int* begin() const;
23a2b3ab8fSHui   int* end() const;
24a2b3ab8fSHui };
25a2b3ab8fSHui 
26a2b3ab8fSHui // Test that begin is not const
27a2b3ab8fSHui template <class T>
28a2b3ab8fSHui concept HasBegin = requires(T t) { t.begin(); };
29a2b3ab8fSHui 
30a2b3ab8fSHui static_assert(HasBegin<std::ranges::split_view<View, View>>);
31a2b3ab8fSHui static_assert(!HasBegin<const std::ranges::split_view<View, View>>);
32a2b3ab8fSHui 
33a2b3ab8fSHui template <template <class> class MakeIter>
34a2b3ab8fSHui constexpr void testOne() {
35a2b3ab8fSHui   constexpr auto make_subrange = []<class T, std::size_t N>(T(&buffer)[N]) {
36a2b3ab8fSHui     using Iter = MakeIter<T*>;
37a2b3ab8fSHui     using Sent = sentinel_wrapper<Iter>;
38a2b3ab8fSHui     return std::ranges::subrange<Iter, Sent>{Iter{buffer}, Sent{Iter{buffer + N}}};
39a2b3ab8fSHui   };
40a2b3ab8fSHui 
41a2b3ab8fSHui   using Iter  = MakeIter<int*>;
42a2b3ab8fSHui   using Sent  = sentinel_wrapper<Iter>;
43a2b3ab8fSHui   using Range = std::ranges::subrange<Iter, Sent>;
44a2b3ab8fSHui 
45a2b3ab8fSHui   // empty view
46a2b3ab8fSHui   {
47a2b3ab8fSHui     std::array<int, 0> a;
48a2b3ab8fSHui     Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}};
49a2b3ab8fSHui     std::ranges::split_view sv{std::move(range), 1};
50a2b3ab8fSHui     auto it         = sv.begin();
51a2b3ab8fSHui     auto firstRange = *it;
52*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(a.data()));
53*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(a.data())));
54a2b3ab8fSHui   }
55a2b3ab8fSHui 
56a2b3ab8fSHui   // empty pattern
57a2b3ab8fSHui   {
58a2b3ab8fSHui     int buffer[] = {1, 2, 3};
59a2b3ab8fSHui     auto range   = make_subrange(buffer);
60a2b3ab8fSHui     std::ranges::split_view sv{std::move(range), std::views::empty<int>};
61a2b3ab8fSHui     auto it         = sv.begin();
62a2b3ab8fSHui     auto firstRange = *it;
63*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(buffer));
64*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(buffer + 1)));
65a2b3ab8fSHui   }
66a2b3ab8fSHui 
67a2b3ab8fSHui   // empty view and empty pattern
68a2b3ab8fSHui   {
69a2b3ab8fSHui     std::array<int, 0> a;
70a2b3ab8fSHui     Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}};
71a2b3ab8fSHui     std::ranges::split_view sv{std::move(range), std::views::empty<int>};
72a2b3ab8fSHui     auto it         = sv.begin();
73a2b3ab8fSHui     auto firstRange = *it;
74*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(a.data()));
75*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(a.data())));
76a2b3ab8fSHui   }
77a2b3ab8fSHui 
78a2b3ab8fSHui   // pattern found at the beginning
79a2b3ab8fSHui   {
80a2b3ab8fSHui     int buffer[]  = {1, 2, 3};
81a2b3ab8fSHui     auto range    = make_subrange(buffer);
82a2b3ab8fSHui     int pattern[] = {1, 2};
83a2b3ab8fSHui     std::ranges::split_view sv{range, pattern};
84a2b3ab8fSHui 
85a2b3ab8fSHui     auto it         = sv.begin();
86a2b3ab8fSHui     auto firstRange = *it;
87*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(buffer));
88*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(buffer)));
89a2b3ab8fSHui   }
90a2b3ab8fSHui 
91a2b3ab8fSHui   // pattern found in the middle
92a2b3ab8fSHui   {
93a2b3ab8fSHui     int buffer[]  = {1, 2, 3, 4};
94a2b3ab8fSHui     auto range    = make_subrange(buffer);
95a2b3ab8fSHui     int pattern[] = {2, 3};
96a2b3ab8fSHui     std::ranges::split_view sv{range, pattern};
97a2b3ab8fSHui 
98a2b3ab8fSHui     auto it         = sv.begin();
99a2b3ab8fSHui     auto firstRange = *it;
100*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(buffer));
101*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(buffer + 1)));
102a2b3ab8fSHui   }
103a2b3ab8fSHui 
104a2b3ab8fSHui   // pattern found at the end
105a2b3ab8fSHui   {
106a2b3ab8fSHui     int buffer[]  = {1, 2, 3};
107a2b3ab8fSHui     auto range    = make_subrange(buffer);
108a2b3ab8fSHui     int pattern[] = {2, 3};
109a2b3ab8fSHui     std::ranges::split_view sv{range, pattern};
110a2b3ab8fSHui 
111a2b3ab8fSHui     auto it         = sv.begin();
112a2b3ab8fSHui     auto firstRange = *it;
113*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(buffer));
114*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(buffer + 1)));
115a2b3ab8fSHui   }
116a2b3ab8fSHui 
117a2b3ab8fSHui   // pattern not found
118a2b3ab8fSHui   {
119a2b3ab8fSHui     int buffer[]  = {1, 2, 3};
120a2b3ab8fSHui     auto range    = make_subrange(buffer);
121a2b3ab8fSHui     int pattern[] = {1, 3};
122a2b3ab8fSHui     std::ranges::split_view sv{range, pattern};
123a2b3ab8fSHui 
124a2b3ab8fSHui     auto it         = sv.begin();
125a2b3ab8fSHui     auto firstRange = *it;
126*f73050e7SLouis Dionne     assert(firstRange.begin() == Iter(buffer));
127*f73050e7SLouis Dionne     assert(firstRange.end() == Sent(Iter(buffer + 3)));
128a2b3ab8fSHui   }
129a2b3ab8fSHui 
130a2b3ab8fSHui   // Make sure that we cache the result of begin() on subsequent calls
131a2b3ab8fSHui   {
132a2b3ab8fSHui     struct Foo {
133a2b3ab8fSHui       int& equalsCalledTimes;
134a2b3ab8fSHui 
135a2b3ab8fSHui       constexpr bool operator==(const Foo&) const {
136a2b3ab8fSHui         ++equalsCalledTimes;
137a2b3ab8fSHui         return true;
138a2b3ab8fSHui       }
139a2b3ab8fSHui     };
140a2b3ab8fSHui 
141a2b3ab8fSHui     int equalsCalledTimes = 0;
142a2b3ab8fSHui     Foo buffer[]          = {Foo{equalsCalledTimes}, Foo{equalsCalledTimes}};
143a2b3ab8fSHui     auto range            = make_subrange(buffer);
144a2b3ab8fSHui 
145a2b3ab8fSHui     std::ranges::split_view sv{range, Foo{equalsCalledTimes}};
146a2b3ab8fSHui 
147a2b3ab8fSHui     assert(equalsCalledTimes == 0);
148a2b3ab8fSHui 
149a2b3ab8fSHui     [[maybe_unused]] auto it1       = sv.begin();
150a2b3ab8fSHui     auto calledTimesAfterFirstBegin = equalsCalledTimes;
151a2b3ab8fSHui     assert(calledTimesAfterFirstBegin != 0);
152a2b3ab8fSHui 
153a2b3ab8fSHui     for (int i = 0; i < 10; ++i) {
154a2b3ab8fSHui       [[maybe_unused]] auto it2 = sv.begin();
155a2b3ab8fSHui       assert(equalsCalledTimes == calledTimesAfterFirstBegin);
156a2b3ab8fSHui     }
157a2b3ab8fSHui   }
158a2b3ab8fSHui }
159a2b3ab8fSHui 
160a2b3ab8fSHui constexpr bool test() {
161a2b3ab8fSHui   testOne<forward_iterator>();
162a2b3ab8fSHui   testOne<bidirectional_iterator>();
163a2b3ab8fSHui   testOne<random_access_iterator>();
164a2b3ab8fSHui   testOne<contiguous_iterator>();
165a2b3ab8fSHui   testOne<std::type_identity_t>();
166a2b3ab8fSHui   return true;
167a2b3ab8fSHui }
168a2b3ab8fSHui 
169a2b3ab8fSHui int main(int, char**) {
170a2b3ab8fSHui   test();
171a2b3ab8fSHui   static_assert(test());
172a2b3ab8fSHui   return 0;
173a2b3ab8fSHui }
174