1 /* ------------------------------------------------------------ 2 * Overloaded operator support 3 4 The directives in this file apply whether or not you use the 5 -builtin option to SWIG, but operator overloads are particularly 6 attractive when using -builtin, because they are much faster 7 than named methods. 8 9 If you're using the -builtin option to SWIG, and you want to define 10 python operator overloads beyond the defaults defined in this file, 11 here's what you need to know: 12 13 There are two ways to define a python slot function: dispatch to a 14 statically defined function; or dispatch to a method defined on the 15 operand. 16 17 To dispatch to a statically defined function, use %feature("python:<slot>"), 18 where <slot> is the name of a field in a PyTypeObject, PyNumberMethods, 19 PyMappingMethods, PySequenceMethods, or PyBufferProcs. For example: 20 21 %{ 22 23 static long myHashFunc (PyObject *pyobj) { 24 MyClass *cobj; 25 // Convert pyobj to cobj 26 return (cobj->field1 * (cobj->field2 << 7)); 27 } 28 29 %} 30 31 %feature("python:tp_hash") MyClass "myHashFunc"; 32 33 NOTE: It is the responsibility of the programmer (that's you) to ensure 34 that a statically defined slot function has the correct signature. 35 36 If, instead, you want to dispatch to an instance method, you can 37 use %feature("python:slot"). For example: 38 39 class MyClass { 40 public: 41 long myHashFunc () const; 42 ... 43 }; 44 45 %feature("python:slot", "tp_hash", functype="hashfunc") MyClass::myHashFunc; 46 47 NOTE: Some python slots use a method signature which does not 48 match the signature of SWIG-wrapped methods. For those slots, 49 SWIG will automatically generate a "closure" function to re-marshall 50 the arguments before dispatching to the wrapped method. Setting 51 the "functype" attribute of the feature enables SWIG to generate 52 a correct closure function. 53 54 -------------------------------------------------------------- 55 56 The tp_richcompare slot is a special case: SWIG automatically generates 57 a rich compare function for all wrapped types. If a type defines C++ 58 operator overloads for comparison (operator==, operator<, etc.), they 59 will be called from the generated rich compare function. If you 60 want to explicitly choose a method to handle a certain comparison 61 operation, you may use %feature("python:slot") like this: 62 63 class MyClass { 64 public: 65 bool lessThan (const MyClass& x) const; 66 ... 67 }; 68 69 %feature("python:slot", "Py_LT") MyClass::lessThan; 70 71 ... where "Py_LT" is one of the rich comparison opcodes defined in the 72 python header file object.h. 73 74 If there's no method defined to handle a particular comparsion operation, 75 the default behavior is to compare pointer values of the wrapped 76 C++ objects. 77 78 -------------------------------------------------------------- 79 80 81 For more information about python slots, including their names and 82 signatures, you may refer to the python documentation : 83 84 http://docs.python.org/c-api/typeobj.html 85 86 * ------------------------------------------------------------ */ 87 88 89 #ifdef __cplusplus 90 91 #if defined(SWIGPYTHON_BUILTIN) 92 #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; 93 #define %pycompare(pyname,oper,comptype) %rename(pyname) oper; %pythonmaybecall oper; %feature("python:compare", #comptype) oper; %feature("python:compare", #comptype) pyname; 94 #else 95 #define %pybinoperator(pyname,oper,functp,slt) %rename(pyname) oper; %pythonmaybecall oper 96 #define %pycompare(pyname,oper,comptype) %pybinoperator(pyname,oper,,comptype) 97 #endif 98 99 %pybinoperator(__add__, *::operator+, binaryfunc, nb_add); 100 %pybinoperator(__pos__, *::operator+(), unaryfunc, nb_positive); 101 %pybinoperator(__pos__, *::operator+() const, unaryfunc, nb_positive); 102 %pybinoperator(__sub__, *::operator-, binaryfunc, nb_subtract); 103 %pybinoperator(__neg__, *::operator-(), unaryfunc, nb_negative); 104 %pybinoperator(__neg__, *::operator-() const, unaryfunc, nb_negative); 105 %pybinoperator(__mul__, *::operator*, binaryfunc, nb_multiply); 106 %pybinoperator(__div__, *::operator/, binaryfunc, nb_div); 107 %pybinoperator(__mod__, *::operator%, binaryfunc, nb_remainder); 108 %pybinoperator(__lshift__, *::operator<<, binaryfunc, nb_lshift); 109 %pybinoperator(__rshift__, *::operator>>, binaryfunc, nb_rshift); 110 %pybinoperator(__and__, *::operator&, binaryfunc, nb_and); 111 %pybinoperator(__or__, *::operator|, binaryfunc, nb_or); 112 %pybinoperator(__xor__, *::operator^, binaryfunc, nb_xor); 113 %pycompare(__lt__, *::operator<, Py_LT); 114 %pycompare(__le__, *::operator<=, Py_LE); 115 %pycompare(__gt__, *::operator>, Py_GT); 116 %pycompare(__ge__, *::operator>=, Py_GE); 117 %pycompare(__eq__, *::operator==, Py_EQ); 118 %pycompare(__ne__, *::operator!=, Py_NE); 119 120 %feature("python:slot", "nb_truediv", functype="binaryfunc") *::operator/; 121 122 /* Special cases */ 123 %rename(__invert__) *::operator~; 124 %feature("python:slot", "nb_invert", functype="unaryfunc") *::operator~; 125 %rename(__call__) *::operator(); 126 %feature("python:slot", "tp_call", functype="ternarycallfunc") *::operator(); 127 128 #if defined(SWIGPYTHON_BUILTIN) 129 %pybinoperator(__nonzero__, *::operator bool, inquiry, nb_nonzero); 130 #else 131 %feature("shadow") *::operator bool %{ 132 def __nonzero__(self): 133 return $action(self) 134 __bool__ = __nonzero__ 135 %}; 136 %rename(__nonzero__) *::operator bool; 137 #endif 138 139 /* Ignored operators */ 140 %ignoreoperator(LNOT) operator!; 141 %ignoreoperator(LAND) operator&&; 142 %ignoreoperator(LOR) operator||; 143 %ignoreoperator(EQ) *::operator=; 144 %ignoreoperator(PLUSPLUS) *::operator++; 145 %ignoreoperator(MINUSMINUS) *::operator--; 146 %ignoreoperator(ARROWSTAR) *::operator->*; 147 %ignoreoperator(INDEX) *::operator[]; 148 149 /* 150 Inplace operator declarations. 151 152 They translate the inplace C++ operators (+=, -=, ...) into the 153 corresponding python equivalents(__iadd__,__isub__), etc, 154 disabling the ownership of the input 'self' pointer, and assigning 155 it to the returning object: 156 157 %feature("del") *::Operator; 158 %feature("new") *::Operator; 159 160 This makes the most common case safe, ie: 161 162 A& A::operator+=(int i) { ...; return *this; } 163 ^^^^ ^^^^^^ 164 165 will work fine, even when the resulting python object shares the 166 'this' pointer with the input one. The input object is usually 167 deleted after the operation, including the shared 'this' pointer, 168 producing 'strange' seg faults, as reported by Lucriz 169 (lucriz (at) sitilandia.it). 170 171 If you have an interface that already takes care of that, ie, you 172 already are using inplace operators and you are not getting 173 seg. faults, with the new scheme you could end with 'free' elements 174 that never get deleted (maybe, not sure, it depends). But if that is 175 the case, you could recover the old behaviour using 176 177 %feature("del","") A::operator+=; 178 %feature("new","") A::operator+=; 179 180 which recovers the old behaviour for the class 'A', or if you are 181 100% sure your entire system works fine in the old way, use: 182 183 %feature("del","") *::operator+=; 184 %feature("new","") *::operator+=; 185 186 */ 187 188 #if defined(SWIGPYTHON_BUILTIN) 189 #define %pyinplaceoper(SwigPyOper, Oper, functp, slt) %delobject Oper; %newobject Oper; %feature("python:slot", #slt, functype=#functp) Oper; %rename(SwigPyOper) Oper 190 #else 191 #define %pyinplaceoper(SwigPyOper, Oper, functp, slt) %delobject Oper; %newobject Oper; %rename(SwigPyOper) Oper 192 #endif 193 194 %pyinplaceoper(__iadd__ , *::operator +=, binaryfunc, nb_inplace_add); 195 %pyinplaceoper(__isub__ , *::operator -=, binaryfunc, nb_inplace_subtract); 196 %pyinplaceoper(__imul__ , *::operator *=, binaryfunc, nb_inplace_multiply); 197 %pyinplaceoper(__idiv__ , *::operator /=, binaryfunc, nb_inplace_divide); 198 %pyinplaceoper(__imod__ , *::operator %=, binaryfunc, nb_inplace_remainder); 199 %pyinplaceoper(__iand__ , *::operator &=, binaryfunc, nb_inplace_and); 200 %pyinplaceoper(__ior__ , *::operator |=, binaryfunc, nb_inplace_or); 201 %pyinplaceoper(__ixor__ , *::operator ^=, binaryfunc, nb_inplace_xor); 202 %pyinplaceoper(__ilshift__, *::operator <<=, binaryfunc, nb_inplace_lshift); 203 %pyinplaceoper(__irshift__, *::operator >>=, binaryfunc, nb_inplace_rshift); 204 205 206 /* Finally, in python we need to mark the binary operations to fail as 207 'maybecall' methods */ 208 209 #define %pybinopermaybecall(oper) %pythonmaybecall __ ## oper ## __; %pythonmaybecall __r ## oper ## __ 210 211 %pybinopermaybecall(add); 212 %pybinopermaybecall(pos); 213 %pybinopermaybecall(pos); 214 %pybinopermaybecall(sub); 215 %pybinopermaybecall(neg); 216 %pybinopermaybecall(neg); 217 %pybinopermaybecall(mul); 218 %pybinopermaybecall(div); 219 %pybinopermaybecall(mod); 220 %pybinopermaybecall(lshift); 221 %pybinopermaybecall(rshift); 222 %pybinopermaybecall(and); 223 %pybinopermaybecall(or); 224 %pybinopermaybecall(xor); 225 %pybinopermaybecall(lt); 226 %pybinopermaybecall(le); 227 %pybinopermaybecall(gt); 228 %pybinopermaybecall(ge); 229 %pybinopermaybecall(eq); 230 %pybinopermaybecall(ne); 231 232 #endif 233 234 235 236