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