diff --git a/CHANGES.current b/CHANGES.current index 977fea758..72833c7a2 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,14 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-07-19: wsfulton + #692 [C#, Java, Perl, Python, Ruby] std::unique_ptr and std::auto_ptr typemaps + provided for inputs types in std_unique_ptr.i and std_auto_ptr.i. + + Now these smart pointers can be used as input parameters to functions. A proxy + class instance transfers memory ownership of the underlying C++ object from the + proxy class to a smart pointer instance passed to the wrapped function. + 2022-07-19: jschueller [Python] #2314 Drop support for Python 3.2. diff --git a/Doc/Manual/Library.html b/Doc/Manual/Library.html index b18ecc957..7dc649c16 100644 --- a/Doc/Manual/Library.html +++ b/Doc/Manual/Library.html @@ -2055,13 +2055,9 @@ equivalent %shared_ptr(T) macro covered in the previous section.

-Note that the support provided is limited to returning this smart pointer from a function. -Any other use of std::auto_ptr is not directly provided yet. +Example usage of a std::unique_ptr being returned from a function is shown below.

-

-Example usage would be -

 %include <std_unique_ptr.i>
@@ -2113,12 +2109,67 @@ Note that the implementation is quite different to the std::shared_ptr
 where the proxy class manages the underlying C++ memory as a pointer to a shared_ptr instead of a plain raw pointer.
 

+

+A possibly less common usage of this smart pointer is as a parameter to a function. +When used like this it indicates that memory usage of the object pointed to by the underlying pointer +is transferred to the function being called. +The code that SWIG generates assumes this happens. +First, it is assumed that a proxy class already owns the underlying C++ object and is used to pass the object to the C++ function being called. +Second, the ownership is transferred from the proxy class to the C++ function being called and +lifetime is then controlled by the function. +Finally, it is assumed the lifetime of the object may not last beyond returning from the C++ function +and hence the proxy class can no longer be used. +

+ +

+Consider expanding the example above with a function that takes a std::unique_ptr as follows: +

+ +
+
+void take(std::unique_ptr);
+
+
+ +

+and use from C#: +

+ +
+
+Klass k = Klass.Create(17); // create an instance of Klass any way you like
+int value = k.getValue();   // ok
+example.take(k);            // memory ownership passes from C# layer to C++ layer
+int v = k.getValue();       // don't do this - invalid use of k
+
+
+ +

+Attempts to use k after the ownership has been passed into the take function +should not be attempted. +The implementation sets the proxy class to an invalid state by setting the class's underlying +C++ pointer to null after the return from the take function. +Subsequent use of an invalid proxy class instance is very much dependent on the implementation +in the target language and ranges from a segfault to giving a nice error. +Consider implementing additional checks via the 'check' typemap. +

+ +

+Attempts to pass ownership from a proxy class to a std::unique parameter more than once will result +in a "Cannot release ownership as memory is not owned" exception. For example, if example.take(k) in the example above is called twice. +

+ +

+Compatibility note: Support for std::unique_ptr was added in SWIG-4.1.0. +

+

12.4.6 auto_ptr smart pointer

While std::auto_ptr is deprecated in C++11, some existing code may -still be using it, so SWIG provides limited support for this class by some target languages. +still be using it. SWIG provides support for this class which is nearly identical +to std::unique_ptr.

@@ -2133,13 +2184,9 @@ the previous two sections.

-Note that the support provided is limited to returning this smart pointer from a function. -Any other use of std::auto_ptr is not directly provided. +Example usage of a std::auto_ptr being returned from a function is shown below.

-

-Example usage would be -

 %include <std_auto_ptr.i>
@@ -2181,6 +2228,10 @@ The implementation simply calls std::auto_ptr::release() to obtain the
 That is, it works the same way covered in the previous section for std::unique_ptr.
 

+

+Input parameters also work the same way as std::unique_ptr covered in the previous section. +

+

12.5 Utility Libraries

diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index c654807d7..b4633e3f6 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -610,6 +610,7 @@ CPP11_TEST_CASES += \ cpp11_rvalue_reference \ cpp11_rvalue_reference2 \ cpp11_rvalue_reference3 \ + cpp11_rvalue_reference_move_input \ cpp11_sizeof_object \ cpp11_static_assert \ cpp11_std_array \ diff --git a/Examples/test-suite/cpp11_rvalue_reference_move_input.i b/Examples/test-suite/cpp11_rvalue_reference_move_input.i new file mode 100644 index 000000000..03abd7322 --- /dev/null +++ b/Examples/test-suite/cpp11_rvalue_reference_move_input.i @@ -0,0 +1,41 @@ +%module cpp11_rvalue_reference_move_input + +// Testcase for testing rvalue reference input typemaps which assume the object is moved during a function call + +#if defined(SWIGD) +%rename(trace) debug; +#endif + +%include "cpp11_move_only_helper.i" + +%rename(MoveAssign) MovableCopyable::operator=(MovableCopyable &&); +%ignore MovableCopyable::operator=(const MovableCopyable &); // ignore copy assignment operator, keep move assignment operator +%ignore MovableCopyable::MovableCopyable(const MovableCopyable &); // ignore copy constructor, keep the move constructor + +%inline %{ +#include +using namespace std; + +bool debug = false; + +class MovableCopyable { +public: + MovableCopyable(int i = 0) { if (debug) cout << "MovableCopyable(" << i << ")" << " " << this << endl; Counter::normal_constructor++; } + + MovableCopyable(const MovableCopyable &other) { if (debug) cout << "MovableCopyable(const MovableCopyable &)" << " " << this << " " << &other << endl; Counter::copy_constructor++;} + MovableCopyable & operator=(const MovableCopyable &other) { if (debug) cout << "operator=(const MovableCopyable &)" << " " << this << " " << &other << endl; Counter::copy_assignment++; return *this; } + + MovableCopyable(MovableCopyable &&other) noexcept { if (debug) cout << "MovableCopyable(MovableCopyable &&)" << " " << this << endl; Counter::move_constructor++; } + MovableCopyable & operator=(MovableCopyable &&other) noexcept { if (debug) cout << "operator=(MovableCopyable &&)" << " " << this << endl; Counter::move_assignment++; return *this; } + ~MovableCopyable() { if (debug) cout << "~MovableCopyable()" << " " << this << endl; Counter::destructor++; } + + static void movein(MovableCopyable &&mcin) { + MovableCopyable mc = std::move(mcin); + } + + static bool is_nullptr(MovableCopyable *p) { + return p == nullptr; + } +}; + +%} diff --git a/Examples/test-suite/cpp11_std_unique_ptr.i b/Examples/test-suite/cpp11_std_unique_ptr.i index 9bd65b97f..ec7505974 100644 --- a/Examples/test-suite/cpp11_std_unique_ptr.i +++ b/Examples/test-suite/cpp11_std_unique_ptr.i @@ -2,6 +2,7 @@ #if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) +%include "std_string.i" %include "std_unique_ptr.i" %unique_ptr(Klass) @@ -22,7 +23,7 @@ public: const char* getLabel() const { return m_label.c_str(); } - ~Klass() + virtual ~Klass() { SwigExamples::Lock lock(critical_section); total_count--; @@ -44,6 +45,26 @@ int Klass::total_count = 0; %inline %{ +// Virtual inheritance used as this usually results in different values for Klass* and KlassInheritance* +// for testing class inheritance and unique_ptr +struct KlassInheritance : virtual Klass { + KlassInheritance(const char* label) : Klass(label) { + // std::cout << "ptrs.... " << std::hex << (Klass*)this << " " << (KlassInheritance*)this << std::endl; + } +}; + +std::string takeKlassUniquePtr(std::unique_ptr k) { + return std::string(k->getLabel()); +} + +bool is_nullptr(Klass *p) { + return p == nullptr; +} + +Klass *get_not_owned_ptr(Klass *p) { + return p; +} + std::unique_ptr makeKlassUniquePtr(const char* label) { return std::unique_ptr(new Klass(label)); } diff --git a/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs b/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs index db5c8cff0..09c6ec0af 100644 --- a/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs +++ b/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs @@ -9,8 +9,75 @@ public class cpp11_std_unique_ptr_runme { System.Threading.Thread.Sleep(10); } + private static void checkCount(int expected_count) + { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new ApplicationException("Counts incorrect, expected:" + expected_count + " actual:" + actual_count); + } + public static void Main() { + // unique_ptr as input + using (Klass kin = new Klass("KlassInput")) { + checkCount(1); + string s = cpp11_std_unique_ptr.takeKlassUniquePtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new ApplicationException("Incorrect string: " + s); + if (!cpp11_std_unique_ptr.is_nullptr(kin)) + throw new ApplicationException("is_nullptr failed"); + } // Dispose should not fail, even though already deleted + checkCount(0); + + using (Klass kin = new Klass("KlassInput")) { + checkCount(1); + string s = cpp11_std_unique_ptr.takeKlassUniquePtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new ApplicationException("Incorrect string: " + s); + if (!cpp11_std_unique_ptr.is_nullptr(kin)) + throw new ApplicationException("is_nullptr failed"); + bool exception_thrown = false; + try { + cpp11_std_unique_ptr.takeKlassUniquePtr(kin); + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new ApplicationException("double usage of takeKlassUniquePtr should have been an error"); + } // Dispose should not fail, even though already deleted + checkCount(0); + + using (Klass kin = new Klass("KlassInput")) { + bool exception_thrown = false; + try { + Klass notowned = cpp11_std_unique_ptr.get_not_owned_ptr(kin); + cpp11_std_unique_ptr.takeKlassUniquePtr(notowned); + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new ApplicationException("Should have thrown 'Cannot release ownership as memory is not owned' error"); + } + checkCount(0); + + using (KlassInheritance kini = new KlassInheritance("KlassInheritanceInput")) { + checkCount(1); + string s = cpp11_std_unique_ptr.takeKlassUniquePtr(kini); + checkCount(0); + if (s != "KlassInheritanceInput") + throw new ApplicationException("Incorrect string: " + s); + if (!cpp11_std_unique_ptr.is_nullptr(kini)) + throw new ApplicationException("is_nullptr failed"); + } // Dispose should not fail, even though already deleted + checkCount(0); + + // unique_ptr as output Klass k1 = cpp11_std_unique_ptr.makeKlassUniquePtr("first"); if (k1.getLabel() != "first") throw new Exception("wrong object label"); diff --git a/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs b/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs index 863b86701..b5ff1fd29 100644 --- a/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs +++ b/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs @@ -9,8 +9,75 @@ public class li_std_auto_ptr_runme { System.Threading.Thread.Sleep(10); } + private static void checkCount(int expected_count) + { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new ApplicationException("Counts incorrect, expected:" + expected_count + " actual:" + actual_count); + } + public static void Main() { + // auto_ptr as input + using (Klass kin = new Klass("KlassInput")) { + checkCount(1); + string s = li_std_auto_ptr.takeKlassAutoPtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new ApplicationException("Incorrect string: " + s); + if (!li_std_auto_ptr.is_nullptr(kin)) + throw new ApplicationException("is_nullptr failed"); + } // Dispose should not fail, even though already deleted + checkCount(0); + + using (Klass kin = new Klass("KlassInput")) { + checkCount(1); + string s = li_std_auto_ptr.takeKlassAutoPtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new ApplicationException("Incorrect string: " + s); + if (!li_std_auto_ptr.is_nullptr(kin)) + throw new ApplicationException("is_nullptr failed"); + bool exception_thrown = false; + try { + li_std_auto_ptr.takeKlassAutoPtr(kin); + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new ApplicationException("double usage of takeKlassAutoPtr should have been an error"); + } // Dispose should not fail, even though already deleted + checkCount(0); + + using (Klass kin = new Klass("KlassInput")) { + bool exception_thrown = false; + try { + Klass notowned = li_std_auto_ptr.get_not_owned_ptr(kin); + li_std_auto_ptr.takeKlassAutoPtr(notowned); + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new ApplicationException("Should have thrown 'Cannot release ownership as memory is not owned' error"); + } + checkCount(0); + + using (KlassInheritance kini = new KlassInheritance("KlassInheritanceInput")) { + checkCount(1); + string s = li_std_auto_ptr.takeKlassAutoPtr(kini); + checkCount(0); + if (s != "KlassInheritanceInput") + throw new ApplicationException("Incorrect string: " + s); + if (!li_std_auto_ptr.is_nullptr(kini)) + throw new ApplicationException("is_nullptr failed"); + } // Dispose should not fail, even though already deleted + checkCount(0); + + // auto_ptr as output Klass k1 = li_std_auto_ptr.makeKlassAutoPtr("first"); if (k1.getLabel() != "first") throw new Exception("wrong object label"); diff --git a/Examples/test-suite/java/cpp11_rvalue_reference_move_input_runme.java b/Examples/test-suite/java/cpp11_rvalue_reference_move_input_runme.java new file mode 100644 index 000000000..dfc09f217 --- /dev/null +++ b/Examples/test-suite/java/cpp11_rvalue_reference_move_input_runme.java @@ -0,0 +1,60 @@ + +import cpp11_rvalue_reference_move_input.*; + +public class cpp11_rvalue_reference_move_input_runme { + + static { + try { + System.loadLibrary("cpp11_rvalue_reference_move_input"); + } 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[]) { + + { + Counter.reset_counts(); + MovableCopyable mo = new MovableCopyable(222); + Counter.check_counts(1, 0, 0, 0, 0, 0); + MovableCopyable.movein(mo); + Counter.check_counts(1, 0, 0, 1, 0, 2); + if (!MovableCopyable.is_nullptr(mo)) + throw new RuntimeException("is_nullptr failed"); + mo.delete(); + Counter.check_counts(1, 0, 0, 1, 0, 2); + } + + { + // Move constructor test + Counter.reset_counts(); + MovableCopyable mo = new MovableCopyable(222); + Counter.check_counts(1, 0, 0, 0, 0, 0); + MovableCopyable mo_moved = new MovableCopyable(mo); + Counter.check_counts(1, 0, 0, 1, 0, 1); + if (!MovableCopyable.is_nullptr(mo)) + throw new RuntimeException("is_nullptr failed"); + mo.delete(); + Counter.check_counts(1, 0, 0, 1, 0, 1); + mo_moved.delete(); + Counter.check_counts(1, 0, 0, 1, 0, 2); + } + + { + // Move assignment operator test + Counter.reset_counts(); + MovableCopyable mo111 = new MovableCopyable(111); + MovableCopyable mo222 = new MovableCopyable(222); + Counter.check_counts(2, 0, 0, 0, 0, 0); + mo111.MoveAssign(mo222); + Counter.check_counts(2, 0, 0, 0, 1, 1); + if (!MovableCopyable.is_nullptr(mo222)) + throw new RuntimeException("is_nullptr failed"); + mo222.delete(); + Counter.check_counts(2, 0, 0, 0, 1, 1); + mo111.delete(); + Counter.check_counts(2, 0, 0, 0, 1, 2); + } + } +} diff --git a/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java b/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java index a734b0e5e..36a9c03fc 100644 --- a/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java +++ b/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java @@ -20,8 +20,82 @@ public class cpp11_std_unique_ptr_runme { } } + private static void checkCount(int expected_count) { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new RuntimeException("Counts incorrect, expected:" + expected_count + " actual:" + actual_count); + } + public static void main(String argv[]) throws Throwable { + // unique_ptr as input + { + Klass kin = new Klass("KlassInput"); + checkCount(1); + String s = cpp11_std_unique_ptr.takeKlassUniquePtr(kin); + checkCount(0); + if (!s.equals("KlassInput")) + throw new RuntimeException("Incorrect string: " + s); + if (!cpp11_std_unique_ptr.is_nullptr(kin)) + throw new RuntimeException("is_nullptr failed"); + kin.delete(); // Should not fail, even though already deleted + checkCount(0); + } + + { + Klass kin = new Klass("KlassInput"); + checkCount(1); + String s = cpp11_std_unique_ptr.takeKlassUniquePtr(kin); + checkCount(0); + if (!s.equals("KlassInput")) + throw new RuntimeException("Incorrect string: " + s); + if (!cpp11_std_unique_ptr.is_nullptr(kin)) + throw new RuntimeException("is_nullptr failed"); + boolean exception_thrown = false; + try { + cpp11_std_unique_ptr.takeKlassUniquePtr(kin); + } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new RuntimeException("double usage of takeKlassUniquePtr should have been an error"); + kin.delete(); // Should not fail, even though already deleted + checkCount(0); + } + + { + Klass kin = new Klass("KlassInput"); + boolean exception_thrown = false; + try { + Klass notowned = cpp11_std_unique_ptr.get_not_owned_ptr(kin); + cpp11_std_unique_ptr.takeKlassUniquePtr(notowned); + } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new RuntimeException("Should have thrown 'Cannot release ownership as memory is not owned' error"); + kin.delete(); + checkCount(0); + } + + { + KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); + checkCount(1); + String s = cpp11_std_unique_ptr.takeKlassUniquePtr(kini); + checkCount(0); + if (!s.equals("KlassInheritanceInput")) + throw new RuntimeException("Incorrect string: " + s); + if (!cpp11_std_unique_ptr.is_nullptr(kini)) + throw new RuntimeException("is_nullptr failed"); + kini.delete(); // Should not fail, even though already deleted + checkCount(0); + } + + // unique_ptr as output Klass k1 = cpp11_std_unique_ptr.makeKlassUniquePtr("first"); if (!k1.getLabel().equals("first")) throw new RuntimeException("wrong object label"); diff --git a/Examples/test-suite/java/li_std_auto_ptr_runme.java b/Examples/test-suite/java/li_std_auto_ptr_runme.java index 50ed113a4..daec84dc0 100644 --- a/Examples/test-suite/java/li_std_auto_ptr_runme.java +++ b/Examples/test-suite/java/li_std_auto_ptr_runme.java @@ -20,8 +20,82 @@ public class li_std_auto_ptr_runme { } } + private static void checkCount(int expected_count) { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new RuntimeException("Counts incorrect, expected:" + expected_count + " actual:" + actual_count); + } + public static void main(String argv[]) throws Throwable { + // auto_ptr as input + { + Klass kin = new Klass("KlassInput"); + checkCount(1); + String s = li_std_auto_ptr.takeKlassAutoPtr(kin); + checkCount(0); + if (!s.equals("KlassInput")) + throw new RuntimeException("Incorrect string: " + s); + if (!li_std_auto_ptr.is_nullptr(kin)) + throw new RuntimeException("is_nullptr failed"); + kin.delete(); // Should not fail, even though already deleted + checkCount(0); + } + + { + Klass kin = new Klass("KlassInput"); + checkCount(1); + String s = li_std_auto_ptr.takeKlassAutoPtr(kin); + checkCount(0); + if (!s.equals("KlassInput")) + throw new RuntimeException("Incorrect string: " + s); + if (!li_std_auto_ptr.is_nullptr(kin)) + throw new RuntimeException("is_nullptr failed"); + boolean exception_thrown = false; + try { + li_std_auto_ptr.takeKlassAutoPtr(kin); + } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new RuntimeException("double usage of takeKlassAutoPtr should have been an error"); + kin.delete(); // Should not fail, even though already deleted + checkCount(0); + } + + { + Klass kin = new Klass("KlassInput"); + boolean exception_thrown = false; + try { + Klass notowned = li_std_auto_ptr.get_not_owned_ptr(kin); + li_std_auto_ptr.takeKlassAutoPtr(notowned); + } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new RuntimeException("Should have thrown 'Cannot release ownership as memory is not owned' error"); + kin.delete(); + checkCount(0); + } + + { + KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); + checkCount(1); + String s = li_std_auto_ptr.takeKlassAutoPtr(kini); + checkCount(0); + if (!s.equals("KlassInheritanceInput")) + throw new RuntimeException("Incorrect string: " + s); + if (!li_std_auto_ptr.is_nullptr(kini)) + throw new RuntimeException("is_nullptr failed"); + kini.delete(); // Should not fail, even though already deleted + checkCount(0); + } + + // auto_ptr as output Klass k1 = li_std_auto_ptr.makeKlassAutoPtr("first"); if (!k1.getLabel().equals("first")) throw new RuntimeException("wrong object label"); diff --git a/Examples/test-suite/java_throws.i b/Examples/test-suite/java_throws.i index 6cd47b448..7c3b6f328 100644 --- a/Examples/test-suite/java_throws.i +++ b/Examples/test-suite/java_throws.i @@ -193,6 +193,37 @@ try { } %} +%typemap(javabody) SWIGTYPE %{ + private transient long swigCPtr; + protected transient boolean swigCMemOwn; + + protected $javaclassname(long cPtr, boolean cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = cPtr; + } + + protected static long getCPtr($javaclassname obj) { + return (obj == null) ? 0 : obj.swigCPtr; + } + + protected static long swigRelease($javaclassname obj) { + long ptr = 0; + if (obj != null) { + if (!obj.swigCMemOwn) + throw new RuntimeException("Cannot release ownership as memory is not owned"); + ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + try { + obj.delete(); + } catch (MyException e) { + throw new RuntimeException(e); + } + } + return ptr; + } +%} + + %inline %{ struct NoExceptTest { unsigned int noExceptionPlease() { return 123; } diff --git a/Examples/test-suite/li_std_auto_ptr.i b/Examples/test-suite/li_std_auto_ptr.i index edfe2ccf5..02c8235f2 100644 --- a/Examples/test-suite/li_std_auto_ptr.i +++ b/Examples/test-suite/li_std_auto_ptr.i @@ -14,6 +14,7 @@ #if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) +%include "std_string.i" %include "std_auto_ptr.i" %auto_ptr(Klass) @@ -27,10 +28,13 @@ namespace std { template class auto_ptr { T *ptr; public: - auto_ptr(T *ptr = 0) : ptr(ptr) {} + explicit auto_ptr(T *p = 0) : ptr(p) {} auto_ptr(auto_ptr&& a) : ptr(a.ptr) { a.ptr = 0;} ~auto_ptr() { delete ptr; } T *release() { T *p = ptr; ptr = 0; return p; } + void reset(T *p = 0) { delete ptr; ptr = p; } + T &operator*() const { return *ptr; } + T *operator->() const { return ptr; } auto_ptr& operator=(auto_ptr&& a) { if (&a != this) { delete ptr; ptr = a.ptr; a.ptr = 0; } return *this; } }; } @@ -53,7 +57,7 @@ public: const char* getLabel() const { return m_label.c_str(); } - ~Klass() + virtual ~Klass() { SwigExamples::Lock lock(critical_section); total_count--; @@ -73,10 +77,28 @@ int Klass::total_count = 0; %} -%template(KlassAutoPtr) std::auto_ptr; - %inline %{ +// Virtual inheritance used as this usually results in different values for Klass* and KlassInheritance* +// for testing class inheritance and auto_ptr +struct KlassInheritance : virtual Klass { + KlassInheritance(const char* label) : Klass(label) { + // std::cout << "ptrs.... " << std::hex << (Klass*)this << " " << (KlassInheritance*)this << std::endl; + } +}; + +std::string takeKlassAutoPtr(std::auto_ptr k) { + return std::string(k->getLabel()); +} + +bool is_nullptr(Klass *p) { + return p == 0; +} + +Klass *get_not_owned_ptr(Klass *p) { + return p; +} + std::auto_ptr makeKlassAutoPtr(const char* label) { return std::auto_ptr(new Klass(label)); } diff --git a/Examples/test-suite/perl5/cpp11_std_unique_ptr_runme.pl b/Examples/test-suite/perl5/cpp11_std_unique_ptr_runme.pl index ce64bbf00..a42580aca 100644 --- a/Examples/test-suite/perl5/cpp11_std_unique_ptr_runme.pl +++ b/Examples/test-suite/perl5/cpp11_std_unique_ptr_runme.pl @@ -1,9 +1,67 @@ use strict; use warnings; -use Test::More tests => 6; +use Test::More tests => 24; BEGIN { use_ok('cpp11_std_unique_ptr') } require_ok('cpp11_std_unique_ptr'); +# adapted from ../java/cpp11_std_unique_ptr_runme.java + +sub checkCount { + my($expected_count) = @_; + my $actual_count = cpp11_std_unique_ptr::Klass::getTotal_count(); + is($actual_count, $expected_count, "Counts incorrect, expected: $expected_count actual: $actual_count"); +} + +# unique_ptr as input +{ + my $kin = new cpp11_std_unique_ptr::Klass("KlassInput"); + checkCount(1); + my $s = cpp11_std_unique_ptr::takeKlassUniquePtr($kin); + checkCount(0); + is($s, "KlassInput", "Incorrect string: $s"); + is(cpp11_std_unique_ptr::is_nullptr($kin), 1, "is_nullptr check"); + undef $kin; # Should not fail, even though already deleted + checkCount(0); +} + +{ + my $kin = new cpp11_std_unique_ptr::Klass("KlassInput"); + checkCount(1); + my $s = cpp11_std_unique_ptr::takeKlassUniquePtr($kin); + checkCount(0); + is($s, "KlassInput", "Incorrect string: $s"); + is(cpp11_std_unique_ptr::is_nullptr($kin), 1, "is_nullptr check"); + eval { + cpp11_std_unique_ptr::takeKlassUniquePtr($kin); + }; + like($@, qr/\bcannot release ownership as memory is not owned\b/, "double usage of takeKlassUniquePtr should be an error"); + undef $kin; # Should not fail, even though already deleted + checkCount(0); +} + +{ + my $kin = new cpp11_std_unique_ptr::Klass("KlassInput"); + eval { + my $notowned = cpp11_std_unique_ptr::get_not_owned_ptr($kin); + cpp11_std_unique_ptr::takeKlassUniquePtr($notowned); + }; + like($@, qr/\bcannot release ownership as memory is not owned\b/, "double usage of takeKlassUniquePtr should be an error"); + undef $kin; + checkCount(0); +} + +{ + my $kini = new cpp11_std_unique_ptr::KlassInheritance("KlassInheritanceInput"); + checkCount(1); + my $s = cpp11_std_unique_ptr::takeKlassUniquePtr($kini); + checkCount(0); + is($s, "KlassInheritanceInput", "Incorrect string: $s"); + is(cpp11_std_unique_ptr::is_nullptr($kini), 1, "is_nullptr failed"); + undef $kini; # Should not fail, even though already deleted + checkCount(0); +} + +# unique_ptr as output my $k1 = cpp11_std_unique_ptr::makeKlassUniquePtr("first"); my $k2 = cpp11_std_unique_ptr::makeKlassUniquePtr("second"); is(cpp11_std_unique_ptr::Klass::getTotal_count, 2, "have 2 pointers"); diff --git a/Examples/test-suite/perl5/li_std_auto_ptr_runme.pl b/Examples/test-suite/perl5/li_std_auto_ptr_runme.pl index 52cb23ac5..8a33f4562 100644 --- a/Examples/test-suite/perl5/li_std_auto_ptr_runme.pl +++ b/Examples/test-suite/perl5/li_std_auto_ptr_runme.pl @@ -1,9 +1,67 @@ use strict; use warnings; -use Test::More tests => 6; +use Test::More tests => 24; BEGIN { use_ok('li_std_auto_ptr') } require_ok('li_std_auto_ptr'); +# adapted from ../java/li_std_auto_ptr_runme.java + +sub checkCount { + my($expected_count) = @_; + my $actual_count = li_std_auto_ptr::Klass::getTotal_count(); + is($actual_count, $expected_count, "Counts incorrect, expected: $expected_count actual: $actual_count"); +} + +# auto_ptr as input +{ + my $kin = new li_std_auto_ptr::Klass("KlassInput"); + checkCount(1); + my $s = li_std_auto_ptr::takeKlassAutoPtr($kin); + checkCount(0); + is($s, "KlassInput", "Incorrect string: $s"); + is(li_std_auto_ptr::is_nullptr($kin), 1, "is_nullptr check"); + undef $kin; # Should not fail, even though already deleted + checkCount(0); +} + +{ + my $kin = new li_std_auto_ptr::Klass("KlassInput"); + checkCount(1); + my $s = li_std_auto_ptr::takeKlassAutoPtr($kin); + checkCount(0); + is($s, "KlassInput", "Incorrect string: $s"); + is(li_std_auto_ptr::is_nullptr($kin), 1, "is_nullptr check"); + eval { + li_std_auto_ptr::takeKlassAutoPtr($kin); + }; + like($@, qr/\bcannot release ownership as memory is not owned\b/, "double usage of takeKlassAutoPtr should be an error"); + undef $kin; # Should not fail, even though already deleted + checkCount(0); +} + +{ + my $kin = new li_std_auto_ptr::Klass("KlassInput"); + eval { + my $notowned = li_std_auto_ptr::get_not_owned_ptr($kin); + li_std_auto_ptr::takeKlassAutoPtr($notowned); + }; + like($@, qr/\bcannot release ownership as memory is not owned\b/, "double usage of takeKlassAutoPtr should be an error"); + undef $kin; + checkCount(0); +} + +{ + my $kini = new li_std_auto_ptr::KlassInheritance("KlassInheritanceInput"); + checkCount(1); + my $s = li_std_auto_ptr::takeKlassAutoPtr($kini); + checkCount(0); + is($s, "KlassInheritanceInput", "Incorrect string: $s"); + is(li_std_auto_ptr::is_nullptr($kini), 1, "is_nullptr failed"); + undef $kini; # Should not fail, even though already deleted + checkCount(0); +} + +# auto_ptr as output my $k1 = li_std_auto_ptr::makeKlassAutoPtr("first"); my $k2 = li_std_auto_ptr::makeKlassAutoPtr("second"); is(li_std_auto_ptr::Klass::getTotal_count, 2, "have 2 pointers"); diff --git a/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py b/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py index a84efcd5f..d317754b4 100644 --- a/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py +++ b/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py @@ -1,5 +1,72 @@ from cpp11_std_unique_ptr import * +def checkCount(expected_count): + actual_count = Klass.getTotal_count() + if (actual_count != expected_count): + raise RuntimeError("Counts incorrect, expected:" + expected_count + " actual:" + actual_count) + +# unique_ptr as input +kin = Klass("KlassInput") +checkCount(1) +s = takeKlassUniquePtr(kin) +checkCount(0) +if kin.thisown: + raise RuntimeError("thisown should be false") +if s != "KlassInput": + raise RuntimeError("Incorrect string: " + s) +if not is_nullptr(kin): + raise RuntimeError("is_nullptr failed") +del kin # Should not fail, even though already deleted +checkCount(0) + +kin = Klass("KlassInput") +checkCount(1) +s = takeKlassUniquePtr(kin) +checkCount(0) +if kin.thisown: + raise RuntimeError("thisown should be false") +if s != "KlassInput": + raise RuntimeError("Incorrect string: " + s) +if not is_nullptr(kin): + raise RuntimeError("is_nullptr failed") +exception_thrown = False +try: + s = takeKlassUniquePtr(kin) +except RuntimeError as e: + if "cannot release ownership as memory is not owned" not in str(e): + raise RuntimeError("incorrect exception message"); + exception_thrown = True +if not exception_thrown: + raise RuntimeError("double usage of takeKlassUniquePtr should have been an error") +del kin # Should not fail, even though already deleted +checkCount(0) + +kin = Klass("KlassInput") +exception_thrown = False +try: + notowned = get_not_owned_ptr(kin) + takeKlassUniquePtr(notowned) +except RuntimeError as e: + exception_thrown = True +if not exception_thrown: + raise RuntimeError("Should have thrown 'Cannot release ownership as memory is not owned' error") +del kin +checkCount(0) + +kini = KlassInheritance("KlassInheritanceInput") +checkCount(1) +s = takeKlassUniquePtr(kini) +checkCount(0) +if kini.thisown: + raise RuntimeError("thisown should be false") +if s != "KlassInheritanceInput": + raise RuntimeError("Incorrect string: " + s) +if not is_nullptr(kini): + raise RuntimeError("is_nullptr failed") +del kini # Should not fail, even though already deleted +checkCount(0) + +# unique_ptr as output k1 = makeKlassUniquePtr("first") k2 = makeKlassUniquePtr("second") if Klass.getTotal_count() != 2: diff --git a/Examples/test-suite/python/li_std_auto_ptr_runme.py b/Examples/test-suite/python/li_std_auto_ptr_runme.py index d62224ff6..c1df7eb76 100644 --- a/Examples/test-suite/python/li_std_auto_ptr_runme.py +++ b/Examples/test-suite/python/li_std_auto_ptr_runme.py @@ -1,5 +1,72 @@ from li_std_auto_ptr import * +def checkCount(expected_count): + actual_count = Klass.getTotal_count() + if (actual_count != expected_count): + raise RuntimeError("Counts incorrect, expected:" + expected_count + " actual:" + actual_count) + +# auto_ptr as input +kin = Klass("KlassInput") +checkCount(1) +s = takeKlassAutoPtr(kin) +checkCount(0) +if kin.thisown: + raise RuntimeError("thisown should be false") +if s != "KlassInput": + raise RuntimeError("Incorrect string: " + s) +if not is_nullptr(kin): + raise RuntimeError("is_nullptr failed") +del kin # Should not fail, even though already deleted +checkCount(0) + +kin = Klass("KlassInput") +checkCount(1) +s = takeKlassAutoPtr(kin) +checkCount(0) +if kin.thisown: + raise RuntimeError("thisown should be false") +if s != "KlassInput": + raise RuntimeError("Incorrect string: " + s) +if not is_nullptr(kin): + raise RuntimeError("is_nullptr failed") +exception_thrown = False +try: + s = takeKlassAutoPtr(kin) +except RuntimeError as e: + if "cannot release ownership as memory is not owned" not in str(e): + raise RuntimeError("incorrect exception message"); + exception_thrown = True +if not exception_thrown: + raise RuntimeError("double usage of takeKlassAutoPtr should have been an error") +del kin # Should not fail, even though already deleted +checkCount(0) + +kin = Klass("KlassInput") +exception_thrown = False +try: + notowned = get_not_owned_ptr(kin) + takeKlassAutoPtr(notowned) +except RuntimeError as e: + exception_thrown = True +if not exception_thrown: + raise RuntimeError("Should have thrown 'Cannot release ownership as memory is not owned' error") +del kin +checkCount(0) + +kini = KlassInheritance("KlassInheritanceInput") +checkCount(1) +s = takeKlassAutoPtr(kini) +checkCount(0) +if kini.thisown: + raise RuntimeError("thisown should be false") +if s != "KlassInheritanceInput": + raise RuntimeError("Incorrect string: " + s) +if not is_nullptr(kini): + raise RuntimeError("is_nullptr failed") +del kini # Should not fail, even though already deleted +checkCount(0) + +# auto_ptr as output k1 = makeKlassAutoPtr("first") k2 = makeKlassAutoPtr("second") if Klass.getTotal_count() != 2: diff --git a/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb b/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb index cfc03fe2a..83bac5f1b 100644 --- a/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb +++ b/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb @@ -11,6 +11,100 @@ def gc_check(expected_count) # swig_assert_equal_simple(expected_count, Cpp11_std_unique_ptr::Klass::getTotal_count()) end +def checkCount(expected_count) + actual_count = Cpp11_std_unique_ptr::Klass.getTotal_count() + if (actual_count != expected_count) + raise RuntimeError, "Counts incorrect, expected:" + expected_count + " actual:" + actual_count + end +end + + +# unique_ptr as input +kin = Cpp11_std_unique_ptr::Klass.new("KlassInput") +checkCount(1) +s = Cpp11_std_unique_ptr.takeKlassUniquePtr(kin) +checkCount(0) +if (s != "KlassInput") + raise RuntimeError, "Incorrect string: " + s +end +exception_thrown = false +begin + Cpp11_std_unique_ptr.is_nullptr(kin) +rescue ObjectPreviouslyDeleted + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "is_nullptr failed to throw" +end +kin = nil +checkCount(0) + +kin = Cpp11_std_unique_ptr::Klass.new("KlassInput") +checkCount(1) +s = Cpp11_std_unique_ptr.takeKlassUniquePtr(kin) +checkCount(0) +if (s != "KlassInput") + raise RuntimeError, "Incorrect string: " + s +end +exception_thrown = false +begin + Cpp11_std_unique_ptr.is_nullptr(kin) +rescue ObjectPreviouslyDeleted + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "is_nullptr failed to throw" +end +exception_thrown = false +begin + Cpp11_std_unique_ptr.takeKlassUniquePtr(kin) +rescue RuntimeError => e + # puts e.message + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "double usage of takeKlassUniquePtr should have been an error" +end +kin = nil +checkCount(0) + +kin = Cpp11_std_unique_ptr::Klass.new("KlassInput") +exception_thrown = false +begin + notowned = Cpp11_std_unique_ptr::get_not_owned_ptr(kin) + Cpp11_std_unique_ptr::takeKlassUniquePtr(notowned) +rescue RuntimeError => e + if (!e.to_s.include? "cannot release ownership as memory is not owned") + raise RuntimeError, "incorrect exception message" + end + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "Should have thrown 'Cannot release ownership as memory is not owned' error" +end +Cpp11_std_unique_ptr.takeKlassUniquePtr(kin) # Ensure object is deleted (can't rely on GC) +checkCount(0) + +kini = Cpp11_std_unique_ptr::KlassInheritance.new("KlassInheritanceInput") +checkCount(1) +s = Cpp11_std_unique_ptr.takeKlassUniquePtr(kini) +checkCount(0) +if (s != "KlassInheritanceInput") + raise RuntimeError, "Incorrect string: " + s +end +exception_thrown = false +begin + Cpp11_std_unique_ptr.is_nullptr(kini) +rescue ObjectPreviouslyDeleted + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "is_nullptr failed to throw" +end +kini = nil +checkCount(0) + +# unique_ptr as output k1 = Cpp11_std_unique_ptr::makeKlassUniquePtr("first") k2 = Cpp11_std_unique_ptr::makeKlassUniquePtr("second") swig_assert_equal_simple(2, Cpp11_std_unique_ptr::Klass::getTotal_count()) diff --git a/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb b/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb index cec48a58c..6562d8d84 100644 --- a/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb +++ b/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb @@ -11,6 +11,100 @@ def gc_check(expected_count) # swig_assert_equal_simple(expected_count, Li_std_auto_ptr::Klass::getTotal_count()) end +def checkCount(expected_count) + actual_count = Li_std_auto_ptr::Klass.getTotal_count() + if (actual_count != expected_count) + raise RuntimeError, "Counts incorrect, expected:" + expected_count + " actual:" + actual_count + end +end + + +# auto_ptr as input +kin = Li_std_auto_ptr::Klass.new("KlassInput") +checkCount(1) +s = Li_std_auto_ptr.takeKlassAutoPtr(kin) +checkCount(0) +if (s != "KlassInput") + raise RuntimeError, "Incorrect string: " + s +end +exception_thrown = false +begin + Li_std_auto_ptr.is_nullptr(kin) +rescue ObjectPreviouslyDeleted + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "is_nullptr failed to throw" +end +kin = nil +checkCount(0) + +kin = Li_std_auto_ptr::Klass.new("KlassInput") +checkCount(1) +s = Li_std_auto_ptr.takeKlassAutoPtr(kin) +checkCount(0) +if (s != "KlassInput") + raise RuntimeError, "Incorrect string: " + s +end +exception_thrown = false +begin + Li_std_auto_ptr.is_nullptr(kin) +rescue ObjectPreviouslyDeleted + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "is_nullptr failed to throw" +end +exception_thrown = false +begin + Li_std_auto_ptr.takeKlassAutoPtr(kin) +rescue RuntimeError => e + # puts e.message + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "double usage of takeKlassAutoPtr should have been an error" +end +kin = nil +checkCount(0) + +kin = Li_std_auto_ptr::Klass.new("KlassInput") +exception_thrown = false +begin + notowned = Li_std_auto_ptr::get_not_owned_ptr(kin) + Li_std_auto_ptr::takeKlassAutoPtr(notowned) +rescue RuntimeError + if (!e.to_s.include? "cannot release ownership as memory is not owned") + raise RuntimeError, "incorrect exception message" + end + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "Should have thrown 'Cannot release ownership as memory is not owned' error" +end +Li_std_auto_ptr.takeKlassAutoPtr(kin) # Ensure object is deleted (can't rely on GC) +checkCount(0) + +kini = Li_std_auto_ptr::KlassInheritance.new("KlassInheritanceInput") +checkCount(1) +s = Li_std_auto_ptr.takeKlassAutoPtr(kini) +checkCount(0) +if (s != "KlassInheritanceInput") + raise RuntimeError, "Incorrect string: " + s +end +exception_thrown = false +begin + Li_std_auto_ptr.is_nullptr(kini) +rescue ObjectPreviouslyDeleted + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "is_nullptr failed to throw" +end +kini = nil +checkCount(0) + +# auto_ptr as output k1 = Li_std_auto_ptr::makeKlassAutoPtr("first") k2 = Li_std_auto_ptr::makeKlassAutoPtr("second") swig_assert_equal_simple(2, Li_std_auto_ptr::Klass::getTotal_count()) diff --git a/Lib/csharp/csharp.swg b/Lib/csharp/csharp.swg index 94e0458a6..60ab388f3 100644 --- a/Lib/csharp/csharp.swg +++ b/Lib/csharp/csharp.swg @@ -913,6 +913,19 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { CPTR_VISIBILITY static global::System.Runtime.InteropServices.HandleRef getCPtr($csclassname obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; } + + CPTR_VISIBILITY static global::System.Runtime.InteropServices.HandleRef swigRelease($csclassname obj) { + if (obj != null) { + if (!obj.swigCMemOwn) + throw new global::System.ApplicationException("Cannot release ownership as memory is not owned"); + global::System.Runtime.InteropServices.HandleRef ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + obj.Dispose(); + return ptr; + } else { + return new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero); + } + } %} // Derived proxy classes @@ -926,6 +939,19 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { CPTR_VISIBILITY static global::System.Runtime.InteropServices.HandleRef getCPtr($csclassname obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; } + + CPTR_VISIBILITY static global::System.Runtime.InteropServices.HandleRef swigRelease($csclassname obj) { + if (obj != null) { + if (!obj.swigCMemOwn) + throw new global::System.ApplicationException("Cannot release ownership as memory is not owned"); + global::System.Runtime.InteropServices.HandleRef ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + obj.Dispose(); + return ptr; + } else { + return new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero); + } + } %} %enddef @@ -945,6 +971,10 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { CPTR_VISIBILITY static global::System.Runtime.InteropServices.HandleRef getCPtr($csclassname obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; } + + CPTR_VISIBILITY static global::System.Runtime.InteropServices.HandleRef swigRelease($csclassname obj) { + return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; + } %} %typemap(csbody) TYPE (CLASS::*) %{ diff --git a/Lib/csharp/std_auto_ptr.i b/Lib/csharp/std_auto_ptr.i index 068d3a9d1..78d7eaf4c 100644 --- a/Lib/csharp/std_auto_ptr.i +++ b/Lib/csharp/std_auto_ptr.i @@ -1,27 +1,36 @@ /* ----------------------------------------------------------------------------- * std_auto_ptr.i * - * The typemaps here allow handling functions returning std::auto_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::auto_ptr. + * Memory ownership is passed from the std::auto_ptr C++ layer to the proxy + * class when returning a std::auto_ptr from a function. + * Memory ownership is passed from the proxy class to the std::auto_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %auto_ptr(TYPE) %typemap (ctype) std::auto_ptr< TYPE > "void *" -%typemap (imtype, out="System.IntPtr") std::auto_ptr< TYPE > "HandleRef" +%typemap (imtype, out="System.IntPtr") std::auto_ptr< TYPE > "global::System.Runtime.InteropServices.HandleRef" %typemap (cstype) std::auto_ptr< TYPE > "$typemap(cstype, TYPE)" + +%typemap(in) std::auto_ptr< TYPE > +%{ $1.reset((TYPE *)$input); %} + +%typemap(csin) std::auto_ptr< TYPE > "$typemap(cstype, TYPE).swigRelease($csinput)" + %typemap (out) std::auto_ptr< TYPE > %{ - $result = (void *)$1.release(); + $result = (void *)$1.release(); %} + %typemap(csout, excode=SWIGEXCODE) std::auto_ptr< TYPE > { - System.IntPtr cPtr = $imcall; - $typemap(cstype, TYPE) ret = (cPtr == System.IntPtr.Zero) ? null : new $typemap(cstype, TYPE)(cPtr, true);$excode - return ret; - } + System.IntPtr cPtr = $imcall; + $typemap(cstype, TYPE) ret = (cPtr == System.IntPtr.Zero) ? null : new $typemap(cstype, TYPE)(cPtr, true);$excode + return ret; + } + %template() std::auto_ptr< TYPE >; %enddef namespace std { - template class auto_ptr {}; -} + template class auto_ptr {}; +} diff --git a/Lib/csharp/std_unique_ptr.i b/Lib/csharp/std_unique_ptr.i index b2716756a..2233cdc06 100644 --- a/Lib/csharp/std_unique_ptr.i +++ b/Lib/csharp/std_unique_ptr.i @@ -1,27 +1,36 @@ /* ----------------------------------------------------------------------------- * std_unique_ptr.i * - * The typemaps here allow handling functions returning std::unique_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::unique_ptr. + * Memory ownership is passed from the std::unique_ptr C++ layer to the proxy + * class when returning a std::unique_ptr from a function. + * Memory ownership is passed from the proxy class to the std::unique_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %unique_ptr(TYPE) %typemap (ctype) std::unique_ptr< TYPE > "void *" -%typemap (imtype, out="System.IntPtr") std::unique_ptr< TYPE > "HandleRef" +%typemap (imtype, out="System.IntPtr") std::unique_ptr< TYPE > "global::System.Runtime.InteropServices.HandleRef" %typemap (cstype) std::unique_ptr< TYPE > "$typemap(cstype, TYPE)" + +%typemap(in) std::unique_ptr< TYPE > +%{ $1.reset((TYPE *)$input); %} + +%typemap(csin) std::unique_ptr< TYPE > "$typemap(cstype, TYPE).swigRelease($csinput)" + %typemap (out) std::unique_ptr< TYPE > %{ - $result = (void *)$1.release(); + $result = (void *)$1.release(); %} + %typemap(csout, excode=SWIGEXCODE) std::unique_ptr< TYPE > { - System.IntPtr cPtr = $imcall; - $typemap(cstype, TYPE) ret = (cPtr == System.IntPtr.Zero) ? null : new $typemap(cstype, TYPE)(cPtr, true);$excode - return ret; - } + System.IntPtr cPtr = $imcall; + $typemap(cstype, TYPE) ret = (cPtr == System.IntPtr.Zero) ? null : new $typemap(cstype, TYPE)(cPtr, true);$excode + return ret; + } + %template() std::unique_ptr< TYPE >; %enddef namespace std { - template class unique_ptr {}; -} + template class unique_ptr {}; +} diff --git a/Lib/java/java.swg b/Lib/java/java.swg index 23744aeb3..19198b7b4 100644 --- a/Lib/java/java.swg +++ b/Lib/java/java.swg @@ -700,6 +700,7 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); } SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "$1_type reference is null"); return $null; } %} +%typemap(freearg) SWIGTYPE && %{ delete $1; %}; %typemap(out) SWIGTYPE * %{ *($&1_ltype)&$result = $1; %} %typemap(out, fragment="SWIG_PackData", noblock=1) SWIGTYPE (CLASS::*) { @@ -1101,7 +1102,8 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); } jobjectArray "$javainput" %typemap(javain) SWIGTYPE "$&javaclassname.getCPtr($javainput)" -%typemap(javain) SWIGTYPE *, SWIGTYPE &, SWIGTYPE &&, SWIGTYPE [] "$javaclassname.getCPtr($javainput)" +%typemap(javain) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [] "$javaclassname.getCPtr($javainput)" +%typemap(javain) SWIGTYPE && "$javaclassname.swigRelease($javainput)" %typemap(javain) SWIGTYPE (CLASS::*) "$javaclassname.getCMemberPtr($javainput)" /* The javaout typemap is used for converting function return types from the return type @@ -1216,6 +1218,18 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); } CPTR_VISIBILITY static long getCPtr($javaclassname obj) { return (obj == null) ? 0 : obj.swigCPtr; } + + CPTR_VISIBILITY static long swigRelease($javaclassname obj) { + long ptr = 0; + if (obj != null) { + if (!obj.swigCMemOwn) + throw new RuntimeException("Cannot release ownership as memory is not owned"); + ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + obj.delete(); + } + return ptr; + } %} // Derived proxy classes @@ -1230,6 +1244,18 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); } CPTR_VISIBILITY static long getCPtr($javaclassname obj) { return (obj == null) ? 0 : obj.swigCPtr; } + + CPTR_VISIBILITY static long swigRelease($javaclassname obj) { + long ptr = 0; + if (obj != null) { + if (!obj.swigCMemOwn) + throw new RuntimeException("Cannot release ownership as memory is not owned"); + ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + obj.delete(); + } + return ptr; + } %} %enddef @@ -1249,6 +1275,10 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); } CPTR_VISIBILITY static long getCPtr($javaclassname obj) { return (obj == null) ? 0 : obj.swigCPtr; } + + CPTR_VISIBILITY static long swigRelease($javaclassname obj) { + return (obj == null) ? 0 : obj.swigCPtr; + } %} %typemap(javabody) TYPE (CLASS::*) %{ diff --git a/Lib/java/std_auto_ptr.i b/Lib/java/std_auto_ptr.i index 0eb5fe155..6d65f0451 100644 --- a/Lib/java/std_auto_ptr.i +++ b/Lib/java/std_auto_ptr.i @@ -1,29 +1,39 @@ /* ----------------------------------------------------------------------------- * std_auto_ptr.i * - * The typemaps here allow handling functions returning std::auto_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::auto_ptr. + * Memory ownership is passed from the std::auto_ptr C++ layer to the proxy + * class when returning a std::auto_ptr from a function. + * Memory ownership is passed from the proxy class to the std::auto_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %auto_ptr(TYPE) + %typemap (jni) std::auto_ptr< TYPE > "jlong" %typemap (jtype) std::auto_ptr< TYPE > "long" %typemap (jstype) std::auto_ptr< TYPE > "$typemap(jstype, TYPE)" +%typemap(in) std::auto_ptr< TYPE > (TYPE *auto_temp) +%{ auto_temp = *(TYPE **)&$input; + $1.reset(auto_temp); %} + +%typemap(javain) std::auto_ptr< TYPE > "$typemap(jstype, TYPE).swigRelease($javainput)" + %typemap (out) std::auto_ptr< TYPE > %{ - jlong lpp = 0; - *(TYPE **) &lpp = $1.release(); - $result = lpp; + jlong lpp = 0; + *(TYPE **) &lpp = $1.release(); + $result = lpp; %} + %typemap(javaout) std::auto_ptr< TYPE > { - long cPtr = $jnicall; - return (cPtr == 0) ? null : new $typemap(jstype, TYPE)(cPtr, true); - } + long cPtr = $jnicall; + return (cPtr == 0) ? null : new $typemap(jstype, TYPE)(cPtr, true); + } + %template() std::auto_ptr< TYPE >; %enddef namespace std { - template class auto_ptr {}; -} + template class auto_ptr {}; +} diff --git a/Lib/java/std_unique_ptr.i b/Lib/java/std_unique_ptr.i index 665d913ae..e1e5a2622 100644 --- a/Lib/java/std_unique_ptr.i +++ b/Lib/java/std_unique_ptr.i @@ -1,29 +1,39 @@ /* ----------------------------------------------------------------------------- * std_unique_ptr.i * - * The typemaps here allow handling functions returning std::unique_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::unique_ptr. + * Memory ownership is passed from the std::unique_ptr C++ layer to the proxy + * class when returning a std::unique_ptr from a function. + * Memory ownership is passed from the proxy class to the std::unique_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %unique_ptr(TYPE) + %typemap (jni) std::unique_ptr< TYPE > "jlong" %typemap (jtype) std::unique_ptr< TYPE > "long" %typemap (jstype) std::unique_ptr< TYPE > "$typemap(jstype, TYPE)" +%typemap(in) std::unique_ptr< TYPE > (TYPE *unique_temp) +%{ unique_temp = *(TYPE **)&$input; + $1.reset(unique_temp); %} + +%typemap(javain) std::unique_ptr< TYPE > "$typemap(jstype, TYPE).swigRelease($javainput)" + %typemap (out) std::unique_ptr< TYPE > %{ - jlong lpp = 0; - *(TYPE **) &lpp = $1.release(); - $result = lpp; + jlong lpp = 0; + *(TYPE **) &lpp = $1.release(); + $result = lpp; %} + %typemap(javaout) std::unique_ptr< TYPE > { - long cPtr = $jnicall; - return (cPtr == 0) ? null : new $typemap(jstype, TYPE)(cPtr, true); - } + long cPtr = $jnicall; + return (cPtr == 0) ? null : new $typemap(jstype, TYPE)(cPtr, true); + } + %template() std::unique_ptr< TYPE >; %enddef namespace std { - template class unique_ptr {}; -} + template class unique_ptr {}; +} diff --git a/Lib/perl5/perlrun.swg b/Lib/perl5/perlrun.swg index 28703d1a6..71f19cbf8 100644 --- a/Lib/perl5/perlrun.swg +++ b/Lib/perl5/perlrun.swg @@ -210,6 +210,7 @@ SWIG_Perl_ConvertPtrAndOwn(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_ swig_cast_info *tc; void *voidptr = (void *)0; SV *tsv = 0; + int check_owned_pointer_release = (flags & SWIG_POINTER_RELEASE) == SWIG_POINTER_RELEASE; if (own) *own = 0; @@ -286,13 +287,14 @@ SWIG_Perl_ConvertPtrAndOwn(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_ /* * DISOWN implementation: we need a perl guru to check this one. */ - if (tsv && (flags & SWIG_POINTER_DISOWN)) { + if (tsv && ((flags & SWIG_POINTER_DISOWN) || check_owned_pointer_release)) { /* * almost copy paste code from below SWIG_POINTER_OWN setting */ SV *obj = sv; HV *stash = SvSTASH(SvRV(obj)); GV *gv = *(GV**)hv_fetch(stash, "OWNER", 5, TRUE); + int owned = 0; if (isGV(gv)) { HV *hv = GvHVn(gv); /* @@ -300,10 +302,21 @@ SWIG_Perl_ConvertPtrAndOwn(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_ * Hence, to remove ownership, we delete the entry. */ if (hv_exists_ent(hv, obj, 0)) { - hv_delete_ent(hv, obj, 0, 0); + owned = 1; + if (flags & SWIG_POINTER_DISOWN) { + hv_delete_ent(hv, obj, 0, 0); + } } } + if (check_owned_pointer_release && !owned) { + return SWIG_ERROR_RELEASE_NOT_OWNED; + } } + + if (tsv && (flags & SWIG_POINTER_CLEAR)) { + SvIV_set(tsv, 0); + } + return SWIG_OK; } diff --git a/Lib/perl5/std_auto_ptr.i b/Lib/perl5/std_auto_ptr.i index ecaea2b0f..d062886e4 100644 --- a/Lib/perl5/std_auto_ptr.i +++ b/Lib/perl5/std_auto_ptr.i @@ -1,19 +1,33 @@ /* ----------------------------------------------------------------------------- * std_auto_ptr.i * - * The typemaps here allow handling functions returning std::auto_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::auto_ptr. + * Memory ownership is passed from the std::auto_ptr C++ layer to the proxy + * class when returning a std::auto_ptr from a function. + * Memory ownership is passed from the proxy class to the std::auto_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %auto_ptr(TYPE) +%typemap(in, noblock=1) std::auto_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + %typemap (out) std::auto_ptr< TYPE > %{ - %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %} + %template() std::auto_ptr< TYPE >; %enddef namespace std { - template class auto_ptr {}; + template class auto_ptr {}; } diff --git a/Lib/perl5/std_unique_ptr.i b/Lib/perl5/std_unique_ptr.i index 163c7c2d1..1a7ec06fa 100644 --- a/Lib/perl5/std_unique_ptr.i +++ b/Lib/perl5/std_unique_ptr.i @@ -1,19 +1,33 @@ /* ----------------------------------------------------------------------------- * std_unique_ptr.i * - * The typemaps here allow handling functions returning std::unique_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::unique_ptr. + * Memory ownership is passed from the std::unique_ptr C++ layer to the proxy + * class when returning a std::unique_ptr from a function. + * Memory ownership is passed from the proxy class to the std::unique_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %unique_ptr(TYPE) +%typemap(in, noblock=1) std::unique_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + %typemap (out) std::unique_ptr< TYPE > %{ - %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %} + %template() std::unique_ptr< TYPE >; %enddef namespace std { - template class unique_ptr {}; + template class unique_ptr {}; } diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index a74843bf1..36a20c422 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -1357,12 +1357,19 @@ SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int } } if (sobj) { - if (own) - *own = *own | sobj->own; - if (flags & SWIG_POINTER_DISOWN) { - sobj->own = 0; + if (((flags & SWIG_POINTER_RELEASE) == SWIG_POINTER_RELEASE) && !sobj->own) { + res = SWIG_ERROR_RELEASE_NOT_OWNED; + } else { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + if (flags & SWIG_POINTER_CLEAR) { + sobj->ptr = 0; + } + res = SWIG_OK; } - res = SWIG_OK; } else { if (implicit_conv) { SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; diff --git a/Lib/python/std_auto_ptr.i b/Lib/python/std_auto_ptr.i index fb044f851..d062886e4 100644 --- a/Lib/python/std_auto_ptr.i +++ b/Lib/python/std_auto_ptr.i @@ -1,19 +1,33 @@ /* ----------------------------------------------------------------------------- * std_auto_ptr.i * - * The typemaps here allow handling functions returning std::auto_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::auto_ptr. + * Memory ownership is passed from the std::auto_ptr C++ layer to the proxy + * class when returning a std::auto_ptr from a function. + * Memory ownership is passed from the proxy class to the std::auto_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %auto_ptr(TYPE) +%typemap(in, noblock=1) std::auto_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + %typemap (out) std::auto_ptr< TYPE > %{ - %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %} + %template() std::auto_ptr< TYPE >; %enddef namespace std { - template class auto_ptr {}; -} + template class auto_ptr {}; +} diff --git a/Lib/python/std_unique_ptr.i b/Lib/python/std_unique_ptr.i index 331817f76..1a7ec06fa 100644 --- a/Lib/python/std_unique_ptr.i +++ b/Lib/python/std_unique_ptr.i @@ -1,19 +1,33 @@ /* ----------------------------------------------------------------------------- * std_unique_ptr.i * - * The typemaps here allow handling functions returning std::unique_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::unique_ptr. + * Memory ownership is passed from the std::unique_ptr C++ layer to the proxy + * class when returning a std::unique_ptr from a function. + * Memory ownership is passed from the proxy class to the std::unique_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %unique_ptr(TYPE) +%typemap(in, noblock=1) std::unique_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + %typemap (out) std::unique_ptr< TYPE > %{ - %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %} + %template() std::unique_ptr< TYPE >; %enddef namespace std { - template class unique_ptr {}; -} + template class unique_ptr {}; +} diff --git a/Lib/ruby/rubyrun.swg b/Lib/ruby/rubyrun.swg index e4c23bde5..6cac4626a 100644 --- a/Lib/ruby/rubyrun.swg +++ b/Lib/ruby/rubyrun.swg @@ -281,6 +281,11 @@ SWIG_Ruby_ConvertPtrAndOwn(VALUE obj, void **ptr, swig_type_info *ty, int flags, own->own = 0; } + if (((flags & SWIG_POINTER_RELEASE) == SWIG_POINTER_RELEASE)) { + if (!RDATA(obj)->dfree) + return SWIG_ERROR_RELEASE_NOT_OWNED; + } + /* Check to see if the input object is giving up ownership of the underlying C struct or C++ object. If so then we need to reset the destructor since the Ruby object no @@ -292,7 +297,7 @@ SWIG_Ruby_ConvertPtrAndOwn(VALUE obj, void **ptr, swig_type_info *ty, int flags, swig_class *sklass = (swig_class *) ty->clientdata; track = sklass->trackObjects; } - + if (track) { /* We are tracking objects for this class. Thus we change the destructor * to SWIG_RubyRemoveTracking. This allows us to @@ -306,6 +311,10 @@ SWIG_Ruby_ConvertPtrAndOwn(VALUE obj, void **ptr, swig_type_info *ty, int flags, } } + if (flags & SWIG_POINTER_CLEAR) { + DATA_PTR(obj) = 0; + } + /* Do type-checking if type info was provided */ if (ty) { if (ty->clientdata) { diff --git a/Lib/ruby/std_auto_ptr.i b/Lib/ruby/std_auto_ptr.i index ecaea2b0f..d062886e4 100644 --- a/Lib/ruby/std_auto_ptr.i +++ b/Lib/ruby/std_auto_ptr.i @@ -1,19 +1,33 @@ /* ----------------------------------------------------------------------------- * std_auto_ptr.i * - * The typemaps here allow handling functions returning std::auto_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::auto_ptr. + * Memory ownership is passed from the std::auto_ptr C++ layer to the proxy + * class when returning a std::auto_ptr from a function. + * Memory ownership is passed from the proxy class to the std::auto_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %auto_ptr(TYPE) +%typemap(in, noblock=1) std::auto_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + %typemap (out) std::auto_ptr< TYPE > %{ - %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %} + %template() std::auto_ptr< TYPE >; %enddef namespace std { - template class auto_ptr {}; + template class auto_ptr {}; } diff --git a/Lib/ruby/std_unique_ptr.i b/Lib/ruby/std_unique_ptr.i index 163c7c2d1..1a7ec06fa 100644 --- a/Lib/ruby/std_unique_ptr.i +++ b/Lib/ruby/std_unique_ptr.i @@ -1,19 +1,33 @@ /* ----------------------------------------------------------------------------- * std_unique_ptr.i * - * The typemaps here allow handling functions returning std::unique_ptr<>, - * which is the most common use of this type. If you have functions taking it - * as parameter, these typemaps can't be used for them and you need to do - * something else (e.g. use shared_ptr<> which SWIG supports fully). + * SWIG library file for handling std::unique_ptr. + * Memory ownership is passed from the std::unique_ptr C++ layer to the proxy + * class when returning a std::unique_ptr from a function. + * Memory ownership is passed from the proxy class to the std::unique_ptr in the + * C++ layer when passed as a parameter to a wrapped function. * ----------------------------------------------------------------------------- */ %define %unique_ptr(TYPE) +%typemap(in, noblock=1) std::unique_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + %typemap (out) std::unique_ptr< TYPE > %{ - %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %} + %template() std::unique_ptr< TYPE >; %enddef namespace std { - template class unique_ptr {}; + template class unique_ptr {}; } diff --git a/Lib/swigerrors.swg b/Lib/swigerrors.swg index 1a6d20366..4d5a8e473 100644 --- a/Lib/swigerrors.swg +++ b/Lib/swigerrors.swg @@ -1,4 +1,4 @@ -/* Errors in SWIG */ +/* SWIG Errors applicable to all language modules, values are reserved from -1 to -99 */ #define SWIG_UnknownError -1 #define SWIG_IOError -2 #define SWIG_RuntimeError -3 @@ -13,4 +13,3 @@ #define SWIG_MemoryError -12 #define SWIG_NullReferenceError -13 - diff --git a/Lib/swigrun.swg b/Lib/swigrun.swg index de0db2dc3..9ec98ccf2 100644 --- a/Lib/swigrun.swg +++ b/Lib/swigrun.swg @@ -44,6 +44,8 @@ #define SWIG_POINTER_DISOWN 0x1 #define SWIG_CAST_NEW_MEMORY 0x2 #define SWIG_POINTER_NO_NULL 0x4 +#define SWIG_POINTER_CLEAR 0x8 +#define SWIG_POINTER_RELEASE (SWIG_POINTER_CLEAR | SWIG_POINTER_DISOWN) /* Flags for new pointer objects */ #define SWIG_POINTER_OWN 0x1 @@ -129,7 +131,13 @@ */ #define SWIG_OK (0) +/* Runtime errors are < 0 */ #define SWIG_ERROR (-1) +/* Errors in range -1 to -99 are in swigerrors.swg (errors for all languages including those not using the runtime) */ +/* Errors in range -100 to -199 are language specific errors defined in *errors.swg */ +/* Errors < -200 are generic runtime specific errors */ +#define SWIG_ERROR_RELEASE_NOT_OWNED (-200) + #define SWIG_IsOK(r) (r >= 0) #define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) @@ -144,7 +152,7 @@ #define SWIG_OLDOBJ (SWIG_OK) #define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) #define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) -/* Check, add and del mask methods */ +/* Check, add and del object mask methods */ #define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) #define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) #define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) diff --git a/Lib/typemaps/exception.swg b/Lib/typemaps/exception.swg index e48294c3f..aece8326f 100644 --- a/Lib/typemaps/exception.swg +++ b/Lib/typemaps/exception.swg @@ -19,6 +19,7 @@ #endif #define %varnullref_fmt(_type,_name) %nullref_fmt() %varfail_fmt(_type, _name) #define %outnullref_fmt(_type) %nullref_fmt() %outfail_fmt(_type) +#define %releasenotownedfail_fmt(_type,_name,_argn) "in method '" `_name` "', cannot release ownership as memory is not owned for argument " `_argn`" of type '" `_type`"'" /* setting an error */ #define %error(code,msg...) SWIG_Error(code, msg) diff --git a/Lib/typemaps/swigtypemaps.swg b/Lib/typemaps/swigtypemaps.swg index 4e5bb2b04..733e5acd0 100644 --- a/Lib/typemaps/swigtypemaps.swg +++ b/Lib/typemaps/swigtypemaps.swg @@ -140,6 +140,7 @@ #define %argument_nullref(type, name, argn) SWIG_exception_fail(SWIG_ValueError, %argnullref_fmt(type, name, argn)) #define %variable_fail(code, type, name) SWIG_exception_fail(%default_code(code), %varfail_fmt(type, name)) #define %variable_nullref(type, name) SWIG_exception_fail(SWIG_ValueError, %varnullref_fmt(type, name)) +#define %releasenotowned_fail(code, type, name, argn) SWIG_exception_fail(%default_code(code), %releasenotownedfail_fmt(type, name, argn)) #if defined(SWIG_DIRECTOR_TYPEMAPS) #define %dirout_fail(code, type) SWIG_DirOutFail(%default_code(code), %outfail_fmt(type))