From: William S F. <ws...@fu...> - 2006-01-13 22:38:18
|
RADESKI, Aleksandar, FM wrote: > I was wondering if it is possible to removed the smart pointer class from > the swigged API. I am swigging a C++ library for use in Java and C#. > > For example: > > class RefCounted { ... } > template <class T> class SmartPtr { ... } > > > class SomeClass : public RefCounted { ... } > typedef SomeClassPtr SmartPtr<SomeClass>; > > > void someFunction(SomeClassPtr obj) {...} > > If I swig this I can get a Java SomeClassPtr and a function that takes this > type. I was wondering if these was some generalised way to change this so > Java only sees SomeClass and someFunction(SomeClass obj), and all the smart > pointer stuff is done in the JNI code. > There is a thread about smart pointers and Java/C#, see http://thread.gmane.org/gmane.comp.programming.swig/7231. In that thread I see that there was an email that didn't make it onto the mailing list for some reason. It was an auto_ptr example that doesn't generate the extra proxy class, so in case you are using an auto_ptr type smart pointer, I've put the email contents below.... William ------- I've put together my auto_ptr typemaps into an example. Actually, I've only ever used out typemaps, so they are tried and tested, however, I've also put together the in typemaps too. They allow one to use the same proxy class for methods that take an auto_ptr, plain pointer, reference or passed by value. Note that the essential difference when wrapping a method that takes an auto_ptr and method that takes an plain pointer is the marshalling is done using getCAutoPtr() instead of the traditional getCPtr()... // proxy methods... public static int useFooAutoPtr(FooInt foo) { int ret = examplePINVOKE.useFooAutoPtr(FooInt.getCAutoPtr(foo)); return ret; } public static int useFoo(FooInt foo) { int ret = examplePINVOKE.useFoo(FooInt.getCPtr(foo)); return ret; } The example uses a templated class so you can see why the SWIG_AUTO_PTR_TYPEMAPS macro takes two types (C type and proxy classname). William /* File : example.i */ %module example /////////////////////////////////////////////////////////////////////////////////////////// // auto_ptr typemaps // The proxy class holds the raw pointer when an auto_ptr is returned from a method and // then manages memory like any other proxy class. // When a C++ method takes an auto_ptr as input, the memory ownership is handed to the method. // The same proxy class can be used for functions that return an object by auto_ptr, // raw pointer, by value or by reference. /////////////////////////////////////////////////////////////////////////////////////////// namespace std { template <class T> class auto_ptr {}; } %define SWIG_AUTO_PTR_TYPEMAPS(PROXYCLASS, TYPE...) #if defined(SWIGJAVA) %typemap (jni) std::auto_ptr<TYPE > "jlong" %typemap (jtype) std::auto_ptr<TYPE > "long" %typemap (jstype) std::auto_ptr<TYPE > "PROXYCLASS" %typemap (out) std::auto_ptr<TYPE > %{ jlong lpp = 0; *(TYPE**)(void *) &lpp = $1.release(); $result = lpp; %} %typemap(javaout) std::auto_ptr<TYPE > { long cPtr = $jnicall; return (cPtr == 0) ? null : new PROXYCLASS(cPtr, true); } %typemap(in) std::auto_ptr<TYPE > %{ $1 = std::auto_ptr<TYPE >(*(TYPE **)(void *)&$input); %} %typemap(javacode) TYPE %{ protected static long getCAutoPtr($javaclassname obj) { long ptr = 0; if (obj != null) { ptr = obj.swigCPtr; obj.swigCPtr = 0; obj.swigCMemOwn = false; } return ptr; } %} %typemap(javain) std::auto_ptr<TYPE > "PROXYCLASS.getCAutoPtr($javainput)" // The following in typemap is to ensure the proxy class gracefully throws exceptions if // the proxy is used after it has been passed to a method that takes an auto_ptr // Caveat: All methods that take a TYPE * must be non NULL. %typemap(in) TYPE * %{ $1 = *($&1_ltype)(void *)&$input; if(!$1) { SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "$1_type is NULL"); return $null; } %} #elif defined(SWIGCSHARP) %typemap (ctype) std::auto_ptr<TYPE > "void *" %typemap (imtype, out="IntPtr") std::auto_ptr<TYPE > "HandleRef" %typemap (cstype) std::auto_ptr<TYPE > "PROXYCLASS" %typemap (out) std::auto_ptr<TYPE > %{ $result = (void *)$1.release(); %} %typemap(csout, excode=SWIGEXCODE) std::auto_ptr<TYPE > { IntPtr cPtr = $imcall; PROXYCLASS ret = (cPtr == IntPtr.Zero) ? null : new PROXYCLASS(cPtr, true);$excode return ret; } // The following in typemap is to ensure the proxy class gracefully throws exceptions if // the proxy is used after it has been passed to a method that takes an auto_ptr // Caveat: All methods that take a TYPE * must be non NULL. %typemap(in) std::auto_ptr<TYPE > %{ $1 = std::auto_ptr<TYPE >((TYPE *)$input); %} %typemap(cscode) TYPE %{ internal static HandleRef getCAutoPtr($csclassname obj) { if (obj != null) { HandleRef ptr = obj.swigCPtr; obj.swigCPtr = new HandleRef(null, IntPtr.Zero); obj.swigCMemOwn = false; return ptr; } else { return new HandleRef(null, IntPtr.Zero); } } %} %typemap(csin) std::auto_ptr<TYPE > "PROXYCLASS.getCAutoPtr($csinput)" #endif %template() std::auto_ptr<TYPE >; %enddef /////////////////////////////////////////////////////////////////////////////////////////// // Example usage of wrapping auto_ptr /////////////////////////////////////////////////////////////////////////////////////////// SWIG_AUTO_PTR_TYPEMAPS(FooInt, Foo<int>) %inline %{ #include <memory> #include <iostream> template <typename T> struct Foo { T value; Foo(T v) : value(v) { std::cout << "Foo::Foo(" << v << ")" << std::endl; } ~Foo() { std::cout << "Foo::~Foo()" << std::endl; } }; std::auto_ptr<Foo<int> > createFoo(int value) { return std::auto_ptr<Foo<int> >(new Foo<int>(value)); } int useFooAutoPtr(std::auto_ptr<Foo<int> > foo) { return foo->value; } int useFoo(Foo<int> * foo) { return foo->value; } %} %template(FooInt) Foo<int>; // This example illustrates how the auto_ptr can be used from Java. public class main { static { try { System.loadLibrary("example"); } catch (UnsatisfiedLinkError e) { System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); System.exit(1); } } public static void main(String argv[]) { System.out.println("Starting"); FooInt f = example.createFoo(100); System.out.println(example.useFoo(f)); // raw pointer usage System.out.println(f.getValue()); System.out.println(example.useFooAutoPtr(f)); // auto_ptr usage // Will throw an exception if used -- move symantics of auto_ptr mean the pointer // shouldn't be used again after passing it to a function. try { int v = f.getValue(); throw new RuntimeException("should not get to here"); } catch (NullPointerException e) { // swallow exception } f.delete(); System.out.println("Finished"); } } // This example illustrates how the auto_ptr can be used from C#. using System; public class runme { static void Main() { Console.WriteLine("Starting"); FooInt f = example.createFoo(100); Console.WriteLine(example.useFoo(f)); // raw pointer usage Console.WriteLine(f.value); Console.WriteLine(example.useFooAutoPtr(f)); // auto_ptr usage try { int v = f.value; throw new Exception("should not get to here"); } catch (NullReferenceException) { } f.Dispose(); Console.WriteLine("Finished"); } } |