blob: ecbe7834e1efdd6188a6207fddffe87658f95950 [file] [log] [blame]
/* ------------------------------------------------------------
* Overloaded operator support
The directives in this file apply whether or not you use the
-builtin option to SWIG, but operator overloads are particularly
attractive when using -builtin, because they are much faster
than named methods.
If you're using the -builtin option to SWIG, and you want to define
python operator overloads beyond the defaults defined in this file,
here's what you need to know:
There are two ways to define a python slot function: dispatch to a
statically defined function; or dispatch to a method defined on the
To dispatch to a statically defined function, use %feature("python:<slot>"),
where <slot> is the name of a field in a PyTypeObject, PyNumberMethods,
PyMappingMethods, PySequenceMethods, or PyBufferProcs. For example:
static long myHashFunc (PyObject *pyobj) {
MyClass *cobj;
// Convert pyobj to cobj
return (cobj->field1 * (cobj->field2 << 7));
%feature("python:tp_hash") MyClass "myHashFunc";
NOTE: It is the responsibility of the programmer (that's you) to ensure
that a statically defined slot function has the correct signature.
If, instead, you want to dispatch to an instance method, you can
use %feature("python:slot"). For example:
class MyClass {
long myHashFunc () const;
%feature("python:slot", "tp_hash", functype="hashfunc") MyClass::myHashFunc;
NOTE: Some python slots use a method signature which does not
match the signature of SWIG-wrapped methods. For those slots,
SWIG will automatically generate a "closure" function to re-marshall
the arguments before dispatching to the wrapped method. Setting
the "functype" attribute of the feature enables SWIG to generate
a correct closure function.
The tp_richcompare slot is a special case: SWIG automatically generates
a rich compare function for all wrapped types. If a type defines C++
operator overloads for comparison (operator==, operator<, etc.), they
will be called from the generated rich compare function. If you
want to explicitly choose a method to handle a certain comparison
operation, you may use %feature("python:slot") like this:
class MyClass {
bool lessThan (const MyClass& x) const;
%feature("python:slot", "Py_LT") MyClass::lessThan;
... where "Py_LT" is one of the rich comparison opcodes defined in the
python header file object.h.
If there's no method defined to handle a particular comparsion operation,
the default behavior is to compare pointer values of the wrapped
C++ objects.
For more information about python slots, including their names and
signatures, you may refer to the python documentation :
* ------------------------------------------------------------ */
#ifdef __cplusplus
#define %pybinoperator(pyname,oper,functp,slt) %rename(pyname) oper; %pythonmaybecall oper; %feature("python:slot", #slt, functype=#functp) oper; %feature("python:slot", #slt, functype=#functp) pyname;
#define %pycompare(pyname,oper,comptype) %rename(pyname) oper; %pythonmaybecall oper; %feature("python:compare", #comptype) oper; %feature("python:compare", #comptype) pyname;
#define %pybinoperator(pyname,oper,functp,slt) %rename(pyname) oper; %pythonmaybecall oper
#define %pycompare(pyname,oper,comptype) %pybinoperator(pyname,oper,,comptype)
%pybinoperator(__add__, *::operator+, binaryfunc, nb_add);
%pybinoperator(__pos__, *::operator+(), unaryfunc, nb_positive);
%pybinoperator(__pos__, *::operator+() const, unaryfunc, nb_positive);
%pybinoperator(__sub__, *::operator-, binaryfunc, nb_subtract);
%pybinoperator(__neg__, *::operator-(), unaryfunc, nb_negative);
%pybinoperator(__neg__, *::operator-() const, unaryfunc, nb_negative);
%pybinoperator(__mul__, *::operator*, binaryfunc, nb_multiply);
%pybinoperator(__div__, *::operator/, binaryfunc, nb_div);
%pybinoperator(__mod__, *::operator%, binaryfunc, nb_remainder);
%pybinoperator(__lshift__, *::operator<<, binaryfunc, nb_lshift);
%pybinoperator(__rshift__, *::operator>>, binaryfunc, nb_rshift);
%pybinoperator(__and__, *::operator&, binaryfunc, nb_and);
%pybinoperator(__or__, *::operator|, binaryfunc, nb_or);
%pybinoperator(__xor__, *::operator^, binaryfunc, nb_xor);
%pycompare(__lt__, *::operator<, Py_LT);
%pycompare(__le__, *::operator<=, Py_LE);
%pycompare(__gt__, *::operator>, Py_GT);
%pycompare(__ge__, *::operator>=, Py_GE);
%pycompare(__eq__, *::operator==, Py_EQ);
%pycompare(__ne__, *::operator!=, Py_NE);
%feature("python:slot", "nb_truediv", functype="binaryfunc") *::operator/;
/* Special cases */
%rename(__invert__) *::operator~;
%feature("python:slot", "nb_invert", functype="unaryfunc") *::operator~;
%rename(__call__) *::operator();
%feature("python:slot", "tp_call", functype="ternarycallfunc") *::operator();
%pybinoperator(__nonzero__, *::operator bool, inquiry, nb_nonzero);
%feature("shadow") *::operator bool %{
def __nonzero__(self):
return $action(self)
__bool__ = __nonzero__
%rename(__nonzero__) *::operator bool;
/* Ignored operators */
%ignoreoperator(LNOT) operator!;
%ignoreoperator(LAND) operator&&;
%ignoreoperator(LOR) operator||;
%ignoreoperator(EQ) *::operator=;
%ignoreoperator(PLUSPLUS) *::operator++;
%ignoreoperator(MINUSMINUS) *::operator--;
%ignoreoperator(ARROWSTAR) *::operator->*;
%ignoreoperator(INDEX) *::operator[];
Inplace operator declarations.
They translate the inplace C++ operators (+=, -=, ...) into the
corresponding python equivalents(__iadd__,__isub__), etc,
disabling the ownership of the input 'self' pointer, and assigning
it to the returning object:
%feature("del") *::Operator;
%feature("new") *::Operator;
This makes the most common case safe, ie:
A& A::operator+=(int i) { ...; return *this; }
^^^^ ^^^^^^
will work fine, even when the resulting python object shares the
'this' pointer with the input one. The input object is usually
deleted after the operation, including the shared 'this' pointer,
producing 'strange' seg faults, as reported by Lucriz
If you have an interface that already takes care of that, ie, you
already are using inplace operators and you are not getting
seg. faults, with the new scheme you could end with 'free' elements
that never get deleted (maybe, not sure, it depends). But if that is
the case, you could recover the old behaviour using
%feature("del","") A::operator+=;
%feature("new","") A::operator+=;
which recovers the old behaviour for the class 'A', or if you are
100% sure your entire system works fine in the old way, use:
%feature("del","") *::operator+=;
%feature("new","") *::operator+=;
#define %pyinplaceoper(SwigPyOper, Oper, functp, slt) %delobject Oper; %newobject Oper; %feature("python:slot", #slt, functype=#functp) Oper; %rename(SwigPyOper) Oper
#define %pyinplaceoper(SwigPyOper, Oper, functp, slt) %delobject Oper; %newobject Oper; %rename(SwigPyOper) Oper
%pyinplaceoper(__iadd__ , *::operator +=, binaryfunc, nb_inplace_add);
%pyinplaceoper(__isub__ , *::operator -=, binaryfunc, nb_inplace_subtract);
%pyinplaceoper(__imul__ , *::operator *=, binaryfunc, nb_inplace_multiply);
%pyinplaceoper(__idiv__ , *::operator /=, binaryfunc, nb_inplace_divide);
%pyinplaceoper(__imod__ , *::operator %=, binaryfunc, nb_inplace_remainder);
%pyinplaceoper(__iand__ , *::operator &=, binaryfunc, nb_inplace_and);
%pyinplaceoper(__ior__ , *::operator |=, binaryfunc, nb_inplace_or);
%pyinplaceoper(__ixor__ , *::operator ^=, binaryfunc, nb_inplace_xor);
%pyinplaceoper(__ilshift__, *::operator <<=, binaryfunc, nb_inplace_lshift);
%pyinplaceoper(__irshift__, *::operator >>=, binaryfunc, nb_inplace_rshift);
/* Finally, in python we need to mark the binary operations to fail as
'maybecall' methods */
#define %pybinopermaybecall(oper) %pythonmaybecall __ ## oper ## __; %pythonmaybecall __r ## oper ## __