• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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