1 /*==============================================================================
2     Copyright (c) 2005-2010 Joel de Guzman
3     Copyright (c) 2010 Thomas Heller
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 #ifndef BOOST_PHOENIX_CORE_FUNCTION_EQUAL_HPP
9 #define BOOST_PHOENIX_CORE_FUNCTION_EQUAL_HPP
10 
11 #include <boost/phoenix/core/limits.hpp>
12 #include <boost/is_placeholder.hpp>
13 #include <boost/mpl/int.hpp>
14 #include <boost/phoenix/core/terminal.hpp>
15 #include <boost/proto/matches.hpp>
16 
17 #ifndef BOOST_PHOENIX_NO_VARIADIC_FUNCTION_EQUAL
18 #   include <boost/phoenix/core/detail/index_sequence.hpp>
19 #endif
20 
21 namespace boost
22 {
23     template <typename> class weak_ptr;
24 }
25 
26 namespace boost { namespace phoenix
27 {
28     template <typename>
29     struct actor;
30 
31     namespace detail
32     {
33         struct compare
34             : proto::callable
35         {
36             typedef bool result_type;
37 
38             template <typename A0, typename A1>
operator ()boost::phoenix::detail::compare39             result_type operator()(A0 const & a0, A1 const & a1) const
40             {
41                 return a0 == a1;
42             }
43 
44             // hard wiring reference_wrapper and weak_ptr here ...
45             // **TODO** find out why boost bind does this ...
46             template <typename A0, typename A1>
47             result_type
operator ()boost::phoenix::detail::compare48             operator()(
49                 reference_wrapper<A0> const & a0
50               , reference_wrapper<A1> const & a1
51             ) const
52             {
53                 return a0.get_pointer() == a1.get_pointer();
54             }
55 
56             template <typename A0, typename A1>
57             result_type
operator ()boost::phoenix::detail::compare58             operator()(weak_ptr<A0> const & a0, weak_ptr<A1> const & a1) const
59             {
60                 return !(a0 < a1) && !(a1 < a0);
61             }
62         };
63 
64         struct function_equal_otherwise;
65 
66         struct function_equal_
67             : proto::when<
68                 proto::if_<
69                     proto::matches<proto::_, proto::_state>()
70                   , proto::or_<
71                         proto::when<
72                             proto::terminal<proto::_>
73                           , compare(
74                                 proto::_value
75                               , proto::call<
76                                     proto::_value(proto::_state)
77                                 >
78                             )
79                         >
80                       , proto::otherwise<function_equal_otherwise(proto::_, proto::_state)>
81                     >
82                   , proto::call<function_equal_otherwise()>
83                 >
84             >
85         {};
86 
87         struct function_equal_otherwise
88             : proto::callable
89         {
90             typedef bool result_type;
91 
operator ()boost::phoenix::detail::function_equal_otherwise92             result_type operator()() const
93             {
94                 return false;
95             }
96 
97 #ifdef BOOST_PHOENIX_NO_VARIADIC_FUNCTION_EQUAL
98             template <typename Expr1>
operator ()boost::phoenix::detail::function_equal_otherwise99             result_type operator()(Expr1 const& e1, Expr1 const& e2) const
100             {
101                 return
102                     this->evaluate(
103                         e1
104                       , e2
105                       , mpl::int_<proto::arity_of<Expr1>::value - 1>()
106                     );
107             }
108 
109         private:
110             template <typename Expr1>
111             static BOOST_FORCEINLINE result_type
evaluateboost::phoenix::detail::function_equal_otherwise112             evaluate(Expr1 const& e1, Expr1 const& e2, mpl::int_<0>)
113             {
114                 return
115                     function_equal_()(
116                         proto::child_c<0>(e1)
117                       , proto::child_c<0>(e2)
118                     );
119             }
120 
121             template <typename Expr1, int N>
122             static BOOST_FORCEINLINE result_type
evaluateboost::phoenix::detail::function_equal_otherwise123             evaluate(Expr1 const& e1, Expr1 const& e2, mpl::int_<N>)
124             {
125                 return
126                     evaluate(
127                         e1
128                       , e2
129                       , mpl::int_<N - 1>()
130                     ) && function_equal_()(
131                         proto::child_c<N>(e1)
132                       , proto::child_c<N>(e2)
133                     );
134             }
135 #else
136             template <typename Expr1>
operator ()boost::phoenix::detail::function_equal_otherwise137             result_type operator()(Expr1 const& e1, Expr1 const& e2) const
138             {
139                 return
140                     this->evaluate(
141                         e1
142                       , e2
143                       , typename make_index_sequence<proto::arity_of<Expr1>::value>::type()
144                     );
145             }
146 
147         private:
148             template <typename Expr1, std::size_t... I>
149             static BOOST_FORCEINLINE result_type
evaluateboost::phoenix::detail::function_equal_otherwise150             evaluate(Expr1 const& e1, Expr1 const& e2, index_sequence<I...>)
151             {
152                 bool result = true;
153                 int dummy[] = { (result && (
154                         result = function_equal_()(proto::child_c<I>(e1), proto::child_c<I>(e2))
155                     ))... };
156                 (void)dummy;
157                 return result;
158             }
159 #endif
160         };
161     }
162 
163     template <typename Expr1, typename Expr2>
function_equal_impl(actor<Expr1> const & a1,actor<Expr2> const & a2)164     inline bool function_equal_impl(actor<Expr1> const& a1, actor<Expr2> const& a2)
165     {
166         return detail::function_equal_()(a1, a2);
167     }
168 
169     template <typename Expr1, typename Expr2>
function_equal(actor<Expr1> const & a1,actor<Expr2> const & a2)170     inline bool function_equal(actor<Expr1> const& a1, actor<Expr2> const& a2)
171     {
172         return function_equal_impl(a1, a2);
173     }
174 
175 }}
176 
177 #endif
178 
179