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