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 decltype(auto) operator*() const;
14
15#include <ranges>
16
17#include <array>
18#include <cassert>
19#include <cstddef>
20#include <string>
21#include <string_view>
22#include <type_traits>
23#include <utility>
24#include <vector>
25
26#include "../types.h"
27
28struct ProxyRef {
29 int& val;
30};
31
32class CommonProxyRef {
33public:
34 constexpr CommonProxyRef(ProxyRef i) : val(i.val) {}
35 constexpr CommonProxyRef(int i) : val(i) {}
36
37 constexpr int get() const { return val; }
38
39private:
40 int val;
41};
42
43template <template <class> class TQual, template <class> class UQual>
44struct std::basic_common_reference<ProxyRef, int, TQual, UQual> {
45 using type = CommonProxyRef;
46};
47
48template <template <class> class TQual, template <class> class UQual>
49struct std::basic_common_reference<int, ProxyRef, TQual, UQual> {
50 using type = CommonProxyRef;
51};
52
53static_assert(std::common_reference_with<int&, ProxyRef>);
54static_assert(std::common_reference_with<int&, CommonProxyRef>);
55
56class ProxyIter {
57public:
58 using value_type = int;
59 using difference_type = std::ptrdiff_t;
60
61 constexpr ProxyIter() : ptr_(nullptr) {}
62 constexpr explicit ProxyIter(int* p) : ptr_(p) {}
63
64 constexpr ProxyRef operator*() const { return ProxyRef{.val: *ptr_}; }
65
66 constexpr ProxyIter& operator++() {
67 ++ptr_;
68 return *this;
69 }
70
71 constexpr ProxyIter operator++(int) {
72 ProxyIter tmp = *this;
73 ++ptr_;
74 return tmp;
75 }
76
77 constexpr bool operator==(const ProxyIter& other) const { return ptr_ == other.ptr_; }
78
79private:
80 int* ptr_;
81};
82
83static_assert(std::forward_iterator<ProxyIter>);
84
85constexpr bool test() {
86 { // Result of `operator*` is (maybe const) lvalue reference
87 using V = std::ranges::owning_view<std::vector<std::string>>;
88 using Pattern = std::ranges::owning_view<std::string>;
89 using JWV = std::ranges::join_with_view<V, Pattern>;
90
91 JWV jwv(V{{"ab", "cd", "ef"}}, Pattern{"><"});
92
93 {
94 auto it = jwv.begin();
95 std::same_as<char&> decltype(auto) v_ref = *std::as_const(it);
96 assert(v_ref == 'a');
97 std::ranges::advance(it, 2);
98 std::same_as<char&> decltype(auto) pattern_ref = *it;
99 assert(pattern_ref == '>');
100 }
101
102 {
103 auto cit = std::as_const(jwv).begin();
104 std::same_as<const char&> decltype(auto) cv_ref = *cit;
105 assert(cv_ref == 'a');
106 std::ranges::advance(cit, 3);
107 std::same_as<const char&> decltype(auto) cpattern_ref = *std::as_const(cit);
108 assert(cpattern_ref == '<');
109 }
110 }
111
112 { // Result of `operator*` is const lvalue reference
113 using V = std::ranges::owning_view<std::vector<std::string_view>>;
114 using Pattern = std::string_view;
115 using JWV = std::ranges::join_with_view<V, Pattern>;
116
117 JWV jwv(V{{"123", "456", "789"}}, Pattern{"._."});
118
119 {
120 auto it = jwv.begin();
121 std::same_as<const char&> decltype(auto) v_ref = *it;
122 assert(v_ref == '1');
123 std::ranges::advance(it, 3);
124 std::same_as<const char&> decltype(auto) pattern_ref = *std::as_const(it);
125 assert(pattern_ref == '.');
126 }
127
128 {
129 auto cit = std::as_const(jwv).begin();
130 std::same_as<const char&> decltype(auto) cv_ref = *std::as_const(cit);
131 assert(cv_ref == '1');
132 std::ranges::advance(cit, 4);
133 std::same_as<const char&> decltype(auto) cpattern_ref = *cit;
134 assert(cpattern_ref == '_');
135 }
136 }
137
138 { // Result of `operator*` is prvalue
139 using V = std::vector<std::string_view>;
140 using Pattern = RvalueVector<char>;
141 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
142
143 JWV jwv(V{"x^2", "y^2", "z^2"}, Pattern{{' ', '+', ' '}});
144
145 {
146 auto it = jwv.begin();
147 std::same_as<char> decltype(auto) v_ref = *std::as_const(it);
148 assert(v_ref == 'x');
149 std::ranges::advance(it, 3);
150 std::same_as<char> decltype(auto) pattern_ref = *it;
151 assert(pattern_ref == ' ');
152 }
153
154 {
155 auto cit = std::as_const(jwv).begin();
156 std::same_as<char> decltype(auto) cv_ref = *cit;
157 assert(cv_ref == 'x');
158 std::ranges::advance(cit, 4);
159 std::same_as<char> decltype(auto) cpattern_ref = *std::as_const(cit);
160 assert(cpattern_ref == '+');
161 }
162 }
163
164 { // Result of `operator*` is (maybe const) rvalue reference
165 using Inner = std::ranges::as_rvalue_view<std::ranges::owning_view<std::string>>;
166 using V = std::ranges::owning_view<std::vector<Inner>>;
167 using Pattern = std::ranges::as_rvalue_view<std::ranges::owning_view<std::array<char, 2>>>;
168 using JWV = std::ranges::join_with_view<V, Pattern>;
169
170 std::vector<Inner> vec;
171 vec.emplace_back(Inner{{"x*y"}});
172 vec.emplace_back(Inner{{"y*z"}});
173 vec.emplace_back(Inner{{"z*x"}});
174 JWV jwv(V(std::move(vec)), Pattern(std::array{',', ' '}));
175
176 {
177 auto it = jwv.begin();
178 std::same_as<char&&> decltype(auto) v_ref = *it;
179 assert(v_ref == 'x');
180 std::ranges::advance(it, 3);
181 std::same_as<char&&> decltype(auto) pattern_ref = *std::as_const(it);
182 assert(pattern_ref == ',');
183 }
184
185 {
186 auto cit = std::as_const(jwv).begin();
187 std::same_as<const char&&> decltype(auto) cv_ref = *std::as_const(cit);
188 assert(cv_ref == 'x');
189 std::ranges::advance(cit, 4);
190 std::same_as<const char&&> decltype(auto) cpattern_ref = *cit;
191 assert(cpattern_ref == ' ');
192 }
193 }
194
195 { // Result of `operator*` is type different from range_reference_t<InnerRng> and range_reference_t<Pattern>
196 using Inner = std::vector<int>;
197 using V = std::vector<Inner>;
198 using Pattern = std::ranges::subrange<ProxyIter, ProxyIter>;
199 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;
200
201 static_assert(!std::same_as<std::ranges::range_reference_t<V>, std::ranges::range_reference_t<JWV>>);
202 static_assert(!std::same_as<std::ranges::range_reference_t<Pattern>, std::ranges::range_reference_t<JWV>>);
203
204 std::array<int, 2> pattern = {-1, -1};
205 Pattern pattern_as_subrange(ProxyIter{pattern.data()}, ProxyIter{pattern.data() + pattern.size()});
206
207 JWV jwv(V{Inner{1, 1}, Inner{2, 2}, Inner{3, 3}}, pattern_as_subrange);
208
209 auto it = jwv.begin();
210 std::same_as<CommonProxyRef> decltype(auto) v_ref = *it;
211 assert(v_ref.get() == 1);
212 std::ranges::advance(it, 7);
213 std::same_as<CommonProxyRef> decltype(auto) pattern_ref = *std::as_const(it);
214 assert(pattern_ref.get() == -1);
215 }
216
217 return true;
218}
219
220int main(int, char**) {
221 test();
222 static_assert(test());
223
224 return 0;
225}
226

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