summaryrefslogtreecommitdiff
path: root/Doc
diff options
context:
space:
mode:
authorWilliam S Fulton <wsf@fultondesigns.co.uk>2022-09-16 08:36:25 +0100
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2022-09-16 08:36:25 +0100
commitdad7c93ca0a923e7d2671347cee711d180dd0338 (patch)
treee4f527a56b5a1e044213ebe1f07200cedcde8153 /Doc
parentde65875955b236ee2644014e41bdeb1d574acc93 (diff)
downloadswig-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.html194
-rw-r--r--Doc/Manual/Contents.html2
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 &amp; operator=(MoveOnly &amp;&amp;) = 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 &amp;) = default;
+ CopyOnly &amp; operator=(const CopyOnly &amp;) = default;
+
+ static CopyOnly create() { return CopyOnly(); }
+ static void take(CopyOnly co);
+};
+
+struct MovableCopyable {
+ int val;
+ MovableCopyable(): val(0) {}
+
+ MovableCopyable(const MovableCopyable &amp;) = default;
+ MovableCopyable(MovableCopyable &amp;&amp;) = default;
+ MovableCopyable &amp; operator=(const MovableCopyable &amp;) = default;
+ MovableCopyable &amp; operator=(MovableCopyable &amp;&amp;) = 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 &gt;=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 &lt;swigmove.i&gt;
+%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&lt; MovableCopyable &gt; arg1 ; // (a) No constructors invoked
+ MovableCopyable *argp1 ;
+
+ argp1 = (MovableCopyable *)jarg1;
+ if (!argp1) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null MovableCopyable", 0);
+ return ;
+ }
+ SwigValueWrapper&lt; MovableCopyable &gt;::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 &lt;swigmove.i&gt;
+%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>