diff --git a/CHANGES.current b/CHANGES.current index c50691bac..2fed37737 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-08-05: wsfulton + [D] Add support for std::unique_ptr in std_unique_ptr.i. + Add support for std::auto_ptr in std_auto_ptr.i. + 2022-08-03: wsfulton [Javascript] Add support for std::unique_ptr in std_unique_ptr.i. Add support for std::auto_ptr in std_auto_ptr.i. diff --git a/Examples/test-suite/cpp11_std_unique_ptr.i b/Examples/test-suite/cpp11_std_unique_ptr.i index 9475890d8..49c85d6aa 100644 --- a/Examples/test-suite/cpp11_std_unique_ptr.i +++ b/Examples/test-suite/cpp11_std_unique_ptr.i @@ -1,6 +1,6 @@ %module cpp11_std_unique_ptr -#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) || defined(SWIGJAVASCRIPT) +#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) || defined(SWIGJAVASCRIPT) || defined(SWIGD) %include "std_string.i" %include "std_unique_ptr.i" diff --git a/Examples/test-suite/d/cpp11_std_unique_ptr_runme.1.d b/Examples/test-suite/d/cpp11_std_unique_ptr_runme.1.d new file mode 100644 index 000000000..7730f255f --- /dev/null +++ b/Examples/test-suite/d/cpp11_std_unique_ptr_runme.1.d @@ -0,0 +1,101 @@ +module cpp11_std_unique_ptr_runme; + +import cpp11_std_unique_ptr.cpp11_std_unique_ptr; +import cpp11_std_unique_ptr.Klass; +import cpp11_std_unique_ptr.KlassInheritance; +import std.conv; +import std.algorithm; + +void checkCount(int expected_count) { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new Exception("Counts incorrect, expected:" ~ to!string(expected_count) ~ " actual:" ~ to!string(actual_count)); +} + +void main() { + // unique_ptr as input + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassUniquePtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassUniquePtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + bool exception_thrown = false; + try { + takeKlassUniquePtr(kin); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("double usage of takeKlassUniquePtr should have been an error"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + bool exception_thrown = false; + Klass notowned = get_not_owned_ptr(kin); + try { + takeKlassUniquePtr(notowned); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("Should have thrown 'Cannot release ownership as memory is not owned' error"); + checkCount(1); + } + checkCount(0); + + /* + { + scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); + checkCount(1); + string s = takeKlassUniquePtr(kini); + checkCount(0); + if (s != "KlassInheritanceInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kini)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + */ + + // unique_ptr as output + Klass k1 = makeKlassUniquePtr("first"); + if (k1.getLabel() != "first") + throw new Exception("wrong object label"); + + Klass k2 = makeKlassUniquePtr("second"); + if (Klass.getTotal_count() != 2) + throw new Exception("number of objects should be 2"); + + k1.dispose(); + if (Klass.getTotal_count() != 1) + throw new Exception("number of objects should be 1"); + + if (k2.getLabel() != "second") + throw new Exception("wrong object label"); + + k2.dispose(); + if (Klass.getTotal_count() != 0) + throw new Exception("no objects should be left"); +} diff --git a/Examples/test-suite/d/cpp11_std_unique_ptr_runme.2.d b/Examples/test-suite/d/cpp11_std_unique_ptr_runme.2.d new file mode 100644 index 000000000..7730f255f --- /dev/null +++ b/Examples/test-suite/d/cpp11_std_unique_ptr_runme.2.d @@ -0,0 +1,101 @@ +module cpp11_std_unique_ptr_runme; + +import cpp11_std_unique_ptr.cpp11_std_unique_ptr; +import cpp11_std_unique_ptr.Klass; +import cpp11_std_unique_ptr.KlassInheritance; +import std.conv; +import std.algorithm; + +void checkCount(int expected_count) { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new Exception("Counts incorrect, expected:" ~ to!string(expected_count) ~ " actual:" ~ to!string(actual_count)); +} + +void main() { + // unique_ptr as input + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassUniquePtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassUniquePtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + bool exception_thrown = false; + try { + takeKlassUniquePtr(kin); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("double usage of takeKlassUniquePtr should have been an error"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + bool exception_thrown = false; + Klass notowned = get_not_owned_ptr(kin); + try { + takeKlassUniquePtr(notowned); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("Should have thrown 'Cannot release ownership as memory is not owned' error"); + checkCount(1); + } + checkCount(0); + + /* + { + scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); + checkCount(1); + string s = takeKlassUniquePtr(kini); + checkCount(0); + if (s != "KlassInheritanceInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kini)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + */ + + // unique_ptr as output + Klass k1 = makeKlassUniquePtr("first"); + if (k1.getLabel() != "first") + throw new Exception("wrong object label"); + + Klass k2 = makeKlassUniquePtr("second"); + if (Klass.getTotal_count() != 2) + throw new Exception("number of objects should be 2"); + + k1.dispose(); + if (Klass.getTotal_count() != 1) + throw new Exception("number of objects should be 1"); + + if (k2.getLabel() != "second") + throw new Exception("wrong object label"); + + k2.dispose(); + if (Klass.getTotal_count() != 0) + throw new Exception("no objects should be left"); +} diff --git a/Examples/test-suite/d/li_std_auto_ptr_runme.1.d b/Examples/test-suite/d/li_std_auto_ptr_runme.1.d new file mode 100644 index 000000000..76c81ffc8 --- /dev/null +++ b/Examples/test-suite/d/li_std_auto_ptr_runme.1.d @@ -0,0 +1,101 @@ +module li_std_auto_ptr_runme; + +import li_std_auto_ptr.li_std_auto_ptr; +import li_std_auto_ptr.Klass; +import li_std_auto_ptr.KlassInheritance; +import std.conv; +import std.algorithm; + +void checkCount(int expected_count) { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new Exception("Counts incorrect, expected:" ~ to!string(expected_count) ~ " actual:" ~ to!string(actual_count)); +} + +void main() { + // auto_ptr as input + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassAutoPtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassAutoPtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + bool exception_thrown = false; + try { + takeKlassAutoPtr(kin); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("double usage of takeKlassAutoPtr should have been an error"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + bool exception_thrown = false; + Klass notowned = get_not_owned_ptr(kin); + try { + takeKlassAutoPtr(notowned); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("Should have thrown 'Cannot release ownership as memory is not owned' error"); + checkCount(1); + } + checkCount(0); + + /* + { + scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); + checkCount(1); + string s = takeKlassAutoPtr(kini); + checkCount(0); + if (s != "KlassInheritanceInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kini)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + */ + + // auto_ptr as output + Klass k1 = makeKlassAutoPtr("first"); + if (k1.getLabel() != "first") + throw new Exception("wrong object label"); + + Klass k2 = makeKlassAutoPtr("second"); + if (Klass.getTotal_count() != 2) + throw new Exception("number of objects should be 2"); + + k1.dispose(); + if (Klass.getTotal_count() != 1) + throw new Exception("number of objects should be 1"); + + if (k2.getLabel() != "second") + throw new Exception("wrong object label"); + + k2.dispose(); + if (Klass.getTotal_count() != 0) + throw new Exception("no objects should be left"); +} diff --git a/Examples/test-suite/d/li_std_auto_ptr_runme.2.d b/Examples/test-suite/d/li_std_auto_ptr_runme.2.d new file mode 100644 index 000000000..76c81ffc8 --- /dev/null +++ b/Examples/test-suite/d/li_std_auto_ptr_runme.2.d @@ -0,0 +1,101 @@ +module li_std_auto_ptr_runme; + +import li_std_auto_ptr.li_std_auto_ptr; +import li_std_auto_ptr.Klass; +import li_std_auto_ptr.KlassInheritance; +import std.conv; +import std.algorithm; + +void checkCount(int expected_count) { + int actual_count = Klass.getTotal_count(); + if (actual_count != expected_count) + throw new Exception("Counts incorrect, expected:" ~ to!string(expected_count) ~ " actual:" ~ to!string(actual_count)); +} + +void main() { + // auto_ptr as input + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassAutoPtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + checkCount(1); + string s = takeKlassAutoPtr(kin); + checkCount(0); + if (s != "KlassInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kin)) + throw new Exception("is_nullptr failed"); + bool exception_thrown = false; + try { + takeKlassAutoPtr(kin); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("double usage of takeKlassAutoPtr should have been an error"); + } // dispose should not fail, even though already deleted + checkCount(0); + + { + scope Klass kin = new Klass("KlassInput"); + bool exception_thrown = false; + Klass notowned = get_not_owned_ptr(kin); + try { + takeKlassAutoPtr(notowned); + } catch (Exception e) { + if (!canFind(e.msg, "Cannot release ownership as memory is not owned")) + throw new Exception("incorrect exception message: " ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("Should have thrown 'Cannot release ownership as memory is not owned' error"); + checkCount(1); + } + checkCount(0); + + /* + { + scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); + checkCount(1); + string s = takeKlassAutoPtr(kini); + checkCount(0); + if (s != "KlassInheritanceInput") + throw new Exception("Incorrect string: " ~ s); + if (!is_nullptr(kini)) + throw new Exception("is_nullptr failed"); + } // dispose should not fail, even though already deleted + checkCount(0); + */ + + // auto_ptr as output + Klass k1 = makeKlassAutoPtr("first"); + if (k1.getLabel() != "first") + throw new Exception("wrong object label"); + + Klass k2 = makeKlassAutoPtr("second"); + if (Klass.getTotal_count() != 2) + throw new Exception("number of objects should be 2"); + + k1.dispose(); + if (Klass.getTotal_count() != 1) + throw new Exception("number of objects should be 1"); + + if (k2.getLabel() != "second") + throw new Exception("wrong object label"); + + k2.dispose(); + if (Klass.getTotal_count() != 0) + throw new Exception("no objects should be left"); +} diff --git a/Examples/test-suite/li_std_auto_ptr.i b/Examples/test-suite/li_std_auto_ptr.i index 06591a971..afa4782c3 100644 --- a/Examples/test-suite/li_std_auto_ptr.i +++ b/Examples/test-suite/li_std_auto_ptr.i @@ -12,7 +12,7 @@ #endif %} -#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) || defined(SWIGJAVASCRIPT) +#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) || defined(SWIGJAVASCRIPT) || defined(SWIGD) %include "std_string.i" %include "std_auto_ptr.i" diff --git a/Lib/d/dclassgen.swg b/Lib/d/dclassgen.swg index 84fa03a0b..e4ff8d5f5 100644 --- a/Lib/d/dclassgen.swg +++ b/Lib/d/dclassgen.swg @@ -76,6 +76,19 @@ public static void* swigGetCPtr(typeof(this) obj) { return (obj is null) ? null : obj.swigCPtr; } +public static void* swigRelease(typeof(this) obj) { + if (obj !is null) { + if (!obj.swigCMemOwn) + throw new Exception("Cannot release ownership as memory is not owned"); + void* ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + obj.dispose(); + return ptr; + } else { + return null; + } +} + mixin $imdmodule.SwigOperatorDefinitions; %} @@ -92,6 +105,19 @@ public static void* swigGetCPtr(typeof(this) obj) { return (obj is null) ? null : obj.swigCPtr; } +public static void* swigRelease(typeof(this) obj) { + if (obj !is null) { + if (!obj.swigCMemOwn) + throw new Exception("Cannot release ownership as memory is not owned"); + void* ptr = obj.swigCPtr; + obj.swigCMemOwn = false; + obj.dispose(); + return ptr; + } else { + return null; + } +} + mixin $imdmodule.SwigOperatorDefinitions; %} @@ -100,7 +126,7 @@ mixin $imdmodule.SwigOperatorDefinitions; * Type wrapper classes. */ -%typemap(dbody) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [] %{ +%typemap(dbody) SWIGTYPE *, SWIGTYPE &, SWIGTYPE &&, SWIGTYPE [] %{ private void* swigCPtr; public this(void* cObject, bool futureUse) { @@ -115,6 +141,10 @@ public static void* swigGetCPtr(typeof(this) obj) { return (obj is null) ? null : obj.swigCPtr; } +public static void* swigRelease(typeof(this) obj) { + return (obj is null) ? null : obj.swigCPtr; +} + mixin $imdmodule.SwigOperatorDefinitions; %} diff --git a/Lib/d/std_auto_ptr.i b/Lib/d/std_auto_ptr.i new file mode 100644 index 000000000..e04a18061 --- /dev/null +++ b/Lib/d/std_auto_ptr.i @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------------- + * std_auto_ptr.i + * + * 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) std::auto_ptr< TYPE > "void*" +%typemap (dtype) std::auto_ptr< TYPE > "$typemap(dtype, TYPE)" + +%typemap(in) std::auto_ptr< TYPE > +%{ $1.reset((TYPE *)$input); %} + +%typemap(din, + nativepointer="cast(void*)$dinput" +) std::auto_ptr< TYPE > "$typemap(dtype, TYPE).swigRelease($dinput)" + +%typemap (out) std::auto_ptr< TYPE > %{ + $result = (void *)$1.release(); +%} + +%typemap(dout, excode=SWIGEXCODE, + nativepointer="{\n auto ret = cast($dtype)$imcall;$excode\n return ret;\n}" +) std::auto_ptr< TYPE > { + void* cPtr = $imcall; + $typemap(dtype, TYPE) ret = (cPtr is null) ? null : new $typemap(dtype, TYPE)(cPtr, true);$excode + return ret; +} + +%template() std::auto_ptr< TYPE >; +%enddef + +namespace std { + template class auto_ptr {}; +} diff --git a/Lib/d/std_unique_ptr.i b/Lib/d/std_unique_ptr.i new file mode 100644 index 000000000..8a06ba066 --- /dev/null +++ b/Lib/d/std_unique_ptr.i @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------------- + * std_unique_ptr.i + * + * 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) std::unique_ptr< TYPE > "void*" +%typemap (dtype) std::unique_ptr< TYPE > "$typemap(dtype, TYPE)" + +%typemap(in) std::unique_ptr< TYPE > +%{ $1.reset((TYPE *)$input); %} + +%typemap(din, + nativepointer="cast(void*)$dinput" +) std::unique_ptr< TYPE > "$typemap(dtype, TYPE).swigRelease($dinput)" + +%typemap (out) std::unique_ptr< TYPE > %{ + $result = (void *)$1.release(); +%} + +%typemap(dout, excode=SWIGEXCODE, + nativepointer="{\n auto ret = cast($dtype)$imcall;$excode\n return ret;\n}" +) std::unique_ptr< TYPE > { + void* cPtr = $imcall; + $typemap(dtype, TYPE) ret = (cPtr is null) ? null : new $typemap(dtype, TYPE)(cPtr, true);$excode + return ret; +} + +%template() std::unique_ptr< TYPE >; +%enddef + +namespace std { + template class unique_ptr {}; +}