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