Add std::unique_ptr && output typemaps

Move semantics are not supported by default.
They behave as if a lvalue reference was returned.
This commit is contained in:
William S Fulton 2024-03-02 18:35:43 +00:00
parent e76952e355
commit 3f1e40d2f4
30 changed files with 201 additions and 2 deletions

View File

@ -12,7 +12,8 @@ Version 4.3.0 (in progress)
2024-02-02: wsfulton
#2650 Add support for movable std::unique_ptr by adding in std::unique_ptr &&
typemaps.
input typemaps. The std::unique && output typemaps do not support move
semantics by default and behave like lvalue references.
2024-01-23: wsfulton
Add missing use of move constructor instead of copy constructor when

View File

@ -2221,6 +2221,19 @@ void grab(std::unique_ptr<Klass> &&);
</pre>
</div>
<p>
Move semantics are not provided when wrapping a C++ function that returns a <tt>std::unique_ptr</tt> by rvalue reference.
The target language proxy class wrapper that is returned does not own the underlying C++ object.
Example:
</p>
<div class="code">
<pre>
std::unique_ptr<Klass> &amp;&amp; RvalueRefReturn();
</pre>
</div>
<p>
<b>Compatibility note:</b> Support for <tt>std::unique_ptr</tt> was first added in SWIG-4.1.0.
This initial support contained the move semantics when passing a <tt>std::unique_ptr</tt> around by value. Support for passing a <tt>std::unique_ptr</tt> around by rvalue reference was added in SWIG-4.3.0.

View File

@ -98,6 +98,26 @@ std::unique_ptr<Klass> makeNullUniquePtr() {
return std::unique_ptr<Klass>();
}
#include <iostream>
std::unique_ptr<Klass>&& makeRVRKlassUniquePtr(const char* label) {
static std::unique_ptr<Klass> up;
#if !defined(SWIGTCL)
up.reset(label ? new Klass(label) : nullptr);
#else // No way to pass a null pointer for a string as "NULL" is only way for Tcl to specify a null pointer
up.reset(strcmp(label, "NULL") != 0 ? new Klass(label) : nullptr);
#endif
return std::move(up);
}
/*
std::unique_ptr<Klass>& makeRefKlassUniquePtr(const char* label) {
static std::unique_ptr<Klass> up;
up.reset(new Klass(label));
return up;
}
*/
int overloadTest() {
return 0;
}

View File

@ -204,5 +204,13 @@ public class cpp11_std_unique_ptr_runme {
if (cpp11_std_unique_ptr.makeNullUniquePtr() != null)
throw new Exception("null failure");
// unique_ptr as output (rvalue ref)
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr("first");
if (k1.getLabel() != "first")
throw new Exception("wrong object label");
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr(null);
if (k1 != null)
throw new Exception("not null");
}
}

View File

@ -200,4 +200,12 @@ void main() {
if (makeNullUniquePtr() !is null)
throw new Exception("null failure");
// unique_ptr as output (rvalue ref)
k1 = makeRVRKlassUniquePtr("first");
if (k1.getLabel() != "first")
throw new Exception("wrong object label");
k1 = makeRVRKlassUniquePtr(null);
if (k1 !is null)
throw new Exception("not null");
}

View File

@ -228,5 +228,13 @@ public class cpp11_std_unique_ptr_runme {
if (cpp11_std_unique_ptr.makeNullUniquePtr() != null)
throw new RuntimeException("null failure");
// unique_ptr as output (rvalue ref)
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr("first");
if (!k1.getLabel().equals("first"))
throw new RuntimeException("wrong object label");
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr(null);
if (k1 != null)
throw new RuntimeException("not null");
}
}

View File

@ -213,3 +213,9 @@ checkCount(0);
if (cpp11_std_unique_ptr.makeNullUniquePtr() != null)
throw new Error("null failure");
// unique_ptr as output (rvalue ref)
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr("first");
if (k1.getLabel() !== "first")
throw new Error("wrong object label");
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr(null);

View File

@ -180,3 +180,10 @@ k2 = nil
checkCount(0)
assert(cpp11_std_unique_ptr.makeNullUniquePtr() == nil)
-- unique_ptr as output (rvalue ref)
k1 = cpp11_std_unique_ptr.makeRVRKlassUniquePtr("first")
if not (k1:getLabel() == "first") then
error("wrong object label")
end
assert(cpp11_std_unique_ptr.makeRVRKlassUniquePtr(nil) == nil)

View File

@ -176,4 +176,11 @@
(unless (null? (makeNullUniquePtr))
(error "null failure"))
; unique_ptr as output (rvalue ref)
(define k1 (makeRVRKlassUniquePtr "first"))
(unless (string=? (Klass-getLabel k1) "first")
(error "wrong object label" ))
(unless (null? (makeRVRKlassUniquePtr '()))
(error "null failure"))
(exit 0)

View File

@ -228,3 +228,11 @@ null_smart_prt = makeNullUniquePtr();
assert(ismatrix(null_smart_prt))
assert(size(null_smart_prt) == size([]))
assert(isequal([], null_smart_prt))
# unique_ptr as output (rvalue ref)
k1 = makeRVRKlassUniquePtr("first");
if (!strcmp(k1.getLabel(), "first"))
error("wrong object label");
endif
k1 = makeRVRKlassUniquePtr([]);
assert(isequal([], k1))

View File

@ -1,6 +1,6 @@
use strict;
use warnings;
use Test::More tests => 58;
use Test::More tests => 60;
BEGIN { use_ok('cpp11_std_unique_ptr') }
require_ok('cpp11_std_unique_ptr');
@ -161,3 +161,8 @@ undef $k2;
checkCount(0);
is(cpp11_std_unique_ptr::makeNullUniquePtr(), undef);
# unique_ptr as output (rvalue ref)
my $k1 = cpp11_std_unique_ptr::makeRVRKlassUniquePtr("first");
is($k1->getLabel, "first", "proper label");
is(cpp11_std_unique_ptr::makeRVRKlassUniquePtr(undef), undef);

View File

@ -181,4 +181,10 @@ checkCount(0);
check::equal(makeNullUniquePtr(), NULL);
# unique_ptr as output (rvalue ref)
$k1 = makeRVRKlassUniquePtr("first");
check::equal($k1->getLabel(), "first", "proper label");
$k1 = makeRVRKlassUniquePtr(NULL);
check::equal(makeRVRKlassUniquePtr(NULL), NULL);
check::done();

View File

@ -185,3 +185,10 @@ checkCount(0)
if (makeNullUniquePtr() != None):
raise RuntimeError("null failure")
# unique_ptr as output (rvalue ref)
k1 = makeRVRKlassUniquePtr("first")
if k1.getLabel() != "first":
raise "wrong object label"
if (makeRVRKlassUniquePtr(None) != None):
raise RuntimeError("null failure")

View File

@ -254,3 +254,8 @@ k2 = nil
gc_check(0)
swig_assert_equal_simple(Cpp11_std_unique_ptr::makeNullUniquePtr(), nil)
# unique_ptr as output (rvalue ref)
k1 = Cpp11_std_unique_ptr::makeRVRKlassUniquePtr("first")
swig_assert_equal_simple(k1.getLabel(), "first")
swig_assert_equal_simple(Cpp11_std_unique_ptr::makeRVRKlassUniquePtr(nil), nil)

View File

@ -254,3 +254,12 @@ checkCount 0
if {[makeNullUniquePtr] != "NULL"} {
error "null failure"
}
# unique_ptr as output (rvalue ref)
set k1 [makeRVRKlassUniquePtr "first"]
if {[$k1 getLabel] != "first"} {
error "wrong object label"
}
if {[makeRVRKlassUniquePtr "NULL"] != "NULL"} {
error "null failure"
}

View File

@ -24,12 +24,22 @@
%typemap (out) std::unique_ptr< TYPE > %{
$result = (void *)$1.release();
%}
%typemap (out) std::unique_ptr< TYPE > && %{
$result = (void *)$1->get();
%}
%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;
}
%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, false);$excode
return ret;
}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *") std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && ""

View File

@ -26,6 +26,10 @@
%typemap (out) std::unique_ptr< TYPE > %{
$result = (void *)$1.release();
%}
%typemap (out) std::unique_ptr< TYPE > && %{
$result = (void *)$1->get();
%}
%typemap(dout, excode=SWIGEXCODE,
nativepointer="{\n auto ret = cast($dtype)$imcall;$excode\n return ret;\n}"
@ -34,6 +38,14 @@
$typemap(dtype, TYPE) ret = (cPtr is null) ? null : new $typemap(dtype, TYPE)(cPtr, true);$excode
return ret;
}
%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, false);$excode
return ret;
}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *") std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && ""

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -28,11 +28,21 @@
*(TYPE **) &lpp = $1.release();
$result = lpp;
%}
%typemap (out) std::unique_ptr< TYPE > && %{
jlong lpp = 0;
*(TYPE **) &lpp = $1->get();
$result = lpp;
%}
%typemap(javaout) std::unique_ptr< TYPE > {
long cPtr = $jnicall;
return (cPtr == 0) ? null : new $typemap(jstype, TYPE)(cPtr, true);
}
%typemap(javaout) std::unique_ptr< TYPE > && {
long cPtr = $jnicall;
return (cPtr == 0) ? null : new $typemap(jstype, TYPE)(cPtr, false);
}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *") std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && ""

View File

@ -34,9 +34,25 @@
$1 = &uptr;
}
%typemap(in, noblock=1) std::unique_ptr< TYPE > && (void *argp = 0, int res = 0, std::unique_ptr< TYPE > uptr) {
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);
}
}
uptr.reset((TYPE *)argp);
$1 = &uptr;
}
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
SWIG_NewPointerObj(L, $1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN); SWIG_arg++;
%}
%typemap (out) std::unique_ptr< TYPE > && %{
SWIG_NewPointerObj(L, $1->get(), $descriptor(TYPE *), $owner); SWIG_arg++;
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -41,6 +41,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
SWIG_SetPointerZval($result, (void *)$1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN);
%}
%typemap (out) std::unique_ptr< TYPE > && %{
SWIG_SetPointerZval($result, (void *)$1->get(), $descriptor(TYPE *), $owner);
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
%set_output(SWIG_NewPointerObj($1->get(), $descriptor(TYPE *), $owner | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;

View File

@ -37,6 +37,9 @@
%typemap (out) std::unique_ptr< TYPE > %{
Tcl_SetObjResult(interp, SWIG_NewInstanceObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN));
%}
%typemap (out) std::unique_ptr< TYPE > && %{
Tcl_SetObjResult(interp, SWIG_NewInstanceObj($1->get(), $descriptor(TYPE *), $owner));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE >, std::unique_ptr< TYPE > && {
void *vptr = 0;