diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2022-09-16 08:36:25 +0100 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2022-09-16 08:36:25 +0100 |
commit | dad7c93ca0a923e7d2671347cee711d180dd0338 (patch) | |
tree | e4f527a56b5a1e044213ebe1f07200cedcde8153 /Doc | |
parent | de65875955b236ee2644014e41bdeb1d574acc93 (diff) | |
download | swig-dad7c93ca0a923e7d2671347cee711d180dd0338.tar.gz |
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
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/Manual/CPlusPlus11.html | 194 | ||||
-rw-r--r-- | Doc/Manual/Contents.html | 2 |
2 files changed, 188 insertions, 8 deletions
diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html index ba60fd3f8..861b80048 100644 --- a/Doc/Manual/CPlusPlus11.html +++ b/Doc/Manual/CPlusPlus11.html @@ -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> +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> -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. +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> diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index 2fdabafa6..d3106bf09 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -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> |