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
21using It1 = IndirectlyReadable<struct Token1>;
22using It2 = IndirectlyReadable<struct Token2>;
23
24template <class I1, class I2>
25struct 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
49static_assert(std::indirect_equivalence_relation<GoodRelation<It1, It2>, It1, It2>);
50static_assert(std::indirect_equivalence_relation<bool(*)(int, long), int*, long*>);
51[[maybe_unused]] auto lambda = [](int i, long j) { return i == j; };
52static_assert(std::indirect_equivalence_relation<decltype(lambda), int*, long*>);
53
54// Should fail when either of the iterators is not indirectly_readable
55struct NotIndirectlyReadable { };
56static_assert(!std::indirect_equivalence_relation<GoodRelation<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>);
57static_assert(!std::indirect_equivalence_relation<GoodRelation<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>);
58
59// Should fail when the function is not copy constructible
60struct BadRelation1 {
61 BadRelation1(BadRelation1 const&) = delete;
62 template <class T, class U> bool operator()(T const&, U const&) const;
63};
64static_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&)
67struct 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};
71static_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)
74struct 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};
78static_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&)
81struct 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};
85static_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)
88struct 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};
92static_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)
95struct 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};
99static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>);
100
101// Test ADL-proofing (P2538R1)
102#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
103struct Incomplete;
104template<class T> struct Holder { T t; };
105static_assert(std::indirect_equivalence_relation<std::equal_to<Holder<Incomplete>*>, Holder<Incomplete>**, Holder<Incomplete>**>);
106static_assert(!std::indirect_equivalence_relation<Holder<Incomplete>*, Holder<Incomplete>**, Holder<Incomplete>**>);
107#endif
108

source code of libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp