1 /*! 2 @file 3 Defines `boost::hana::equal`. 4 5 @copyright Louis Dionne 2013-2017 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 BOOST_HANA_NAMESPACE_BEGIN 44 //! @cond 45 template <typename X, typename Y> operator ()(X && x,Y && y) const46 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> applyequal_impl57 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> applyequal_impl84 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> applyequal_impl96 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> applyequal_impl109 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> applyequal_impl122 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> applydetail::compare_finite_sequences140 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> applydetail::compare_finite_sequences149 constexpr auto apply(hana::false_, hana::false_) const 150 { return hana::false_c; } 151 152 template <std::size_t i, typename Result> applydetail::compare_finite_sequences153 constexpr auto apply(hana::true_, Result r) const 154 { return r; } 155 156 template <std::size_t i> applydetail::compare_finite_sequences157 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> applyequal_impl170 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> operator ()detail::compare_struct_members186 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<hana::Struct<S>::value>> { 195 template <typename X, typename Y> applyequal_impl196 static constexpr auto apply(X const& x, Y const& y) { 197 return hana::all_of(hana::accessors<S>(), 198 detail::compare_struct_members<X, Y>{x, y}); 199 } 200 }; 201 BOOST_HANA_NAMESPACE_END 202 203 #endif // !BOOST_HANA_EQUAL_HPP 204