• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright David Abrahams 2002.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 #ifndef OPERATORS_DWA2002530_HPP
6 # define OPERATORS_DWA2002530_HPP
7 
8 # include <boost/python/detail/prefix.hpp>
9 
10 # include <boost/python/def_visitor.hpp>
11 # include <boost/python/converter/arg_to_python.hpp>
12 # include <boost/python/detail/operator_id.hpp>
13 # include <boost/python/detail/not_specified.hpp>
14 # include <boost/python/back_reference.hpp>
15 # include <boost/mpl/if.hpp>
16 # include <boost/mpl/eval_if.hpp>
17 # include <boost/python/self.hpp>
18 # include <boost/python/other.hpp>
19 # include <boost/lexical_cast.hpp>
20 # include <boost/python/refcount.hpp>
21 # include <boost/python/detail/unwrap_wrapper.hpp>
22 # include <string>
23 # include <complex>
24 
25 namespace boost { namespace python {
26 
27 namespace detail
28 {
29   // This is essentially the old v1 to_python(). It will be eliminated
30   // once the public interface for to_python is settled on.
31   template <class T>
convert_result(T const & x)32   PyObject* convert_result(T const& x)
33   {
34       return converter::arg_to_python<T>(x).release();
35   }
36 
37   // Operator implementation template declarations. The nested apply
38   // declaration here keeps MSVC6 happy.
39   template <operator_id> struct operator_l
40   {
41       template <class L, class R> struct apply;
42   };
43 
44   template <operator_id> struct operator_r
45   {
46       template <class L, class R> struct apply;
47   };
48 
49   template <operator_id> struct operator_1
50   {
51       template <class T> struct apply;
52   };
53 
54   // MSVC6 doesn't want us to do this sort of inheritance on a nested
55   // class template, so we use this layer of indirection to avoid
56   // ::template<...> on the nested apply functions below
57   template <operator_id id, class L, class R>
58   struct operator_l_inner
59       : operator_l<id>::template apply<L,R>
60   {};
61 
62   template <operator_id id, class L, class R>
63   struct operator_r_inner
64       : operator_r<id>::template apply<L,R>
65   {};
66 
67   template <operator_id id, class T>
68   struct operator_1_inner
69       : operator_1<id>::template apply<T>
70   {};
71 
72   // Define three different binary_op templates which take care of
73   // these cases:
74   //    self op self
75   //    self op R
76   //    L op self
77   //
78   // The inner apply metafunction is used to adjust the operator to
79   // the class type being defined. Inheritance of the outer class is
80   // simply used to provide convenient access to the operation's
81   // name().
82 
83   // self op self
84   template <operator_id id>
85   struct binary_op : operator_l<id>
86   {
87       template <class T>
88       struct apply : operator_l_inner<id,T,T>
89       {
90       };
91   };
92 
93   // self op R
94   template <operator_id id, class R>
95   struct binary_op_l : operator_l<id>
96   {
97       template <class T>
98       struct apply : operator_l_inner<id,T,R>
99       {
100       };
101   };
102 
103   // L op self
104   template <operator_id id, class L>
105   struct binary_op_r : operator_r<id>
106   {
107       template <class T>
108       struct apply : operator_r_inner<id,L,T>
109       {
110       };
111   };
112 
113   template <operator_id id>
114   struct unary_op : operator_1<id>
115   {
116       template <class T>
117       struct apply : operator_1_inner<id,T>
118       {
119       };
120   };
121 
122   // This type is what actually gets returned from operators used on
123   // self_t
124   template <operator_id id, class L = not_specified, class R = not_specified>
125   struct operator_
126     : def_visitor<operator_<id,L,R> >
127   {
128    private:
129       template <class ClassT>
visitboost::python::detail::operator_130       void visit(ClassT& cl) const
131       {
132           typedef typename mpl::eval_if<
133               is_same<L,self_t>
134             , mpl::if_<
135                   is_same<R,self_t>
136                 , binary_op<id>
137                 , binary_op_l<
138                       id
139                     , BOOST_DEDUCED_TYPENAME unwrap_other<R>::type
140                   >
141               >
142             , mpl::if_<
143                   is_same<L,not_specified>
144                 , unary_op<id>
145                 , binary_op_r<
146                       id
147                     , BOOST_DEDUCED_TYPENAME unwrap_other<L>::type
148                   >
149               >
150           >::type generator;
151 
152           cl.def(
153               generator::name()
154             , &generator::template apply<
155                  BOOST_DEDUCED_TYPENAME ClassT::wrapped_type
156               >::execute
157           );
158       }
159 
160       friend class python::def_visitor_access;
161   };
162 }
163 
164 # define BOOST_PYTHON_BINARY_OPERATION(id, rid, expr)       \
165 namespace detail                                            \
166 {                                                           \
167   template <>                                               \
168   struct operator_l<op_##id>                                \
169   {                                                         \
170       template <class L, class R>                           \
171       struct apply                                          \
172       {                                                     \
173           typedef typename unwrap_wrapper_<L>::type lhs;    \
174           typedef typename unwrap_wrapper_<R>::type rhs;    \
175           static PyObject* execute(lhs& l, rhs const& r)    \
176           {                                                 \
177               return detail::convert_result(expr);          \
178           }                                                 \
179       };                                                    \
180       static char const* name() { return "__" #id "__"; }   \
181   };                                                        \
182                                                             \
183   template <>                                               \
184   struct operator_r<op_##id>                                \
185   {                                                         \
186       template <class L, class R>                           \
187       struct apply                                          \
188       {                                                     \
189           typedef typename unwrap_wrapper_<L>::type lhs;    \
190           typedef typename unwrap_wrapper_<R>::type rhs;    \
191           static PyObject* execute(rhs& r, lhs const& l)    \
192           {                                                 \
193               return detail::convert_result(expr);          \
194           }                                                 \
195       };                                                    \
196       static char const* name() { return "__" #rid "__"; }  \
197   };                                                        \
198 }
199 
200 # define BOOST_PYTHON_BINARY_OPERATOR(id, rid, op)      \
201 BOOST_PYTHON_BINARY_OPERATION(id, rid, l op r)          \
202 namespace self_ns                                       \
203 {                                                       \
204   template <class L, class R>                           \
205   inline detail::operator_<detail::op_##id,L,R>         \
206   operator op(L const&, R const&)                       \
207   {                                                     \
208       return detail::operator_<detail::op_##id,L,R>();  \
209   }                                                     \
210 }
211 
212 BOOST_PYTHON_BINARY_OPERATOR(add, radd, +)
213 BOOST_PYTHON_BINARY_OPERATOR(sub, rsub, -)
214 BOOST_PYTHON_BINARY_OPERATOR(mul, rmul, *)
215 #if PY_VERSION_HEX >= 0x03000000
216     BOOST_PYTHON_BINARY_OPERATOR(truediv, rtruediv, /)
217 #else
218     BOOST_PYTHON_BINARY_OPERATOR(div, rdiv, /)
219 #endif
220 BOOST_PYTHON_BINARY_OPERATOR(mod, rmod, %)
221 BOOST_PYTHON_BINARY_OPERATOR(lshift, rlshift, <<)
222 BOOST_PYTHON_BINARY_OPERATOR(rshift, rrshift, >>)
223 BOOST_PYTHON_BINARY_OPERATOR(and, rand, &)
224 BOOST_PYTHON_BINARY_OPERATOR(xor, rxor, ^)
225 BOOST_PYTHON_BINARY_OPERATOR(or, ror, |)
226 BOOST_PYTHON_BINARY_OPERATOR(gt, lt, >)
227 BOOST_PYTHON_BINARY_OPERATOR(ge, le, >=)
228 BOOST_PYTHON_BINARY_OPERATOR(lt, gt, <)
229 BOOST_PYTHON_BINARY_OPERATOR(le, ge, <=)
230 BOOST_PYTHON_BINARY_OPERATOR(eq, eq, ==)
231 BOOST_PYTHON_BINARY_OPERATOR(ne, ne, !=)
232 # undef BOOST_PYTHON_BINARY_OPERATOR
233 
234 // pow isn't an operator in C++; handle it specially.
235 BOOST_PYTHON_BINARY_OPERATION(pow, rpow, pow(l,r))
236 # undef BOOST_PYTHON_BINARY_OPERATION
237 
238 namespace self_ns
239 {
240 # ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
241   template <class L, class R>
242   inline detail::operator_<detail::op_pow,L,R>
pow(L const &,R const &)243   pow(L const&, R const&)
244   {
245       return detail::operator_<detail::op_pow,L,R>();
246   }
247 # else
248   // When there's no argument-dependent lookup, we need these
249   // overloads to handle the case when everything is imported into the
250   // global namespace. Note that the plain overload below does /not/
251   // take const& arguments. This is needed by MSVC6 at least, or it
252   // complains of ambiguities, since there's no partial ordering.
253   inline detail::operator_<detail::op_pow,self_t,self_t>
254   pow(self_t, self_t)
255   {
256       return detail::operator_<detail::op_pow,self_t,self_t>();
257   }
258   template <class R>
259   inline detail::operator_<detail::op_pow,self_t,R>
260   pow(self_t const&, R const&)
261   {
262       return detail::operator_<detail::op_pow,self_t,R>();
263   }
264   template <class L>
265   inline detail::operator_<detail::op_pow,L,self_t>
266   pow(L const&, self_t const&)
267   {
268       return detail::operator_<detail::op_pow,L,self_t>();
269   }
270 # endif
271 }
272 
273 
274 # define BOOST_PYTHON_INPLACE_OPERATOR(id, op)                  \
275 namespace detail                                                \
276 {                                                               \
277   template <>                                                   \
278   struct operator_l<op_##id>                                    \
279   {                                                             \
280       template <class L, class R>                               \
281       struct apply                                              \
282       {                                                         \
283           typedef typename unwrap_wrapper_<L>::type lhs;        \
284           typedef typename unwrap_wrapper_<R>::type rhs;        \
285           static PyObject*                                      \
286           execute(back_reference<lhs&> l, rhs const& r)         \
287           {                                                     \
288               l.get() op r;                                     \
289               return python::incref(l.source().ptr());          \
290           }                                                     \
291       };                                                        \
292       static char const* name() { return "__" #id "__"; }       \
293   };                                                            \
294 }                                                               \
295 namespace self_ns                                               \
296 {                                                               \
297   template <class R>                                            \
298   inline detail::operator_<detail::op_##id,self_t,R>            \
299   operator op(self_t const&, R const&)                          \
300   {                                                             \
301       return detail::operator_<detail::op_##id,self_t,R>();     \
302   }                                                             \
303 }
304 
305 BOOST_PYTHON_INPLACE_OPERATOR(iadd,+=)
306 BOOST_PYTHON_INPLACE_OPERATOR(isub,-=)
307 BOOST_PYTHON_INPLACE_OPERATOR(imul,*=)
308 BOOST_PYTHON_INPLACE_OPERATOR(idiv,/=)
309 BOOST_PYTHON_INPLACE_OPERATOR(imod,%=)
310 BOOST_PYTHON_INPLACE_OPERATOR(ilshift,<<=)
311 BOOST_PYTHON_INPLACE_OPERATOR(irshift,>>=)
312 BOOST_PYTHON_INPLACE_OPERATOR(iand,&=)
313 BOOST_PYTHON_INPLACE_OPERATOR(ixor,^=)
314 BOOST_PYTHON_INPLACE_OPERATOR(ior,|=)
315 
316 # define BOOST_PYTHON_UNARY_OPERATOR(id, op, func_name)         \
317 namespace detail                                                \
318 {                                                               \
319   template <>                                                   \
320   struct operator_1<op_##id>                                    \
321   {                                                             \
322       template <class T>                                        \
323       struct apply                                              \
324       {                                                         \
325           typedef typename unwrap_wrapper_<T>::type self_t;     \
326           static PyObject* execute(self_t& x)                   \
327           {                                                     \
328               return detail::convert_result(op(x));             \
329           }                                                     \
330       };                                                        \
331       static char const* name() { return "__" #id "__"; }       \
332   };                                                            \
333 }                                                               \
334 namespace self_ns                                               \
335 {                                                               \
336   inline detail::operator_<detail::op_##id>                     \
337   func_name(self_t const&)                                      \
338   {                                                             \
339       return detail::operator_<detail::op_##id>();              \
340   }                                                             \
341 }
342 # undef BOOST_PYTHON_INPLACE_OPERATOR
343 
344 BOOST_PYTHON_UNARY_OPERATOR(neg, -, operator-)
345 BOOST_PYTHON_UNARY_OPERATOR(pos, +, operator+)
346 BOOST_PYTHON_UNARY_OPERATOR(abs, abs, abs)
347 BOOST_PYTHON_UNARY_OPERATOR(invert, ~, operator~)
348 #if PY_VERSION_HEX >= 0x03000000
349 BOOST_PYTHON_UNARY_OPERATOR(bool, !!, operator!)
350 #else
351 BOOST_PYTHON_UNARY_OPERATOR(nonzero, !!, operator!)
352 #endif
353 BOOST_PYTHON_UNARY_OPERATOR(int, long, int_)
354 BOOST_PYTHON_UNARY_OPERATOR(long, PyLong_FromLong, long_)
355 BOOST_PYTHON_UNARY_OPERATOR(float, double, float_)
356 BOOST_PYTHON_UNARY_OPERATOR(complex, std::complex<double>, complex_)
357 BOOST_PYTHON_UNARY_OPERATOR(str, lexical_cast<std::string>, str)
358 BOOST_PYTHON_UNARY_OPERATOR(repr, lexical_cast<std::string>, repr)
359 # undef BOOST_PYTHON_UNARY_OPERATOR
360 
361 }} // namespace boost::python
362 
363 # ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
364 using boost::python::self_ns::abs;
365 using boost::python::self_ns::int_;
366 using boost::python::self_ns::long_;
367 using boost::python::self_ns::float_;
368 using boost::python::self_ns::complex_;
369 using boost::python::self_ns::str;
370 using boost::python::self_ns::repr;
371 using boost::python::self_ns::pow;
372 # endif
373 
374 #endif // OPERATORS_DWA2002530_HPP
375