375 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			375 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | // Copyright David Abrahams 2002.
 | ||
|  | // Distributed under the Boost Software License, Version 1.0. (See
 | ||
|  | // accompanying file LICENSE_1_0.txt or copy at
 | ||
|  | // http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | #ifndef OPERATORS_DWA2002530_HPP
 | ||
|  | # define OPERATORS_DWA2002530_HPP
 | ||
|  | 
 | ||
|  | # include <boost/python/detail/prefix.hpp>
 | ||
|  | 
 | ||
|  | # include <boost/python/def_visitor.hpp>
 | ||
|  | # include <boost/python/converter/arg_to_python.hpp>
 | ||
|  | # include <boost/python/detail/operator_id.hpp>
 | ||
|  | # include <boost/python/detail/not_specified.hpp>
 | ||
|  | # include <boost/python/back_reference.hpp>
 | ||
|  | # include <boost/mpl/if.hpp>
 | ||
|  | # include <boost/mpl/eval_if.hpp>
 | ||
|  | # include <boost/python/self.hpp>
 | ||
|  | # include <boost/python/other.hpp>
 | ||
|  | # include <boost/lexical_cast.hpp>
 | ||
|  | # include <boost/python/refcount.hpp>
 | ||
|  | # include <boost/python/detail/unwrap_wrapper.hpp>
 | ||
|  | # include <string>
 | ||
|  | # include <complex>
 | ||
|  | 
 | ||
|  | namespace boost { namespace python {  | ||
|  | 
 | ||
|  | namespace detail | ||
|  | { | ||
|  |   // This is essentially the old v1 to_python(). It will be eliminated
 | ||
|  |   // once the public interface for to_python is settled on.
 | ||
|  |   template <class T> | ||
|  |   PyObject* convert_result(T const& x) | ||
|  |   { | ||
|  |       return converter::arg_to_python<T>(x).release(); | ||
|  |   } | ||
|  | 
 | ||
|  |   // Operator implementation template declarations. The nested apply
 | ||
|  |   // declaration here keeps MSVC6 happy.
 | ||
|  |   template <operator_id> struct operator_l | ||
|  |   { | ||
|  |       template <class L, class R> struct apply; | ||
|  |   }; | ||
|  |    | ||
|  |   template <operator_id> struct operator_r | ||
|  |   { | ||
|  |       template <class L, class R> struct apply; | ||
|  |   }; | ||
|  | 
 | ||
|  |   template <operator_id> struct operator_1 | ||
|  |   { | ||
|  |       template <class T> struct apply; | ||
|  |   }; | ||
|  | 
 | ||
|  |   // MSVC6 doesn't want us to do this sort of inheritance on a nested
 | ||
|  |   // class template, so we use this layer of indirection to avoid
 | ||
|  |   // ::template<...> on the nested apply functions below
 | ||
|  |   template <operator_id id, class L, class R> | ||
|  |   struct operator_l_inner | ||
|  |       : operator_l<id>::template apply<L,R> | ||
|  |   {}; | ||
|  |        | ||
|  |   template <operator_id id, class L, class R> | ||
|  |   struct operator_r_inner | ||
|  |       : operator_r<id>::template apply<L,R> | ||
|  |   {}; | ||
|  | 
 | ||
|  |   template <operator_id id, class T> | ||
|  |   struct operator_1_inner | ||
|  |       : operator_1<id>::template apply<T> | ||
|  |   {}; | ||
|  |        | ||
|  |   // Define three different binary_op templates which take care of
 | ||
|  |   // these cases:
 | ||
|  |   //    self op self
 | ||
|  |   //    self op R
 | ||
|  |   //    L op self
 | ||
|  |   // 
 | ||
|  |   // The inner apply metafunction is used to adjust the operator to
 | ||
|  |   // the class type being defined. Inheritance of the outer class is
 | ||
|  |   // simply used to provide convenient access to the operation's
 | ||
|  |   // name().
 | ||
|  | 
 | ||
|  |   // self op self
 | ||
|  |   template <operator_id id> | ||
|  |   struct binary_op : operator_l<id> | ||
|  |   { | ||
|  |       template <class T> | ||
|  |       struct apply : operator_l_inner<id,T,T> | ||
|  |       { | ||
|  |       }; | ||
|  |   }; | ||
|  | 
 | ||
|  |   // self op R
 | ||
|  |   template <operator_id id, class R> | ||
|  |   struct binary_op_l : operator_l<id> | ||
|  |   { | ||
|  |       template <class T> | ||
|  |       struct apply : operator_l_inner<id,T,R> | ||
|  |       { | ||
|  |       }; | ||
|  |   }; | ||
|  | 
 | ||
|  |   // L op self
 | ||
|  |   template <operator_id id, class L> | ||
|  |   struct binary_op_r : operator_r<id> | ||
|  |   { | ||
|  |       template <class T> | ||
|  |       struct apply : operator_r_inner<id,L,T> | ||
|  |       { | ||
|  |       }; | ||
|  |   }; | ||
|  | 
 | ||
|  |   template <operator_id id> | ||
|  |   struct unary_op : operator_1<id> | ||
|  |   { | ||
|  |       template <class T> | ||
|  |       struct apply : operator_1_inner<id,T> | ||
|  |       { | ||
|  |       }; | ||
|  |   }; | ||
|  | 
 | ||
|  |   // This type is what actually gets returned from operators used on
 | ||
|  |   // self_t
 | ||
|  |   template <operator_id id, class L = not_specified, class R = not_specified> | ||
|  |   struct operator_ | ||
|  |     : def_visitor<operator_<id,L,R> > | ||
|  |   { | ||
|  |    private: | ||
|  |       template <class ClassT> | ||
|  |       void visit(ClassT& cl) const | ||
|  |       { | ||
|  |           typedef typename mpl::eval_if< | ||
|  |               is_same<L,self_t> | ||
|  |             , mpl::if_< | ||
|  |                   is_same<R,self_t> | ||
|  |                 , binary_op<id> | ||
|  |                 , binary_op_l< | ||
|  |                       id | ||
|  |                     , BOOST_DEDUCED_TYPENAME unwrap_other<R>::type | ||
|  |                   > | ||
|  |               > | ||
|  |             , mpl::if_< | ||
|  |                   is_same<L,not_specified> | ||
|  |                 , unary_op<id> | ||
|  |                 , binary_op_r< | ||
|  |                       id | ||
|  |                     , BOOST_DEDUCED_TYPENAME unwrap_other<L>::type | ||
|  |                   > | ||
|  |               > | ||
|  |           >::type generator; | ||
|  |        | ||
|  |           cl.def( | ||
|  |               generator::name() | ||
|  |             , &generator::template apply< | ||
|  |                  BOOST_DEDUCED_TYPENAME ClassT::wrapped_type | ||
|  |               >::execute | ||
|  |           ); | ||
|  |       } | ||
|  |      | ||
|  |       friend class python::def_visitor_access; | ||
|  |   }; | ||
|  | } | ||
|  | 
 | ||
|  | # define BOOST_PYTHON_BINARY_OPERATION(id, rid, expr)       \
 | ||
|  | namespace detail                                            \ | ||
|  | {                                                           \ | ||
|  |   template <>                                               \ | ||
|  |   struct operator_l<op_##id>                                \ | ||
|  |   {                                                         \ | ||
|  |       template <class L, class R>                           \ | ||
|  |       struct apply                                          \ | ||
|  |       {                                                     \ | ||
|  |           typedef typename unwrap_wrapper_<L>::type lhs;    \ | ||
|  |           typedef typename unwrap_wrapper_<R>::type rhs;    \ | ||
|  |           static PyObject* execute(lhs& l, rhs const& r)    \ | ||
|  |           {                                                 \ | ||
|  |               return detail::convert_result(expr);          \ | ||
|  |           }                                                 \ | ||
|  |       };                                                    \ | ||
|  |       static char const* name() { return "__" #id "__"; }   \ | ||
|  |   };                                                        \ | ||
|  |                                                             \ | ||
|  |   template <>                                               \ | ||
|  |   struct operator_r<op_##id>                                \ | ||
|  |   {                                                         \ | ||
|  |       template <class L, class R>                           \ | ||
|  |       struct apply                                          \ | ||
|  |       {                                                     \ | ||
|  |           typedef typename unwrap_wrapper_<L>::type lhs;    \ | ||
|  |           typedef typename unwrap_wrapper_<R>::type rhs;    \ | ||
|  |           static PyObject* execute(rhs& r, lhs const& l)    \ | ||
|  |           {                                                 \ | ||
|  |               return detail::convert_result(expr);          \ | ||
|  |           }                                                 \ | ||
|  |       };                                                    \ | ||
|  |       static char const* name() { return "__" #rid "__"; }  \ | ||
|  |   };                                                        \ | ||
|  | }  | ||
|  | 
 | ||
|  | # define BOOST_PYTHON_BINARY_OPERATOR(id, rid, op)      \
 | ||
|  | BOOST_PYTHON_BINARY_OPERATION(id, rid, l op r)          \ | ||
|  | namespace self_ns                                       \ | ||
|  | {                                                       \ | ||
|  |   template <class L, class R>                           \ | ||
|  |   inline detail::operator_<detail::op_##id,L,R>         \ | ||
|  |   operator op(L const&, R const&)                       \ | ||
|  |   {                                                     \ | ||
|  |       return detail::operator_<detail::op_##id,L,R>();  \ | ||
|  |   }                                                     \ | ||
|  | } | ||
|  |    | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(add, radd, +) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(sub, rsub, -) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(mul, rmul, *) | ||
|  | #if PY_VERSION_HEX >= 0x03000000
 | ||
|  |     BOOST_PYTHON_BINARY_OPERATOR(truediv, rtruediv, /) | ||
|  | #else
 | ||
|  |     BOOST_PYTHON_BINARY_OPERATOR(div, rdiv, /) | ||
|  | #endif
 | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(mod, rmod, %) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(lshift, rlshift, <<) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(rshift, rrshift, >>) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(and, rand, &) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(xor, rxor, ^) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(or, ror, |) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(gt, lt, >) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(ge, le, >=) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(lt, gt, <) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(le, ge, <=) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(eq, eq, ==) | ||
|  | BOOST_PYTHON_BINARY_OPERATOR(ne, ne, !=) | ||
|  | # undef BOOST_PYTHON_BINARY_OPERATOR
 | ||
|  |      | ||
|  | // pow isn't an operator in C++; handle it specially.
 | ||
|  | BOOST_PYTHON_BINARY_OPERATION(pow, rpow, pow(l,r)) | ||
|  | # undef BOOST_PYTHON_BINARY_OPERATION
 | ||
|  |      | ||
|  | namespace self_ns | ||
|  | { | ||
|  | # ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
 | ||
|  |   template <class L, class R> | ||
|  |   inline detail::operator_<detail::op_pow,L,R> | ||
|  |   pow(L const&, R const&) | ||
|  |   { | ||
|  |       return detail::operator_<detail::op_pow,L,R>(); | ||
|  |   } | ||
|  | # else
 | ||
|  |   // When there's no argument-dependent lookup, we need these
 | ||
|  |   // overloads to handle the case when everything is imported into the
 | ||
|  |   // global namespace. Note that the plain overload below does /not/
 | ||
|  |   // take const& arguments. This is needed by MSVC6 at least, or it
 | ||
|  |   // complains of ambiguities, since there's no partial ordering.
 | ||
|  |   inline detail::operator_<detail::op_pow,self_t,self_t> | ||
|  |   pow(self_t, self_t) | ||
|  |   { | ||
|  |       return detail::operator_<detail::op_pow,self_t,self_t>(); | ||
|  |   } | ||
|  |   template <class R> | ||
|  |   inline detail::operator_<detail::op_pow,self_t,R> | ||
|  |   pow(self_t const&, R const&) | ||
|  |   { | ||
|  |       return detail::operator_<detail::op_pow,self_t,R>(); | ||
|  |   } | ||
|  |   template <class L> | ||
|  |   inline detail::operator_<detail::op_pow,L,self_t> | ||
|  |   pow(L const&, self_t const&) | ||
|  |   { | ||
|  |       return detail::operator_<detail::op_pow,L,self_t>(); | ||
|  |   } | ||
|  | # endif 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | # define BOOST_PYTHON_INPLACE_OPERATOR(id, op)                  \
 | ||
|  | namespace detail                                                \ | ||
|  | {                                                               \ | ||
|  |   template <>                                                   \ | ||
|  |   struct operator_l<op_##id>                                    \ | ||
|  |   {                                                             \ | ||
|  |       template <class L, class R>                               \ | ||
|  |       struct apply                                              \ | ||
|  |       {                                                         \ | ||
|  |           typedef typename unwrap_wrapper_<L>::type lhs;        \ | ||
|  |           typedef typename unwrap_wrapper_<R>::type rhs;        \ | ||
|  |           static PyObject*                                      \ | ||
|  |           execute(back_reference<lhs&> l, rhs const& r)         \ | ||
|  |           {                                                     \ | ||
|  |               l.get() op r;                                     \ | ||
|  |               return python::incref(l.source().ptr());          \ | ||
|  |           }                                                     \ | ||
|  |       };                                                        \ | ||
|  |       static char const* name() { return "__" #id "__"; }       \ | ||
|  |   };                                                            \ | ||
|  | }                                                               \ | ||
|  | namespace self_ns                                               \ | ||
|  | {                                                               \ | ||
|  |   template <class R>                                            \ | ||
|  |   inline detail::operator_<detail::op_##id,self_t,R>            \ | ||
|  |   operator op(self_t const&, R const&)                          \ | ||
|  |   {                                                             \ | ||
|  |       return detail::operator_<detail::op_##id,self_t,R>();     \ | ||
|  |   }                                                             \ | ||
|  | } | ||
|  | 
 | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(iadd,+=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(isub,-=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(imul,*=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(idiv,/=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(imod,%=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(ilshift,<<=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(irshift,>>=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(iand,&=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(ixor,^=) | ||
|  | BOOST_PYTHON_INPLACE_OPERATOR(ior,|=) | ||
|  |      | ||
|  | # define BOOST_PYTHON_UNARY_OPERATOR(id, op, func_name)         \
 | ||
|  | namespace detail                                                \ | ||
|  | {                                                               \ | ||
|  |   template <>                                                   \ | ||
|  |   struct operator_1<op_##id>                                    \ | ||
|  |   {                                                             \ | ||
|  |       template <class T>                                        \ | ||
|  |       struct apply                                              \ | ||
|  |       {                                                         \ | ||
|  |           typedef typename unwrap_wrapper_<T>::type self_t;     \ | ||
|  |           static PyObject* execute(self_t& x)                   \ | ||
|  |           {                                                     \ | ||
|  |               return detail::convert_result(op(x));             \ | ||
|  |           }                                                     \ | ||
|  |       };                                                        \ | ||
|  |       static char const* name() { return "__" #id "__"; }       \ | ||
|  |   };                                                            \ | ||
|  | }                                                               \ | ||
|  | namespace self_ns                                               \ | ||
|  | {                                                               \ | ||
|  |   inline detail::operator_<detail::op_##id>                     \ | ||
|  |   func_name(self_t const&)                                      \ | ||
|  |   {                                                             \ | ||
|  |       return detail::operator_<detail::op_##id>();              \ | ||
|  |   }                                                             \ | ||
|  | } | ||
|  | # undef BOOST_PYTHON_INPLACE_OPERATOR
 | ||
|  | 
 | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(neg, -, operator-) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(pos, +, operator+) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(abs, abs, abs) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(invert, ~, operator~) | ||
|  | #if PY_VERSION_HEX >= 0x03000000
 | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(bool, !!, operator!) | ||
|  | #else
 | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(nonzero, !!, operator!) | ||
|  | #endif
 | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(int, long, int_) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(long, PyLong_FromLong, long_) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(float, double, float_) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(complex, std::complex<double>, complex_) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(str, lexical_cast<std::string>, str) | ||
|  | BOOST_PYTHON_UNARY_OPERATOR(repr, lexical_cast<std::string>, repr) | ||
|  | # undef BOOST_PYTHON_UNARY_OPERATOR
 | ||
|  | 
 | ||
|  | }} // namespace boost::python
 | ||
|  | 
 | ||
|  | # ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
 | ||
|  | using boost::python::self_ns::abs; | ||
|  | using boost::python::self_ns::int_; | ||
|  | using boost::python::self_ns::long_; | ||
|  | using boost::python::self_ns::float_; | ||
|  | using boost::python::self_ns::complex_; | ||
|  | using boost::python::self_ns::str; | ||
|  | using boost::python::self_ns::repr; | ||
|  | using boost::python::self_ns::pow; | ||
|  | # endif
 | ||
|  | 
 | ||
|  | #endif // OPERATORS_DWA2002530_HPP
 |