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// REQUIRES: std-at-least-c++23
10
11// <ranges>
12
13// constexpr auto end();
14// constexpr auto end() const
15// requires forward_range<const V> && forward_range<const Pattern> &&
16// is_reference_v<range_reference_t<const V>> &&
17// input_range<range_reference_t<const V>>;
18
19// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=10000000
20
21#include <ranges>
22
23#include <algorithm>
24#include <string>
25#include <vector>
26
27#include "../types.h"
28#include "test_iterators.h"
29
30template <class V, class Pattern>
31concept JoinWithViewHasConstEnd = requires(const std::ranges::join_with_view<V, Pattern> jwv) { jwv.end(); };
32
33template <size_t Bits>
34 requires(Bits < (1 << 7))
35constexpr void test_end() {
36 constexpr bool v_models_forward_range = static_cast<bool>(Bits & (1 << 0));
37 constexpr bool inner_range_is_reference = static_cast<bool>(Bits & (1 << 1));
38 constexpr bool inner_range_models_forward_range = static_cast<bool>(Bits & (1 << 2));
39 constexpr bool v_models_common_range = static_cast<bool>(Bits & (1 << 3));
40 constexpr bool inner_range_models_common_range = static_cast<bool>(Bits & (1 << 4));
41 constexpr bool v_models_simple_range = static_cast<bool>(Bits & (1 << 5));
42 constexpr bool pattern_models_simple_range = static_cast<bool>(Bits & (1 << 6));
43
44 constexpr ViewProperties inner_range_props{.common = inner_range_models_common_range};
45 using InnerRange =
46 std::conditional_t<inner_range_models_forward_range,
47 BasicView<std::vector<int>, inner_range_props, forward_iterator>,
48 BasicView<std::vector<int>, inner_range_props, DefaultCtorInputIter>>;
49
50 constexpr ViewProperties v_props{.simple = v_models_simple_range, .common = v_models_common_range};
51 using UnderlyingV = std::conditional_t<inner_range_is_reference, std::vector<InnerRange>, RvalueVector<InnerRange>>;
52 using V = std::conditional_t<v_models_forward_range,
53 BasicView<UnderlyingV, v_props, forward_iterator>,
54 BasicView<UnderlyingV, v_props, DefaultCtorInputIter>>;
55
56 using UnderlyingPattern = std::vector<int>;
57 using Pattern = BasicView<UnderlyingPattern, ViewProperties{.simple = pattern_models_simple_range}, forward_iterator>;
58
59 using JWV = std::ranges::join_with_view<V, Pattern>;
60 using Iter = std::ranges::iterator_t<JWV>;
61
62 // Test when `JWV` models common range
63 static_assert(std::same_as<Iter, std::ranges::sentinel_t<JWV>> ==
64 (v_models_forward_range && inner_range_is_reference && inner_range_models_forward_range &&
65 v_models_common_range && inner_range_models_common_range));
66
67 { // `V` and `Pattern` are empty
68 V v{};
69 Pattern pattern{};
70 JWV jwv(std::move(v), std::move(pattern));
71 Iter it = jwv.begin();
72 std::sentinel_for<Iter> decltype(auto) se = jwv.end();
73 assert(it == se);
74 }
75
76 { // `V` is empty, `Pattern` contains some elements
77 V v{};
78 Pattern pattern{std::vector<int>{0}};
79 JWV jwv(std::move(v), std::move(pattern));
80 Iter it = jwv.begin();
81 std::sentinel_for<Iter> decltype(auto) se = jwv.end();
82 assert(it == se);
83 }
84
85 { // `V` is not empty, `Pattern is empty`
86 V v{UnderlyingV{
87 std::vector<InnerRange>{InnerRange(std::vector<int>{1, 2, 3}), InnerRange(std::vector<int>{4, 5, 6})}}};
88 Pattern pattern{};
89 JWV jwv(std::move(v), std::move(pattern));
90 Iter it = jwv.begin();
91 std::sentinel_for<Iter> decltype(auto) se = jwv.end();
92 assert(std::ranges::next(it, 6) == se);
93 }
94
95 { // `V` and `Pattern` are not empty
96 V v{UnderlyingV{std::vector<InnerRange>{
97 InnerRange(std::vector<int>{6, 5}),
98 InnerRange(std::vector<int>{4, 3}),
99 InnerRange(std::vector<int>{2, 1, 0})}}};
100 Pattern pattern{std::vector<int>{-1, -1}};
101 JWV jwv(std::move(v), std::move(pattern));
102 Iter it = jwv.begin();
103 std::sentinel_for<Iter> decltype(auto) se = jwv.end();
104 assert(std::ranges::next(it, 11) == se);
105 }
106}
107
108template <std::size_t Bits>
109 requires(Bits < (1 << 7))
110constexpr void test_const_end() {
111 constexpr bool const_v_models_forward_range = static_cast<bool>(Bits & (1 << 0));
112 constexpr bool const_pattern_models_forward_range = static_cast<bool>(Bits & (1 << 1));
113 constexpr bool inner_const_range_is_reference = static_cast<bool>(Bits & (1 << 2));
114 constexpr bool inner_const_range_models_input_range = static_cast<bool>(Bits & (1 << 3));
115 constexpr bool inner_const_range_models_forward_range = static_cast<bool>(Bits & (1 << 4));
116 constexpr bool const_v_models_common_range = static_cast<bool>(Bits & (1 << 5));
117 constexpr bool inner_const_range_models_common_range = static_cast<bool>(Bits & (1 << 6));
118
119 constexpr ViewProperties inner_range_props{.common = inner_const_range_models_common_range};
120 using InnerRange =
121 std::conditional_t<inner_const_range_models_forward_range,
122 BasicView<std::vector<int>, inner_range_props, forward_iterator>,
123 std::conditional_t<inner_const_range_models_input_range,
124 BasicView<std::vector<int>, inner_range_props, DefaultCtorInputIter>,
125 InputRangeButOutputWhenConst<int>>>;
126
127 constexpr ViewProperties v_props{.common = const_v_models_common_range};
128 using UnderlyingV =
129 std::conditional_t<inner_const_range_is_reference, std::vector<InnerRange>, RvalueVector<InnerRange>>;
130 using V = std::conditional_t<const_v_models_forward_range,
131 BasicView<UnderlyingV, v_props, forward_iterator>,
132 BasicView<UnderlyingV, v_props, DefaultCtorInputIter>>;
133 using Pattern =
134 std::conditional_t<const_pattern_models_forward_range,
135 BasicView<std::vector<int>, ViewProperties{}, forward_iterator>,
136 ForwardViewButInputWhenConst<int>>;
137
138 using JWV = std::ranges::join_with_view<V, Pattern>;
139 static_assert(JoinWithViewHasConstEnd<V, Pattern> ==
140 (const_v_models_forward_range && const_pattern_models_forward_range && inner_const_range_is_reference &&
141 (inner_const_range_models_input_range || inner_const_range_models_forward_range)));
142 static_assert(JoinWithViewHasConstEnd<V, Pattern> == std::ranges::range<const JWV>);
143
144 if constexpr (std::ranges::range<const JWV>) {
145 using ConstIter = std::ranges::iterator_t<const JWV>;
146
147 // Test when `const JWV` models common range
148 static_assert(std::same_as<ConstIter, std::ranges::sentinel_t<const JWV>> ==
149 (inner_const_range_models_forward_range && const_v_models_common_range &&
150 inner_const_range_models_common_range));
151
152 { // `const V` and `const Pattern` are empty
153 V v{};
154 Pattern pattern{};
155 const JWV jwv(std::move(v), std::move(pattern));
156 ConstIter it = jwv.begin();
157 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();
158 assert(it == se);
159 }
160
161 { // `const V` is empty, `const Pattern` contains some elements
162 V v{};
163 Pattern pattern{std::vector<int>{1}};
164 const JWV jwv(std::move(v), std::move(pattern));
165 ConstIter it = jwv.begin();
166 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();
167 assert(it == se);
168 }
169
170 { // `const V` is not empty, `const Pattern is empty`
171 V v{UnderlyingV{
172 std::vector<InnerRange>{InnerRange(std::vector<int>{1, 2, 3}), InnerRange(std::vector<int>{4, 5, 6})}}};
173 Pattern pattern{};
174 const JWV jwv(std::move(v), std::move(pattern));
175 ConstIter it = jwv.begin();
176 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();
177 assert(std::ranges::next(it, 6) == se);
178 }
179
180 { // `const V` and `const Pattern` are not empty
181 V v{UnderlyingV{std::vector<InnerRange>{
182 InnerRange(std::vector<int>{1}), InnerRange(std::vector<int>{2, 2}), InnerRange(std::vector<int>{3, 3, 3})}}};
183 Pattern pattern{std::vector<int>{0}};
184 const JWV jwv(std::move(v), std::move(pattern));
185 ConstIter it = jwv.begin();
186 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();
187 assert(std::ranges::next(it, 8) == se);
188 }
189 }
190}
191
192constexpr bool test() {
193 []<std::size_t... Bits>(std::index_sequence<Bits...>) {
194 (test_end<Bits>(), ...);
195 (test_const_end<Bits>(), ...);
196 }(std::make_index_sequence<(1 << 7)>{});
197
198 { // Check situation when iterators returned by `end()` and `end() const` are of the same type
199 using V = BasicView<std::vector<std::string>, ViewProperties{.simple = true}, forward_iterator>;
200 using Pattern = BasicView<std::string, ViewProperties{.simple = true}, forward_iterator>;
201 using JWV = std::ranges::join_with_view<V, Pattern>;
202 using Sentinel = std::ranges::sentinel_t<JWV&>;
203 using ConstSentinel = std::ranges::sentinel_t<const JWV&>;
204 static_assert(std::input_iterator<Sentinel>);
205 static_assert(std::input_iterator<ConstSentinel>);
206 static_assert(std::same_as<Sentinel, ConstSentinel>);
207 }
208
209 { // Check situation when sentinels returned by `end()` and `end() const` are of the same type
210 using V = BasicView<std::vector<std::string>, ViewProperties{.simple = true, .common = false}, forward_iterator>;
211 using Pattern = BasicView<std::string, ViewProperties{.simple = true}, forward_iterator>;
212 using JWV = std::ranges::join_with_view<V, Pattern>;
213 using Sentinel = std::ranges::sentinel_t<JWV&>;
214 using ConstSentinel = std::ranges::sentinel_t<const JWV&>;
215 static_assert(!std::input_iterator<Sentinel>);
216 static_assert(!std::input_iterator<ConstSentinel>);
217 static_assert(std::same_as<Sentinel, ConstSentinel>);
218 }
219
220 // Check LWG-4074: compatible-joinable-ranges is underconstrained
221 static_assert(!JoinWithViewHasConstEnd<BasicVectorView<int, ViewProperties{}, forward_iterator>,
222 lwg4074::PatternWithProxyConstAccess>);
223
224 return true;
225}
226
227int main(int, char**) {
228 test();
229 static_assert(test());
230
231 return 0;
232}
233

source code of libcxx/test/std/ranges/range.adaptors/range.join.with/range.join.with.view/end.pass.cpp