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
21struct View : std::ranges::view_base {
22 int* begin() const;
23 int* end() const;
24};
25
26// Test that begin is not const
27template <class T>
28concept HasBegin = requires(T t) { t.begin(); };
29
30static_assert(HasBegin<std::ranges::split_view<View, View>>);
31static_assert(!HasBegin<const std::ranges::split_view<View, View>>);
32
33template <template <class> class MakeIter>
34constexpr 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
160constexpr 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
169int main(int, char**) {
170 test();
171 static_assert(test());
172 return 0;
173}
174

source code of libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp