diff --git a/CHANGES.current b/CHANGES.current
index 6584e1781..57dd6c765 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,6 +7,16 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress)
===========================
+2022-07-02: wsfulton
+ #1722 [C#, Java, Python, Ruby] Add std::unique_ptr support. Ported from std::auto_ptr.
+ Use the %unique_ptr(T) macro as follows for usage std::unique_ptr. For example, for
+ a class called Klass:
+
+ %include "std_unique_ptr.i"
+ %unique_ptr(Klass)
+
+ Support is currently limited to only returning a std::unique_ptr from a function.
+
2022-06-29: wsfulton
#999 #1044 Enhance SWIGTYPE "out" typemaps to use std::move when copying
objects, thereby making use of move semantics when wrapping a function returning
diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html
index b98713961..52764eeef 100644
--- a/Doc/Manual/CPlusPlus11.html
+++ b/Doc/Manual/CPlusPlus11.html
@@ -1236,8 +1236,10 @@ While SWIG could provide wrappers for the new C++11 regular expressions classes,
SWIG provides special smart pointer handling for std::shared_ptr in the same way it has support for boost::shared_ptr.
-Please see the shared_ptr smart pointer library section.
-There is no special smart pointer handling available for std::weak_ptr and std::unique_ptr yet.
+Please see the shared_ptr smart pointer
+and unique_ptr smart pointer library sections.
+There is no special smart pointer handling available for std::weak_ptr.
+
diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html
index ef87cf78d..39d83bd14 100644
--- a/Doc/Manual/Contents.html
+++ b/Doc/Manual/Contents.html
@@ -448,6 +448,7 @@
shared_ptr and templates
shared_ptr and directors
+unique_ptr smart pointer
auto_ptr smart pointer
Utility Libraries
diff --git a/Doc/Manual/Library.html b/Doc/Manual/Library.html
index 3ecfc3a39..b18ecc957 100644
--- a/Doc/Manual/Library.html
+++ b/Doc/Manual/Library.html
@@ -40,6 +40,7 @@
shared_ptr and templates
shared_ptr and directors
+unique_ptr smart pointer
auto_ptr smart pointer
Utility Libraries
@@ -2040,38 +2041,45 @@ The SWIG code below shows the required ordering:
The languages that support shared_ptr also have support for using shared_ptr with directors.
-
-
+
-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:
-std_auto_ptr.i defines the typemaps which apply to the functions
-returning objects of this type. Any other use of std_auto_ptr.i is not
-directly supported.
+The std_unique_ptr.i library file provides SWIG's unique_ptr support.
+It defines typemaps and a macro, %unique_ptr(T), to use for handling
+std::unique_ptr<T> for a type T.
+The type T must be non-primitive.
+This macro should be used before any code declaring or using type T.
+Ordering requirements for using this smart pointer macro are the same as the
+equivalent %shared_ptr(T) macro covered in the previous section.
-A typical example of use would be
+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 would be
-%include <std_auto_ptr.i>
+%include <std_unique_ptr.i>
-%auto_ptr(Klass)
+%unique_ptr(Klass)
%inline %{
+#include <memory>
class Klass {
public:
// Factory function creating objects of this class:
- static std::auto_ptr<Klass> Create(int value) {
- return std::auto_ptr<Klass>(new Klass(value));
+ static std::unique_ptr<Klass> Create(int value) {
+ return std::unique_ptr<Klass>(new Klass(value));
}
int getValue() const { return m_value; }
private:
- DerivedIntValue(int value) : m_value(value) {}
+ Klass(int value) : m_value(value) {}
int m_value;
};
%}
@@ -2090,6 +2098,89 @@ int value = k.getValue();
+
+The implementation simply calls std::unique_ptr::release() to obtain
+the underlying raw pointer. The pointer is then used to create a target language
+proxy class in the same way that SWIG handles a C++ function returning a class by value.
+The target language proxy class then owns the memory pointed to by the raw pointer
+and memory handling is identical to normal SWIG proxy class handling of the underlying C++ memory.
+Note that an object returned by value is first copied/moved from the stack onto the heap in order to obtain
+a raw pointer on the heap, whereas the underlying raw pointer in std::unique_ptr already points to an object the heap.
+
+
+
+Note that the implementation is quite different to the std::shared_ptr smart pointer,
+where the proxy class manages the underlying C++ memory as a pointer to a shared_ptr instead of a plain raw 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.
+
+
+
+The std_auto_ptr.i library file provides SWIG's auto_ptr support.
+It defines typemaps and a macro, %auto_ptr(T), to use for handling
+std::auto_ptr<T> for a type T.
+The type T must be non-primitive.
+This macro should be used before any code declaring or using type T.
+Ordering requirements for using this smart pointer macro are the same as the
+equivalent %shared_ptr(T) and %unique_ptr macros covered in
+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 would be
+
+
+
+%include <std_auto_ptr.i>
+
+%auto_ptr(Klass)
+%inline %{
+#include <memory>
+class Klass {
+public:
+ // Factory function creating objects of this class:
+ static std::auto_ptr<Klass> Create(int value) {
+ return std::auto_ptr<Klass>(new Klass(value));
+ }
+
+ int getValue() const { return m_value; }
+
+private:
+ Klass(int value) : m_value(value) {}
+ int m_value;
+};
+%}
+
+
+
+
+The returned objects can be used naturally from the target language, e.g. from
+C#:
+
+
+
+
+Klass k = Klass.Create(17);
+int value = k.getValue();
+
+
+
+
+The implementation simply calls std::auto_ptr::release() to obtain the underlying raw pointer.
+That is, it works the same way covered in the previous section for std::unique_ptr.
+
+
diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
index a640febc1..bf0e52f02 100644
--- a/Examples/test-suite/common.mk
+++ b/Examples/test-suite/common.mk
@@ -612,6 +612,7 @@ CPP11_TEST_CASES += \
cpp11_sizeof_object \
cpp11_static_assert \
cpp11_std_array \
+ cpp11_std_unique_ptr \
cpp11_strongly_typed_enumerations \
cpp11_thread_local \
cpp11_template_double_brackets \
diff --git a/Examples/test-suite/cpp11_std_unique_ptr.i b/Examples/test-suite/cpp11_std_unique_ptr.i
new file mode 100644
index 000000000..518d9be6e
--- /dev/null
+++ b/Examples/test-suite/cpp11_std_unique_ptr.i
@@ -0,0 +1,53 @@
+%module cpp11_std_unique_ptr
+
+#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY)
+
+%include "std_unique_ptr.i"
+
+%unique_ptr(Klass)
+
+%inline %{
+#include
+#include
+#include "swig_examples_lock.h"
+
+class Klass {
+public:
+ explicit Klass(const char* label) :
+ m_label(label)
+ {
+ SwigExamples::Lock lock(critical_section);
+ total_count++;
+ }
+
+ const char* getLabel() const { return m_label.c_str(); }
+
+ ~Klass()
+ {
+ SwigExamples::Lock lock(critical_section);
+ total_count--;
+ }
+
+ static int getTotal_count() { return total_count; }
+
+private:
+ static SwigExamples::CriticalSection critical_section;
+ static int total_count;
+
+ std::string m_label;
+};
+
+SwigExamples::CriticalSection Klass::critical_section;
+int Klass::total_count = 0;
+
+%}
+
+%inline %{
+
+std::unique_ptr makeKlassUniquePtr(const char* label) {
+ return std::unique_ptr(new Klass(label));
+}
+
+%}
+
+#endif
diff --git a/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs b/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs
new file mode 100644
index 000000000..db5c8cff0
--- /dev/null
+++ b/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs
@@ -0,0 +1,64 @@
+using System;
+using cpp11_std_unique_ptrNamespace;
+
+public class cpp11_std_unique_ptr_runme {
+ private static void WaitForGC()
+ {
+ System.GC.Collect();
+ System.GC.WaitForPendingFinalizers();
+ System.Threading.Thread.Sleep(10);
+ }
+
+ public static void Main()
+ {
+ Klass k1 = cpp11_std_unique_ptr.makeKlassUniquePtr("first");
+ if (k1.getLabel() != "first")
+ throw new Exception("wrong object label");
+
+ Klass k2 = cpp11_std_unique_ptr.makeKlassUniquePtr("second");
+ if (Klass.getTotal_count() != 2)
+ throw new Exception("number of objects should be 2");
+
+ using (Klass k3 = cpp11_std_unique_ptr.makeKlassUniquePtr("second")) {
+ if (Klass.getTotal_count() != 3)
+ throw new Exception("number of objects should be 3");
+ }
+ if (Klass.getTotal_count() != 2)
+ throw new Exception("number of objects should be 2");
+
+ k1 = null;
+ {
+ int countdown = 500;
+ int expectedCount = 1;
+ while (true) {
+ WaitForGC();
+ if (--countdown == 0)
+ break;
+ if (Klass.getTotal_count() == expectedCount)
+ break;
+ };
+ int actualCount = Klass.getTotal_count();
+ if (actualCount != expectedCount)
+ Console.Error.WriteLine("Expected count: " + expectedCount + " Actual count: " + actualCount); // Finalizers are not guaranteed to be run and sometimes they just don't
+ }
+
+ if (k2.getLabel() != "second")
+ throw new Exception("wrong object label");
+
+ k2 = null;
+ {
+ int countdown = 500;
+ int expectedCount = 0;
+ while (true) {
+ WaitForGC();
+ if (--countdown == 0)
+ break;
+ if (Klass.getTotal_count() == expectedCount)
+ break;
+ }
+ int actualCount = Klass.getTotal_count();
+ if (actualCount != expectedCount)
+ Console.Error.WriteLine("Expected count: " + expectedCount + " Actual count: " + actualCount); // Finalizers are not guaranteed to be run and sometimes they just don't
+ }
+ }
+}
diff --git a/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java b/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java
new file mode 100644
index 000000000..a734b0e5e
--- /dev/null
+++ b/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java
@@ -0,0 +1,68 @@
+import cpp11_std_unique_ptr.*;
+
+public class cpp11_std_unique_ptr_runme {
+ static {
+ try {
+ System.loadLibrary("cpp11_std_unique_ptr");
+ } 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);
+ }
+ }
+
+ private static void WaitForGC()
+ {
+ System.gc();
+ System.runFinalization();
+ try {
+ java.lang.Thread.sleep(10);
+ } catch (java.lang.InterruptedException e) {
+ }
+ }
+
+ public static void main(String argv[]) throws Throwable
+ {
+ Klass k1 = cpp11_std_unique_ptr.makeKlassUniquePtr("first");
+ if (!k1.getLabel().equals("first"))
+ throw new RuntimeException("wrong object label");
+
+ Klass k2 = cpp11_std_unique_ptr.makeKlassUniquePtr("second");
+ if (Klass.getTotal_count() != 2)
+ throw new RuntimeException("number of objects should be 2");
+
+ k1 = null;
+ {
+ int countdown = 500;
+ int expectedCount = 1;
+ while (true) {
+ WaitForGC();
+ if (--countdown == 0)
+ break;
+ if (Klass.getTotal_count() == expectedCount)
+ break;
+ }
+ int actualCount = Klass.getTotal_count();
+ if (actualCount != expectedCount)
+ System.err.println("GC failed to run (cpp11_std_unique_ptr 1). Expected count: " + expectedCount + " Actual count: " + actualCount); // Finalizers are not guaranteed to be run and sometimes they just don't
+ }
+
+ if (!k2.getLabel().equals("second"))
+ throw new RuntimeException("wrong object label");
+
+ k2 = null;
+ {
+ int countdown = 500;
+ int expectedCount = 0;
+ while (true) {
+ WaitForGC();
+ if (--countdown == 0)
+ break;
+ if (Klass.getTotal_count() == expectedCount)
+ break;
+ };
+ int actualCount = Klass.getTotal_count();
+ if (actualCount != expectedCount)
+ System.err.println("GC failed to run (cpp11_std_unique_ptr 2). Expected count: " + expectedCount + " Actual count: " + actualCount); // Finalizers are not guaranteed to be run and sometimes they just don't
+ }
+ }
+}
diff --git a/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py b/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py
new file mode 100644
index 000000000..a84efcd5f
--- /dev/null
+++ b/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py
@@ -0,0 +1,17 @@
+from cpp11_std_unique_ptr import *
+
+k1 = makeKlassUniquePtr("first")
+k2 = makeKlassUniquePtr("second")
+if Klass.getTotal_count() != 2:
+ raise "number of objects should be 2"
+
+del k1
+if Klass.getTotal_count() != 1:
+ raise "number of objects should be 1"
+
+if k2.getLabel() != "second":
+ raise "wrong object label"
+
+del k2
+if Klass.getTotal_count() != 0:
+ raise "no objects should be left"
diff --git a/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb b/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb
new file mode 100644
index 000000000..cfc03fe2a
--- /dev/null
+++ b/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+
+require 'swig_assert'
+
+require 'cpp11_std_unique_ptr'
+
+def gc_check(expected_count)
+# GC.start(full_mark: true, immediate_sweep: true)
+ GC.start
+# GC is not reliably run, skip check
+# swig_assert_equal_simple(expected_count, Cpp11_std_unique_ptr::Klass::getTotal_count())
+end
+
+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())
+
+gc_check(2)
+k1 = nil
+gc_check(1)
+
+swig_assert_equal_simple(k2.getLabel(), "second")
+gc_check(1)
+
+k2 = nil
+gc_check(0)
+
diff --git a/Lib/csharp/std_unique_ptr.i b/Lib/csharp/std_unique_ptr.i
new file mode 100644
index 000000000..b2716756a
--- /dev/null
+++ b/Lib/csharp/std_unique_ptr.i
@@ -0,0 +1,27 @@
+/* -----------------------------------------------------------------------------
+ * 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).
+ * ----------------------------------------------------------------------------- */
+
+%define %unique_ptr(TYPE)
+%typemap (ctype) std::unique_ptr< TYPE > "void *"
+%typemap (imtype, out="System.IntPtr") std::unique_ptr< TYPE > "HandleRef"
+%typemap (cstype) std::unique_ptr< TYPE > "$typemap(cstype, TYPE)"
+%typemap (out) std::unique_ptr< TYPE > %{
+ $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;
+ }
+%template() std::unique_ptr< TYPE >;
+%enddef
+
+namespace std {
+ template class unique_ptr {};
+}
diff --git a/Lib/java/std_unique_ptr.i b/Lib/java/std_unique_ptr.i
new file mode 100644
index 000000000..665d913ae
--- /dev/null
+++ b/Lib/java/std_unique_ptr.i
@@ -0,0 +1,29 @@
+/* -----------------------------------------------------------------------------
+ * 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).
+ * ----------------------------------------------------------------------------- */
+
+%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 (out) std::unique_ptr< TYPE > %{
+ 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);
+ }
+%template() std::unique_ptr< TYPE >;
+%enddef
+
+namespace std {
+ template class unique_ptr {};
+}
diff --git a/Lib/python/std_unique_ptr.i b/Lib/python/std_unique_ptr.i
new file mode 100644
index 000000000..331817f76
--- /dev/null
+++ b/Lib/python/std_unique_ptr.i
@@ -0,0 +1,19 @@
+/* -----------------------------------------------------------------------------
+ * 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).
+ * ----------------------------------------------------------------------------- */
+
+%define %unique_ptr(TYPE)
+%typemap (out) std::unique_ptr< TYPE > %{
+ %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 {};
+}
diff --git a/Lib/ruby/std_unique_ptr.i b/Lib/ruby/std_unique_ptr.i
new file mode 100644
index 000000000..163c7c2d1
--- /dev/null
+++ b/Lib/ruby/std_unique_ptr.i
@@ -0,0 +1,19 @@
+/* -----------------------------------------------------------------------------
+ * 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).
+ * ----------------------------------------------------------------------------- */
+
+%define %unique_ptr(TYPE)
+%typemap (out) std::unique_ptr< TYPE > %{
+ %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 {};
+}