2
0
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:
Ullrich Köthe
2000-11-14 19:34:43 +00:00
parent 80ebaf94f5
commit 9f30f7dfd7
6 changed files with 1265 additions and 24 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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 &

View File

@@ -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&>());

View File

@@ -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 &

View File

@@ -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 ==========