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 F, class I1, class I2 = I1> |
12 | // concept indirect_equivalence_relation; |
13 | |
14 | #include <concepts> |
15 | #include <functional> |
16 | #include <iterator> |
17 | |
18 | #include "indirectly_readable.h" |
19 | #include "test_macros.h" |
20 | |
21 | using It1 = IndirectlyReadable<struct Token1>; |
22 | using It2 = IndirectlyReadable<struct Token2>; |
23 | |
24 | template <class I1, class I2> |
25 | struct GoodRelation { |
26 | bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I1>&) const; |
27 | bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I2>&) const; |
28 | bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const; |
29 | bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I1>&) const; |
30 | |
31 | bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const; |
32 | bool operator()(std::iter_reference_t<I2>, std::iter_value_t<I1>&) const; |
33 | bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I2>) const; |
34 | |
35 | bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const; |
36 | bool operator()(std::iter_value_t<I2>&, std::iter_reference_t<I1>) const; |
37 | bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I1>) const; |
38 | |
39 | bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const; |
40 | bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I1>) const; |
41 | |
42 | bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I1>) const; |
43 | bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I2>) const; |
44 | bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const; |
45 | bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I1>) const; |
46 | }; |
47 | |
48 | // Should work when all constraints are satisfied |
49 | static_assert(std::indirect_equivalence_relation<GoodRelation<It1, It2>, It1, It2>); |
50 | static_assert(std::indirect_equivalence_relation<bool(*)(int, long), int*, long*>); |
51 | [[maybe_unused]] auto lambda = [](int i, long j) { return i == j; }; |
52 | static_assert(std::indirect_equivalence_relation<decltype(lambda), int*, long*>); |
53 | |
54 | // Should fail when either of the iterators is not indirectly_readable |
55 | struct NotIndirectlyReadable { }; |
56 | static_assert(!std::indirect_equivalence_relation<GoodRelation<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>); |
57 | static_assert(!std::indirect_equivalence_relation<GoodRelation<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>); |
58 | |
59 | // Should fail when the function is not copy constructible |
60 | struct BadRelation1 { |
61 | BadRelation1(BadRelation1 const&) = delete; |
62 | template <class T, class U> bool operator()(T const&, U const&) const; |
63 | }; |
64 | static_assert(!std::indirect_equivalence_relation<BadRelation1, It1, It2>); |
65 | |
66 | // Should fail when the function can't be called with (iter_value_t&, iter_value_t&) |
67 | struct BadRelation2 { |
68 | template <class T, class U> bool operator()(T const&, U const&) const; |
69 | bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete; |
70 | }; |
71 | static_assert(!std::indirect_equivalence_relation<BadRelation2, It1, It2>); |
72 | |
73 | // Should fail when the function can't be called with (iter_value_t&, iter_reference_t) |
74 | struct BadRelation3 { |
75 | template <class T, class U> bool operator()(T const&, U const&) const; |
76 | bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete; |
77 | }; |
78 | static_assert(!std::indirect_equivalence_relation<BadRelation3, It1, It2>); |
79 | |
80 | // Should fail when the function can't be called with (iter_reference_t, iter_value_t&) |
81 | struct BadRelation4 { |
82 | template <class T, class U> bool operator()(T const&, U const&) const; |
83 | bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete; |
84 | }; |
85 | static_assert(!std::indirect_equivalence_relation<BadRelation4, It1, It2>); |
86 | |
87 | // Should fail when the function can't be called with (iter_reference_t, iter_reference_t) |
88 | struct BadRelation5 { |
89 | template <class T, class U> bool operator()(T const&, U const&) const; |
90 | bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete; |
91 | }; |
92 | static_assert(!std::indirect_equivalence_relation<BadRelation5, It1, It2>); |
93 | |
94 | // Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) |
95 | struct BadRelation6 { |
96 | template <class T, class U> bool operator()(T const&, U const&) const; |
97 | bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete; |
98 | }; |
99 | static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>); |
100 | |
101 | // Test ADL-proofing (P2538R1) |
102 | #if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION) |
103 | struct Incomplete; |
104 | template<class T> struct Holder { T t; }; |
105 | static_assert(std::indirect_equivalence_relation<std::equal_to<Holder<Incomplete>*>, Holder<Incomplete>**, Holder<Incomplete>**>); |
106 | static_assert(!std::indirect_equivalence_relation<Holder<Incomplete>*, Holder<Incomplete>**, Holder<Incomplete>**>); |
107 | #endif |
108 | |