1 // Copyright (c) 2004 Daniel Wallin and Arvid Norberg
2 
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
9 
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
12 
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 #ifndef OPERATOR_040729_HPP
24 #define OPERATOR_040729_HPP
25 
26 #include <luabind/detail/other.hpp>
27 #include <luabind/raw_policy.hpp>
28 
29 #include <boost/mpl/apply_wrap.hpp>
30 #include <boost/mpl/eval_if.hpp>
31 #include <boost/mpl/identity.hpp>
32 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
33 #include <boost/preprocessor/repetition/enum_params.hpp>
34 #include <boost/preprocessor/repetition/enum_trailing.hpp>
35 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
36 #include <boost/type_traits/is_same.hpp>
37 
38 #if defined(__GNUC__) && __GNUC__ < 3
39 # define LUABIND_NO_STRINGSTREAM
40 #else
41 # if defined(BOOST_NO_STRINGSTREAM)
42 #  define LUABIND_NO_STRINGSTREAM
43 # endif
44 #endif
45 
46 #ifdef LUABIND_NO_STRINGSTREAM
47 #include <strstream>
48 #else
49 #include <sstream>
50 #endif
51 
52 namespace luabind { namespace detail {
53 
54     template<class W, class T> struct unwrap_parameter_type;
55     template<class Derived> struct operator_ {};
56 
57     struct operator_void_return {};
58 
59     template<class T>
operator ,(T const & x,operator_void_return)60     inline T const& operator,(T const& x, operator_void_return)
61     {
62         return x;
63     }
64 
65 }} // namespace luabind
66 
67 #include <boost/preprocessor/iteration/iterate.hpp>
68 
69 namespace luabind { namespace operators {
70 
71    #define BOOST_PP_ITERATION_PARAMS_1 (3, \
72        (0, LUABIND_MAX_ARITY, <luabind/detail/call_operator_iterate.hpp>))
73    #include BOOST_PP_ITERATE()
74 
75 }} // namespace luabind::operators
76 
77 #include <boost/preprocessor/iteration/local.hpp>
78 
79 namespace luabind {
80 
81     template<class Derived>
82     struct self_base
83     {
operator ()luabind::self_base84         operators::call_operator0<Derived> operator()() const
85         {
86             return 0;
87         }
88 
89 #define BOOST_PP_LOCAL_MACRO(n) \
90         template<BOOST_PP_ENUM_PARAMS(n, class A)> \
91         BOOST_PP_CAT(operators::call_operator, n)< \
92             Derived \
93             BOOST_PP_ENUM_TRAILING_PARAMS(n, A) \
94         >\
95         operator()( \
96             BOOST_PP_ENUM_BINARY_PARAMS(n, A, const& BOOST_PP_INTERCEPT) \
97         ) const \
98         { \
99             return 0; \
100         }
101 
102 #define BOOST_PP_LOCAL_LIMITS (1, LUABIND_MAX_ARITY)
103 #include BOOST_PP_LOCAL_ITERATE()
104 
105     };
106 
107     struct self_type : self_base<self_type>
108     {
109     };
110 
111     struct const_self_type : self_base<const_self_type>
112     {
113     };
114 
115 namespace detail {
116 
117     template<class W, class T>
118     struct unwrap_parameter_type
119     {
120         typedef typename boost::mpl::eval_if<
121             boost::is_same<T, self_type>
122           , boost::mpl::identity<W&>
123           , boost::mpl::eval_if<
124                 boost::is_same<T, const_self_type>
125               , boost::mpl::identity<W const&>
126               , unwrap_other<T>
127             >
128         >::type type;
129     };
130 
131     template<class Derived, class A, class B>
132     struct binary_operator
133         : operator_<binary_operator<Derived, A, B> >
134     {
binary_operatorluabind::detail::binary_operator135         binary_operator(int) {}
136 
137         template<class T, class Policies>
138         struct apply
139         {
140             typedef typename unwrap_parameter_type<T, A>::type arg0;
141             typedef typename unwrap_parameter_type<T, B>::type arg1;
142 
executeluabind::detail::binary_operator::apply143             static void execute(lua_State* L, arg0 _0, arg1 _1)
144             {
145                 Derived::template apply<arg0, arg1, Policies>::execute(
146                     L, _0, _1);
147             }
148         };
149 
nameluabind::detail::binary_operator150         static char const* name()
151         {
152             return Derived::name();
153         }
154     };
155 
156     template<class Derived, class A>
157     struct unary_operator
158         : operator_<unary_operator<Derived, A> >
159     {
unary_operatorluabind::detail::unary_operator160         unary_operator(int) {}
161 
162         template<class T, class Policies>
163         struct apply
164         {
165             typedef typename unwrap_parameter_type<T, A>::type arg0;
166 
executeluabind::detail::unary_operator::apply167             static void execute(lua_State* L, arg0 _0)
168             {
169                 Derived::template apply<arg0, Policies>::execute(L, _0);
170             }
171         };
172 
nameluabind::detail::unary_operator173         static char const* name()
174         {
175             return Derived::name();
176         }
177     };
178 
179     template<class Policies>
operator_result(lua_State *,operator_void_return,Policies *)180     inline void operator_result(lua_State*, operator_void_return, Policies*)
181     {
182     }
183 
184     namespace mpl = boost::mpl;
185 
186     template<class T, class Policies>
operator_result(lua_State * L,T const & x,Policies *)187     inline void operator_result(lua_State* L, T const& x, Policies*)
188     {
189         typedef typename find_conversion_policy<
190             0
191           , Policies
192         >::type cv_policy;
193 
194         typename mpl::apply_wrap2<cv_policy,T,cpp_to_lua>::type cv;
195 
196         cv.apply(L, x);
197     }
198 
199 }} // namespace detail::luabind
200 
201 namespace luabind {
202 
203 #define LUABIND_BINARY_OPERATOR(name_, op) \
204     namespace operators { \
205 \
206         struct name_ \
207         { \
208             template<class T0, class T1, class Policies> \
209             struct apply \
210             { \
211                 static void execute(lua_State* L, T0 _0, T1 _1) \
212                 { \
213                     detail::operator_result(L, _0 op _1, static_cast<Policies*>(0)); \
214                 } \
215             }; \
216 \
217             static char const* name() \
218             { \
219                 return "__" # name_; \
220             } \
221         }; \
222 \
223     } \
224     \
225     template<class T, class U> \
226     detail::binary_operator< \
227         operators::name_ \
228       , U \
229       , T \
230     > \
231     inline operator op(self_base<U>, T const&) \
232     { \
233         return 0; \
234     } \
235     \
236     template<class T, class U> \
237     detail::binary_operator< \
238         operators::name_ \
239       , T \
240       , U \
241     > \
242     inline operator op(T const&, self_base<U>) \
243     { \
244         return 0; \
245     } \
246     \
247     detail::binary_operator< \
248         operators::name_ \
249       , self_type \
250       , self_type \
251     > \
252     inline operator op(self_type, self_type) \
253     { \
254         return 0; \
255     } \
256     \
257     detail::binary_operator< \
258         operators::name_ \
259       , self_type \
260       , const_self_type \
261     > \
262     inline operator op(self_type, const_self_type) \
263     { \
264         return 0; \
265     } \
266     \
267     detail::binary_operator< \
268         operators::name_ \
269       , const_self_type \
270       , self_type \
271     > \
272     inline operator op(const_self_type, self_type) \
273     { \
274         return 0; \
275     } \
276     \
277     detail::binary_operator< \
278         operators::name_ \
279       , const_self_type \
280       , const_self_type \
281     > \
282     inline operator op(const_self_type, const_self_type) \
283     { \
284         return 0; \
285     }
286 
287     LUABIND_BINARY_OPERATOR(add, +)
288     LUABIND_BINARY_OPERATOR(sub, -)
289     LUABIND_BINARY_OPERATOR(mul, *)
290     LUABIND_BINARY_OPERATOR(div, /)
291     LUABIND_BINARY_OPERATOR(mod, %)
292     LUABIND_BINARY_OPERATOR(pow, ^)
293     LUABIND_BINARY_OPERATOR(lt, <)
294     LUABIND_BINARY_OPERATOR(le, <=)
295     LUABIND_BINARY_OPERATOR(eq, ==)
296 
297 #undef LUABIND_BINARY_OPERATOR
298 
299 #define LUABIND_UNARY_OPERATOR(name_, op, fn) \
300     namespace operators { \
301 \
302         struct name_ \
303         { \
304             template<class T, class Policies> \
305             struct apply \
306             { \
307                 static void execute(lua_State* L, T x) \
308                 { \
309                     detail::operator_result(L, op(x), static_cast<Policies*>(0)); \
310                 } \
311             }; \
312 \
313             static char const* name() \
314             { \
315                 return "__" # name_; \
316             } \
317         }; \
318 \
319     } \
320     \
321     template<class T> \
322     detail::unary_operator< \
323         operators::name_ \
324       , T \
325     > \
326     inline fn(self_base<T>) \
327     { \
328         return 0; \
329     }
330 
331     template<class T>
tostring_operator(T const & x)332     std::string tostring_operator(T const& x)
333     {
334 #ifdef LUABIND_NO_STRINGSTREAM
335         std::strstream s;
336         s << x << std::ends;
337 #else
338         std::stringstream s;
339         s << x;
340 #endif
341         return s.str();
342     }
343 
344     LUABIND_UNARY_OPERATOR(tostring, tostring_operator, tostring)
345     LUABIND_UNARY_OPERATOR(unm, -, operator-)
346 
347 #undef LUABIND_UNARY_OPERATOR
348 
349     // defined in operator.cpp
350     LUABIND_API extern self_type self;
351     LUABIND_API extern const_self_type const_self;
352 } // namespace luabind
353 
354 #endif // OPERATOR_040729_HPP
355