]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Defines `boost::hana::equal`. | |
4 | ||
b32b8144 | 5 | @copyright Louis Dionne 2013-2017 |
7c673cae FG |
6 | Distributed under the Boost Software License, Version 1.0. |
7 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) | |
8 | */ | |
9 | ||
10 | #ifndef BOOST_HANA_EQUAL_HPP | |
11 | #define BOOST_HANA_EQUAL_HPP | |
12 | ||
13 | #include <boost/hana/fwd/equal.hpp> | |
14 | ||
15 | #include <boost/hana/accessors.hpp> | |
16 | #include <boost/hana/all_of.hpp> | |
17 | #include <boost/hana/and.hpp> | |
18 | #include <boost/hana/at.hpp> | |
19 | #include <boost/hana/bool.hpp> | |
20 | #include <boost/hana/concept/comparable.hpp> | |
21 | #include <boost/hana/concept/constant.hpp> | |
22 | #include <boost/hana/concept/product.hpp> | |
23 | #include <boost/hana/concept/sequence.hpp> | |
24 | #include <boost/hana/concept/struct.hpp> | |
25 | #include <boost/hana/config.hpp> | |
26 | #include <boost/hana/core/common.hpp> | |
27 | #include <boost/hana/core/to.hpp> | |
28 | #include <boost/hana/core/dispatch.hpp> | |
29 | #include <boost/hana/core/tag_of.hpp> | |
30 | #include <boost/hana/core/when.hpp> | |
31 | #include <boost/hana/detail/concepts.hpp> | |
7c673cae FG |
32 | #include <boost/hana/detail/has_common_embedding.hpp> |
33 | #include <boost/hana/detail/nested_to.hpp> // required by fwd decl | |
34 | #include <boost/hana/first.hpp> | |
35 | #include <boost/hana/if.hpp> | |
36 | #include <boost/hana/length.hpp> | |
37 | #include <boost/hana/second.hpp> | |
38 | #include <boost/hana/value.hpp> | |
39 | ||
40 | #include <cstddef> | |
41 | ||
42 | ||
43 | BOOST_HANA_NAMESPACE_BEGIN | |
44 | //! @cond | |
45 | template <typename X, typename Y> | |
46 | constexpr auto equal_t::operator()(X&& x, Y&& y) const { | |
47 | using T = typename hana::tag_of<X>::type; | |
48 | using U = typename hana::tag_of<Y>::type; | |
49 | using Equal = equal_impl<T, U>; | |
50 | return Equal::apply(static_cast<X&&>(x), static_cast<Y&&>(y)); | |
51 | } | |
52 | //! @endcond | |
53 | ||
54 | template <typename T, typename U, bool condition> | |
55 | struct equal_impl<T, U, when<condition>> : default_ { | |
56 | template <typename X, typename Y> | |
57 | static constexpr auto apply(X const&, Y const&) { | |
b32b8144 FG |
58 | // Delay the static_assert by ensuring T_ is dependent. |
59 | using T_ = typename hana::tag_of<X>::type; | |
7c673cae FG |
60 | static_assert(!hana::is_convertible<T_, U>::value && |
61 | !hana::is_convertible<U, T_>::value, | |
62 | "No default implementation of hana::equal is provided for related " | |
63 | "types that can't be safely embedded into a common type, because " | |
64 | "those are most likely programming errors. If this is really what " | |
65 | "you want, you can manually convert both objects to a common " | |
66 | "Comparable type before performing the comparison. If you think " | |
67 | "you have made your types Comparable but you see this, perhaps you " | |
68 | "forgot to define some of the necessary methods for an automatic " | |
69 | "model of Comparable to kick in. A possible culprit is defining " | |
70 | "'operator==' but not 'operator!='."); | |
71 | ||
72 | return hana::false_c; | |
73 | } | |
74 | }; | |
75 | ||
76 | // Cross-type overload | |
77 | template <typename T, typename U> | |
78 | struct equal_impl<T, U, when< | |
79 | detail::has_nontrivial_common_embedding<Comparable, T, U>::value && | |
80 | !detail::EqualityComparable<T, U>::value | |
81 | >> { | |
82 | using C = typename hana::common<T, U>::type; | |
83 | template <typename X, typename Y> | |
84 | static constexpr auto apply(X&& x, Y&& y) { | |
85 | return hana::equal(hana::to<C>(static_cast<X&&>(x)), | |
86 | hana::to<C>(static_cast<Y&&>(y))); | |
87 | } | |
88 | }; | |
89 | ||
90 | ////////////////////////////////////////////////////////////////////////// | |
91 | // Model for EqualityComparable data types | |
92 | ////////////////////////////////////////////////////////////////////////// | |
93 | template <typename T, typename U> | |
94 | struct equal_impl<T, U, when<detail::EqualityComparable<T, U>::value>> { | |
95 | template <typename X, typename Y> | |
96 | static constexpr auto apply(X&& x, Y&& y) | |
97 | { return static_cast<X&&>(x) == static_cast<Y&&>(y); } | |
98 | }; | |
99 | ||
100 | ////////////////////////////////////////////////////////////////////////// | |
101 | // Model for Constants wrapping a Comparable | |
102 | ////////////////////////////////////////////////////////////////////////// | |
103 | template <typename C> | |
104 | struct equal_impl<C, C, when< | |
105 | hana::Constant<C>::value && | |
106 | Comparable<typename C::value_type>::value | |
107 | >> { | |
108 | template <typename X, typename Y> | |
109 | static constexpr auto apply(X const&, Y const&) { | |
110 | constexpr auto eq = hana::equal(hana::value<X>(), hana::value<Y>()); | |
111 | constexpr bool truth_value = hana::if_(eq, true, false); | |
112 | return hana::bool_<truth_value>{}; | |
113 | } | |
114 | }; | |
115 | ||
116 | ////////////////////////////////////////////////////////////////////////// | |
117 | // Comparable for Products | |
118 | ////////////////////////////////////////////////////////////////////////// | |
119 | template <typename T, typename U> | |
120 | struct equal_impl<T, U, when<hana::Product<T>::value && hana::Product<U>::value>> { | |
121 | template <typename X, typename Y> | |
122 | static constexpr auto apply(X const& x, Y const& y) { | |
123 | return hana::and_( | |
124 | hana::equal(hana::first(x), hana::first(y)), | |
125 | hana::equal(hana::second(x), hana::second(y)) | |
126 | ); | |
127 | } | |
128 | }; | |
129 | ||
130 | ////////////////////////////////////////////////////////////////////////// | |
131 | // Comparable for Sequences | |
132 | ////////////////////////////////////////////////////////////////////////// | |
133 | namespace detail { | |
134 | template <typename Xs, typename Ys, std::size_t Length> | |
135 | struct compare_finite_sequences { | |
136 | Xs const& xs; | |
137 | Ys const& ys; | |
138 | ||
139 | template <std::size_t i> | |
140 | constexpr auto apply(hana::false_, hana::true_) const { | |
141 | return compare_finite_sequences::apply<i+1>( | |
142 | hana::bool_<i+1 == Length>{}, | |
143 | hana::if_(hana::equal(hana::at_c<i>(xs), hana::at_c<i>(ys)), | |
144 | hana::true_c, hana::false_c) | |
145 | ); | |
146 | } | |
147 | ||
148 | template <std::size_t i> | |
149 | constexpr auto apply(hana::false_, hana::false_) const | |
150 | { return hana::false_c; } | |
151 | ||
152 | template <std::size_t i, typename Result> | |
153 | constexpr auto apply(hana::true_, Result r) const | |
154 | { return r; } | |
155 | ||
156 | template <std::size_t i> | |
157 | constexpr bool apply(hana::false_, bool b) const { | |
158 | return b && compare_finite_sequences::apply<i+1>( | |
159 | hana::bool_<i+1 == Length>{}, | |
160 | hana::if_(hana::equal(hana::at_c<i>(xs), hana::at_c<i>(ys)), | |
161 | hana::true_c, hana::false_c) | |
162 | ); | |
163 | } | |
164 | }; | |
165 | } | |
166 | ||
167 | template <typename T, typename U> | |
168 | struct equal_impl<T, U, when<Sequence<T>::value && hana::Sequence<U>::value>> { | |
169 | template <typename Xs, typename Ys> | |
170 | static constexpr auto apply(Xs const& xs, Ys const& ys) { | |
171 | constexpr std::size_t xs_size = decltype(hana::length(xs))::value; | |
172 | constexpr std::size_t ys_size = decltype(hana::length(ys))::value; | |
173 | detail::compare_finite_sequences<Xs, Ys, xs_size> comp{xs, ys}; | |
174 | return comp.template apply<0>(hana::bool_<xs_size == 0>{}, | |
175 | hana::bool_<xs_size == ys_size>{}); | |
176 | } | |
177 | }; | |
178 | ||
179 | namespace detail { | |
180 | template <typename X, typename Y> | |
181 | struct compare_struct_members { | |
182 | X const& x; | |
183 | Y const& y; | |
184 | ||
185 | template <typename Member> | |
186 | constexpr auto operator()(Member&& member) const { | |
187 | auto accessor = hana::second(static_cast<Member&&>(member)); | |
188 | return hana::equal(accessor(x), accessor(y)); | |
189 | } | |
190 | }; | |
191 | } | |
192 | ||
193 | template <typename S> | |
20effc67 TL |
194 | struct equal_impl<S, S, when< |
195 | hana::Struct<S>::value && | |
196 | !detail::EqualityComparable<S, S>::value | |
197 | >> { | |
7c673cae FG |
198 | template <typename X, typename Y> |
199 | static constexpr auto apply(X const& x, Y const& y) { | |
200 | return hana::all_of(hana::accessors<S>(), | |
201 | detail::compare_struct_members<X, Y>{x, y}); | |
202 | } | |
203 | }; | |
204 | BOOST_HANA_NAMESPACE_END | |
205 | ||
206 | #endif // !BOOST_HANA_EQUAL_HPP |