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, c++20
10
11// <ranges>
12
13// constexpr iterator begin();
14
15#include <ranges>
16
17#include <cassert>
18#include <utility>
19
20#include "test_iterators.h"
21#include "types.h"
22
23struct Range : std::ranges::view_base {
24 using Iterator = forward_iterator<int*>;
25 using Sentinel = sentinel_wrapper<Iterator>;
26 constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}
27 constexpr Iterator begin() const { return Iterator(begin_); }
28 constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
29
30private:
31 int* begin_;
32 int* end_;
33};
34
35struct TrackingPred : TrackInitialization {
36 using TrackInitialization::TrackInitialization;
37 constexpr bool operator()(int x, int y) { return x != -y; }
38};
39
40template <class T>
41concept HasBegin = requires(T t) { t.begin(); };
42
43static_assert(HasBegin<std::ranges::chunk_by_view<Range, TrackingPred>>);
44static_assert(!HasBegin<const std::ranges::chunk_by_view<Range, TrackingPred>>);
45
46constexpr bool test() {
47 int buff[] = {-4, -3, -2, -1, 1, 2, 3, 4};
48
49 // Check the return type of `begin()`
50 {
51 Range range(buff, buff + 1);
52 auto pred = [](int, int) { return true; };
53 std::ranges::chunk_by_view view(range, pred);
54 using ChunkByIterator = std::ranges::iterator_t<decltype(view)>;
55 ASSERT_SAME_TYPE(ChunkByIterator, decltype(view.begin()));
56 }
57
58 // begin() over an empty range
59 {
60 Range range(buff, buff);
61 auto pred = [](int, int) { return true; };
62 std::ranges::chunk_by_view view(range, pred);
63 auto it = view.begin();
64 assert(it == view.begin());
65 assert(it == view.end());
66 }
67
68 // begin() over a 1-element range
69 {
70 Range range(buff, buff + 1);
71 auto pred = [](int x, int y) { return x == y; };
72 std::ranges::chunk_by_view view(range, pred);
73 auto it = view.begin();
74 assert(base((*it).begin()) == buff);
75 assert(base((*it).end()) == buff + 1);
76 }
77
78 // begin() over a 2-element range
79 {
80 Range range(buff, buff + 2);
81 auto pred = [](int x, int y) { return x == y; };
82 std::ranges::chunk_by_view view(range, pred);
83 auto it = view.begin();
84 assert(base((*it).begin()) == buff);
85 assert(base((*it).end()) == buff + 1);
86 assert(base((*++it).begin()) == buff + 1);
87 assert(base((*it).end()) == buff + 2);
88 }
89
90 // begin() over a longer range
91 {
92 Range range(buff, buff + 8);
93 auto pred = [](int x, int y) { return x != -y; };
94 std::ranges::chunk_by_view view(range, pred);
95 auto it = view.begin();
96 assert(base((*it).end()) == buff + 4);
97 }
98
99 // Make sure we do not make a copy of the predicate when we call begin()
100 // (we should be passing it to ranges::adjacent_find using std::ref)
101 {
102 bool moved = false, copied = false;
103 Range range(buff, buff + 2);
104 std::ranges::chunk_by_view view(range, TrackingPred(&moved, &copied));
105 std::exchange(obj&: moved, new_val: false);
106 [[maybe_unused]] auto it = view.begin();
107 assert(!moved);
108 assert(!copied);
109 }
110
111 // Test with a non-const predicate
112 {
113 Range range(buff, buff + 8);
114 auto pred = [](int x, int y) mutable { return x != -y; };
115 std::ranges::chunk_by_view view(range, pred);
116 auto it = view.begin();
117 assert(base((*it).end()) == buff + 4);
118 }
119
120 // Test with a predicate that takes by non-const reference
121 {
122 Range range(buff, buff + 8);
123 auto pred = [](int& x, int& y) { return x != -y; };
124 std::ranges::chunk_by_view view(range, pred);
125 auto it = view.begin();
126 assert(base((*it).end()) == buff + 4);
127 }
128
129 // Test caching
130 {
131 // Make sure that we cache the result of begin() on subsequent calls
132 Range range(buff, buff + 8);
133 int called = 0;
134 auto pred = [&](int x, int y) {
135 ++called;
136 return x != -y;
137 };
138
139 std::ranges::chunk_by_view view(range, pred);
140 assert(called == 0);
141 for (int k = 0; k != 3; ++k) {
142 auto it = view.begin();
143 assert(base((*it).end()) == buff + 4);
144 assert(called == 4); // 4, because the cached iterator is 'buff + 4' (end of the first chunk)
145 }
146 }
147
148 return true;
149}
150
151int main(int, char**) {
152 test();
153 static_assert(test());
154
155 return 0;
156}
157

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