mirror of https://github.com/swig/swig
Provide SWIGTYPE MOVE typemaps in swigmove.i
For implementing full move semantics when passing parameters by value. Based on SWIGTYPE && and std::unique_ptr typemaps which implement move semantics. Added for all languages, but untested for: Go, Ocaml, R, Scilab (and unlikely to be fully functional for same reasons as for std::unique_ptr support). Issue #999
This commit is contained in:
parent
de65875955
commit
dad7c93ca0
|
@ -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-09-16: wsfulton
|
||||
#999 Provide SWIGTYPE MOVE typemaps in swigmove.i for implementing full
|
||||
move semantics when passing parameters by value.
|
||||
|
||||
2022-08-31: wsfulton
|
||||
#999 Improve move semantics when using rvalue references.
|
||||
The SWIGTYPE && input typemaps now assume the object has been moved.
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<ul>
|
||||
<li><a href="#CPlusPlus11_rvalue_reference_inputs">Rvalue reference inputs</a>
|
||||
<li><a href="#CPlusPlus11_rvalue_reference_outputs">Rvalue reference outputs</a>
|
||||
<li><a href="#CPlusPlus11_move_only">Movable and move-only types</a>
|
||||
<li><a href="#CPlusPlus11_move_only">Movable and move-only types by value</a>
|
||||
</ul>
|
||||
<li><a href="#CPlusPlus11_generalized_constant_expressions">Generalized constant expressions</a>
|
||||
<li><a href="#CPlusPlus11_extern_template">Extern template</a>
|
||||
|
@ -240,7 +240,7 @@ Another alternative would be to modify the output rvalue reference typemap to al
|
|||
Fortunately you're highly unlikely to have to solve any of these issues!
|
||||
</p>
|
||||
|
||||
<H4><a name="CPlusPlus11_move_only">7.2.1.3 Movable and move-only types</a></H4>
|
||||
<H4><a name="CPlusPlus11_move_only">7.2.1.3 Movable and move-only types by value</a></H4>
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -252,7 +252,10 @@ Movable types can appear in function signatures for passing 'by value' and in C+
|
|||
</p>
|
||||
|
||||
<p>
|
||||
SWIG has been enhanced with support for both copyable and/or movable types but this is currently just for function return values.
|
||||
SWIG has support for both copyable and/or movable types.
|
||||
Support for move semantics is quite seamless when returning by value from a function.
|
||||
Support for move semantics is less so and may require some customisation when passing by value to a function.
|
||||
First let's consider returning by value from a function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -283,6 +286,7 @@ struct MoveOnly {
|
|||
MoveOnly & operator=(MoveOnly &&) = default;
|
||||
|
||||
static MoveOnly create() { return MoveOnly(); }
|
||||
static void take(MoveOnly mo);
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
|
@ -303,17 +307,193 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_MoveOnly_create() {
|
|||
|
||||
<p>
|
||||
<tt>SwigValueWrapper</tt> is covered in <a href="SWIGPlus.html#SWIGPlus_nn19">Pass and return by value</a>.
|
||||
Note that the generated code could be optimised further using the <a href="Typemaps.html#Typemaps_optimal">"optimal" attribute</a> in the "out" typemap.
|
||||
Note that the generated code could be optimised further using the <a href="Typemaps.html#Typemaps_optimal">"optimal" attribute</a>
|
||||
in the "out" typemap, so if the above typemap is customised as follows (note that this is C# specific):
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%typemap(out, optimal="1") MoveOnly %{
|
||||
$result = new $1_ltype($1);
|
||||
%}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
then the generated code will result in the object being optimally moved:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_MoveOnly_create() {
|
||||
void * jresult ;
|
||||
jresult = new MoveOnly(MoveOnly::create());
|
||||
return jresult;
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Now let's consider passing by value.
|
||||
We'll consider three cases; namely types that are:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li> Copyable and not movable - <tt>CopyOnly</tt>.</li>
|
||||
<li> Copyable and movable - <tt>MovableCopyable</tt>.</li>
|
||||
<li> Movable and not copyable - <tt>MoveOnly</tt>.</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
and for clarification, define these two additional types as follows:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
struct CopyOnly {
|
||||
int val;
|
||||
CopyOnly(): val(0) {}
|
||||
|
||||
CopyOnly(const CopyOnly &) = default;
|
||||
CopyOnly & operator=(const CopyOnly &) = default;
|
||||
|
||||
static CopyOnly create() { return CopyOnly(); }
|
||||
static void take(CopyOnly co);
|
||||
};
|
||||
|
||||
struct MovableCopyable {
|
||||
int val;
|
||||
MovableCopyable(): val(0) {}
|
||||
|
||||
MovableCopyable(const MovableCopyable &) = default;
|
||||
MovableCopyable(MovableCopyable &&) = default;
|
||||
MovableCopyable & operator=(const MovableCopyable &) = default;
|
||||
MovableCopyable & operator=(MovableCopyable &&) = default;
|
||||
|
||||
static MovableCopyable create() { return MovableCopyable(); }
|
||||
static void take(MovableCopyable mc);
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The generated code is shown below for <tt>CopyOnly::take</tt> (with additional comments for when constructors and assignment operators are called).
|
||||
While the code shown is C# specific, the generated constructor and/or assignment operator calls are ultimately the same for all target languages.
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_CopyOnly_take(void * jarg1) {
|
||||
CopyOnly arg1 ; // (a) Default constructor
|
||||
CopyOnly *argp1 ;
|
||||
|
||||
argp1 = (CopyOnly *)jarg1;
|
||||
if (!argp1) {
|
||||
SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null CopyOnly", 0);
|
||||
return ;
|
||||
}
|
||||
arg1 = *argp1; // (b) Copy assignment
|
||||
CopyOnly::take(SWIG_STD_MOVE(arg1)); // (c) Copy constructor
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Note that <tt>SWIG_STD_MOVE</tt> is a macro defined as shown below to use <tt>std::move</tt> which is only available from C++11 onwards:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
#if __cplusplus >=201103L
|
||||
# define SWIG_STD_MOVE(OBJ) std::move(OBJ)
|
||||
#else
|
||||
# define SWIG_STD_MOVE(OBJ) OBJ
|
||||
#endif
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Also note: <i>(c) Copy constructor</i>.
|
||||
Yes, when passing by value the copy constructor is called for all versions of C++, even C++11 and later even though std::move is specified.
|
||||
It's a C++ language feature for types that don't have move semantics!
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There is currently only partial support for move-only types as
|
||||
support for move-only types used as a parameter in a function, that are passed 'by value', is not yet available.
|
||||
The generated code for <tt>MovableCopyable::take</tt> is the same as for <tt>CopyOnly::take</tt>, however, the C++ compiler will choose the move constructor this time where commented <i>(c) Move constructor</i>:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_MovableCopyable_take(void * jarg1) {
|
||||
MovableCopyable arg1 ; // (a) Default constructor
|
||||
MovableCopyable *argp1 ;
|
||||
|
||||
argp1 = (MovableCopyable *)jarg1;
|
||||
if (!argp1) {
|
||||
SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null MovableCopyable", 0);
|
||||
return ;
|
||||
}
|
||||
arg1 = *argp1; // (b) Copy assignment
|
||||
MovableCopyable::take(SWIG_STD_MOVE(arg1)); // (c) Move constructor
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
There are two optimisation opportunities available.
|
||||
</p>
|
||||
<ol>
|
||||
<li> Remove the default constructor call with the <tt>%feature("valuewrapper")</tt> covered in <a href="SWIGPlus.html#SWIGPlus_nn19">Pass and return by value</a> and replace it with <tt>SwigValueWrapper</tt>.
|
||||
</li>
|
||||
<li> Apply the SWIGTYPE MOVE typemaps which are designed specifically to implement full move semantics when passing parameters by value.
|
||||
They replace the copy assignment with a call to <tt>SwigValueWrapper::reset</tt>, which works much like <tt>std::unique_ptr::reset</tt>.
|
||||
These typemaps could alternatively have replaced the copy assignment with a move assignment, but this is not maximally optimal.
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
Simply add the following before the <tt>MovableCopyable::take</tt> method is parsed:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%valuewrapper MovableCopyable;
|
||||
%include <swigmove.i>
|
||||
%apply SWIGTYPE MOVE { MovableCopyable }
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
will result in this optimal code where just one move constructor is invoked:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_MovableCopyable_take(void * jarg1) {
|
||||
SwigValueWrapper< MovableCopyable > arg1 ; // (a) No constructors invoked
|
||||
MovableCopyable *argp1 ;
|
||||
|
||||
argp1 = (MovableCopyable *)jarg1;
|
||||
if (!argp1) {
|
||||
SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null MovableCopyable", 0);
|
||||
return ;
|
||||
}
|
||||
SwigValueWrapper< MovableCopyable >::reset(arg1, argp1); // (b) No constructor or assignment operator invoked
|
||||
MovableCopyable::take(SWIG_STD_MOVE(arg1)); // (c) Move constructor
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Note that <tt>SwigValueWrapper</tt> will call the destructor for the pointer passed to it in the <tt>reset</tt> function.
|
||||
This pointer is the underlying C++ object that the proxy class owns.
|
||||
The details aren't shown, but the 'csin' typemap also generates C# code to ensure that the proxy class releases ownership of the object.
|
||||
Please see the 'SWIGTYPE MOVE' typemaps in the swigmove.i file provided for each target language.
|
||||
Therefore full move semantics are implemented; ownership is moved from the proxy class into the C++ layer and the net effect
|
||||
is the same as using an <a href="#CPlusPlus11_rvalue_reference_inputs">rvalue reference parameter</a> discussed earlier.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Lastly, let's consider the <tt>MoveOnly::take</tt> function defined earlier.
|
||||
By default the generated code fails to compile as <tt>MoveOnly</tt> does not have a copy assignment operator.
|
||||
SWIG is not designed to select a different typemap automatically for move-only types and the user
|
||||
must apply the SWIGTYPE MOVE typemaps to ensure that only move-only semantics are used.
|
||||
However, SWIG is able to automatically use <tt>%feature("valuewrapper")</tt> for move-only
|
||||
types so it is not necessary to explicitly use this feature.
|
||||
So in this move-only case, simply add the following before <tt>MoveOnly::take</tt> is parsed, which results in the same optimal code shown above for <tt>MovableCopyable</tt>:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%include <swigmove.i>
|
||||
%apply SWIGTYPE MOVE { MoveOnly }
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
<b>Compatibility note:</b>
|
||||
SWIG-4.1.0 introduced support for taking advantage of types with move semantics and wrapping functions that return movable or move-only types 'by value'.
|
||||
SWIG-4.1.0 introduced support for taking advantage of types with move semantics and making it possible to easily use move only types.
|
||||
</p>
|
||||
|
||||
|
||||
|
|
|
@ -300,7 +300,7 @@
|
|||
<ul>
|
||||
<li><a href="CPlusPlus11.html#CPlusPlus11_rvalue_reference_inputs">Rvalue reference inputs</a>
|
||||
<li><a href="CPlusPlus11.html#CPlusPlus11_rvalue_reference_outputs">Rvalue reference outputs</a>
|
||||
<li><a href="CPlusPlus11.html#CPlusPlus11_move_only">Movable and move-only types</a>
|
||||
<li><a href="CPlusPlus11.html#CPlusPlus11_move_only">Movable and move-only types by value</a>
|
||||
</ul>
|
||||
<li><a href="CPlusPlus11.html#CPlusPlus11_generalized_constant_expressions">Generalized constant expressions</a>
|
||||
<li><a href="CPlusPlus11.html#CPlusPlus11_extern_template">Extern template</a>
|
||||
|
|
|
@ -597,8 +597,9 @@ CPP11_TEST_CASES += \
|
|||
cpp11_initializer_list \
|
||||
cpp11_initializer_list_extend \
|
||||
cpp11_lambda_functions \
|
||||
cpp11_move_only \
|
||||
cpp11_move_only_valuewrapper \
|
||||
cpp11_move_only \
|
||||
cpp11_move_typemaps \
|
||||
cpp11_move_only_valuewrapper \
|
||||
cpp11_noexcept \
|
||||
cpp11_null_pointer_constant \
|
||||
cpp11_raw_string_literals \
|
||||
|
|
|
@ -12,19 +12,23 @@ using namespace std;
|
|||
bool trace = false;
|
||||
|
||||
struct MoveOnly {
|
||||
MoveOnly(int i = 0) { if (trace) cout << "MoveOnly(" << i << ")" << " " << this << endl; Counter::normal_constructor++; }
|
||||
int val;
|
||||
MoveOnly(int i = 0) : val(i) { if (trace) cout << "MoveOnly(" << i << ")" << " " << this << endl; Counter::normal_constructor++; }
|
||||
|
||||
MoveOnly(const MoveOnly &other) = delete;
|
||||
MoveOnly & operator=(const MoveOnly &other) = delete;
|
||||
|
||||
MoveOnly(MoveOnly &&other) noexcept { if (trace) cout << "MoveOnly(MoveOnly &&)" << " " << this << endl; Counter::move_constructor++; }
|
||||
MoveOnly & operator=(MoveOnly &&other) noexcept { if (trace) cout << "operator=(MoveOnly &&)" << " " << this << endl; Counter::move_assignment++; return *this; }
|
||||
MoveOnly(MoveOnly &&other) noexcept : val(std::move(other.val)) { if (trace) cout << "MoveOnly(MoveOnly &&)" << " " << this << endl; Counter::move_constructor++; }
|
||||
MoveOnly & operator=(MoveOnly &&other) noexcept { if (trace) cout << "operator=(MoveOnly &&)" << " " << this << endl; Counter::move_assignment++; if (this != &other) { val = std::move(other.val); } return *this; }
|
||||
~MoveOnly() { if (trace) cout << "~MoveOnly()" << " " << this << endl; Counter::destructor++; }
|
||||
|
||||
static MoveOnly create() { return MoveOnly(111); }
|
||||
// static const MoveOnly createConst() { return MoveOnly(111); } // not supported by default
|
||||
|
||||
// static void take(MoveOnly mo) { if (trace) cout << "take(MoveOnly)" << " " << &mo << endl; }
|
||||
// compile error by default, see cpp11_move_typemaps.i
|
||||
#if defined(WRAP_TAKE_METHOD)
|
||||
static void take(MoveOnly mo) { if (trace) cout << "take(MoveOnly)" << " " << &mo << endl; }
|
||||
#endif
|
||||
};
|
||||
%}
|
||||
|
||||
|
@ -35,13 +39,14 @@ struct MoveOnly {
|
|||
%inline %{
|
||||
// Movable and Copyable
|
||||
struct MovableCopyable {
|
||||
MovableCopyable(int i = 0) { if (trace) cout << "MovableCopyable(" << i << ")" << " " << this << endl; Counter::normal_constructor++; }
|
||||
int val;
|
||||
MovableCopyable(int i = 0) : val(i) { if (trace) cout << "MovableCopyable(" << i << ")" << " " << this << endl; Counter::normal_constructor++; }
|
||||
|
||||
MovableCopyable(const MovableCopyable &other) { if (trace) cout << "MovableCopyable(const MovableCopyable &)" << " " << this << " " << &other << endl; Counter::copy_constructor++;}
|
||||
MovableCopyable & operator=(const MovableCopyable &other) { if (trace) cout << "operator=(const MovableCopyable &)" << " " << this << " " << &other << endl; Counter::copy_assignment++; return *this; }
|
||||
MovableCopyable(const MovableCopyable &other) : val(other.val) { if (trace) cout << "MovableCopyable(const MovableCopyable &)" << " " << this << " " << &other << endl; Counter::copy_constructor++;}
|
||||
MovableCopyable & operator=(const MovableCopyable &other) { if (trace) cout << "operator=(const MovableCopyable &)" << " " << this << " " << &other << endl; Counter::copy_assignment++; if (this != &other) { val = other.val; } return *this; }
|
||||
|
||||
MovableCopyable(MovableCopyable &&other) noexcept { if (trace) cout << "MovableCopyable(MovableCopyable &&)" << " " << this << endl; Counter::move_constructor++; }
|
||||
MovableCopyable & operator=(MovableCopyable &&other) noexcept { if (trace) cout << "operator=(MovableCopyable &&)" << " " << this << endl; Counter::move_assignment++; return *this; }
|
||||
MovableCopyable(MovableCopyable &&other) noexcept : val(std::move(other.val)) { if (trace) cout << "MovableCopyable(MovableCopyable &&)" << " " << this << endl; Counter::move_constructor++; }
|
||||
MovableCopyable & operator=(MovableCopyable &&other) noexcept { if (trace) cout << "operator=(MovableCopyable &&)" << " " << this << endl; Counter::move_assignment++; if (this != &other) { val = std::move(other.val); } return *this; }
|
||||
~MovableCopyable() { if (trace) cout << "~MovableCopyable()" << " " << this << endl; Counter::destructor++; }
|
||||
|
||||
static MovableCopyable create() { return MovableCopyable(111); }
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
%module cpp11_move_typemaps
|
||||
|
||||
%include <swigmove.i>
|
||||
%apply SWIGTYPE MOVE { MoveOnly mo }
|
||||
%valuewrapper MovableCopyable;
|
||||
%apply SWIGTYPE MOVE { MovableCopyable mc }
|
||||
|
||||
%inline %{
|
||||
#define WRAP_TAKE_METHOD
|
||||
%}
|
||||
|
||||
%include "cpp11_move_only.i"
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using cpp11_move_typemapsNamespace;
|
||||
|
||||
public class cpp11_move_typemaps_runme {
|
||||
|
||||
public static void Main() {
|
||||
Counter.reset_counts();
|
||||
using (MoveOnly mo = new MoveOnly(111)) {
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MoveOnly.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
Counter.reset_counts();
|
||||
using (MovableCopyable mo = new MovableCopyable(111)) {
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MovableCopyable.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
using (MoveOnly mo = new MoveOnly(222)) {
|
||||
MoveOnly.take(mo);
|
||||
bool exception_thrown = false;
|
||||
try {
|
||||
MoveOnly.take(mo);
|
||||
} 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 take should have been an error");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
module cpp11_move_typemaps_runme;
|
||||
|
||||
import cpp11_move_typemaps.Counter;
|
||||
import cpp11_move_typemaps.MoveOnly;
|
||||
import cpp11_move_typemaps.MovableCopyable;
|
||||
import std.conv;
|
||||
import std.algorithm;
|
||||
|
||||
void main() {
|
||||
{
|
||||
Counter.reset_counts();
|
||||
scope MoveOnly mo = new MoveOnly(111);
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MoveOnly.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
Counter.reset_counts();
|
||||
scope MovableCopyable mo = new MovableCopyable(111);
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MovableCopyable.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
scope MoveOnly mo = new MoveOnly(222);
|
||||
MoveOnly.take(mo);
|
||||
bool exception_thrown = false;
|
||||
try {
|
||||
MoveOnly.take(mo);
|
||||
} 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 take should have been an error");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
module cpp11_move_typemaps_runme;
|
||||
|
||||
import cpp11_move_typemaps.Counter;
|
||||
import cpp11_move_typemaps.MoveOnly;
|
||||
import cpp11_move_typemaps.MovableCopyable;
|
||||
import std.conv;
|
||||
import std.algorithm;
|
||||
|
||||
void main() {
|
||||
{
|
||||
Counter.reset_counts();
|
||||
scope MoveOnly mo = new MoveOnly(111);
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MoveOnly.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
Counter.reset_counts();
|
||||
scope MovableCopyable mo = new MovableCopyable(111);
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MovableCopyable.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
scope MoveOnly mo = new MoveOnly(222);
|
||||
MoveOnly.take(mo);
|
||||
bool exception_thrown = false;
|
||||
try {
|
||||
MoveOnly.take(mo);
|
||||
} 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 take should have been an error");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
(dynamic-call "scm_init_cpp11_move_typemaps_module" (dynamic-link "./libcpp11_move_typemaps"))
|
||||
(load "testsuite.scm")
|
||||
(load "../schemerunme/cpp11_move_typemaps.scm")
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
import cpp11_move_typemaps.*;
|
||||
|
||||
public class cpp11_move_typemaps_runme {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("cpp11_move_typemaps");
|
||||
} 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();
|
||||
MoveOnly mo = new MoveOnly(111);
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MoveOnly.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
mo.delete();
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
Counter.reset_counts();
|
||||
MovableCopyable mo = new MovableCopyable(111);
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
MovableCopyable.take(mo);
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
mo.delete();
|
||||
}
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
MoveOnly mo = new MoveOnly(222);
|
||||
MoveOnly.take(mo);
|
||||
boolean exception_thrown = false;
|
||||
try {
|
||||
MoveOnly.take(mo);
|
||||
} 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 take should have been an error");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
var cpp11_move_typemaps = require("cpp11_move_typemaps");
|
||||
|
||||
cpp11_move_typemaps.Counter.reset_counts();
|
||||
mo = new cpp11_move_typemaps.MoveOnly(111);
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
cpp11_move_typemaps.MoveOnly.take(mo);
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
delete mo;
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
cpp11_move_typemaps.Counter.reset_counts();
|
||||
mo = new cpp11_move_typemaps.MovableCopyable(111);
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 0, 0, 0);
|
||||
cpp11_move_typemaps.MovableCopyable.take(mo);
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
delete mo;
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
mo = new cpp11_move_typemaps.MoveOnly(222);
|
||||
cpp11_move_typemaps.MoveOnly.take(mo);
|
||||
exception_thrown = false;
|
||||
try {
|
||||
cpp11_move_typemaps.MoveOnly.take(mo);
|
||||
} catch (e) {
|
||||
if (!e.message.includes("cannot release ownership as memory is not owned"))
|
||||
throw new Error("incorrect exception message:" + e.message);
|
||||
exception_thrown = true;
|
||||
}
|
||||
if (!exception_thrown)
|
||||
throw new Error("double usage of take should have been an error");
|
|
@ -0,0 +1,28 @@
|
|||
require("import") -- the import fn
|
||||
import("cpp11_move_typemaps") -- import code
|
||||
|
||||
-- catch "undefined" global variables
|
||||
local env = _ENV -- Lua 5.2
|
||||
if not env then env = getfenv () end -- Lua 5.1
|
||||
setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end})
|
||||
|
||||
cpp11_move_typemaps.Counter.reset_counts()
|
||||
mo = cpp11_move_typemaps.MoveOnly(111)
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 0, 0, 0)
|
||||
cpp11_move_typemaps.MoveOnly.take(mo)
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
mo = nil
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
|
||||
cpp11_move_typemaps.Counter.reset_counts()
|
||||
mo = cpp11_move_typemaps.MovableCopyable(111)
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 0, 0, 0)
|
||||
cpp11_move_typemaps.MovableCopyable.take(mo)
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
mo = nil
|
||||
cpp11_move_typemaps.Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
|
||||
mo = cpp11_move_typemaps.MoveOnly(222)
|
||||
cpp11_move_typemaps.MoveOnly.take(mo)
|
||||
s, msg = pcall(function() cpp11_move_typemaps.MoveOnly.take(mo) end)
|
||||
assert(s == false and msg:find("Cannot release ownership as memory is not owned", 1, true))
|
|
@ -0,0 +1,35 @@
|
|||
(load-extension "cpp11_move_typemaps.so")
|
||||
(require (lib "defmacro.ss"))
|
||||
|
||||
; Copied from ../schemerunme/cpp11_move_typemaps.scm and modified for exceptions
|
||||
|
||||
; Define an equivalent to Guile's gc procedure
|
||||
(define-macro (gc)
|
||||
`(collect-garbage 'major))
|
||||
|
||||
(Counter-reset-counts)
|
||||
(define mo (new-MoveOnly 111))
|
||||
(Counter-check-counts 1 0 0 0 0 0)
|
||||
(MoveOnly-take mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
(delete-MoveOnly mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
|
||||
(Counter-reset-counts)
|
||||
(define mo (new-MovableCopyable 111))
|
||||
(Counter-check-counts 1 0 0 0 0 0)
|
||||
(MovableCopyable-take mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
(delete-MovableCopyable mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
|
||||
(define mo (new-MoveOnly 222))
|
||||
(MoveOnly-take mo)
|
||||
(define exception_thrown "no exception thrown for mo")
|
||||
(with-handlers ([exn:fail? (lambda (exn)
|
||||
(set! exception_thrown (exn-message exn)))])
|
||||
(MoveOnly-take mo))
|
||||
(unless (string-contains? exception_thrown "cannot release ownership as memory is not owned")
|
||||
(error "Wrong or no exception thrown: " exception_thrown))
|
||||
|
||||
(exit 0)
|
|
@ -0,0 +1,37 @@
|
|||
# do not dump Octave core
|
||||
if exist("crash_dumps_octave_core", "builtin")
|
||||
crash_dumps_octave_core(0);
|
||||
endif
|
||||
|
||||
cpp11_move_typemaps
|
||||
|
||||
Counter.reset_counts();
|
||||
mo = MoveOnly(111);
|
||||
Counter_check_counts(1, 0, 0, 0, 0, 0);
|
||||
MoveOnly.take(mo);
|
||||
Counter_check_counts(1, 0, 0, 1, 0, 2);
|
||||
clear mo;
|
||||
Counter_check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
Counter.reset_counts();
|
||||
mo = MovableCopyable(111);
|
||||
Counter_check_counts(1, 0, 0, 0, 0, 0);
|
||||
MovableCopyable.take(mo);
|
||||
Counter_check_counts(1, 0, 0, 1, 0, 2);
|
||||
clear mo;
|
||||
Counter_check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
mo = MoveOnly(222);
|
||||
MoveOnly.take(mo);
|
||||
exception_thrown = false;
|
||||
try
|
||||
MoveOnly.take(mo);
|
||||
catch e
|
||||
if (isempty(strfind(e.message, "cannot release ownership as memory is not owned")))
|
||||
error("incorrect exception message %s", e.message);
|
||||
endif
|
||||
exception_thrown = true;
|
||||
end_try_catch
|
||||
if (!exception_thrown)
|
||||
error("double usage of take should have been an error");
|
||||
endif
|
|
@ -0,0 +1,34 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 3;
|
||||
BEGIN { use_ok('cpp11_move_typemaps') }
|
||||
require_ok('cpp11_move_typemaps');
|
||||
|
||||
{
|
||||
cpp11_move_typemaps::Counter::reset_counts();
|
||||
my $mo = new cpp11_move_typemaps::MoveOnly(111);
|
||||
cpp11_move_typemaps::Counter::check_counts(1, 0, 0, 0, 0, 0);
|
||||
cpp11_move_typemaps::MoveOnly::take($mo);
|
||||
cpp11_move_typemaps::Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
undef $mo;
|
||||
}
|
||||
cpp11_move_typemaps::Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
cpp11_move_typemaps::Counter::reset_counts();
|
||||
my $mo = new cpp11_move_typemaps::MovableCopyable(111);
|
||||
cpp11_move_typemaps::Counter::check_counts(1, 0, 0, 0, 0, 0);
|
||||
cpp11_move_typemaps::MovableCopyable::take($mo);
|
||||
cpp11_move_typemaps::Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
undef $mo;
|
||||
}
|
||||
cpp11_move_typemaps::Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
{
|
||||
my $mo = new cpp11_move_typemaps::MoveOnly(222);
|
||||
cpp11_move_typemaps::MoveOnly::take($mo);
|
||||
eval {
|
||||
cpp11_move_typemaps::MoveOnly::take($mo);
|
||||
};
|
||||
like($@, qr/\bcannot release ownership as memory is not owned\b/, "double usage of takeKlassUniquePtr should be an error");
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
require "tests.php";
|
||||
|
||||
Counter::reset_counts();
|
||||
$mo = new MoveOnly(111);
|
||||
Counter::check_counts(1, 0, 0, 0, 0, 0);
|
||||
MoveOnly::take($mo);
|
||||
Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
$mo = NULL;
|
||||
Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
Counter::reset_counts();
|
||||
$mo = new MovableCopyable(111);
|
||||
Counter::check_counts(1, 0, 0, 0, 0, 0);
|
||||
MovableCopyable::take($mo);
|
||||
Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
$mo = NULL;
|
||||
Counter::check_counts(1, 0, 0, 1, 0, 2);
|
||||
|
||||
$mo = new MoveOnly(222);
|
||||
MoveOnly::take($mo);
|
||||
$exception_thrown = false;
|
||||
try {
|
||||
MoveOnly::take($mo);
|
||||
} catch (TypeError $e) {
|
||||
check::str_contains($e->getMessage(), "Cannot release ownership as memory is not owned", "incorrect exception message: {$e->getMessage()}");
|
||||
$exception_thrown = true;
|
||||
}
|
||||
check::equal($exception_thrown, true, "double usage of takeKlassUniquePtr should have been an error");
|
||||
|
||||
check::done();
|
|
@ -0,0 +1,29 @@
|
|||
from cpp11_move_typemaps import *
|
||||
|
||||
Counter.reset_counts()
|
||||
mo = MoveOnly(111)
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0)
|
||||
MoveOnly.take(mo)
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
del mo
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
|
||||
Counter.reset_counts()
|
||||
mo = MovableCopyable(111)
|
||||
Counter.check_counts(1, 0, 0, 0, 0, 0)
|
||||
MovableCopyable.take(mo)
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
del mo
|
||||
Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
|
||||
mo = MoveOnly(222)
|
||||
MoveOnly.take(mo)
|
||||
exception_thrown = False
|
||||
try:
|
||||
MoveOnly.take(mo)
|
||||
except RuntimeError as e:
|
||||
if "cannot release ownership as memory is not owned" not in str(e):
|
||||
raise RuntimeError("incorrect exception message:" + str(e))
|
||||
exception_thrown = True
|
||||
if not exception_thrown:
|
||||
raise RuntimeError("Should have thrown 'Cannot release ownership as memory is not owned' error")
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'swig_assert'
|
||||
|
||||
require 'cpp11_move_typemaps'
|
||||
|
||||
Cpp11_move_typemaps::Counter.reset_counts()
|
||||
mo = Cpp11_move_typemaps::MoveOnly.new(111)
|
||||
Cpp11_move_typemaps::Counter.check_counts(1, 0, 0, 0, 0, 0)
|
||||
Cpp11_move_typemaps::MoveOnly.take(mo)
|
||||
Cpp11_move_typemaps::Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
mo = nil
|
||||
Cpp11_move_typemaps::Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
|
||||
Cpp11_move_typemaps::Counter.reset_counts()
|
||||
mo = Cpp11_move_typemaps::MovableCopyable.new(111)
|
||||
Cpp11_move_typemaps::Counter.check_counts(1, 0, 0, 0, 0, 0)
|
||||
Cpp11_move_typemaps::MovableCopyable.take(mo)
|
||||
Cpp11_move_typemaps::Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
mo = nil
|
||||
Cpp11_move_typemaps::Counter.check_counts(1, 0, 0, 1, 0, 2)
|
||||
|
||||
mo = Cpp11_move_typemaps::MoveOnly.new(222)
|
||||
Cpp11_move_typemaps::MoveOnly.take(mo)
|
||||
exception_thrown = false
|
||||
begin
|
||||
Cpp11_move_typemaps::MoveOnly.take(mo)
|
||||
rescue RuntimeError => e
|
||||
if (!e.to_s.include? "cannot release ownership as memory is not owned")
|
||||
raise RuntimeError, "incorrect exception message: #{e.to_s}"
|
||||
end
|
||||
exception_thrown = true
|
||||
end
|
||||
if (!exception_thrown)
|
||||
raise RuntimeError, "Should have thrown 'Cannot release ownership as memory is not owned' error"
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
(Counter-reset-counts)
|
||||
(define mo (new-MoveOnly 111))
|
||||
(Counter-check-counts 1 0 0 0 0 0)
|
||||
(MoveOnly-take mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
(delete-MoveOnly mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
|
||||
(Counter-reset-counts)
|
||||
(define mo (new-MovableCopyable 111))
|
||||
(Counter-check-counts 1 0 0 0 0 0)
|
||||
(MovableCopyable-take mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
(delete-MovableCopyable mo)
|
||||
(Counter-check-counts 1 0 0 1 0 2)
|
||||
|
||||
(define mo (new-MoveOnly 222))
|
||||
(MoveOnly-take mo)
|
||||
(expect-throw 'misc-error
|
||||
(MoveOnly-take mo))
|
||||
; TODO: check the exception message
|
||||
|
||||
(exit 0)
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
if [ catch { load ./cpp11_move_typemaps[info sharedlibextension] cpp11_move_typemaps} err_msg ] {
|
||||
puts stderr "Could not load shared object:\n$err_msg"
|
||||
}
|
||||
|
||||
Counter_reset_counts
|
||||
MoveOnly mo 111
|
||||
Counter_check_counts 1 0 0 0 0 0
|
||||
MoveOnly_take mo
|
||||
Counter_check_counts 1 0 0 1 0 2
|
||||
mo -delete
|
||||
Counter_check_counts 1 0 0 1 0 2
|
||||
|
||||
Counter_reset_counts
|
||||
MovableCopyable mo 111
|
||||
Counter_check_counts 1 0 0 0 0 0
|
||||
MovableCopyable_take mo
|
||||
Counter_check_counts 1 0 0 1 0 2
|
||||
mo -delete
|
||||
Counter_check_counts 1 0 0 1 0 2
|
||||
|
||||
MoveOnly mo 222
|
||||
MoveOnly_take mo
|
||||
set exception_thrown 0
|
||||
if [ catch {
|
||||
MoveOnly_take mo
|
||||
} e ] {
|
||||
if {[string first "cannot release ownership as memory is not owned" $e] == -1} {
|
||||
error "incorrect exception message: $e"
|
||||
}
|
||||
set exception_thrown 1
|
||||
}
|
||||
if {!$exception_thrown} {
|
||||
error "Should have thrown 'Cannot release ownership as memory is not owned' error"
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, canthrow=1, fragment="<memory>") SWIGTYPE MOVE ($&1_type argp)
|
||||
%{ argp = ($&1_ltype)$input;
|
||||
if (!argp) {
|
||||
SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null $1_type", 0);
|
||||
return $null;
|
||||
}
|
||||
SwigValueWrapper< $1_ltype >::reset($1, argp); %}
|
||||
|
||||
%typemap(csin) SWIGTYPE MOVE "$&csclassname.swigRelease($csinput)"
|
|
@ -0,0 +1,16 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, canthrow=1) SWIGTYPE MOVE ($&1_type argp)
|
||||
%{ argp = ($&1_ltype)$input;
|
||||
if (!argp) {
|
||||
SWIG_DSetPendingException(SWIG_DIllegalArgumentException, "Attempt to dereference null $1_type");
|
||||
return $null;
|
||||
}
|
||||
SwigValueWrapper< $1_ltype >::reset($1, argp); %}
|
||||
|
||||
%typemap(din) SWIGTYPE MOVE "$dclassname.swigRelease($dinput)"
|
|
@ -0,0 +1,15 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in) SWIGTYPE MOVE ($&1_type argp)
|
||||
%{
|
||||
argp = ($&1_ltype)$input;
|
||||
if (argp == NULL) {
|
||||
_swig_gopanic("Attempt to dereference null $1_type");
|
||||
}
|
||||
SwigValueWrapper< $1_ltype >::reset($1, argp);
|
||||
%}
|
|
@ -0,0 +1,19 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, noblock=1) SWIGTYPE MOVE (void *argp = 0, int res = 0) {
|
||||
res = SWIG_ConvertPtr($input, &argp, $&1_descriptor, SWIG_POINTER_RELEASE);
|
||||
if (!SWIG_IsOK(res)) {
|
||||
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
|
||||
%releasenotowned_fail(res, "$1_type", $symname, $argnum);
|
||||
} else {
|
||||
%argument_fail(res, "$1_type", $symname, $argnum);
|
||||
}
|
||||
}
|
||||
if (!argp) { %argument_nullref("$1_type", $symname, $argnum); }
|
||||
SwigValueWrapper< $1_ltype >::reset($1, ($&1_type)argp);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in) SWIGTYPE MOVE ($&1_type argp)
|
||||
%{ argp = *($&1_ltype*)&$input;
|
||||
if (!argp) {
|
||||
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null $1_type");
|
||||
return $null;
|
||||
}
|
||||
SwigValueWrapper< $1_ltype >::reset($1, argp); %}
|
||||
|
||||
%typemap(javain) SWIGTYPE MOVE "$&javaclassname.swigRelease($javainput)"
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1,18 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, checkfn="lua_isuserdata", noblock=1) SWIGTYPE MOVE (void *argp = 0, int res = 0) {
|
||||
res = SWIG_ConvertPtr(L, $input, &argp, $&1_descriptor, SWIG_POINTER_RELEASE);
|
||||
if (!SWIG_IsOK(res)) {
|
||||
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
|
||||
lua_pushfstring(L, "Cannot release ownership as memory is not owned for argument $argnum of type '$1_type' in $symname"); SWIG_fail;
|
||||
} else {
|
||||
SWIG_fail_ptr("$symname", $argnum, $&1_descriptor);
|
||||
}
|
||||
}
|
||||
SwigValueWrapper< $1_ltype >::reset($1, ($&1_type)argp);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, noblock=1) SWIGTYPE MOVE (void *argp = 0, int res = 0) {
|
||||
res = SWIG_ConvertPtr($input, &argp, $&1_descriptor, SWIG_POINTER_RELEASE);
|
||||
if (!SWIG_IsOK(res)) {
|
||||
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
|
||||
scheme_signal_error(FUNC_NAME ": cannot release ownership as memory is not owned for argument $argnum of type '$1_type'");
|
||||
} else {
|
||||
%argument_fail(res, "$1_type", $symname, $argnum);
|
||||
}
|
||||
}
|
||||
if (argp == NULL) scheme_signal_error(FUNC_NAME ": swig-type-error (null reference)");
|
||||
SwigValueWrapper< $1_ltype >::reset($1, ($&1_type)argp);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, noblock=1) SWIGTYPE MOVE (void *argp = 0) {
|
||||
argp1 = ($&1_ltype) caml_ptr_val($input,$&1_descriptor);
|
||||
SwigValueWrapper< $1_ltype >::reset($1, ($&1_type)argp);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1,24 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.i
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, noblock=1) SWIGTYPE MOVE (void *argp = 0, int res = 0) {
|
||||
res = SWIG_ConvertPtr(&$input, &argp, $&1_descriptor, SWIG_POINTER_RELEASE);
|
||||
if (!SWIG_IsOK(res)) {
|
||||
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
|
||||
zend_type_error("Cannot release ownership as memory is not owned for argument $argnum of $&1_descriptor of $symname");
|
||||
return;
|
||||
} else {
|
||||
zend_type_error("Expected $&1_descriptor for argument $argnum of $symname");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!argp) {
|
||||
zend_type_error("Invalid null reference for argument $argnum of $&1_descriptor of $symname");
|
||||
return;
|
||||
}
|
||||
SwigValueWrapper< $1_ltype >::reset($1, ($&1_type)argp);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
12
Lib/swig.swg
12
Lib/swig.swg
|
@ -656,6 +656,16 @@ namespace std {
|
|||
* arg1 = *inarg1; // Assignment from a pointer
|
||||
* arg1 = Vector(1,2,3); // Assignment from a value
|
||||
*
|
||||
* SwigValueWrapper is a drop in replacement to modify normal value semantics by
|
||||
* using the heap instead of the stack to copy/move the underlying object it is
|
||||
* managing. Smart pointers also manage an underlying object on the heap, so
|
||||
* SwigValueWrapper has characteristics of a smart pointer. The reset function
|
||||
* is specific smart pointer functionality, but cannot be a non-static member as
|
||||
* when SWIG modifies typemap code it assumes non-static member function calls
|
||||
* are routed to the underlying object, changing for example $1.f() to (&x)->f().
|
||||
* The reset function was added as an optimisation to avoid some copying/moving
|
||||
* and to take ownership of an object already created on the heap.
|
||||
*
|
||||
* The class offers a strong guarantee of exception safety.
|
||||
* With regards to the implementation, the private SwigSmartPointer nested class is
|
||||
* a simple smart pointer providing exception safety, much like std::auto_ptr.
|
||||
|
@ -677,6 +687,7 @@ template<typename T> class SwigValueWrapper {
|
|||
SwigSmartPointer(T *p) : ptr(p) { }
|
||||
~SwigSmartPointer() { delete ptr; }
|
||||
SwigSmartPointer& operator=(SwigSmartPointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; }
|
||||
void reset(T *p) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = p; }
|
||||
} pointer;
|
||||
SwigValueWrapper& operator=(const SwigValueWrapper<T>& rhs);
|
||||
SwigValueWrapper(const SwigValueWrapper<T>& rhs);
|
||||
|
@ -690,6 +701,7 @@ public:
|
|||
operator T&() const { return *pointer.ptr; }
|
||||
#endif
|
||||
T *operator&() const { return pointer.ptr; }
|
||||
static void reset(SwigValueWrapper& t, T *p) { t.pointer.reset(p); }
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
%include <typemaps/swigmove.swg>
|
|
@ -0,0 +1,19 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* swigmove.swg
|
||||
*
|
||||
* Input typemaps library for implementing full move semantics when passing
|
||||
* parameters by value.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%typemap(in, noblock=1) SWIGTYPE MOVE (void *argp = 0, int res = 0) {
|
||||
res = SWIG_ConvertPtr($input, &argp, $&1_descriptor, SWIG_POINTER_RELEASE);
|
||||
if (!SWIG_IsOK(res)) {
|
||||
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
|
||||
%releasenotowned_fail(res, "$1_type", $symname, $argnum);
|
||||
} else {
|
||||
%argument_fail(res, "$1_type", $symname, $argnum);
|
||||
}
|
||||
}
|
||||
if (!argp) { %argument_nullref("$1_type", $symname, $argnum); }
|
||||
SwigValueWrapper< $1_ltype >::reset($1, ($&1_type)argp);
|
||||
}
|
Loading…
Reference in New Issue