diff --git a/Examples/python/index.html b/Examples/python/index.html index 68b0bdfa1..ade5ea426 100644 --- a/Examples/python/index.html +++ b/Examples/python/index.html @@ -19,6 +19,7 @@ certain C declarations are turned into constants.
  • variables. An example showing how to access C global variables from Python.
  • value. How to pass and return structures by value.
  • class. Wrapping a simple C++ class. +
  • reference. C++ references.

    Compilation Issues

    diff --git a/Examples/python/reference/Makefile b/Examples/python/reference/Makefile new file mode 100644 index 000000000..71af176f9 --- /dev/null +++ b/Examples/python/reference/Makefile @@ -0,0 +1,19 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' python_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='mypython' INTERFACE='$(INTERFACE)' python_cpp_static + +clean:: + rm -f *_wrap* *.o *~ *.so mypython *.pyc .~* core + +check: all diff --git a/Examples/python/reference/example.cxx b/Examples/python/reference/example.cxx new file mode 100644 index 000000000..384e40bb7 --- /dev/null +++ b/Examples/python/reference/example.cxx @@ -0,0 +1,41 @@ +/* File : example.cxx */ + +#include "example.h" +#include +#include + +Vector operator+(const Vector &a, const Vector &b) { + Vector r; + r.x = a.x + b.x; + r.y = a.y + b.y; + r.z = a.z + b.z; + return r; +} + +char *Vector::print() { + static char temp[512]; + sprintf(temp,"Vector %x (%g,%g,%g)", this, x,y,z); + return temp; +} + +VectorArray::VectorArray(int size) { + items = new Vector[size]; + maxsize = size; +} + +VectorArray::~VectorArray() { + delete [] items; +} + +Vector &VectorArray::operator[](int index) { + if ((index < 0) || (index >= maxsize)) { + printf("Panic! Array index out of bounds.\n"); + exit(1); + } + return items[index]; +} + +int VectorArray::size() { + return maxsize; +} + diff --git a/Examples/python/reference/example.h b/Examples/python/reference/example.h new file mode 100644 index 000000000..4915adb1b --- /dev/null +++ b/Examples/python/reference/example.h @@ -0,0 +1,26 @@ +/* File : example.h */ + +class Vector { +private: + double x,y,z; +public: + Vector() : x(0), y(0), z(0) { }; + Vector(double x, double y, double z) : x(x), y(y), z(z) { }; + friend Vector operator+(const Vector &a, const Vector &b); + char *print(); +}; + +class VectorArray { +private: + Vector *items; + int maxsize; +public: + VectorArray(int maxsize); + ~VectorArray(); + Vector &operator[](int); + int size(); +}; + + + + diff --git a/Examples/python/reference/example.i b/Examples/python/reference/example.i new file mode 100644 index 000000000..8538326f6 --- /dev/null +++ b/Examples/python/reference/example.i @@ -0,0 +1,46 @@ +/* File : example.i */ + +/* This file has a few "typical" uses of C++ references. */ + +%module example + +%{ +#include "example.h" +%} + +class Vector { +public: + Vector(double x, double y, double z); + ~Vector(); + char *print(); +}; + +/* This helper function calls an overloaded operator */ +%inline %{ +Vector addv(Vector &a, Vector &b) { + return a+b; +} +%} + +/* Wrapper around an array of vectors class */ + +class VectorArray { +public: + VectorArray(int maxsize); + ~VectorArray(); + int size(); + + /* This wrapper provides an alternative to the [] operator */ + %addmethods { + Vector &get(int index) { + return (*self)[index]; + } + void set(int index, Vector &a) { + (*self)[index] = a; + } + } +}; + + + + diff --git a/Examples/python/reference/example.py b/Examples/python/reference/example.py new file mode 100644 index 000000000..dae49f181 --- /dev/null +++ b/Examples/python/reference/example.py @@ -0,0 +1,72 @@ +# file: example.py + +# This file illustrates the manipulation of C++ references in Python +# This uses the low-level interface. Shadow classes work differently. + +import example + +# ----- Object creation ----- + +print "Creating some objects:" +a = example.new_Vector(3,4,5) +b = example.new_Vector(10,11,12) + +print " Created",example.Vector_print(a) +print " Created",example.Vector_print(b) + +# ----- Call an overloaded operator ----- + +# This calls the wrapper we placed around +# +# operator+(const Vector &a, const Vector &) +# +# It returns a new allocated object. + +print "Adding a+b" +c = example.addv(a,b) +print " a+b =", example.Vector_print(c) + +# Note: Unless we free the result, a memory leak will occur +example.delete_Vector(c) + +# ----- Create a vector array ----- + +# Note: Using the high-level interface here +print "Creating an array of vectors" +va = example.new_VectorArray(10) +print " va = ",va + +# ----- Set some values in the array ----- + +# These operators copy the value of $a and $b to the vector array +example.VectorArray_set(va,0,a) +example.VectorArray_set(va,1,b) + +# This will work, but it will cause a memory leak! + +example.VectorArray_set(va,2,example.addv(a,b)) + +# The non-leaky way to do it + +c = example.addv(a,b) +example.VectorArray_set(va,3,c) +example.delete_Vector(c) + +# Get some values from the array + +print "Getting some array values" +for i in range(0,5): + print " va(%d) = %s" % (i, example.Vector_print(example.VectorArray_get(va,i))) + +# Watch under resource meter to check on this +print "Making sure we don't leak memory." +for i in xrange(0,1000000): + c = example.VectorArray_get(va,i % 10) + +# ----- Clean up ----- +print "Cleaning up" + +example.delete_VectorArray(va) +example.delete_Vector(a) +example.delete_Vector(b) + diff --git a/Examples/python/reference/index.html b/Examples/python/reference/index.html new file mode 100644 index 000000000..82eaa3638 --- /dev/null +++ b/Examples/python/reference/index.html @@ -0,0 +1,149 @@ + + +SWIG:Examples:python:reference + + + + + +SWIG/Examples/python/reference/ +
    + +

    C++ Reference Handling

    + +$Header$
    + +

    +This example tests SWIG's handling of C++ references. Since C++ +references are closely related to pointers (as both refer to a +location in memory), SWIG simply collapses all references into +pointers when creating wrappers. + +

    Some examples

    + +References are most commonly used as function parameter. For example, +you might have an operator like this: + +
    +
    +Vector operator+(const Vector &a, const Vector &b) {
    +   Vector result;
    +   result.x = a.x + b.x;
    +   result.y = a.y + b.y;
    +   result.z = a.z + b.z;
    +   return result;
    +}
    +
    +
    + +or a function: + +
    +
    +Vector addv(const Vector &a, const Vector &b) {
    +   Vector result;
    +   result.x = a.x + b.x;
    +   result.y = a.y + b.y;
    +   result.z = a.z + b.z;
    +   return result;
    +}
    +
    +
    + +In these cases, SWIG transforms everything into a pointer and creates a wrapper +that looks like this: + +
    +
    +Vector wrap_addv(Vector *a, Vector *b) {
    +    return addv(*a,*b);
    +}
    +
    +
    + +Occasionally, a reference is used as a return value of a function +when the return result is to be used as an lvalue in an expression. +The prototypical example is an operator like this: + +
    +
    +Vector &operator[](int index);
    +
    +
    + +or a method: + +
    +
    +Vector &get(int index);
    +
    +
    + +For functions returning references, a wrapper like this is created: + +
    +
    +Vector *wrap_Object_get(Object *self, int index) {
    +    Vector &result = self->get(index);
    +    return &result;
    +}
    +
    +
    + +The following header file contains some class +definitions with some operators and use of references. + +

    SWIG Interface

    + +SWIG does NOT support overloaded operators so it can not directly build +an interface to the classes in the above file. However, a number of workarounds +can be made. For example, an overloaded operator can be stuck behind a function +call such as the addv() function above. Array access can be handled +with a pair of set/get functions like this: + +
    +
    +class VectorArray {
    +public:
    + ...
    +   %addmethods {
    +    Vector &get(int index) {
    +      return (*self)[index];
    +    }
    +    void set(int index, Vector &a) {
    +      (*self)[index] = a;
    +    }
    +   }
    +   ...
    +}
    +
    +
    + +Click here to see a SWIG interface file with these additions. + +

    Sample Python script

    + +Click here to see a script that manipulates some C++ references. + +

    Notes:

    + +
      +
    • C++ references primarily provide notational convenience for C++ +source code. However, Python only supports the 'x.a' +notation so it doesn't much matter. + +

      +

    • When a program returns a reference, a pointer is returned. +Unlike return by value, memory is not allocated to hold the +return result. + +

      +

    • SWIG has particular trouble handling various combinations of references +and pointers. This is side effect of an old parsing scheme and +type representation that will be replaced in future versions. + +
    + +
    + +