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-no-concepts
11 // UNSUPPORTED: gcc-10
12 
13 // template<class I1, class I2>
14 // concept indirectly_swappable;
15 
16 #include <iterator>
17 
18 #include "test_macros.h"
19 
20 template<class T, class ValueType = T>
21 struct PointerTo {
22   using value_type = ValueType;
23   T& operator*() const;
24 };
25 
26 static_assert(std::indirectly_swappable<PointerTo<int>>);
27 static_assert(std::indirectly_swappable<PointerTo<int>, PointerTo<int>>);
28 
29 struct B;
30 
31 struct A {
32   friend void iter_swap(const PointerTo<A>&, const PointerTo<A>&);
33 };
34 
35 // Is indirectly swappable.
36 struct B {
37   friend void iter_swap(const PointerTo<B>&, const PointerTo<B>&);
38   friend void iter_swap(const PointerTo<A>&, const PointerTo<B>&);
39   friend void iter_swap(const PointerTo<B>&, const PointerTo<A>&);
40 };
41 
42 // Valid except ranges::iter_swap(i2, i1).
43 struct C {
44   friend void iter_swap(const PointerTo<C>&, const PointerTo<C>&);
45   friend void iter_swap(const PointerTo<A>&, const PointerTo<C>&);
46   friend void iter_swap(const PointerTo<C>&, const PointerTo<A>&) = delete;
47 };
48 
49 // Valid except ranges::iter_swap(i1, i2).
50 struct D {
51   friend void iter_swap(const PointerTo<D>&, const PointerTo<D>&);
52   friend void iter_swap(const PointerTo<A>&, const PointerTo<D>&) = delete;
53   friend void iter_swap(const PointerTo<D>&, const PointerTo<A>&);
54 };
55 
56 // Valid except ranges::iter_swap(i2, i2).
57 struct E {
58   E operator=(const E&) = delete;
59   friend void iter_swap(const PointerTo<E>&, const PointerTo<E>&) = delete;
60   friend void iter_swap(const PointerTo<A>&, const PointerTo<E>&);
61   friend void iter_swap(const PointerTo<E>&, const PointerTo<A>&);
62 };
63 
64 struct F {
65   friend void iter_swap(const PointerTo<F>&, const PointerTo<F>&) = delete;
66 };
67 
68 // Valid except ranges::iter_swap(i1, i1).
69 struct G {
70   friend void iter_swap(const PointerTo<G>&, const PointerTo<G>&);
71   friend void iter_swap(const PointerTo<F>&, const PointerTo<G>&);
72   friend void iter_swap(const PointerTo<G>&, const PointerTo<F>&);
73 };
74 
75 
76 static_assert( std::indirectly_swappable<PointerTo<A>, PointerTo<B>>);
77 static_assert(!std::indirectly_swappable<PointerTo<A>, PointerTo<C>>);
78 static_assert(!std::indirectly_swappable<PointerTo<A>, PointerTo<D>>);
79 static_assert(!std::indirectly_swappable<PointerTo<A>, PointerTo<E>>);
80 static_assert(!std::indirectly_swappable<PointerTo<A>, PointerTo<G>>);
81