You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
374 lines
14 KiB
374 lines
14 KiB
// 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
|
|
|