mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 17:12:22 +00:00
implemented export of operators
[SVN r8203]
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# define CLASS_WRAPPER_DWA101000_H_
|
||||
|
||||
#include "extclass.h"
|
||||
#include "operators.h"
|
||||
#include "module.h"
|
||||
#include "py.h"
|
||||
#include "cast.h"
|
||||
@@ -26,6 +27,21 @@ class ClassWrapper
|
||||
void def(const Signature& signature)
|
||||
{ m_class->def(signature); }
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
|
||||
// py::left_operand<int const &>());
|
||||
template <int which, class left, class right>
|
||||
void def(operators<which, right> o1, left_operand<left> o2)
|
||||
{ m_class->def(o1, o2); }
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
|
||||
// py::right_operand<int const &>());
|
||||
template <int which, class left, class right>
|
||||
void def(operators<which, left> o1, right_operand<right> o2)
|
||||
{ m_class->def(o1, o2); }
|
||||
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
|
||||
261
extclass.cpp
261
extclass.cpp
@@ -11,6 +11,17 @@
|
||||
|
||||
namespace py {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
Tuple extension_class_coerce(PyObject * l, PyObject * r)
|
||||
{
|
||||
return py::Tuple(Ptr(new detail::operator_dispatcher(l, l)),
|
||||
Ptr(new detail::operator_dispatcher(r, 0)));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
ExtensionInstance* get_extension_instance(PyObject* p)
|
||||
{
|
||||
// The object's type will just be some Class<ExtensionInstance> object,
|
||||
@@ -325,4 +336,254 @@ void ExtensionClassBase::set_attribute(const char* name, Ptr x)
|
||||
detail::enable_named_method(this, name);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
PyTypeObject operator_dispatcher::type_object =
|
||||
{
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"operator_dispatcher",
|
||||
sizeof(operator_dispatcher),
|
||||
0,
|
||||
(destructor)&operator_dispatcher::dealloc,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&operator_dispatcher::call_cmp,
|
||||
0,
|
||||
&operator_dispatcher::number_methods,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
PyNumberMethods operator_dispatcher::number_methods =
|
||||
{
|
||||
&operator_dispatcher::call_add,
|
||||
&operator_dispatcher::call_sub,
|
||||
&operator_dispatcher::call_mul,
|
||||
&operator_dispatcher::call_div,
|
||||
&operator_dispatcher::call_mod,
|
||||
&operator_dispatcher::call_divmod,
|
||||
&operator_dispatcher::call_pow,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&operator_dispatcher::call_lshift,
|
||||
&operator_dispatcher::call_rshift,
|
||||
&operator_dispatcher::call_and,
|
||||
&operator_dispatcher::call_xor,
|
||||
&operator_dispatcher::call_or,
|
||||
&operator_dispatcher::coerce,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
operator_dispatcher::operator_dispatcher(PyObject * o, PyObject * s)
|
||||
: object(o), self(s)
|
||||
{
|
||||
ob_refcnt = 1;
|
||||
ob_type = &type_object;
|
||||
}
|
||||
|
||||
void operator_dispatcher::dealloc(PyObject *self)
|
||||
{
|
||||
delete static_cast<operator_dispatcher *>(self);
|
||||
}
|
||||
|
||||
int operator_dispatcher::coerce(PyObject ** l, PyObject ** r)
|
||||
{
|
||||
Py_INCREF(*l);
|
||||
*r = new operator_dispatcher(*r, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define py_define_operator(id, symbol) \
|
||||
PyObject * operator_dispatcher::call_##id(PyObject * left, PyObject * right) \
|
||||
{ \
|
||||
/* unwrap the arguments from their OperatorDispatcher */ \
|
||||
PyObject * self, * other; \
|
||||
bool reverse = unwrap_args(left, right, self, other); \
|
||||
\
|
||||
/* call the function */ \
|
||||
PyObject * result = \
|
||||
PyEval_CallMethod(self, \
|
||||
const_cast<char*>(reverse ? "__r" #id "__" : "__" #id "__"), \
|
||||
const_cast<char*>("(O)"), \
|
||||
other); \
|
||||
if(result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \
|
||||
{ \
|
||||
PyErr_Clear(); \
|
||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \
|
||||
} \
|
||||
return result; \
|
||||
}
|
||||
|
||||
py_define_operator(add, +)
|
||||
py_define_operator(sub, -)
|
||||
py_define_operator(mul, *)
|
||||
py_define_operator(div, /)
|
||||
py_define_operator(mod, %)
|
||||
py_define_operator(divmod, divmod)
|
||||
py_define_operator(lshift, <<)
|
||||
py_define_operator(rshift, >>)
|
||||
py_define_operator(and, &)
|
||||
py_define_operator(xor, ^)
|
||||
py_define_operator(or, |)
|
||||
|
||||
/* coercion rules for heterogeneous pow():
|
||||
pow(Foo, int): left, right coerced; m: None => reverse = 0
|
||||
pow(int, Foo): left, right coerced; m: None => reverse = 1
|
||||
pow(Foo, int, int): left, right, m coerced => reverse = 0
|
||||
pow(int, Foo, int): left, right, m coerced => reverse = 1
|
||||
pow(int, int, Foo): left, right, m coerced => reverse = 2
|
||||
pow(Foo, Foo, int): left, right coerced; m coerced twice => reverse = 0
|
||||
pow(Foo, int, Foo): left, right, m coerced => reverse = 0
|
||||
pow(int, Foo, Foo): left, right, m coerced => reverse = 1
|
||||
*/
|
||||
PyObject * operator_dispatcher::call_pow(PyObject * left, PyObject * right, PyObject * m)
|
||||
{
|
||||
int reverse;
|
||||
PyObject * self, * first, * second;
|
||||
if(m->ob_type == Py_None->ob_type)
|
||||
{
|
||||
reverse = unwrap_args(left, right, self, first);
|
||||
second = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
reverse = unwrap_pow_args(left, right, m, self, first, second);
|
||||
}
|
||||
|
||||
/* call the function */
|
||||
PyObject * result =
|
||||
PyEval_CallMethod(self,
|
||||
const_cast<char*>((reverse == 0) ?
|
||||
"__pow__" :
|
||||
(reverse == 1) ?
|
||||
"__rpow__" :
|
||||
"__rrpow__"),
|
||||
const_cast<char*>("(OO)"),
|
||||
first, second);
|
||||
if(result == 0 &&
|
||||
(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) ||
|
||||
PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)))
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int operator_dispatcher::call_cmp(PyObject * left, PyObject * right)
|
||||
{
|
||||
/* unwrap the arguments from their OperatorDispatcher */
|
||||
PyObject * self, * other;
|
||||
bool reverse = unwrap_args(left, right, self, other);
|
||||
|
||||
/* call the function */
|
||||
PyObject * result =
|
||||
PyEval_CallMethod(self,
|
||||
const_cast<char*>(reverse ? "__rcmp__" : "__cmp__"),
|
||||
const_cast<char*>("(O)"),
|
||||
other);
|
||||
if(result == 0)
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp()");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PY_CONVERSION::from_python(result, Type<int>());
|
||||
}
|
||||
}
|
||||
|
||||
bool operator_dispatcher::unwrap_args(PyObject * left, PyObject * right,
|
||||
PyObject * & self, PyObject * & other)
|
||||
{
|
||||
if(left->ob_type != &operator_dispatcher::type_object ||
|
||||
right->ob_type != &operator_dispatcher::type_object)
|
||||
{
|
||||
std::cerr << "operator_dispatcher::unwrap_args(): internal error (" __FILE__ ", " <<
|
||||
__LINE__ << ")" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
PyPtr<operator_dispatcher> lwrapper(static_cast<operator_dispatcher *>(left));
|
||||
PyPtr<operator_dispatcher> rwrapper(static_cast<operator_dispatcher *>(right));
|
||||
if(lwrapper->self != 0)
|
||||
{
|
||||
self = lwrapper->self;
|
||||
other = rwrapper->object;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
self = rwrapper->self;
|
||||
other = lwrapper->object;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int operator_dispatcher::unwrap_pow_args(PyObject * left, PyObject * right, PyObject * m,
|
||||
PyObject * & self, PyObject * & first, PyObject * & second)
|
||||
{
|
||||
if(left->ob_type != &operator_dispatcher::type_object ||
|
||||
right->ob_type != &operator_dispatcher::type_object ||
|
||||
m->ob_type != &operator_dispatcher::type_object)
|
||||
{
|
||||
std::cerr << "operator_dispatcher::unwrap_pow_args(): internal error (" __FILE__ ", " <<
|
||||
__LINE__ << ")" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
PyPtr<operator_dispatcher> lwrapper(static_cast<operator_dispatcher *>(left));
|
||||
PyPtr<operator_dispatcher> rwrapper(static_cast<operator_dispatcher *>(right));
|
||||
PyPtr<operator_dispatcher> mwrapper(static_cast<operator_dispatcher *>(m));
|
||||
|
||||
if(mwrapper->object->ob_type == &operator_dispatcher::type_object)
|
||||
{
|
||||
mwrapper = static_cast<operator_dispatcher *>(mwrapper->object);
|
||||
}
|
||||
|
||||
if(lwrapper->self != 0)
|
||||
{
|
||||
self = lwrapper->self;
|
||||
first = rwrapper->object;
|
||||
second = mwrapper->object;
|
||||
return 0;
|
||||
}
|
||||
else if(rwrapper->self != 0)
|
||||
{
|
||||
self = rwrapper->self;
|
||||
first = lwrapper->object;
|
||||
second = mwrapper->object;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
self = mwrapper->self;
|
||||
first = lwrapper->object;
|
||||
second = rwrapper->object;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace py
|
||||
|
||||
415
extclass.h
415
extclass.h
@@ -118,6 +118,41 @@ class ClassRegistry
|
||||
static std::vector<py::detail::DerivedClassInfo> static_derived_class_info;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct operator_dispatcher
|
||||
: public PyObject
|
||||
{
|
||||
static PyTypeObject type_object;
|
||||
static PyNumberMethods number_methods;
|
||||
|
||||
operator_dispatcher(PyObject * o, PyObject * s);
|
||||
static void dealloc(PyObject *self);
|
||||
static int coerce(PyObject ** l, PyObject ** r);
|
||||
static PyObject * call_add(PyObject *, PyObject *);
|
||||
static PyObject * call_sub(PyObject *, PyObject *);
|
||||
static PyObject * call_mul(PyObject *, PyObject *);
|
||||
static PyObject * call_div(PyObject *, PyObject *);
|
||||
static PyObject * call_mod(PyObject *, PyObject *);
|
||||
static PyObject * call_divmod(PyObject *, PyObject *);
|
||||
static PyObject * call_lshift(PyObject *, PyObject *);
|
||||
static PyObject * call_rshift(PyObject *, PyObject *);
|
||||
static PyObject * call_and(PyObject *, PyObject *);
|
||||
static PyObject * call_xor(PyObject *, PyObject *);
|
||||
static PyObject * call_or(PyObject *, PyObject *);
|
||||
static PyObject * call_pow(PyObject *, PyObject *, PyObject *);
|
||||
static int call_cmp(PyObject *, PyObject *);
|
||||
|
||||
static bool unwrap_args(PyObject * left, PyObject * right,
|
||||
PyObject * & self, PyObject * & other);
|
||||
static int unwrap_pow_args(PyObject *, PyObject *, PyObject *,
|
||||
PyObject * &, PyObject * &, PyObject * &);
|
||||
|
||||
PyObject * object;
|
||||
PyObject * self;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PY_BEGIN_CONVERSION_NAMESPACE
|
||||
@@ -284,6 +319,9 @@ PyObject* to_python(const T& x)
|
||||
return py_extension_class_converters(py::Type<T>()).to_python(x);
|
||||
}
|
||||
|
||||
inline PyObject * to_python(py::detail::operator_dispatcher * n) { return n; }
|
||||
|
||||
|
||||
PY_END_CONVERSION_NAMESPACE
|
||||
|
||||
namespace py {
|
||||
@@ -302,22 +340,66 @@ class ReadOnlySetattrFunction : public Function
|
||||
String m_name;
|
||||
};
|
||||
|
||||
enum operator_id
|
||||
{
|
||||
op_add = 0x1,
|
||||
op_sub = 0x2,
|
||||
op_mul = 0x4,
|
||||
op_div = 0x8,
|
||||
op_mod = 0x10,
|
||||
op_divmod =0x20,
|
||||
op_pow = 0x40,
|
||||
op_lshift = 0x80,
|
||||
op_rshift = 0x100,
|
||||
op_and = 0x200,
|
||||
op_xor = 0x400,
|
||||
op_or = 0x800,
|
||||
op_neg = 0x1000,
|
||||
op_pos = 0x2000,
|
||||
op_abs = 0x4000,
|
||||
op_invert = 0x8000,
|
||||
op_int = 0x10000,
|
||||
op_long = 0x20000,
|
||||
op_float = 0x40000,
|
||||
op_str = 0x80000,
|
||||
op_cmp = 0x100000
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class From, class To>
|
||||
struct DefineConversion
|
||||
{
|
||||
static void * upcast_ptr(void * v)
|
||||
{
|
||||
return static_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
struct auto_operand {};
|
||||
|
||||
static void * downcast_ptr(void * v)
|
||||
{
|
||||
return dynamic_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
};
|
||||
template <int i>
|
||||
struct define_operator;
|
||||
|
||||
}
|
||||
|
||||
template <int which, class operand = py::detail::auto_operand>
|
||||
struct operators {};
|
||||
|
||||
template <class T>
|
||||
struct left_operand {};
|
||||
|
||||
template <class T>
|
||||
struct right_operand {};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class From, class To>
|
||||
struct DefineConversion
|
||||
{
|
||||
static void * upcast_ptr(void * v)
|
||||
{
|
||||
return static_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
|
||||
static void * downcast_ptr(void * v)
|
||||
{
|
||||
return dynamic_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -366,6 +448,299 @@ class ExtensionClass
|
||||
Signature0()))))));
|
||||
}
|
||||
|
||||
|
||||
// export homogeneous operators (type of both lhs and rhs is 'operator')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>());
|
||||
template <int which, class operand>
|
||||
void def(operators<which, operand>)
|
||||
{
|
||||
register_coerce();
|
||||
|
||||
if(which & py::op_add)
|
||||
add_method(new typename detail::define_operator<(which & py::op_add)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_add)>::name());
|
||||
|
||||
if(which & py::op_sub)
|
||||
add_method(new typename detail::define_operator<(which & py::op_sub)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_sub)>::name());
|
||||
|
||||
if(which & py::op_mul)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mul)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_mul)>::name());
|
||||
|
||||
if(which & py::op_div)
|
||||
add_method(new typename detail::define_operator<(which & py::op_div)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_div)>::name());
|
||||
|
||||
if(which & py::op_mod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mod)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_mod)>::name());
|
||||
|
||||
if(which & py::op_divmod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_divmod)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_divmod)>::name());
|
||||
|
||||
if(which & py::op_pow)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pow)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_pow)>::name());
|
||||
|
||||
if(which & py::op_lshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_lshift)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_lshift)>::name());
|
||||
|
||||
if(which & py::op_rshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_rshift)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_rshift)>::name());
|
||||
|
||||
if(which & py::op_and)
|
||||
add_method(new typename detail::define_operator<(which & py::op_and)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_and)>::name());
|
||||
|
||||
if(which & py::op_xor)
|
||||
add_method(new typename detail::define_operator<(which & py::op_xor)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_xor)>::name());
|
||||
|
||||
if(which & py::op_or)
|
||||
add_method(new typename detail::define_operator<(which & py::op_or)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_or)>::name());
|
||||
|
||||
if(which & py::op_neg)
|
||||
add_method(new typename detail::define_operator<(which & py::op_neg)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_neg)>::name());
|
||||
|
||||
if(which & py::op_pos)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pos)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_pos)>::name());
|
||||
|
||||
if(which & py::op_abs)
|
||||
add_method(new typename detail::define_operator<(which & py::op_abs)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_abs)>::name());
|
||||
|
||||
if(which & py::op_invert)
|
||||
add_method(new typename detail::define_operator<(which & py::op_invert)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_invert)>::name());
|
||||
|
||||
if(which & py::op_int)
|
||||
add_method(new typename detail::define_operator<(which & py::op_int)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_int)>::name());
|
||||
|
||||
if(which & py::op_long)
|
||||
add_method(new typename detail::define_operator<(which & py::op_long)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_long)>::name());
|
||||
|
||||
if(which & py::op_float)
|
||||
add_method(new typename detail::define_operator<(which & py::op_float)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_float)>::name());
|
||||
|
||||
if(which & py::op_cmp)
|
||||
add_method(new typename detail::define_operator<(which & py::op_cmp)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_cmp)>::name());
|
||||
|
||||
if(which & py::op_str)
|
||||
add_method(new typename detail::define_operator<(which & py::op_str)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_str)>::name());
|
||||
|
||||
}
|
||||
|
||||
// export homogeneous operators (type of both lhs and rhs is 'T const &')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>());
|
||||
template <int which>
|
||||
void def(operators<which, py::detail::auto_operand>)
|
||||
{
|
||||
def(operators<which, T const &>());
|
||||
}
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
|
||||
// py::right_operand<int const &>());
|
||||
template <int which, class left, class right>
|
||||
void def(operators<which, left>, right_operand<right>)
|
||||
{
|
||||
register_coerce();
|
||||
|
||||
if(which & py::op_add)
|
||||
add_method(new typename detail::define_operator<(which & py::op_add)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_add)>::name());
|
||||
|
||||
if(which & py::op_sub)
|
||||
add_method(new typename detail::define_operator<(which & py::op_sub)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_sub)>::name());
|
||||
|
||||
if(which & py::op_mul)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mul)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_mul)>::name());
|
||||
|
||||
if(which & py::op_div)
|
||||
add_method(new typename detail::define_operator<(which & py::op_div)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_div)>::name());
|
||||
|
||||
if(which & py::op_mod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mod)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_mod)>::name());
|
||||
|
||||
if(which & py::op_divmod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_divmod)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_divmod)>::name());
|
||||
|
||||
if(which & py::op_pow)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pow)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_pow)>::name());
|
||||
|
||||
if(which & py::op_lshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_lshift)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_lshift)>::name());
|
||||
|
||||
if(which & py::op_rshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_rshift)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_rshift)>::name());
|
||||
|
||||
if(which & py::op_and)
|
||||
add_method(new typename detail::define_operator<(which & py::op_and)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_and)>::name());
|
||||
|
||||
if(which & py::op_xor)
|
||||
add_method(new typename detail::define_operator<(which & py::op_xor)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_xor)>::name());
|
||||
|
||||
if(which & py::op_or)
|
||||
add_method(new typename detail::define_operator<(which & py::op_or)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_or)>::name());
|
||||
|
||||
if(which & py::op_cmp)
|
||||
add_method(new typename detail::define_operator<(which & py::op_cmp)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_cmp)>::name());
|
||||
|
||||
}
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'T const &', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
|
||||
// py::right_operand<int const &>());
|
||||
template <int which, class right>
|
||||
void def(operators<which, py::detail::auto_operand>, right_operand<right> r)
|
||||
{
|
||||
def(operators<which, T const &>(), r);
|
||||
}
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
|
||||
// py::left_operand<int const &>());
|
||||
template <int which, class left, class right>
|
||||
void def(operators<which, right>, left_operand<left>)
|
||||
{
|
||||
register_coerce();
|
||||
|
||||
if(which & py::op_add)
|
||||
add_method(new typename detail::define_operator<(which & py::op_add)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_add)>::rname());
|
||||
|
||||
if(which & py::op_sub)
|
||||
add_method(new typename detail::define_operator<(which & py::op_sub)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_sub)>::rname());
|
||||
|
||||
if(which & py::op_mul)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mul)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_mul)>::rname());
|
||||
|
||||
if(which & py::op_div)
|
||||
add_method(new typename detail::define_operator<(which & py::op_div)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_div)>::rname());
|
||||
|
||||
if(which & py::op_mod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mod)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_mod)>::rname());
|
||||
|
||||
if(which & py::op_divmod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_divmod)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_divmod)>::rname());
|
||||
|
||||
if(which & py::op_pow)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pow)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_pow)>::rname());
|
||||
|
||||
if(which & py::op_lshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_lshift)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_lshift)>::rname());
|
||||
|
||||
if(which & py::op_rshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_rshift)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_rshift)>::rname());
|
||||
|
||||
if(which & py::op_and)
|
||||
add_method(new typename detail::define_operator<(which & py::op_and)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_and)>::rname());
|
||||
|
||||
if(which & py::op_xor)
|
||||
add_method(new typename detail::define_operator<(which & py::op_xor)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_xor)>::rname());
|
||||
|
||||
if(which & py::op_or)
|
||||
add_method(new typename detail::define_operator<(which & py::op_or)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_or)>::rname());
|
||||
|
||||
if(which & py::op_cmp)
|
||||
add_method(new typename detail::define_operator<(which & py::op_cmp)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_cmp)>::rname());
|
||||
|
||||
}
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'T const &')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
|
||||
// py::left_operand<int const &>());
|
||||
template <int which, class left>
|
||||
void def(operators<which, py::detail::auto_operand>, left_operand<left> l)
|
||||
{
|
||||
def(operators<which, T const &>(), l);
|
||||
}
|
||||
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
@@ -476,6 +851,8 @@ class ExtensionClass
|
||||
{
|
||||
this->add_constructor_object(InitFunction<Holder>::create(sig));
|
||||
}
|
||||
|
||||
void register_coerce();
|
||||
};
|
||||
|
||||
// A simple wrapper over a T which allows us to use ExtensionClass<T> with a
|
||||
@@ -593,6 +970,11 @@ class ExtensionInstance : public Instance
|
||||
// Template function implementations
|
||||
//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
Tuple extension_class_coerce(PyObject * l, PyObject * r);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
ExtensionClass<T, U>::ExtensionClass()
|
||||
: ExtensionClassBase(typeid(T).name())
|
||||
@@ -607,6 +989,15 @@ ExtensionClass<T, U>::ExtensionClass(const char* name)
|
||||
ClassRegistry<T>::register_class(this);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
void ExtensionClass<T, U>::register_coerce()
|
||||
{
|
||||
Ptr coerce_fct = dict().get_item(String("__coerce__"));
|
||||
|
||||
if(coerce_fct.get() == 0) // not yet defined
|
||||
this->def(&py::detail::extension_class_coerce, "__coerce__");
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline
|
||||
std::vector<detail::BaseClassInfo> const &
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "extclass_demo.h"
|
||||
#include "class_wrapper.h"
|
||||
#include <stdio.h> // used for portability on broken compilers
|
||||
#include <math.h> // for pow()
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
namespace extclass_demo {
|
||||
@@ -633,6 +634,49 @@ struct Fubar {
|
||||
Fubar(int) {}
|
||||
};
|
||||
|
||||
/************************************************************/
|
||||
/* */
|
||||
/* Int */
|
||||
/* this class tests operator export */
|
||||
/* */
|
||||
/************************************************************/
|
||||
|
||||
struct Int
|
||||
{
|
||||
explicit Int(int i) : i_(i) { }
|
||||
|
||||
int i() const { return i_; }
|
||||
|
||||
int i_;
|
||||
};
|
||||
|
||||
Int operator+(Int const & l, Int const & r) { return Int(l.i_ + r.i_); }
|
||||
Int operator+(Int const & l, int const & r) { return Int(l.i_ + r); }
|
||||
Int operator+(int const & l, Int const & r) { return Int(l + r.i_); }
|
||||
|
||||
Int operator-(Int const & l, Int const & r) { return Int(l.i_ - r.i_); }
|
||||
Int operator-(Int const & l, int const & r) { return Int(l.i_ - r); }
|
||||
Int operator-(int const & l, Int const & r) { return Int(l - r.i_); }
|
||||
Int operator-(Int const & r) { return Int(- r.i_); }
|
||||
|
||||
Int mul(Int const & l, Int const & r) { return Int(l.i_ * r.i_); }
|
||||
Int imul(Int const & l, int const & r) { return Int(l.i_ * r); }
|
||||
Int rmul(Int const & r, int const & l) { return Int(l * r.i_); }
|
||||
|
||||
Int operator/(Int const & l, Int const & r) { return Int(l.i_ / r.i_); }
|
||||
|
||||
Int operator%(Int const & l, Int const & r) { return Int(l.i_ % r.i_); }
|
||||
|
||||
bool operator<(Int const & l, Int const & r) { return l.i_ < r.i_; }
|
||||
bool operator<(Int const & l, int const & r) { return l.i_ < r; }
|
||||
bool operator<(int const & l, Int const & r) { return l < r.i_; }
|
||||
|
||||
Int pow(Int const & l, Int const & r) { return Int(::pow(l.i_, r.i_)); }
|
||||
Int powmod(Int const & l, Int const & r, Int const & m) { return Int((int)::pow(l.i_, r.i_) % m.i_); }
|
||||
Int pow(Int const & l, int const & r) { return Int(::pow(l.i_, r)); }
|
||||
|
||||
std::ostream & operator<<(std::ostream & o, Int const & r) { return (o << r.i_); }
|
||||
|
||||
/************************************************************/
|
||||
/* */
|
||||
/* double tests from Mark Evans(<mark.evans@clarisay.com>) */
|
||||
@@ -704,6 +748,8 @@ struct EnumOwner
|
||||
|
||||
namespace py {
|
||||
template class enum_as_int_converters<extclass_demo::EnumOwner::enum_type>;
|
||||
|
||||
using extclass_demo::pow;
|
||||
}
|
||||
|
||||
// This is just a way of getting the converters instantiated
|
||||
@@ -883,6 +929,30 @@ void init_module(py::Module& m)
|
||||
m.def_raw(&raw, "raw");
|
||||
m.def_raw(&raw1, "raw1");
|
||||
m.def_raw(&raw2, "raw2");
|
||||
|
||||
py::ClassWrapper<Int> int_class(m, "Int");
|
||||
int_class.def(py::Constructor<int>());
|
||||
int_class.def(&Int::i, "i");
|
||||
|
||||
// wrap homogeneous operators
|
||||
int_class.def(py::operators<(py::op_add | py::op_sub | py::op_neg |
|
||||
py::op_cmp | py::op_str | py::op_divmod | py::op_pow )>());
|
||||
// export non-operator functions as homogeneous operators
|
||||
int_class.def(&mul, "__mul__");
|
||||
int_class.def(&powmod, "__pow__");
|
||||
|
||||
// wrap heterogeneous operators (lhs: Int const &, rhs: int const &)
|
||||
int_class.def(py::operators<(py::op_add | py::op_sub | py::op_cmp | py::op_pow)>(),
|
||||
py::right_operand<int const & >());
|
||||
// export non-operator function as heterogeneous operator
|
||||
int_class.def(&imul, "__mul__");
|
||||
|
||||
// wrap heterogeneous operators (lhs: int const &, rhs: Int const &)
|
||||
int_class.def(py::operators<(py::op_add | py::op_sub | py::op_cmp)>(),
|
||||
py::left_operand<int const & >());
|
||||
// export non-operator function as heterogeneous reverse-argument operator
|
||||
int_class.def(&rmul, "__rmul__");
|
||||
|
||||
|
||||
py::ClassWrapper<EnumOwner> enum_owner(m, "EnumOwner");
|
||||
enum_owner.def(py::Constructor<EnumOwner::enum_type, const EnumOwner::enum_type&>());
|
||||
|
||||
415
gen_extclass.py
415
gen_extclass.py
@@ -123,6 +123,41 @@ class ClassRegistry
|
||||
static std::vector<py::detail::DerivedClassInfo> static_derived_class_info;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct operator_dispatcher
|
||||
: public PyObject
|
||||
{
|
||||
static PyTypeObject type_object;
|
||||
static PyNumberMethods number_methods;
|
||||
|
||||
operator_dispatcher(PyObject * o, PyObject * s);
|
||||
static void dealloc(PyObject *self);
|
||||
static int coerce(PyObject ** l, PyObject ** r);
|
||||
static PyObject * call_add(PyObject *, PyObject *);
|
||||
static PyObject * call_sub(PyObject *, PyObject *);
|
||||
static PyObject * call_mul(PyObject *, PyObject *);
|
||||
static PyObject * call_div(PyObject *, PyObject *);
|
||||
static PyObject * call_mod(PyObject *, PyObject *);
|
||||
static PyObject * call_divmod(PyObject *, PyObject *);
|
||||
static PyObject * call_lshift(PyObject *, PyObject *);
|
||||
static PyObject * call_rshift(PyObject *, PyObject *);
|
||||
static PyObject * call_and(PyObject *, PyObject *);
|
||||
static PyObject * call_xor(PyObject *, PyObject *);
|
||||
static PyObject * call_or(PyObject *, PyObject *);
|
||||
static PyObject * call_pow(PyObject *, PyObject *, PyObject *);
|
||||
static int call_cmp(PyObject *, PyObject *);
|
||||
|
||||
static bool unwrap_args(PyObject * left, PyObject * right,
|
||||
PyObject * & self, PyObject * & other);
|
||||
static int unwrap_pow_args(PyObject *, PyObject *, PyObject *,
|
||||
PyObject * &, PyObject * &, PyObject * &);
|
||||
|
||||
PyObject * object;
|
||||
PyObject * self;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PY_BEGIN_CONVERSION_NAMESPACE
|
||||
@@ -289,6 +324,9 @@ PyObject* to_python(const T& x)
|
||||
return py_extension_class_converters(py::Type<T>()).to_python(x);
|
||||
}
|
||||
|
||||
inline PyObject * to_python(py::detail::operator_dispatcher * n) { return n; }
|
||||
|
||||
|
||||
PY_END_CONVERSION_NAMESPACE
|
||||
|
||||
namespace py {
|
||||
@@ -307,22 +345,66 @@ class ReadOnlySetattrFunction : public Function
|
||||
String m_name;
|
||||
};
|
||||
|
||||
enum operator_id
|
||||
{
|
||||
op_add = 0x1,
|
||||
op_sub = 0x2,
|
||||
op_mul = 0x4,
|
||||
op_div = 0x8,
|
||||
op_mod = 0x10,
|
||||
op_divmod =0x20,
|
||||
op_pow = 0x40,
|
||||
op_lshift = 0x80,
|
||||
op_rshift = 0x100,
|
||||
op_and = 0x200,
|
||||
op_xor = 0x400,
|
||||
op_or = 0x800,
|
||||
op_neg = 0x1000,
|
||||
op_pos = 0x2000,
|
||||
op_abs = 0x4000,
|
||||
op_invert = 0x8000,
|
||||
op_int = 0x10000,
|
||||
op_long = 0x20000,
|
||||
op_float = 0x40000,
|
||||
op_str = 0x80000,
|
||||
op_cmp = 0x100000
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class From, class To>
|
||||
struct DefineConversion
|
||||
{
|
||||
static void * upcast_ptr(void * v)
|
||||
{
|
||||
return static_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
struct auto_operand {};
|
||||
|
||||
static void * downcast_ptr(void * v)
|
||||
{
|
||||
return dynamic_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
};
|
||||
template <int i>
|
||||
struct define_operator;
|
||||
|
||||
}
|
||||
|
||||
template <int which, class operand = py::detail::auto_operand>
|
||||
struct operators {};
|
||||
|
||||
template <class T>
|
||||
struct left_operand {};
|
||||
|
||||
template <class T>
|
||||
struct right_operand {};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class From, class To>
|
||||
struct DefineConversion
|
||||
{
|
||||
static void * upcast_ptr(void * v)
|
||||
{
|
||||
return static_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
|
||||
static void * downcast_ptr(void * v)
|
||||
{
|
||||
return dynamic_cast<To *>(static_cast<From *>(v));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -371,6 +453,299 @@ class ExtensionClass
|
||||
""", args)
|
||||
+
|
||||
"""
|
||||
|
||||
// export homogeneous operators (type of both lhs and rhs is 'operator')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>());
|
||||
template <int which, class operand>
|
||||
void def(operators<which, operand>)
|
||||
{
|
||||
register_coerce();
|
||||
|
||||
if(which & py::op_add)
|
||||
add_method(new typename detail::define_operator<(which & py::op_add)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_add)>::name());
|
||||
|
||||
if(which & py::op_sub)
|
||||
add_method(new typename detail::define_operator<(which & py::op_sub)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_sub)>::name());
|
||||
|
||||
if(which & py::op_mul)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mul)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_mul)>::name());
|
||||
|
||||
if(which & py::op_div)
|
||||
add_method(new typename detail::define_operator<(which & py::op_div)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_div)>::name());
|
||||
|
||||
if(which & py::op_mod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mod)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_mod)>::name());
|
||||
|
||||
if(which & py::op_divmod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_divmod)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_divmod)>::name());
|
||||
|
||||
if(which & py::op_pow)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pow)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_pow)>::name());
|
||||
|
||||
if(which & py::op_lshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_lshift)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_lshift)>::name());
|
||||
|
||||
if(which & py::op_rshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_rshift)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_rshift)>::name());
|
||||
|
||||
if(which & py::op_and)
|
||||
add_method(new typename detail::define_operator<(which & py::op_and)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_and)>::name());
|
||||
|
||||
if(which & py::op_xor)
|
||||
add_method(new typename detail::define_operator<(which & py::op_xor)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_xor)>::name());
|
||||
|
||||
if(which & py::op_or)
|
||||
add_method(new typename detail::define_operator<(which & py::op_or)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_or)>::name());
|
||||
|
||||
if(which & py::op_neg)
|
||||
add_method(new typename detail::define_operator<(which & py::op_neg)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_neg)>::name());
|
||||
|
||||
if(which & py::op_pos)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pos)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_pos)>::name());
|
||||
|
||||
if(which & py::op_abs)
|
||||
add_method(new typename detail::define_operator<(which & py::op_abs)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_abs)>::name());
|
||||
|
||||
if(which & py::op_invert)
|
||||
add_method(new typename detail::define_operator<(which & py::op_invert)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_invert)>::name());
|
||||
|
||||
if(which & py::op_int)
|
||||
add_method(new typename detail::define_operator<(which & py::op_int)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_int)>::name());
|
||||
|
||||
if(which & py::op_long)
|
||||
add_method(new typename detail::define_operator<(which & py::op_long)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_long)>::name());
|
||||
|
||||
if(which & py::op_float)
|
||||
add_method(new typename detail::define_operator<(which & py::op_float)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_float)>::name());
|
||||
|
||||
if(which & py::op_cmp)
|
||||
add_method(new typename detail::define_operator<(which & py::op_cmp)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_cmp)>::name());
|
||||
|
||||
if(which & py::op_str)
|
||||
add_method(new typename detail::define_operator<(which & py::op_str)>::
|
||||
operator_function<operand>(),
|
||||
detail::define_operator<(which & py::op_str)>::name());
|
||||
|
||||
}
|
||||
|
||||
// export homogeneous operators (type of both lhs and rhs is 'T const &')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>());
|
||||
template <int which>
|
||||
void def(operators<which, py::detail::auto_operand>)
|
||||
{
|
||||
def(operators<which, T const &>());
|
||||
}
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
|
||||
// py::right_operand<int const &>());
|
||||
template <int which, class left, class right>
|
||||
void def(operators<which, left>, right_operand<right>)
|
||||
{
|
||||
register_coerce();
|
||||
|
||||
if(which & py::op_add)
|
||||
add_method(new typename detail::define_operator<(which & py::op_add)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_add)>::name());
|
||||
|
||||
if(which & py::op_sub)
|
||||
add_method(new typename detail::define_operator<(which & py::op_sub)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_sub)>::name());
|
||||
|
||||
if(which & py::op_mul)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mul)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_mul)>::name());
|
||||
|
||||
if(which & py::op_div)
|
||||
add_method(new typename detail::define_operator<(which & py::op_div)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_div)>::name());
|
||||
|
||||
if(which & py::op_mod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mod)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_mod)>::name());
|
||||
|
||||
if(which & py::op_divmod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_divmod)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_divmod)>::name());
|
||||
|
||||
if(which & py::op_pow)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pow)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_pow)>::name());
|
||||
|
||||
if(which & py::op_lshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_lshift)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_lshift)>::name());
|
||||
|
||||
if(which & py::op_rshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_rshift)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_rshift)>::name());
|
||||
|
||||
if(which & py::op_and)
|
||||
add_method(new typename detail::define_operator<(which & py::op_and)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_and)>::name());
|
||||
|
||||
if(which & py::op_xor)
|
||||
add_method(new typename detail::define_operator<(which & py::op_xor)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_xor)>::name());
|
||||
|
||||
if(which & py::op_or)
|
||||
add_method(new typename detail::define_operator<(which & py::op_or)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_or)>::name());
|
||||
|
||||
if(which & py::op_cmp)
|
||||
add_method(new typename detail::define_operator<(which & py::op_cmp)>::
|
||||
operator_function<left, right>(),
|
||||
detail::define_operator<(which & py::op_cmp)>::name());
|
||||
|
||||
}
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'T const &', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
|
||||
// py::right_operand<int const &>());
|
||||
template <int which, class right>
|
||||
void def(operators<which, py::detail::auto_operand>, right_operand<right> r)
|
||||
{
|
||||
def(operators<which, T const &>(), r);
|
||||
}
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
|
||||
// py::left_operand<int const &>());
|
||||
template <int which, class left, class right>
|
||||
void def(operators<which, right>, left_operand<left>)
|
||||
{
|
||||
register_coerce();
|
||||
|
||||
if(which & py::op_add)
|
||||
add_method(new typename detail::define_operator<(which & py::op_add)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_add)>::rname());
|
||||
|
||||
if(which & py::op_sub)
|
||||
add_method(new typename detail::define_operator<(which & py::op_sub)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_sub)>::rname());
|
||||
|
||||
if(which & py::op_mul)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mul)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_mul)>::rname());
|
||||
|
||||
if(which & py::op_div)
|
||||
add_method(new typename detail::define_operator<(which & py::op_div)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_div)>::rname());
|
||||
|
||||
if(which & py::op_mod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_mod)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_mod)>::rname());
|
||||
|
||||
if(which & py::op_divmod)
|
||||
add_method(new typename detail::define_operator<(which & py::op_divmod)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_divmod)>::rname());
|
||||
|
||||
if(which & py::op_pow)
|
||||
add_method(new typename detail::define_operator<(which & py::op_pow)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_pow)>::rname());
|
||||
|
||||
if(which & py::op_lshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_lshift)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_lshift)>::rname());
|
||||
|
||||
if(which & py::op_rshift)
|
||||
add_method(new typename detail::define_operator<(which & py::op_rshift)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_rshift)>::rname());
|
||||
|
||||
if(which & py::op_and)
|
||||
add_method(new typename detail::define_operator<(which & py::op_and)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_and)>::rname());
|
||||
|
||||
if(which & py::op_xor)
|
||||
add_method(new typename detail::define_operator<(which & py::op_xor)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_xor)>::rname());
|
||||
|
||||
if(which & py::op_or)
|
||||
add_method(new typename detail::define_operator<(which & py::op_or)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_or)>::rname());
|
||||
|
||||
if(which & py::op_cmp)
|
||||
add_method(new typename detail::define_operator<(which & py::op_cmp)>::
|
||||
roperator_function<right, left>(),
|
||||
detail::define_operator<(which & py::op_cmp)>::rname());
|
||||
|
||||
}
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'T const &')
|
||||
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
|
||||
// py::left_operand<int const &>());
|
||||
template <int which, class left>
|
||||
void def(operators<which, py::detail::auto_operand>, left_operand<left> l)
|
||||
{
|
||||
def(operators<which, T const &>(), l);
|
||||
}
|
||||
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
@@ -481,6 +856,8 @@ class ExtensionClass
|
||||
{
|
||||
this->add_constructor_object(InitFunction<Holder>::create(sig));
|
||||
}
|
||||
|
||||
void register_coerce();
|
||||
};
|
||||
|
||||
// A simple wrapper over a T which allows us to use ExtensionClass<T> with a
|
||||
@@ -579,6 +956,11 @@ class ExtensionInstance : public Instance
|
||||
// Template function implementations
|
||||
//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
Tuple extension_class_coerce(PyObject * l, PyObject * r);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
ExtensionClass<T, U>::ExtensionClass()
|
||||
: ExtensionClassBase(typeid(T).name())
|
||||
@@ -593,6 +975,15 @@ ExtensionClass<T, U>::ExtensionClass(const char* name)
|
||||
ClassRegistry<T>::register_class(this);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
void ExtensionClass<T, U>::register_coerce()
|
||||
{
|
||||
Ptr coerce_fct = dict().get_item(String("__coerce__"));
|
||||
|
||||
if(coerce_fct.get() == 0) // not yet defined
|
||||
this->def(&py::detail::extension_class_coerce, "__coerce__");
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline
|
||||
std::vector<detail::BaseClassInfo> const &
|
||||
|
||||
112
test_extclass.py
112
test_extclass.py
@@ -878,6 +878,118 @@ test inheritB2
|
||||
>>> raw2()
|
||||
0
|
||||
|
||||
========= test export of operators ==========
|
||||
|
||||
>>> i = Int(2)
|
||||
>>> j = i+i
|
||||
>>> j.i()
|
||||
4
|
||||
>>> j = i-i
|
||||
>>> j.i()
|
||||
0
|
||||
>>> j = i*i
|
||||
>>> j.i()
|
||||
4
|
||||
>>> i<i
|
||||
0
|
||||
>>> cmp(i,i)
|
||||
0
|
||||
>>> k = Int(5)
|
||||
>>> j = divmod(k, i)
|
||||
>>> j[0].i()
|
||||
2
|
||||
>>> j[1].i()
|
||||
1
|
||||
>>> j = pow(i, k)
|
||||
>>> j.i()
|
||||
32
|
||||
>>> j = pow(i, k, k)
|
||||
>>> j.i()
|
||||
2
|
||||
>>> j = -i
|
||||
>>> j.i()
|
||||
-2
|
||||
>>> str(i)
|
||||
'2'
|
||||
>>> j = i/i
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type(s) for /
|
||||
>>> j = abs(i)
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type for abs()
|
||||
>>> j = i+1
|
||||
>>> j.i()
|
||||
3
|
||||
>>> j = i-1
|
||||
>>> j.i()
|
||||
1
|
||||
>>> j = i*1
|
||||
>>> j.i()
|
||||
2
|
||||
>>> i<1
|
||||
0
|
||||
>>> cmp(i,1)
|
||||
1
|
||||
>>> j = pow(i, 5)
|
||||
>>> j.i()
|
||||
32
|
||||
>>> j = pow(i, 5, k)
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type(s) for pow()
|
||||
>>> j = pow(i, 5, 5)
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type(s) for pow()
|
||||
>>> j = i/1
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type(s) for /
|
||||
>>> j = 1+i
|
||||
>>> j.i()
|
||||
3
|
||||
>>> j = 1-i
|
||||
>>> j.i()
|
||||
-1
|
||||
>>> j = 1*i
|
||||
>>> j.i()
|
||||
2
|
||||
>>> 1<i
|
||||
1
|
||||
>>> cmp(1,i)
|
||||
-1
|
||||
>>> j = 1/i
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type(s) for /
|
||||
>>> pow(1,i)
|
||||
Traceback (innermost last):
|
||||
TypeError: bad operand type(s) for pow()
|
||||
|
||||
Test operator export to a subclass
|
||||
>>> class Foo(Int):
|
||||
... def __init__(self, i):
|
||||
... Int.__init__(self, i)
|
||||
... def __str__(self):
|
||||
... return 'Foo: ' + str(self.i())
|
||||
... def __coerce__(self, other):
|
||||
... return Int.__coerce__(self, other)
|
||||
...
|
||||
>>> f = Foo(3)
|
||||
>>> str(f)
|
||||
'Foo: 3'
|
||||
>>> j = f * f
|
||||
>>> j.i()
|
||||
9
|
||||
>>> j = f * i
|
||||
>>> j.i()
|
||||
6
|
||||
>>> j = f * 5
|
||||
>>> j.i()
|
||||
15
|
||||
>>> j = i * f
|
||||
>>> j.i()
|
||||
6
|
||||
>>> j = 5 * f
|
||||
>>> j.i()
|
||||
15
|
||||
|
||||
|
||||
========= Prove that the "phantom base class" issue is resolved ==========
|
||||
|
||||
|
||||
Reference in New Issue
Block a user