diff --git a/CHANGES.current b/CHANGES.current index 631c04f73..c5f3d91e6 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,5 +1,19 @@ Version 1.3.20 (In progress) ============================ +08/29/2003: mrose (Mark Rose) + Completed initial support for wrapping abstract classes with directors. + Constructor wrappers will be generated for abstract classes that have + directors, and instances of the director classes will be created regardless + of whether the proxy class has been subclassed in the target language. + No checks are made during construction to ensure that all pure virtual + methods are implemented in the target language. Instead, calls to + unimplemented methods will throw SWIG_DIRECTOR_PURE_VIRTUAL exceptions in + C++. + + Integrated Prabhu Ramachandran's typemap patches, which provide director + typemap support for enums and std::size_t, and fix a couple bugs in the + director std::vector<> typemaps. + 08/29/2003: cheetah (William Fulton) [C#] Implemented exception handling for throwing C# exceptions from C/C++ code. A few delegate functions are available for calling which then throw the C# diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 038bc31ec..eb2b34561 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -101,6 +101,7 @@ CPP_TEST_CASES += \ default_constructor \ default_ns \ default_ref \ + director_abstract \ director_basic \ director_exception \ director_finalizer \ diff --git a/Examples/test-suite/director_abstract.i b/Examples/test-suite/director_abstract.i new file mode 100644 index 000000000..bcdf4df24 --- /dev/null +++ b/Examples/test-suite/director_abstract.i @@ -0,0 +1,26 @@ +%module(directors="1") director_abstract +%{ +#include + +class Foo { +public: + virtual ~Foo() {} + virtual std::string ping() = 0; + virtual std::string pong() { return "Foo::pong();" + ping(); } +}; + +%} + +%include "typemaps.i" +%include "exception.i" +%include "std_string.i" + +%feature("director") Foo; + +class Foo { +public: + virtual ~Foo() {} + virtual std::string ping() = 0; + virtual std::string pong() { return "Foo::pong();" + ping(); } +}; + diff --git a/Examples/test-suite/python/director_abstract_runme.py b/Examples/test-suite/python/director_abstract_runme.py new file mode 100644 index 000000000..0c20fda23 --- /dev/null +++ b/Examples/test-suite/python/director_abstract_runme.py @@ -0,0 +1,16 @@ +import director_abstract + +class MyFoo(director_abstract.Foo): + def ping(self): + return "MyFoo::ping()" + + +a = MyFoo() + +if a.ping() != "MyFoo::ping()": + raise RuntimeError, a.ping() + +if a.pong() != "Foo::pong();MyFoo::ping()": + raise RuntimeError, a.pong() + + diff --git a/Lib/python/director.swg b/Lib/python/director.swg index 9f3e77192..7f7f1c5e6 100644 --- a/Lib/python/director.swg +++ b/Lib/python/director.swg @@ -53,6 +53,7 @@ class SWIG_DIRECTOR_PURE_VIRTUAL_EXCEPTION: public SWIG_DIRECTOR_EXCEPTION { }; #endif #endif + /* director base class */ class __DIRECTOR__ { private: @@ -171,6 +172,7 @@ public: }; +namespace { int __DIRECTOR__::_up = 0; #ifdef __PTHREAD__ @@ -179,6 +181,8 @@ int __DIRECTOR__::_up = 0; int __DIRECTOR__::_mutex_active = 0; #endif +} + #endif /* __cplusplus */ diff --git a/Lib/python/python.swg b/Lib/python/python.swg index 51d1fc163..7f8a47a6c 100644 --- a/Lib/python/python.swg +++ b/Lib/python/python.swg @@ -435,6 +435,7 @@ %typemap(inv,parse="d") double ""; %typemap(inv,parse="s") char* ""; %typemap(inv,parse="i") bool ""; +%typemap(inv,parse="i") enum SWIGTYPE ""; %typemap(inv,parse="l") unsigned int, unsigned short, unsigned long, unsigned char "(long) $1_name"; @@ -453,6 +454,7 @@ %typemap(inv, parse="O") PyObject* ""; +%typemap(inv, parse="l") std::size_t "(long) $input"; /* // this is rather dangerous %typemap(inv) SWIGTYPE { @@ -514,6 +516,7 @@ OUTV_TYPEMAP(double, PyFloat_AsDouble); OUTV_TYPEMAP(bool, PyInt_AsLong); OUTV_TYPEMAP(PyObject *, ); OUTV_TYPEMAP(char *, PyString_AsString); +OUTV_TYPEMAP(std::size_t, PyInt_AsLong); /* Object returned by value. Convert from a pointer */ %typemap(outv) SWIGTYPE ($<ype argp) diff --git a/Lib/python/std_complex.i b/Lib/python/std_complex.i index dc4920735..dc052f2dd 100644 --- a/Lib/python/std_complex.i +++ b/Lib/python/std_complex.i @@ -72,7 +72,7 @@ SwigComplex_AsComplexDouble(PyObject *o) } %typemap(inv) const complex & { - $inupt = PyComplex_FromDoubles($1_name->real(), $1_name->imag()); + $input = PyComplex_FromDoubles($1_name->real(), $1_name->imag()); } %typemap(outv) complex { diff --git a/Lib/python/std_vector.i b/Lib/python/std_vector.i index 3d16668de..3b0ee93f1 100644 --- a/Lib/python/std_vector.i +++ b/Lib/python/std_vector.i @@ -203,9 +203,9 @@ namespace std { } } %typemap(inv) vector { - $input = PyTuple_New($1.size()); - for (unsigned int i=0; i<$1.size(); i++) { - T* ptr = new T((($1_type &)$1)[i]); + $input = PyTuple_New($1_name.size()); + for (unsigned int i=0; i<$1_name.size(); i++) { + T* ptr = new T((($1_type &)$1_name)[i]); PyTuple_SetItem($input,i, SWIG_NewPointerObj((void *) ptr, $descriptor(T *), 1)); @@ -486,7 +486,7 @@ namespace std { %typemap(inv) vector { $input = PyTuple_New($1_name.size()); for (unsigned int i=0; i<$1_name.size(); i++) { - T ptr = (($1_type &)$1)[i]; + T ptr = (($1_type &)$1_name)[i]; PyTuple_SetItem($input,i, SWIG_NewPointerObj((void *) ptr, $descriptor(T), 0)); diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index c5762a9c7..4f2cf7e37 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -1640,6 +1640,8 @@ int Language::classDeclaration(Node *n) { int Language::classHandler(Node *n) { + bool hasDirector = Swig_directorclass(n); + /* Emit all of the class members */ emit_children(n); @@ -1659,7 +1661,7 @@ int Language::classHandler(Node *n) { if (!ImportMode && (GenerateDefault && !Getattr(n,"feature:nodefault"))) { if (!Getattr(n,"has_constructor") && !Getattr(n,"allocate:has_constructor") && (Getattr(n,"allocate:default_constructor"))) { /* Note: will need to change this to support different kinds of classes */ - if (!Abstract) { + if (!Abstract || hasDirector) { Setattr(CurrentClass,"feature:new","1"); constructorHandler(CurrentClass); Delattr(CurrentClass,"feature:new"); @@ -1671,7 +1673,7 @@ int Language::classHandler(Node *n) { } /* emit director disown method */ - if (Getattr(n, "vtable")) { + if (hasDirector) { classDirectorDisown(n); } diff --git a/Source/Swig/cwrap.c b/Source/Swig/cwrap.c index 8f0d0d568..255ec3514 100644 --- a/Source/Swig/cwrap.c +++ b/Source/Swig/cwrap.c @@ -650,24 +650,38 @@ Swig_ConstructorToFunction(Node *n, String *classname, if (cplus) { /* if a C++ director class exists, create it rather than the original class */ if (use_director) { + int abstract = Getattr(n, "abstract") != 0; Node *parent = Swig_methodclass(n); String *name = Getattr(parent, "sym:name"); String* directorname = NewStringf("__DIRECTOR__%s", name); String* action = NewString(""); String* tmp_none_comparison = Copy(none_comparison); + String* director_call; + String* nodirector_call; Replaceall( tmp_none_comparison, "$arg", "arg1" ); - /* if Python class has been subclassed, create a director instance. - * otherwise, just create a normal instance. - */ - /* arty: arg1 != Py_None => tmp_none_comparison */ - Printv(action, "if (",tmp_none_comparison,") {/* subclassed */\n", - Swig_cresult(type, "result", Swig_cppconstructor_director_call(directorname, parms)), - "} else {\n", - Swig_cresult(type, "result", Swig_cppconstructor_nodirector_call(classname, parms)), - "}\n", - NULL); + director_call = Swig_cppconstructor_director_call(directorname, parms); + nodirector_call = Swig_cppconstructor_nodirector_call(classname, parms); + if (abstract) { + /* whether or not the abstract class has been subclassed in python, + * create a director instance (there's no way to create a normal + * instance). if any of the pure virtual methods haven't been + * implemented in the target language, calls to those methods will + * generate SWIG_DIRECTOR_PURE_VIRTUAL exceptions. + */ + Printv(action, Swig_cresult(type, "result", director_call), NULL); + } else { + /* if the proxy class has been subclassed, create a director instance. + * otherwise, just create a normal instance. + */ + Printv(action, + "if (",tmp_none_comparison,") {/* subclassed */\n", + Swig_cresult(type, "result", director_call), + "} else {\n", + Swig_cresult(type, "result", nodirector_call), + "}\n", NULL); + } Setattr(n, "wrap:action", action); Delete(tmp_none_comparison); Delete(action);