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