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// template<class In, class Out>
12// concept indirectly_copyable_storable;
13
14#include <iterator>
15
16#include "MoveOnly.h"
17#include "test_macros.h"
18
19struct CopyOnly {
20 CopyOnly(CopyOnly&&) = delete;
21 CopyOnly(CopyOnly const&) = default;
22 CopyOnly& operator=(CopyOnly&&) = delete;
23 CopyOnly& operator=(CopyOnly const&) = default;
24 CopyOnly() = default;
25};
26
27template<class T>
28struct PointerTo {
29 using value_type = T;
30 T& operator*() const;
31};
32
33// Copying the underlying object between pointers (or dereferenceable classes) works. This is a non-exhaustive check
34// because this functionality comes from `indirectly_copyable`.
35static_assert( std::indirectly_copyable_storable<int*, int*>);
36static_assert( std::indirectly_copyable_storable<const int*, int*>);
37static_assert(!std::indirectly_copyable_storable<int*, const int*>);
38static_assert(!std::indirectly_copyable_storable<const int*, const int*>);
39static_assert( std::indirectly_copyable_storable<int*, int[2]>);
40static_assert(!std::indirectly_copyable_storable<int[2], int*>);
41static_assert(!std::indirectly_copyable_storable<MoveOnly*, MoveOnly*>);
42static_assert(!std::indirectly_copyable_storable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>);
43// `indirectly_copyable_storable` requires the type to be `copyable`, which in turns requires it to be `movable`.
44static_assert(!std::indirectly_copyable_storable<CopyOnly*, CopyOnly*>);
45static_assert(!std::indirectly_copyable_storable<PointerTo<CopyOnly>, PointerTo<CopyOnly>>);
46
47// The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a
48// non-const lvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
49struct NoLvalueAssignment {
50 struct ValueType;
51
52 struct ReferenceType {
53 ReferenceType& operator=(ValueType const&);
54 ReferenceType& operator=(ValueType&) = delete;
55 ReferenceType& operator=(ValueType&&);
56 ReferenceType& operator=(ValueType const&&);
57 };
58
59 struct ValueType {
60 operator ReferenceType&() const;
61 };
62
63 using value_type = ValueType;
64 ReferenceType& operator*() const;
65};
66
67static_assert( std::indirectly_writable<NoLvalueAssignment, std::iter_reference_t<NoLvalueAssignment>>);
68static_assert(!std::indirectly_writable<NoLvalueAssignment, std::iter_value_t<NoLvalueAssignment>&>);
69static_assert( std::indirectly_writable<NoLvalueAssignment, const std::iter_value_t<NoLvalueAssignment>&>);
70static_assert( std::indirectly_writable<NoLvalueAssignment, std::iter_value_t<NoLvalueAssignment>&&>);
71static_assert( std::indirectly_writable<NoLvalueAssignment, const std::iter_value_t<NoLvalueAssignment>&&>);
72static_assert(!std::indirectly_copyable_storable<NoLvalueAssignment, NoLvalueAssignment>);
73
74// The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a
75// const lvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
76struct NoConstLvalueAssignment {
77 struct ValueType;
78
79 struct ReferenceType {
80 ReferenceType& operator=(ValueType const&) = delete;
81 ReferenceType& operator=(ValueType&);
82 ReferenceType& operator=(ValueType&&);
83 ReferenceType& operator=(ValueType const&&);
84 };
85
86 struct ValueType {
87 operator ReferenceType&() const;
88 };
89
90 using value_type = ValueType;
91 ReferenceType& operator*() const;
92};
93
94static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_reference_t<NoConstLvalueAssignment>>);
95static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_value_t<NoConstLvalueAssignment>&>);
96static_assert(!std::indirectly_writable<NoConstLvalueAssignment, const std::iter_value_t<NoConstLvalueAssignment>&>);
97static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_value_t<NoConstLvalueAssignment>&&>);
98static_assert( std::indirectly_writable<NoConstLvalueAssignment, const std::iter_value_t<NoConstLvalueAssignment>&&>);
99static_assert(!std::indirectly_copyable_storable<NoConstLvalueAssignment, NoConstLvalueAssignment>);
100
101// The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a
102// non-const rvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
103struct NoRvalueAssignment {
104 struct ValueType;
105
106 struct ReferenceType {
107 ReferenceType& operator=(ValueType const&);
108 ReferenceType& operator=(ValueType&);
109 ReferenceType& operator=(ValueType&&) = delete;
110 ReferenceType& operator=(ValueType const&&);
111 };
112
113 struct ValueType {
114 operator ReferenceType&() const;
115 };
116
117 using value_type = ValueType;
118 ReferenceType& operator*() const;
119};
120
121static_assert( std::indirectly_writable<NoRvalueAssignment, std::iter_reference_t<NoRvalueAssignment>>);
122static_assert( std::indirectly_writable<NoRvalueAssignment, std::iter_value_t<NoRvalueAssignment>&>);
123static_assert( std::indirectly_writable<NoRvalueAssignment, const std::iter_value_t<NoRvalueAssignment>&>);
124static_assert(!std::indirectly_writable<NoRvalueAssignment, std::iter_value_t<NoRvalueAssignment>&&>);
125static_assert( std::indirectly_writable<NoRvalueAssignment, const std::iter_value_t<NoRvalueAssignment>&&>);
126static_assert(!std::indirectly_copyable_storable<NoRvalueAssignment, NoRvalueAssignment>);
127
128// The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a
129// const rvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
130struct NoConstRvalueAssignment {
131 struct ValueType;
132
133 struct ReferenceType {
134 ReferenceType& operator=(ValueType const&);
135 ReferenceType& operator=(ValueType&);
136 ReferenceType& operator=(ValueType&&);
137 ReferenceType& operator=(ValueType const&&) = delete;
138 };
139
140 struct ValueType {
141 operator ReferenceType&() const;
142 };
143
144 using value_type = ValueType;
145 ReferenceType& operator*() const;
146};
147
148static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_reference_t<NoConstRvalueAssignment>>);
149static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_value_t<NoConstRvalueAssignment>&>);
150static_assert( std::indirectly_writable<NoConstRvalueAssignment, const std::iter_value_t<NoConstRvalueAssignment>&>);
151static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_value_t<NoConstRvalueAssignment>&&>);
152static_assert(!std::indirectly_writable<NoConstRvalueAssignment, const std::iter_value_t<NoConstRvalueAssignment>&&>);
153static_assert(!std::indirectly_copyable_storable<NoConstRvalueAssignment, NoConstRvalueAssignment>);
154
155struct DeletedCopyCtor {
156 DeletedCopyCtor(DeletedCopyCtor const&) = delete;
157 DeletedCopyCtor& operator=(DeletedCopyCtor const&) = default;
158};
159
160struct DeletedNonconstCopyCtor {
161 DeletedNonconstCopyCtor(DeletedNonconstCopyCtor const&) = default;
162 DeletedNonconstCopyCtor(DeletedNonconstCopyCtor&) = delete;
163 DeletedNonconstCopyCtor& operator=(DeletedNonconstCopyCtor const&) = default;
164};
165
166struct DeletedMoveCtor {
167 DeletedMoveCtor(DeletedMoveCtor&&) = delete;
168 DeletedMoveCtor& operator=(DeletedMoveCtor&&) = default;
169};
170
171struct DeletedConstMoveCtor {
172 DeletedConstMoveCtor(DeletedConstMoveCtor&&) = default;
173 DeletedConstMoveCtor(DeletedConstMoveCtor const&&) = delete;
174 DeletedConstMoveCtor& operator=(DeletedConstMoveCtor&&) = default;
175};
176
177struct DeletedCopyAssignment {
178 DeletedCopyAssignment(DeletedCopyAssignment const&) = default;
179 DeletedCopyAssignment& operator=(DeletedCopyAssignment const&) = delete;
180};
181
182struct DeletedNonconstCopyAssignment {
183 DeletedNonconstCopyAssignment(DeletedNonconstCopyAssignment const&) = default;
184 DeletedNonconstCopyAssignment& operator=(DeletedNonconstCopyAssignment const&) = default;
185 DeletedNonconstCopyAssignment& operator=(DeletedNonconstCopyAssignment&) = delete;
186};
187
188struct DeletedMoveAssignment {
189 DeletedMoveAssignment(DeletedMoveAssignment&&) = default;
190 DeletedMoveAssignment& operator=(DeletedMoveAssignment&&) = delete;
191};
192
193struct DeletedConstMoveAssignment {
194 DeletedConstMoveAssignment(DeletedConstMoveAssignment&&) = default;
195 DeletedConstMoveAssignment& operator=(DeletedConstMoveAssignment&&) = delete;
196};
197
198static_assert(!std::indirectly_copyable_storable<DeletedCopyCtor*, DeletedCopyCtor*>);
199static_assert(!std::indirectly_copyable_storable<DeletedNonconstCopyCtor*, DeletedNonconstCopyCtor*>);
200static_assert(!std::indirectly_copyable_storable<DeletedMoveCtor*, DeletedMoveCtor*>);
201static_assert(!std::indirectly_copyable_storable<DeletedConstMoveCtor*, DeletedConstMoveCtor*>);
202static_assert(!std::indirectly_copyable_storable<DeletedCopyAssignment*, DeletedCopyAssignment*>);
203static_assert(!std::indirectly_copyable_storable<DeletedNonconstCopyAssignment*, DeletedNonconstCopyAssignment*>);
204static_assert(!std::indirectly_copyable_storable<DeletedMoveAssignment*, DeletedMoveAssignment*>);
205static_assert(!std::indirectly_copyable_storable<DeletedConstMoveAssignment*, DeletedConstMoveAssignment*>);
206
207struct InconsistentIterator {
208 struct ValueType;
209
210 struct ReferenceType {
211 ReferenceType& operator=(ValueType const&);
212 };
213
214 struct ValueType {
215 ValueType() = default;
216 ValueType(const ReferenceType&);
217 };
218
219 using value_type = ValueType;
220 ReferenceType& operator*() const;
221};
222
223// `ValueType` can be constructed with a `ReferenceType` and assigned to a `ReferenceType`, so it does model
224// `indirectly_copyable_storable`.
225static_assert( std::indirectly_copyable_storable<InconsistentIterator, InconsistentIterator>);
226
227struct CommonType { };
228
229// ReferenceType is a (proxy) reference for ValueType, but ValueType is not constructible from ReferenceType.
230struct NotConstructibleFromRefIn {
231 struct ReferenceType;
232
233 struct ValueType {
234 ValueType(ReferenceType) = delete;
235 operator CommonType&() const;
236 };
237
238 struct ReferenceType {
239 operator CommonType&() const;
240 };
241
242 using value_type = ValueType;
243 ReferenceType& operator*() const;
244};
245
246template <template <class> class X, template <class> class Y>
247struct std::basic_common_reference<NotConstructibleFromRefIn::ValueType,
248 NotConstructibleFromRefIn::ReferenceType, X, Y> {
249 using type = CommonType&;
250};
251
252template <template <class> class X, template <class> class Y>
253struct std::basic_common_reference<NotConstructibleFromRefIn::ReferenceType,
254 NotConstructibleFromRefIn::ValueType, X, Y> {
255 using type = CommonType&;
256};
257
258static_assert(std::common_reference_with<NotConstructibleFromRefIn::ValueType&,
259 NotConstructibleFromRefIn::ReferenceType&>);
260
261struct AssignableFromAnything {
262 template<class T>
263 AssignableFromAnything& operator=(T&&);
264};
265
266// A type that can't be constructed from its own reference isn't `indirectly_copyable_storable`, even when assigning it
267// to a type that can be assigned from anything.
268static_assert(!std::indirectly_copyable_storable<NotConstructibleFromRefIn, AssignableFromAnything*>);
269
270// ReferenceType is a (proxy) reference for ValueType, but ValueType is not assignable from ReferenceType.
271struct NotAssignableFromRefIn {
272 struct ReferenceType;
273
274 struct ValueType {
275 ValueType(ReferenceType);
276 ValueType& operator=(ReferenceType) = delete;
277 operator CommonType&() const;
278 };
279
280 struct ReferenceType {
281 operator CommonType&() const;
282 };
283
284 using value_type = ValueType;
285 ReferenceType& operator*() const;
286};
287
288template <template <class> class X, template <class> class Y>
289struct std::basic_common_reference<NotAssignableFromRefIn::ValueType,
290 NotAssignableFromRefIn::ReferenceType, X, Y> {
291 using type = CommonType&;
292};
293
294template <template <class> class X, template <class> class Y>
295struct std::basic_common_reference<NotAssignableFromRefIn::ReferenceType,
296 NotAssignableFromRefIn::ValueType, X, Y> {
297 using type = CommonType&;
298};
299
300static_assert(std::common_reference_with<NotAssignableFromRefIn::ValueType&, NotAssignableFromRefIn::ReferenceType&>);
301
302// A type that can't be assigned from its own reference isn't `indirectly_copyable_storable`, even when assigning it
303// to a type that can be assigned from anything.
304static_assert(!std::indirectly_copyable_storable<NotAssignableFromRefIn, AssignableFromAnything*>);
305

source code of libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.compile.pass.cpp