| 1 | /*! |
| 2 | @file |
| 3 | Defines `boost::hana::equal`. |
| 4 | |
| 5 | Copyright Louis Dionne 2013-2022 |
| 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> |
| 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 | namespace boost { namespace hana { |
| 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&) { |
| 58 | // Delay the static_assert by ensuring T_ is dependent. |
| 59 | using T_ = typename hana::tag_of<X>::type; |
| 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> |
| 194 | struct equal_impl<S, S, when< |
| 195 | hana::Struct<S>::value && |
| 196 | !detail::EqualityComparable<S, S>::value |
| 197 | >> { |
| 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 | }} // end namespace boost::hana |
| 205 | |
| 206 | #endif // !BOOST_HANA_EQUAL_HPP |
| 207 | |