1065dc485SJakub Mazurkiewicz //===----------------------------------------------------------------------===//
2065dc485SJakub Mazurkiewicz //
3065dc485SJakub Mazurkiewicz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4065dc485SJakub Mazurkiewicz // See https://llvm.org/LICENSE.txt for license information.
5065dc485SJakub Mazurkiewicz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6065dc485SJakub Mazurkiewicz //
7065dc485SJakub Mazurkiewicz //===----------------------------------------------------------------------===//
8065dc485SJakub Mazurkiewicz 
9065dc485SJakub Mazurkiewicz // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10065dc485SJakub Mazurkiewicz 
11065dc485SJakub Mazurkiewicz // <ranges>
12065dc485SJakub Mazurkiewicz 
13065dc485SJakub Mazurkiewicz // constexpr iterator& operator++();
14065dc485SJakub Mazurkiewicz // constexpr iterator operator++(int);
15065dc485SJakub Mazurkiewicz 
16065dc485SJakub Mazurkiewicz #include <ranges>
17065dc485SJakub Mazurkiewicz 
18065dc485SJakub Mazurkiewicz #include <array>
19065dc485SJakub Mazurkiewicz #include <cassert>
20065dc485SJakub Mazurkiewicz #include <concepts>
21065dc485SJakub Mazurkiewicz #include <functional>
22065dc485SJakub Mazurkiewicz #include <span>
23065dc485SJakub Mazurkiewicz #include <type_traits>
24065dc485SJakub Mazurkiewicz #include <utility>
25065dc485SJakub Mazurkiewicz 
26065dc485SJakub Mazurkiewicz #include "../types.h"
27065dc485SJakub Mazurkiewicz #include "test_iterators.h"
28065dc485SJakub Mazurkiewicz #include "test_macros.h"
29065dc485SJakub Mazurkiewicz 
30065dc485SJakub Mazurkiewicz struct TrackingPred : TrackInitialization {
31065dc485SJakub Mazurkiewicz   using TrackInitialization::TrackInitialization;
operator ()TrackingPred32065dc485SJakub Mazurkiewicz   constexpr bool operator()(int x, int y) const { return x <= y; }
33065dc485SJakub Mazurkiewicz };
34065dc485SJakub Mazurkiewicz 
35065dc485SJakub Mazurkiewicz template <class Iterator, IsConst Constant>
test()36065dc485SJakub Mazurkiewicz constexpr void test() {
37065dc485SJakub Mazurkiewicz   using Sentinel        = sentinel_wrapper<Iterator>;
38065dc485SJakub Mazurkiewicz   using Underlying      = View<Iterator, Sentinel>;
39065dc485SJakub Mazurkiewicz   using ChunkByView     = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
40065dc485SJakub Mazurkiewicz   using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
41065dc485SJakub Mazurkiewicz 
42*f1db578fSStephan T. Lavavej   auto make_chunk_by_view = [](auto& arr) {
43*f1db578fSStephan T. Lavavej     View view{Iterator{arr.data()}, Sentinel{Iterator{arr.data() + arr.size()}}};
44065dc485SJakub Mazurkiewicz     return ChunkByView{std::move(view), std::ranges::less_equal{}};
45065dc485SJakub Mazurkiewicz   };
46065dc485SJakub Mazurkiewicz 
47065dc485SJakub Mazurkiewicz   // Increment the iterator when it won't find another satisfied value after begin()
48065dc485SJakub Mazurkiewicz   {
49065dc485SJakub Mazurkiewicz     std::array array{0, 1, 2, 3, 4};
50*f1db578fSStephan T. Lavavej     ChunkByView view   = make_chunk_by_view(array);
51065dc485SJakub Mazurkiewicz     ChunkByIterator it = view.begin();
52065dc485SJakub Mazurkiewicz 
53065dc485SJakub Mazurkiewicz     std::same_as<ChunkByIterator&> decltype(auto) result = ++it;
54065dc485SJakub Mazurkiewicz     assert(&result == &it);
55065dc485SJakub Mazurkiewicz     assert(result == view.end());
56065dc485SJakub Mazurkiewicz     assert(result == std::default_sentinel);
57065dc485SJakub Mazurkiewicz   }
58065dc485SJakub Mazurkiewicz 
59065dc485SJakub Mazurkiewicz   // Increment the iterator and it finds another value after begin()
60065dc485SJakub Mazurkiewicz   {
61065dc485SJakub Mazurkiewicz     std::array array{1, 2, 3, -1, -2, -3};
62*f1db578fSStephan T. Lavavej     int const* second_chunk = array.data() + 3;
63*f1db578fSStephan T. Lavavej     ChunkByView view        = make_chunk_by_view(array);
64065dc485SJakub Mazurkiewicz 
65065dc485SJakub Mazurkiewicz     ChunkByIterator it = view.begin();
66065dc485SJakub Mazurkiewicz     ++it;
67065dc485SJakub Mazurkiewicz     assert(base((*it).begin()) == second_chunk);
68065dc485SJakub Mazurkiewicz   }
69065dc485SJakub Mazurkiewicz 
70065dc485SJakub Mazurkiewicz   // Increment advances all the way to the end of the range
71065dc485SJakub Mazurkiewicz   {
72065dc485SJakub Mazurkiewicz     std::array array{1, 2, 3, 4, 1};
73*f1db578fSStephan T. Lavavej     ChunkByView view = make_chunk_by_view(array);
74065dc485SJakub Mazurkiewicz 
75065dc485SJakub Mazurkiewicz     ChunkByIterator it = view.begin();
76065dc485SJakub Mazurkiewicz     ++it;
77*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 4);
78065dc485SJakub Mazurkiewicz   }
79065dc485SJakub Mazurkiewicz 
80065dc485SJakub Mazurkiewicz   // Increment an iterator multiple times
81065dc485SJakub Mazurkiewicz   {
82065dc485SJakub Mazurkiewicz     std::array array{0, 1, 0, 2, 0, 3, 0, 4};
83*f1db578fSStephan T. Lavavej     ChunkByView view = make_chunk_by_view(array);
84065dc485SJakub Mazurkiewicz 
85065dc485SJakub Mazurkiewicz     ChunkByIterator it = view.begin();
86*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data());
87065dc485SJakub Mazurkiewicz     ++it;
88*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 2);
89065dc485SJakub Mazurkiewicz     ++it;
90*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 4);
91065dc485SJakub Mazurkiewicz     ++it;
92*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 6);
93065dc485SJakub Mazurkiewicz     ++it;
94065dc485SJakub Mazurkiewicz     assert(it == std::default_sentinel);
95065dc485SJakub Mazurkiewicz   }
96065dc485SJakub Mazurkiewicz 
97065dc485SJakub Mazurkiewicz   // Test with a predicate that takes by non-const reference
98065dc485SJakub Mazurkiewicz   if constexpr (!std::to_underlying(Constant)) {
99065dc485SJakub Mazurkiewicz     std::array array{1, 2, 3, -3, -2, -1};
100*f1db578fSStephan T. Lavavej     View v{Iterator{array.data()}, Sentinel{Iterator{array.data() + array.size()}}};
101065dc485SJakub Mazurkiewicz     auto view = std::views::chunk_by(std::move(v), [](int& x, int& y) { return x <= y; });
102065dc485SJakub Mazurkiewicz 
103065dc485SJakub Mazurkiewicz     auto it = view.begin();
104*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data());
105065dc485SJakub Mazurkiewicz     ++it;
106*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 3);
107065dc485SJakub Mazurkiewicz   }
108065dc485SJakub Mazurkiewicz 
109065dc485SJakub Mazurkiewicz   // Test with a predicate that is invocable but not callable (i.e. cannot be called like regular function 'f()')
110065dc485SJakub Mazurkiewicz   {
111065dc485SJakub Mazurkiewicz     std::array array = {1, 2, 3, -3, -2, -1};
112*f1db578fSStephan T. Lavavej     auto v           = View{Iterator{array.data()}, Sentinel{Iterator{array.data() + array.size()}}} |
113*f1db578fSStephan T. Lavavej              std::views::transform([](int x) { return IntWrapper{x}; });
114065dc485SJakub Mazurkiewicz     auto view = std::views::chunk_by(std::move(v), &IntWrapper::lessEqual);
115065dc485SJakub Mazurkiewicz 
116065dc485SJakub Mazurkiewicz     auto it = view.begin();
117*f1db578fSStephan T. Lavavej     assert(base((*it).begin().base()) == array.data());
118065dc485SJakub Mazurkiewicz     ++it;
119*f1db578fSStephan T. Lavavej     assert(base((*it).begin().base()) == array.data() + 3);
120065dc485SJakub Mazurkiewicz   }
121065dc485SJakub Mazurkiewicz 
122065dc485SJakub Mazurkiewicz   // Make sure we do not make a copy of the predicate when we increment
123065dc485SJakub Mazurkiewicz   // (we should be passing it to ranges::adjacent_find using std::ref)
124065dc485SJakub Mazurkiewicz   {
125065dc485SJakub Mazurkiewicz     bool moved = false, copied = false;
126065dc485SJakub Mazurkiewicz     std::array array{1, 2, 1, 3};
127*f1db578fSStephan T. Lavavej     View v{Iterator(array.data()), Sentinel(Iterator(array.data() + array.size()))};
128065dc485SJakub Mazurkiewicz     auto view = std::views::chunk_by(std::move(v), TrackingPred(&moved, &copied));
129065dc485SJakub Mazurkiewicz     assert(std::exchange(moved, false));
130065dc485SJakub Mazurkiewicz     auto it = view.begin();
131065dc485SJakub Mazurkiewicz     ++it;
132065dc485SJakub Mazurkiewicz     it++;
133065dc485SJakub Mazurkiewicz     assert(!moved);
134065dc485SJakub Mazurkiewicz     assert(!copied);
135065dc485SJakub Mazurkiewicz   }
136065dc485SJakub Mazurkiewicz 
137065dc485SJakub Mazurkiewicz   // Check post-increment
138065dc485SJakub Mazurkiewicz   {
139065dc485SJakub Mazurkiewicz     std::array array{0, 1, 2, -3, -2, -1, -6, -5, -4};
140*f1db578fSStephan T. Lavavej     ChunkByView view   = make_chunk_by_view(array);
141065dc485SJakub Mazurkiewicz     ChunkByIterator it = view.begin();
142065dc485SJakub Mazurkiewicz 
143065dc485SJakub Mazurkiewicz     std::same_as<ChunkByIterator> decltype(auto) result = it++;
144065dc485SJakub Mazurkiewicz     assert(result != it);
145*f1db578fSStephan T. Lavavej     assert(base((*result).begin()) == array.data());
146*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 3);
147065dc485SJakub Mazurkiewicz 
148065dc485SJakub Mazurkiewicz     result = it++;
149*f1db578fSStephan T. Lavavej     assert(base((*result).begin()) == array.data() + 3);
150*f1db578fSStephan T. Lavavej     assert(base((*it).begin()) == array.data() + 6);
151065dc485SJakub Mazurkiewicz 
152065dc485SJakub Mazurkiewicz     result = it++;
153*f1db578fSStephan T. Lavavej     assert(base((*result).begin()) == array.data() + 6);
154065dc485SJakub Mazurkiewicz     assert(it == std::default_sentinel);
155065dc485SJakub Mazurkiewicz   }
156065dc485SJakub Mazurkiewicz }
157065dc485SJakub Mazurkiewicz 
tests()158065dc485SJakub Mazurkiewicz constexpr bool tests() {
159065dc485SJakub Mazurkiewicz   test<forward_iterator<int*>, IsConst::no>();
160065dc485SJakub Mazurkiewicz   test<bidirectional_iterator<int*>, IsConst::no>();
161065dc485SJakub Mazurkiewicz   test<random_access_iterator<int*>, IsConst::no>();
162065dc485SJakub Mazurkiewicz   test<contiguous_iterator<int*>, IsConst::no>();
163065dc485SJakub Mazurkiewicz   test<int*, IsConst::no>();
164065dc485SJakub Mazurkiewicz 
165065dc485SJakub Mazurkiewicz   test<forward_iterator<int const*>, IsConst::yes>();
166065dc485SJakub Mazurkiewicz   test<bidirectional_iterator<int const*>, IsConst::yes>();
167065dc485SJakub Mazurkiewicz   test<random_access_iterator<int const*>, IsConst::yes>();
168065dc485SJakub Mazurkiewicz   test<contiguous_iterator<int const*>, IsConst::yes>();
169065dc485SJakub Mazurkiewicz   test<int const*, IsConst::yes>();
170065dc485SJakub Mazurkiewicz 
171065dc485SJakub Mazurkiewicz   return true;
172065dc485SJakub Mazurkiewicz }
173065dc485SJakub Mazurkiewicz 
main(int,char **)174065dc485SJakub Mazurkiewicz int main(int, char**) {
175065dc485SJakub Mazurkiewicz   tests();
176065dc485SJakub Mazurkiewicz   static_assert(tests());
177065dc485SJakub Mazurkiewicz 
178065dc485SJakub Mazurkiewicz   return 0;
179065dc485SJakub Mazurkiewicz }
180