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:
Marcelo Matus 2004-04-09 21:58:47 +00:00
commit fd1c9fb316
2 changed files with 82 additions and 10 deletions

View file

@ -18,16 +18,6 @@
%rename(__or__) *::operator|;
%rename(__xor__) *::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(__le__) *::operator<=;
%rename(__gt__) *::operator>;
@ -48,4 +38,60 @@
%ignorewarn("386:operator->* ignored") 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

View file

@ -624,6 +624,32 @@ Swig_MethodToFunction(Node *n, String *classname, int flags) {
SwigType_add_pointer(type);
p = NewParm(type,"self");
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);
Delete(type);