diff --git a/CHANGES.current b/CHANGES.current index 349b69707..e60bdc1d2 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,12 @@ Version 1.3.39 (in progress) ============================ +2008-02-14: wsfulton + Extend attribute library support for structs/classes and the accessor functions use + pass/return by value semantics. Two new macros are available and usage is identical + to %attribute. These are %attributeval for structs/classes and %attributestring for + string classes, like std::string. See attribute.swg for more details. + 2008-02-13: wsfulton Add support for %extend and memberin typemaps. Previously the memberin typemaps were ignored for member variables within a %extend block. diff --git a/Examples/test-suite/csharp/li_attribute_runme.cs b/Examples/test-suite/csharp/li_attribute_runme.cs new file mode 100644 index 000000000..46f982637 --- /dev/null +++ b/Examples/test-suite/csharp/li_attribute_runme.cs @@ -0,0 +1,78 @@ +// Ported from Python li_attribute_runme.py + +using System; +using li_attributeNamespace; + +public class li_attribute_runme { + + public static void Main() { + A aa = new A(1,2,3); + + if (aa.a != 1) + throw new ApplicationException("error"); + aa.a = 3; + if (aa.a != 3) + throw new ApplicationException("error"); + + if (aa.b != 2) + throw new ApplicationException("error"); + aa.b = 5; + if (aa.b != 5) + throw new ApplicationException("error"); + + if (aa.d != aa.b) + throw new ApplicationException("error"); + + if (aa.c != 3) + throw new ApplicationException("error"); + //aa.c = 5; + //if (aa.c != 3) + // throw new ApplicationException("error"); + + Param_i pi = new Param_i(7); + if (pi.value != 7) + throw new ApplicationException("error"); + + pi.value=3; + if (pi.value != 3) + throw new ApplicationException("error"); + + B b = new B(aa); + + if (b.a.c != 3) + throw new ApplicationException("error"); + + // class/struct attribute with get/set methods using return/pass by reference + MyFoo myFoo = new MyFoo(); + myFoo.x = 8; + MyClass myClass = new MyClass(); + myClass.Foo = myFoo; + if (myClass.Foo.x != 8) + throw new ApplicationException("error"); + + // class/struct attribute with get/set methods using return/pass by value + MyClassVal myClassVal = new MyClassVal(); + if (myClassVal.ReadWriteFoo.x != -1) + throw new ApplicationException("error"); + if (myClassVal.ReadOnlyFoo.x != -1) + throw new ApplicationException("error"); + myClassVal.ReadWriteFoo = myFoo; + if (myClassVal.ReadWriteFoo.x != 8) + throw new ApplicationException("error"); + if (myClassVal.ReadOnlyFoo.x != 8) + throw new ApplicationException("error"); + + // string attribute with get/set methods using return/pass by value + MyStringyClass myStringClass = new MyStringyClass("initial string"); + if (myStringClass.ReadWriteString != "initial string") + throw new ApplicationException("error"); + if (myStringClass.ReadOnlyString != "initial string") + throw new ApplicationException("error"); + myStringClass.ReadWriteString = "changed string"; + if (myStringClass.ReadWriteString != "changed string") + throw new ApplicationException("error"); + if (myStringClass.ReadOnlyString != "changed string") + throw new ApplicationException("error"); + } +} + diff --git a/Examples/test-suite/li_attribute.i b/Examples/test-suite/li_attribute.i index 5b4379ebf..4f9497afb 100644 --- a/Examples/test-suite/li_attribute.i +++ b/Examples/test-suite/li_attribute.i @@ -93,9 +93,11 @@ struct MyFoo; // %attribute2 does not work with templates %template(Param_i) Param; +// class/struct attribute with get/set methods using return/pass by reference %attribute2(MyClass, MyFoo, Foo, GetFoo, SetFoo); %inline %{ struct MyFoo { + MyFoo() : x(-1) {} int x; }; class MyClass { @@ -106,3 +108,32 @@ struct MyFoo; // %attribute2 does not work with templates }; %} + +// class/struct attribute with get/set methods using return/pass by value +%attributeval(MyClassVal, MyFoo, ReadWriteFoo, GetFoo, SetFoo); +%attributeval(MyClassVal, MyFoo, ReadOnlyFoo, GetFoo); +%inline %{ + class MyClassVal { + MyFoo foo; + public: + MyFoo GetFoo() { return foo; } + void SetFoo(MyFoo other) { foo = other; } + }; +%} + + +// string attribute with get/set methods using return/pass by value +%include +%attributestring(MyStringyClass, std::string, ReadWriteString, GetString, SetString); +%attributestring(MyStringyClass, std::string, ReadOnlyString, GetString); +%inline %{ + class MyStringyClass { + std::string str; + public: + MyStringyClass(const std::string &val) : str(val) {} + std::string GetString() { return str; } + void SetString(std::string other) { str = other; } + }; +%} + + diff --git a/Examples/test-suite/octave/li_attribute_runme.m b/Examples/test-suite/octave/li_attribute_runme.m index c66e27c5b..548e733ed 100644 --- a/Examples/test-suite/octave/li_attribute_runme.m +++ b/Examples/test-suite/octave/li_attribute_runme.m @@ -10,7 +10,6 @@ if (aa.a != 3) error("aa.a = %i",aa.a) endif - if (aa.b != 2) error(aa.b) endif @@ -19,8 +18,6 @@ if (aa.b != 5) error endif - - if (aa.d != aa.b) error endif @@ -39,14 +36,13 @@ if (pi.value != 3) error endif - b = li_attribute.B(aa); if (b.a.c != 3) error endif - +# class/struct attribute with get/set methods using return/pass by reference myFoo = li_attribute.MyFoo(); myFoo.x = 8; myClass = li_attribute.MyClass(); @@ -55,3 +51,35 @@ if (myClass.Foo.x != 8) error endif +# class/struct attribute with get/set methods using return/pass by value +myClassVal = li_attribute.MyClassVal(); +if (myClassVal.ReadWriteFoo.x != -1) + error +endif +if (myClassVal.ReadOnlyFoo.x != -1) + error +endif +myClassVal.ReadWriteFoo = myFoo; +if (myClassVal.ReadWriteFoo.x != 8) + error +endif +if (myClassVal.ReadOnlyFoo.x != 8) + error +endif + +# string attribute with get/set methods using return/pass by value +myStringyClass = li_attribute.MyStringyClass("initial string"); +if (myStringyClass.ReadWriteString != "initial string") + error +endif +if (myStringyClass.ReadOnlyString != "initial string") + error +endif +myStringyClass.ReadWriteString = "changed string"; +if (myStringyClass.ReadWriteString != "changed string") + error +endif +if (myStringyClass.ReadOnlyString != "changed string") + error +endif + diff --git a/Examples/test-suite/python/li_attribute_runme.py b/Examples/test-suite/python/li_attribute_runme.py index 5eeec299b..db40b9b2a 100644 --- a/Examples/test-suite/python/li_attribute_runme.py +++ b/Examples/test-suite/python/li_attribute_runme.py @@ -1,3 +1,5 @@ +# Ported to C# li_attribute_runme.cs + import li_attribute aa = li_attribute.A(1,2,3) @@ -9,7 +11,6 @@ if aa.a != 3: print aa.a raise RuntimeError - if aa.b != 2: print aa.b raise RuntimeError @@ -17,8 +18,6 @@ aa.b = 5 if aa.b != 5: raise RuntimeError - - if aa.d != aa.b: raise RuntimeError @@ -36,17 +35,40 @@ pi.value=3 if pi.value != 3: raise RuntimeError - b = li_attribute.B(aa) if b.a.c != 3: raise RuntimeError - -myFoo = li_attribute.MyFoo +# class/struct attribute with get/set methods using return/pass by reference +myFoo = li_attribute.MyFoo() myFoo.x = 8 -myClass = li_attribute.MyClass +myClass = li_attribute.MyClass() myClass.Foo = myFoo if myClass.Foo.x != 8: raise RuntimeError +# class/struct attribute with get/set methods using return/pass by value +myClassVal = li_attribute.MyClassVal() +if myClassVal.ReadWriteFoo.x != -1: + raise RuntimeError +if myClassVal.ReadOnlyFoo.x != -1: + raise RuntimeError +myClassVal.ReadWriteFoo = myFoo +if myClassVal.ReadWriteFoo.x != 8: + raise RuntimeError +if myClassVal.ReadOnlyFoo.x != 8: + raise RuntimeError + +# string attribute with get/set methods using return/pass by value +myStringyClass = li_attribute.MyStringyClass("initial string") +if myStringyClass.ReadWriteString != "initial string": + raise RuntimeError +if myStringyClass.ReadOnlyString != "initial string": + raise RuntimeError +myStringyClass.ReadWriteString = "changed string" +if myStringyClass.ReadWriteString != "changed string": + raise RuntimeError +if myStringyClass.ReadOnlyString != "changed string": + raise RuntimeError + diff --git a/Lib/typemaps/attribute.swg b/Lib/typemaps/attribute.swg index f6335be82..4bc6315b7 100644 --- a/Lib/typemaps/attribute.swg +++ b/Lib/typemaps/attribute.swg @@ -11,7 +11,7 @@ The following macros convert a pair of set/get methods into a "native" attribute. - Use %attribute when you have a pair of get/set methods + Use %attribute when you have a pair of get/set methods to a primitive type like in: %attribute(A, int, a, get_a, set_a); @@ -27,8 +27,8 @@ %attribute(A, int, c, get_c); - Use %attributeref when you have const/non-const reference - access methods, like in: + Use %attributeref when you have const/non-const reference access methods + for primitive types or class/structs, like in: %attributeref(A, int, b); @@ -99,6 +99,40 @@ where %arg() 'normalizes' the type to be understood as a single argument, otherwise the macro will get confused by the comma. + + The %attributeval is the same as %attribute, but should be used when the type + is a class/struct (ie a non-primitive type) and when the get and set methods + return/pass by value. The following is very similar to the above example, but + note that the access is by value rather than reference. + + %attributeval(MyClassVal, MyFoo, ReadWriteFoo, GetFoo, SetFoo); + %attributeval(MyClassVal, MyFoo, ReadOnlyFoo, GetFoo); + %inline %{ + class MyClassVal { + MyFoo foo; + public: + MyFoo GetFoo() { return foo; } + void SetFoo(MyFoo other) { foo = other; } + }; + %} + + The %attributestring is the same as %attributeval, but should be used for string + class types, which are unusual as they are a class on the C++ side, but normally an + immutable/primitive type in the target language. Example usage for std::string: + + %include + %attributestring(MyStringyClass, std::string, ReadWriteString, GetString, SetString); + %attributestring(MyStringyClass, std::string, ReadOnlyString, GetString); + %inline %{ + class MyStringyClass { + std::string str; + public: + MyStringyClass(const std::string &val) : str(val) {} + std::string GetString() { return str; } + void SetString(std::string other) { str = other; } + }; + %} + */ // @@ -203,3 +237,50 @@ #endif %enddef + +%define %attributeval(Class, AttributeType, AttributeName, GetMethod, SetMethod...) + %{ + #define %mangle(Class) ##_## AttributeName ## _get(self_) new AttributeType(self_->GetMethod()) + %} + #if #SetMethod != "" + %{ + #define %mangle(Class) ##_## AttributeName ## _set(self_, val_) self_->SetMethod(*val_) + %} + #if #SetMethod != #AttributeName + %ignore Class::SetMethod; + #endif + #else + %immutable Class::AttributeName; + #endif + %ignore Class::GetMethod(); + %ignore Class::GetMethod() const; + %newobject Class::AttributeName; + %extend Class { + AttributeType AttributeName; + } +%enddef + + +%define %attributestring(Class, AttributeType, AttributeName, GetMethod, SetMethod...) + %{ + #define %mangle(Class) ##_## AttributeName ## _get(self_) *new AttributeType(self_->GetMethod()) + %} + #if #SetMethod != "" + %{ + #define %mangle(Class) ##_## AttributeName ## _set(self_, val_) self_->SetMethod(val_) + %} + #if #SetMethod != #AttributeName + %ignore Class::SetMethod; + #endif + #else + %immutable Class::AttributeName; + #endif + %ignore Class::GetMethod(); + %ignore Class::GetMethod() const; + %newobject Class::AttributeName; + %typemap(newfree) const AttributeType &AttributeName "delete $1;// my newfree override" + %extend Class { + AttributeType AttributeName; + } +%enddef +