xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp (revision 6a664674990094c1b5d2e717256f08cb04485899)
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 iterator& operator--();
12 //              requires ref-is-glvalue && bidirectional_range<Base> &&
13 //                       bidirectional_range<range_reference_t<Base>> &&
14 //                       common_range<range_reference_t<Base>>;
15 // constexpr iterator operator--(int);
16 //              requires ref-is-glvalue && bidirectional_range<Base> &&
17 //                       bidirectional_range<range_reference_t<Base>> &&
18 //                       common_range<range_reference_t<Base>>;
19 
20 #include <algorithm>
21 #include <array>
22 #include <cassert>
23 #include <ranges>
24 #include <type_traits>
25 #include <vector>
26 
27 #include "../types.h"
28 
29 template <class T>
30 concept CanPreDecrement = requires(T& t) { --t; };
31 
32 template <class T>
33 concept CanPostDecrement = requires(T& t) { t--; };
34 
noDecrementTest(auto && jv)35 constexpr void noDecrementTest(auto&& jv) {
36   auto iter = jv.begin();
37   static_assert(!CanPreDecrement<decltype(iter)>);
38   static_assert(!CanPostDecrement<decltype(iter)>);
39 }
40 
test()41 constexpr bool test() {
42   int buffer[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
43 
44   {
45     // outer == ranges::end
46     std::ranges::join_view jv(buffer);
47     auto iter = std::next(jv.begin(), 16);
48     for (int i = 16; i != 0; --i) {
49       assert(*--iter == i);
50     }
51   }
52 
53   {
54     // outer == ranges::end
55     std::ranges::join_view jv(buffer);
56     auto iter = std::next(jv.begin(), 13);
57     for (int i = 13; i != 0; --i) {
58       assert(*--iter == i);
59     }
60   }
61 
62   {
63     // outer != ranges::end
64     std::ranges::join_view jv(buffer);
65     auto iter = std::next(jv.begin(), 12);
66     for (int i = 12; i != 0; --i) {
67       assert(*--iter == i);
68     }
69   }
70 
71   {
72     // outer != ranges::end
73     std::ranges::join_view jv(buffer);
74     auto iter = std::next(jv.begin());
75     for (int i = 1; i != 0; --i) {
76       assert(*--iter == i);
77     }
78   }
79 
80   {
81     int small[2][1] = {{1}, {2}};
82     std::ranges::join_view jv(small);
83     auto iter = std::next(jv.begin(), 2);
84     for (int i = 2; i != 0; --i) {
85       assert(*--iter == i);
86     }
87   }
88 
89   {
90 #if defined(__GNUG__) && !defined(__clang__)
91     // This seems to be a gcc bug where evaluating the following code
92     // at compile time results in wrong array index
93     if (!std::is_constant_evaluated()) {
94 #endif
95       // skip empty inner
96       BidiCommonInner inners[4] = {buffer[0], {nullptr, 0}, {nullptr, 0}, buffer[1]};
97       std::ranges::join_view jv(inners);
98       auto iter = jv.end();
99       for (int i = 8; i != 0; --i) {
100         assert(*--iter == i);
101       }
102 #if defined(__GNUG__) && !defined(__clang__)
103     }
104 #endif
105   }
106 
107   {
108     // basic type checking
109     std::ranges::join_view jv(buffer);
110     auto iter1 = std::ranges::next(jv.begin(), 4);
111     using iterator = decltype(iter1);
112 
113     decltype(auto) iter2 = --iter1;
114     static_assert(std::same_as<decltype(iter2), iterator&>);
115     assert(&iter1 == &iter2);
116 
117     std::same_as<iterator> decltype(auto) iter3 = iter1--;
118     assert(iter3 == std::next(iter1));
119   }
120 
121   {
122     // !ref-is-glvalue
123     BidiCommonInner inners[2] = {buffer[0], buffer[1]};
124     InnerRValue<BidiCommonOuter<BidiCommonInner>> outer{inners};
125     std::ranges::join_view jv(outer);
126     noDecrementTest(jv);
127   }
128 
129   {
130     // !bidirectional_range<Base>
131     BidiCommonInner inners[2] = {buffer[0], buffer[1]};
132     SimpleForwardCommonOuter<BidiCommonInner> outer{inners};
133     std::ranges::join_view jv(outer);
134     noDecrementTest(jv);
135   }
136 
137   {
138     // !bidirectional_range<range_reference_t<Base>>
139     ForwardCommonInner inners[2] = {buffer[0], buffer[1]};
140     std::ranges::join_view jv(inners);
141     noDecrementTest(jv);
142   }
143 
144   {
145     // LWG3313 `join_view::iterator::operator--` is incorrectly constrained
146     // `join_view::iterator` should not have `operator--` if
147     // !common_range<range_reference_t<Base>>
148     BidiNonCommonInner inners[2] = {buffer[0], buffer[1]};
149     std::ranges::join_view jv(inners);
150     auto iter = jv.begin();
151     static_assert(!CanPreDecrement<decltype(iter)>);
152     static_assert(!CanPostDecrement<decltype(iter)>);
153   }
154 
155   {
156     // LWG3791: `join_view::iterator::operator--` may be ill-formed
157     std::vector<std::vector<int>> vec = {{1, 2}, {3, 4}, {5, 6}};
158     auto r = vec | std::views::transform([](auto& x) -> auto&& { return std::move(x); }) | std::views::join;
159     auto e = --r.end();
160     assert(*e == 6);
161     assert(std::ranges::equal(std::views::reverse(r), std::array{6, 5, 4, 3, 2, 1}));
162   }
163 
164   return true;
165 }
166 
main(int,char **)167 int main(int, char**) {
168   test();
169   static_assert(test());
170 
171   return 0;
172 }
173