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