fix inplace python opers
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@5859 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
be31340148
commit
fd1c9fb316
2 changed files with 82 additions and 10 deletions
|
|
@ -18,16 +18,6 @@
|
||||||
%rename(__or__) *::operator|;
|
%rename(__or__) *::operator|;
|
||||||
%rename(__xor__) *::operator^;
|
%rename(__xor__) *::operator^;
|
||||||
%rename(__invert__) *::operator~;
|
%rename(__invert__) *::operator~;
|
||||||
%rename(__iadd__) *::operator+=;
|
|
||||||
%rename(__isub__) *::operator-=;
|
|
||||||
%rename(__imul__) *::operator*=;
|
|
||||||
%rename(__idiv__) *::operator/=;
|
|
||||||
%rename(__imod__) *::operator%=;
|
|
||||||
%rename(__ilshift__) *::operator<<=;
|
|
||||||
%rename(__irshift__) *::operator>>=;
|
|
||||||
%rename(__iand__) *::operator&=;
|
|
||||||
%rename(__ior__) *::operator|=;
|
|
||||||
%rename(__ixor__) *::operator^=;
|
|
||||||
%rename(__lt__) *::operator<;
|
%rename(__lt__) *::operator<;
|
||||||
%rename(__le__) *::operator<=;
|
%rename(__le__) *::operator<=;
|
||||||
%rename(__gt__) *::operator>;
|
%rename(__gt__) *::operator>;
|
||||||
|
|
@ -48,4 +38,60 @@
|
||||||
%ignorewarn("386:operator->* ignored") operator->*;
|
%ignorewarn("386:operator->* ignored") operator->*;
|
||||||
%ignorewarn("389:operator[] ignored (consider using %extend)") operator[];
|
%ignorewarn("389:operator[] ignored (consider using %extend)") 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("self:disown") *::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
|
||||||
|
(lucriz@sitilandia.it).
|
||||||
|
|
||||||
|
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("self:disown","") 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("self:disown","") *::operator+=;
|
||||||
|
%feature("new","") *::operator+=;
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
%define %swig_inplace_oper(Oper, PyOper)
|
||||||
|
%feature("self:disown") *::Oper;
|
||||||
|
%feature("new") *::Oper;
|
||||||
|
%rename(__##PyOper##__) *::Oper;
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%swig_inplace_oper(operator +=, iadd);
|
||||||
|
%swig_inplace_oper(operator -=, isub);
|
||||||
|
%swig_inplace_oper(operator *=, imul);
|
||||||
|
%swig_inplace_oper(operator /=, idiv);
|
||||||
|
%swig_inplace_oper(operator %=, imod);
|
||||||
|
%swig_inplace_oper(operator &=, iand);
|
||||||
|
%swig_inplace_oper(operator |=, ior);
|
||||||
|
%swig_inplace_oper(operator ^=, ixor);
|
||||||
|
%swig_inplace_oper(operator <<=, ilshift);
|
||||||
|
%swig_inplace_oper(operator >>=, irshift);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -624,6 +624,32 @@ Swig_MethodToFunction(Node *n, String *classname, int flags) {
|
||||||
SwigType_add_pointer(type);
|
SwigType_add_pointer(type);
|
||||||
p = NewParm(type,"self");
|
p = NewParm(type,"self");
|
||||||
Setattr(p,"hidden","1");
|
Setattr(p,"hidden","1");
|
||||||
|
/*
|
||||||
|
Disable the 'this' ownership in 'self' to manage inplace
|
||||||
|
operations like:
|
||||||
|
|
||||||
|
A& A::operator+=(int i) { ...; return *this;}
|
||||||
|
|
||||||
|
Here the 'self' parameter ownership needs to be disabled since
|
||||||
|
there could be two objects sharing the same 'this' pointer: the
|
||||||
|
input and the result one. And worse, the pointer could be deleted
|
||||||
|
in one of the objects (input), leaving the other (output) with
|
||||||
|
just a seg. fault to happen.
|
||||||
|
|
||||||
|
To avoid the previous problem, use
|
||||||
|
|
||||||
|
%feature("self:disown") *::operator+=;
|
||||||
|
%feature("new") *::operator+=;
|
||||||
|
|
||||||
|
These two lines just transfer the ownership of the 'this' pointer
|
||||||
|
from the input to the output wrapping object.
|
||||||
|
|
||||||
|
This happens in python, but may also happens in other target
|
||||||
|
languages.
|
||||||
|
*/
|
||||||
|
if (Getattr(n,"feature:self:disown")) {
|
||||||
|
Setattr(p,"wrap:disown",Getattr(n,"feature:self:disown"));
|
||||||
|
}
|
||||||
set_nextSibling(p,parms);
|
set_nextSibling(p,parms);
|
||||||
Delete(type);
|
Delete(type);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue