diff --git a/SWIG/Examples/python/callback/Makefile b/SWIG/Examples/python/callback/Makefile new file mode 100644 index 000000000..2906b3d74 --- /dev/null +++ b/SWIG/Examples/python/callback/Makefile @@ -0,0 +1,22 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm +SWIGOPT = +SWIGLIB = SWIG_LIB=/b/mrose/projects/swig/SWIG/Lib + +all:: + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' python_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='mypython' INTERFACE='$(INTERFACE)' python_cpp_static + +clean:: + $(MAKE) -f $(TOP)/Makefile python_clean + rm -f $(TARGET).py + +check: all diff --git a/SWIG/Examples/python/callback/example.cxx b/SWIG/Examples/python/callback/example.cxx new file mode 100644 index 000000000..450d75608 --- /dev/null +++ b/SWIG/Examples/python/callback/example.cxx @@ -0,0 +1,4 @@ +/* File : example.cxx */ + +#include "example.h" + diff --git a/SWIG/Examples/python/callback/example.h b/SWIG/Examples/python/callback/example.h new file mode 100644 index 000000000..261d49c62 --- /dev/null +++ b/SWIG/Examples/python/callback/example.h @@ -0,0 +1,23 @@ +/* File : example.h */ + +#include +#include + +class Callback { +public: + virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; } + virtual void run() { std::cout << "Callback::run()" << std::endl; } +}; + + +class Caller { +private: + Callback *_callback; +public: + Caller(): _callback(0) {} + ~Caller() { delCallback(); } + void delCallback() { if (_callback) delete _callback; _callback = 0; } + void setCallback(Callback *cb) { delCallback(); _callback = cb; } + void call() { if (_callback) _callback->run(); } +}; + diff --git a/SWIG/Examples/python/callback/example.i b/SWIG/Examples/python/callback/example.i new file mode 100644 index 000000000..2e5a657ab --- /dev/null +++ b/SWIG/Examples/python/callback/example.i @@ -0,0 +1,15 @@ +/* File : example.i */ +%module(directors="1") example +%{ +#include "example.h" +%} + +%include "typemaps.i" +%include "std_vector.i" +%include "std_string.i" + +/* turn on director wrapping Callback */ +%feature("director") Callback; + +%include "example.h" + diff --git a/SWIG/Examples/python/callback/index.html b/SWIG/Examples/python/callback/index.html new file mode 100644 index 000000000..34fe4d127 --- /dev/null +++ b/SWIG/Examples/python/callback/index.html @@ -0,0 +1,21 @@ + + +SWIG:Examples:python:callback + + + + + +SWIG/Examples/python/extend/ +
+ +

Implementing C++ callbacks in Python

+ +$Header$
+ +

+This example illustrates how to use directors to implement C++ callbacks in Python. + +


+ + diff --git a/SWIG/Examples/python/callback/runme.py b/SWIG/Examples/python/callback/runme.py new file mode 100644 index 000000000..5240973c2 --- /dev/null +++ b/SWIG/Examples/python/callback/runme.py @@ -0,0 +1,66 @@ +# file: runme.py + +# This file illustrates the cross language polymorphism using directors. + +import example + + +# CEO class, which overrides Employee::getPosition(). + +class PyCallback(example.Callback): + def __init__(self): + example.Callback.__init__(self) + def run(self): + print "PyCallback.run()" + def __del__(self): + print "PyCallback.__del__()" + # for shadow class extensions that are not "disowned" and + # define a __del__ method, it is very important to call the + # base class __del__. otherwise the c++ objects will never + # be deleted. + example.Callback.__del__(self) + + +# Create an Caller instance + +caller = example.Caller() + +# Add a simple C++ callback (caller owns the callback, so +# we disown it first by clearing the .thisown flag). + +print "Adding and calling a normal C++ callback" +print "----------------------------------------" + +callback = example.Callback() +callback.thisown = 0 +caller.setCallback(callback) +caller.call() +caller.delCallback(); + +print +print "Adding and calling a Python callback" +print "------------------------------------" + +# Add a Python callback (caller owns the callback, so we +# disown it first by calling __disown__). + +caller.setCallback(PyCallback().__disown__()) +caller.call() +caller.delCallback() + +print +print "Adding and calling another Python callback" +print "------------------------------------------" + +# Lets do the same but use the weak reference this time. + +callback = PyCallback().__disown__() +caller.setCallback(callback) +caller.call() +caller.delCallback() + +# All done. + +print +print "python exit" + diff --git a/SWIG/Examples/python/check.list b/SWIG/Examples/python/check.list index 9577bf9b3..f00dad1e2 100644 --- a/SWIG/Examples/python/check.list +++ b/SWIG/Examples/python/check.list @@ -1,8 +1,10 @@ # see top-level Makefile.in +callback class constants enum exceptshadow +extend funcattr funcptr funcptr2 diff --git a/SWIG/Examples/python/extend/Makefile b/SWIG/Examples/python/extend/Makefile new file mode 100644 index 000000000..2906b3d74 --- /dev/null +++ b/SWIG/Examples/python/extend/Makefile @@ -0,0 +1,22 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm +SWIGOPT = +SWIGLIB = SWIG_LIB=/b/mrose/projects/swig/SWIG/Lib + +all:: + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' python_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='mypython' INTERFACE='$(INTERFACE)' python_cpp_static + +clean:: + $(MAKE) -f $(TOP)/Makefile python_clean + rm -f $(TARGET).py + +check: all diff --git a/SWIG/Examples/python/extend/example.cxx b/SWIG/Examples/python/extend/example.cxx new file mode 100644 index 000000000..77a6c743d --- /dev/null +++ b/SWIG/Examples/python/extend/example.cxx @@ -0,0 +1,4 @@ +/* File : example.c */ + +#include "example.h" + diff --git a/SWIG/Examples/python/extend/example.h b/SWIG/Examples/python/extend/example.h new file mode 100644 index 000000000..b27ab9711 --- /dev/null +++ b/SWIG/Examples/python/extend/example.h @@ -0,0 +1,56 @@ +/* File : example.h */ + +#include +#include +#include +#include +#include + +class Employee { +private: + std::string name; +public: + Employee(const char* n): name(n) {} + virtual std::string getTitle() { return getPosition() + " " + getName(); } + virtual std::string getName() { return name; } + virtual std::string getPosition() const { return "Employee"; } + virtual ~Employee() { printf("~Employee() @ %p\n", this); } +}; + + +class Manager: public Employee { +public: + Manager(const char* n): Employee(n) {} + virtual std::string getPosition() const { return "Manager"; } +}; + + +class EmployeeList { + std::vector list; +public: + EmployeeList() { + list.push_back(new Employee("Bob")); + list.push_back(new Employee("Jane")); + list.push_back(new Manager("Ted")); + } + void addEmployee(Employee *p) { + list.push_back(p); + std::cout << "New employee added. Current employees are:" << std::endl; + std::vector::iterator i; + for (i=list.begin(); i!=list.end(); i++) { + std::cout << " " << (*i)->getTitle() << std::endl; + } + } + const Employee *get_item(int i) { + return list[i]; + } + ~EmployeeList() { + std::vector::iterator i; + std::cout << "~EmployeeList, deleting " << list.size() << " employees." << std::endl; + for (i=list.begin(); i!=list.end(); i++) { + delete *i; + } + std::cout << "~EmployeeList empty." << std::endl; + } +}; + diff --git a/SWIG/Examples/python/extend/example.i b/SWIG/Examples/python/extend/example.i new file mode 100644 index 000000000..c83709948 --- /dev/null +++ b/SWIG/Examples/python/extend/example.i @@ -0,0 +1,16 @@ +/* File : example.i */ +%module(directors="1") example +%{ +#include "example.h" +%} + +%include "typemaps.i" +%include "std_vector.i" +%include "std_string.i" + +/* turn on director wrapping for Manager */ +%feature("director") Employee; +%feature("director") Manager; + +%include "example.h" + diff --git a/SWIG/Examples/python/extend/index.html b/SWIG/Examples/python/extend/index.html new file mode 100644 index 000000000..fe1bf9a1a --- /dev/null +++ b/SWIG/Examples/python/extend/index.html @@ -0,0 +1,21 @@ + + +SWIG:Examples:python:extend + + + + + +SWIG/Examples/python/extend/ +
+ +

Extending a simple C++ class in Python

+ +$Header$
+ +

+This example illustrates the extending of a C++ class with cross language polymorphism. + +


+ + diff --git a/SWIG/Examples/python/extend/runme.py b/SWIG/Examples/python/extend/runme.py new file mode 100644 index 000000000..97fad2de8 --- /dev/null +++ b/SWIG/Examples/python/extend/runme.py @@ -0,0 +1,88 @@ +# file: runme.py + +# This file illustrates the cross language polymorphism using directors. + +import example + + +# CEO class, which overrides Employee::getPosition(). + +class CEO(example.Manager): + def __init__(self, name): + example.Manager.__init__(self, name) + def getPosition(self): + return "CEO" + def __del__(self): + print "CEO.__del__(),", self.getName() + # for shadow class extensions that are not "disowned" and + # define a __del__ method, it is very important to call the + # base class __del__. otherwise the c++ objects will never + # be deleted. + example.Manager.__del__(self) + + +# Create an instance of our employee extension class, CEO. The calls to +# getName() and getPosition() are standard, the call to getTitle() uses +# the director wrappers to call CEO.getPosition. e = CEO("Alice") + +e = CEO("Alice") +print e.getName(), "is a", e.getPosition() +print "Just call her \"%s\"" % e.getTitle() +print "----------------------" + + +# Create a new EmployeeList instance. This class does not have a C++ +# director wrapper, but can be used freely with other classes that do. + +list = example.EmployeeList() + +# EmployeeList owns its items, so we must surrender ownership of objects +# we add. This involves first calling the __disown__ method to tell the +# C++ director to start reference counting. We reassign the resulting +# weakref.proxy to e so that no hard references remain. This can also be +# done when the object is constructed, as in: e = +# CEO("Alice").__disown__() + +e = e.__disown__() +list.addEmployee(e) +print "----------------------" + +# Now we access the first four items in list (three are C++ objects that +# EmployeeList's constructor adds, the last is our CEO). The virtual +# methods of all these instances are treated the same. For items 0, 1, and +# 2, both all methods resolve in C++. For item 3, our CEO, getTitle calls +# getPosition which resolves in Python. The call to getPosition is +# slightly different, however, from the e.getPosition() call above, since +# now the object reference has been "laundered" by passing through +# EmployeeList as an Employee*. Previously, Python resolved the call +# immediately in CEO, but now Python thinks the object is an instance of +# class Employee (actually EmployeePtr). So the call passes through the +# Employee shadow class and on to the C wrappers and C++ director, +# eventually ending up back at the CEO implementation of getPosition(). +# The call to getTitle() for item 3 runs the C++ Employee::getTitle() +# method, which in turn calls getPosition(). This virtual method call +# passes down through the C++ director class to the Python implementation +# in CEO. All this routing takes place transparently. + +print "(position, title) for items 0-3:" + +print " %s, \"%s\"" % (list.get_item(0).getPosition(), list.get_item(0).getTitle()) +print " %s, \"%s\"" % (list.get_item(1).getPosition(), list.get_item(1).getTitle()) +print " %s, \"%s\"" % (list.get_item(2).getPosition(), list.get_item(2).getTitle()) +print " %s, \"%s\"" % (list.get_item(3).getPosition(), list.get_item(3).getTitle()) +print "----------------------" + +# Time to delete the EmployeeList, which will delete all the Employee* +# items it contains. The last item is our CEO, which gets destroyed as its +# reference count goes to zero. The Python destructor runs, and is still +# able to call self.getName() since the underlying C++ object still +# exists. After this destructor runs the remaining C++ destructors run as +# usual to destroy the object. + +del list +print "----------------------" + +# All done. + +print "python exit" +