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
29template <class T>
30concept CanPreDecrement = requires(T& t) { --t; };
31
32template <class T>
33concept CanPostDecrement = requires(T& t) { t--; };
34
35constexpr void noDecrementTest(auto&& jv) {
36 auto iter = jv.begin();
37 static_assert(!CanPreDecrement<decltype(iter)>);
38 static_assert(!CanPostDecrement<decltype(iter)>);
39}
40
41constexpr 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
167int main(int, char**) {
168 test();
169 static_assert(test());
170
171 return 0;
172}
173

source code of libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp