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
41 changed files with 909 additions and 19 deletions
|
|
@ -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)
|
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
|
2022-08-31: wsfulton
|
||||||
#999 Improve move semantics when using rvalue references.
|
#999 Improve move semantics when using rvalue references.
|
||||||
The SWIGTYPE && input typemaps now assume the object has been moved.
|
The SWIGTYPE && input typemaps now assume the object has been moved.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#CPlusPlus11_rvalue_reference_inputs">Rvalue reference inputs</a>
|
<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_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>
|
</ul>
|
||||||
<li><a href="#CPlusPlus11_generalized_constant_expressions">Generalized constant expressions</a>
|
<li><a href="#CPlusPlus11_generalized_constant_expressions">Generalized constant expressions</a>
|
||||||
<li><a href="#CPlusPlus11_extern_template">Extern template</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!
|
Fortunately you're highly unlikely to have to solve any of these issues!
|
||||||
</p>
|
</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>
|
<p>
|
||||||
|
|
@ -252,7 +252,10 @@ Movable types can appear in function signatures for passing 'by value' and in C+
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -283,6 +286,7 @@ struct MoveOnly {
|
||||||
MoveOnly & operator=(MoveOnly &&) = default;
|
MoveOnly & operator=(MoveOnly &&) = default;
|
||||||
|
|
||||||
static MoveOnly create() { return MoveOnly(); }
|
static MoveOnly create() { return MoveOnly(); }
|
||||||
|
static void take(MoveOnly mo);
|
||||||
};
|
};
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
|
|
@ -303,17 +307,193 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_MoveOnly_create() {
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>SwigValueWrapper</tt> is covered in <a href="SWIGPlus.html#SWIGPlus_nn19">Pass and return by value</a>.
|
<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>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
There is currently only partial support for move-only types as
|
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>:
|
||||||
support for move-only types used as a parameter in a function, that are passed 'by value', is not yet available.
|
|
||||||
</p>
|
</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>
|
<p>
|
||||||
<b>Compatibility note:</b>
|
<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>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="CPlusPlus11.html#CPlusPlus11_rvalue_reference_inputs">Rvalue reference inputs</a>
|
<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_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>
|
</ul>
|
||||||
<li><a href="CPlusPlus11.html#CPlusPlus11_generalized_constant_expressions">Generalized constant expressions</a>
|
<li><a href="CPlusPlus11.html#CPlusPlus11_generalized_constant_expressions">Generalized constant expressions</a>
|
||||||
<li><a href="CPlusPlus11.html#CPlusPlus11_extern_template">Extern template</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 \
|
||||||
cpp11_initializer_list_extend \
|
cpp11_initializer_list_extend \
|
||||||
cpp11_lambda_functions \
|
cpp11_lambda_functions \
|
||||||
cpp11_move_only \
|
cpp11_move_only \
|
||||||
cpp11_move_only_valuewrapper \
|
cpp11_move_typemaps \
|
||||||
|
cpp11_move_only_valuewrapper \
|
||||||
cpp11_noexcept \
|
cpp11_noexcept \
|
||||||
cpp11_null_pointer_constant \
|
cpp11_null_pointer_constant \
|
||||||
cpp11_raw_string_literals \
|
cpp11_raw_string_literals \
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,23 @@ using namespace std;
|
||||||
bool trace = false;
|
bool trace = false;
|
||||||
|
|
||||||
struct MoveOnly {
|
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(const MoveOnly &other) = delete;
|
||||||
MoveOnly & operator=(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(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++; return *this; }
|
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++; }
|
~MoveOnly() { if (trace) cout << "~MoveOnly()" << " " << this << endl; Counter::destructor++; }
|
||||||
|
|
||||||
static MoveOnly create() { return MoveOnly(111); }
|
static MoveOnly create() { return MoveOnly(111); }
|
||||||
// static const MoveOnly createConst() { return MoveOnly(111); } // not supported by default
|
// 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 %{
|
%inline %{
|
||||||
// Movable and Copyable
|
// Movable and Copyable
|
||||||
struct MovableCopyable {
|
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(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++; return *this; }
|
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(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++; return *this; }
|
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++; }
|
~MovableCopyable() { if (trace) cout << "~MovableCopyable()" << " " << this << endl; Counter::destructor++; }
|
||||||
|
|
||||||
static MovableCopyable create() { return MovableCopyable(111); }
|
static MovableCopyable create() { return MovableCopyable(111); }
|
||||||
|
|
|
||||||
12
Examples/test-suite/cpp11_move_typemaps.i
Normal file
12
Examples/test-suite/cpp11_move_typemaps.i
Normal file
|
|
@ -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"
|
||||||
37
Examples/test-suite/csharp/cpp11_move_typemaps_runme.cs
Normal file
37
Examples/test-suite/csharp/cpp11_move_typemaps_runme.cs
Normal file
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Examples/test-suite/d/cpp11_move_typemaps_runme.1.d
Normal file
42
Examples/test-suite/d/cpp11_move_typemaps_runme.1.d
Normal file
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Examples/test-suite/d/cpp11_move_typemaps_runme.2.d
Normal file
42
Examples/test-suite/d/cpp11_move_typemaps_runme.2.d
Normal file
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Examples/test-suite/guile/cpp11_move_typemaps_runme.scm
Normal file
3
Examples/test-suite/guile/cpp11_move_typemaps_runme.scm
Normal file
|
|
@ -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")
|
||||||
51
Examples/test-suite/java/cpp11_move_typemaps_runme.java
Normal file
51
Examples/test-suite/java/cpp11_move_typemaps_runme.java
Normal file
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Examples/test-suite/javascript/cpp11_move_typemaps_runme.js
Normal file
30
Examples/test-suite/javascript/cpp11_move_typemaps_runme.js
Normal file
|
|
@ -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");
|
||||||
28
Examples/test-suite/lua/cpp11_move_typemaps_runme.lua
Normal file
28
Examples/test-suite/lua/cpp11_move_typemaps_runme.lua
Normal file
|
|
@ -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))
|
||||||
35
Examples/test-suite/mzscheme/cpp11_move_typemaps_runme.scm
Normal file
35
Examples/test-suite/mzscheme/cpp11_move_typemaps_runme.scm
Normal file
|
|
@ -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)
|
||||||
37
Examples/test-suite/octave/cpp11_move_typemaps_runme.m
Normal file
37
Examples/test-suite/octave/cpp11_move_typemaps_runme.m
Normal file
|
|
@ -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
|
||||||
34
Examples/test-suite/perl5/cpp11_move_typemaps_runme.pl
Normal file
34
Examples/test-suite/perl5/cpp11_move_typemaps_runme.pl
Normal file
|
|
@ -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");
|
||||||
|
}
|
||||||
32
Examples/test-suite/php/cpp11_move_typemaps_runme.php
Normal file
32
Examples/test-suite/php/cpp11_move_typemaps_runme.php
Normal file
|
|
@ -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();
|
||||||
29
Examples/test-suite/python/cpp11_move_typemaps_runme.py
Normal file
29
Examples/test-suite/python/cpp11_move_typemaps_runme.py
Normal file
|
|
@ -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")
|
||||||
36
Examples/test-suite/ruby/cpp11_move_typemaps_runme.rb
Normal file
36
Examples/test-suite/ruby/cpp11_move_typemaps_runme.rb
Normal file
|
|
@ -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
|
||||||
23
Examples/test-suite/schemerunme/cpp11_move_typemaps.scm
Normal file
23
Examples/test-suite/schemerunme/cpp11_move_typemaps.scm
Normal file
|
|
@ -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)
|
||||||
35
Examples/test-suite/tcl/cpp11_move_typemaps_runme.tcl
Normal file
35
Examples/test-suite/tcl/cpp11_move_typemaps_runme.tcl
Normal file
|
|
@ -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"
|
||||||
|
}
|
||||||
16
Lib/csharp/swigmove.i
Normal file
16
Lib/csharp/swigmove.i
Normal file
|
|
@ -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)"
|
||||||
16
Lib/d/swigmove.i
Normal file
16
Lib/d/swigmove.i
Normal file
|
|
@ -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)"
|
||||||
15
Lib/go/swigmove.i
Normal file
15
Lib/go/swigmove.i
Normal file
|
|
@ -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);
|
||||||
|
%}
|
||||||
19
Lib/guile/swigmove.i
Normal file
19
Lib/guile/swigmove.i
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
16
Lib/java/swigmove.i
Normal file
16
Lib/java/swigmove.i
Normal file
|
|
@ -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)"
|
||||||
1
Lib/javascript/jsc/swigmove.i
Normal file
1
Lib/javascript/jsc/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
1
Lib/javascript/v8/swigmove.i
Normal file
1
Lib/javascript/v8/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
18
Lib/lua/swigmove.i
Normal file
18
Lib/lua/swigmove.i
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
19
Lib/mzscheme/swigmove.i
Normal file
19
Lib/mzscheme/swigmove.i
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
11
Lib/ocaml/swigmove.i
Normal file
11
Lib/ocaml/swigmove.i
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
1
Lib/octave/swigmove.i
Normal file
1
Lib/octave/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
1
Lib/perl5/swigmove.i
Normal file
1
Lib/perl5/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
24
Lib/php/swigmove.i
Normal file
24
Lib/php/swigmove.i
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
1
Lib/python/swigmove.i
Normal file
1
Lib/python/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
1
Lib/r/swigmove.i
Normal file
1
Lib/r/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
1
Lib/ruby/swigmove.i
Normal file
1
Lib/ruby/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
1
Lib/scilab/swigmove.i
Normal file
1
Lib/scilab/swigmove.i
Normal file
|
|
@ -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 = *inarg1; // Assignment from a pointer
|
||||||
* arg1 = Vector(1,2,3); // Assignment from a value
|
* 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.
|
* The class offers a strong guarantee of exception safety.
|
||||||
* With regards to the implementation, the private SwigSmartPointer nested class is
|
* With regards to the implementation, the private SwigSmartPointer nested class is
|
||||||
* a simple smart pointer providing exception safety, much like std::auto_ptr.
|
* 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(T *p) : ptr(p) { }
|
||||||
~SwigSmartPointer() { delete ptr; }
|
~SwigSmartPointer() { delete ptr; }
|
||||||
SwigSmartPointer& operator=(SwigSmartPointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; }
|
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;
|
} pointer;
|
||||||
SwigValueWrapper& operator=(const SwigValueWrapper<T>& rhs);
|
SwigValueWrapper& operator=(const SwigValueWrapper<T>& rhs);
|
||||||
SwigValueWrapper(const SwigValueWrapper<T>& rhs);
|
SwigValueWrapper(const SwigValueWrapper<T>& rhs);
|
||||||
|
|
@ -690,6 +701,7 @@ public:
|
||||||
operator T&() const { return *pointer.ptr; }
|
operator T&() const { return *pointer.ptr; }
|
||||||
#endif
|
#endif
|
||||||
T *operator&() const { return pointer.ptr; }
|
T *operator&() const { return pointer.ptr; }
|
||||||
|
static void reset(SwigValueWrapper& t, T *p) { t.pointer.reset(p); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
1
Lib/tcl/swigmove.i
Normal file
1
Lib/tcl/swigmove.i
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
%include <typemaps/swigmove.swg>
|
||||||
19
Lib/typemaps/swigmove.swg
Normal file
19
Lib/typemaps/swigmove.swg
Normal file
|
|
@ -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…
Add table
Add a link
Reference in a new issue