Merge pull request #647 from smarchetto/master

[Scilab] #552 pointer type tracking: fix doc and CHANGES
This commit is contained in:
William S Fulton 2016-04-06 21:51:03 +01:00
commit ec2c67f59b
3 changed files with 134 additions and 33 deletions

View file

@ -5,6 +5,11 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 3.0.9 (in progress) Version 3.0.9 (in progress)
=========================== ===========================
2016-04-06: smarchetto
[Scilab] #552 Make Scilab runtime keep track of pointer types
Instead of a Scilab pointer which has no type, SWIG Scilab maps a
pointer to a structure tlist containing the pointer adress and its type.
2016-04-02: ahnolds 2016-04-02: ahnolds
[Python] Apply #598. Fix misleading error message when attempting to read a non-existent [Python] Apply #598. Fix misleading error message when attempting to read a non-existent
attribute. The previous cryptic error message: attribute. The previous cryptic error message:
@ -13,7 +18,7 @@ Version 3.0.9 (in progress)
AttributeError: 'Foo' object has no attribute 'bar' AttributeError: 'Foo' object has no attribute 'bar'
2016-04-02: derkuci 2016-04-02: derkuci
[Python] Patch #610 to fix #607. [Python] Patch #610 to fix #607.
Fix single arguments when using python -builtin -O with %feature("compactdefaultargs") Fix single arguments when using python -builtin -O with %feature("compactdefaultargs")
2016-03-31: wsfulton 2016-03-31: wsfulton
@ -79,7 +84,7 @@ Version 3.0.9 (in progress)
strips the symbol's suffix instead of the prefix. The example below strips the symbol's suffix instead of the prefix. The example below
will rename SomeThingCls to SomeThing and AnotherThingCls to AnotherThing: will rename SomeThingCls to SomeThing and AnotherThingCls to AnotherThing:
%rename("%(rstrip:[Cls])s") ""; %rename("%(rstrip:[Cls])s") "";
class SomeThingCls {}; class SomeThingCls {};
struct AnotherThingCls {}; struct AnotherThingCls {};

View file

@ -45,6 +45,7 @@
<li><a href="#Scilab_wrapping_structs">Structures</a> <li><a href="#Scilab_wrapping_structs">Structures</a>
<li><a href="#Scilab_wrapping_cpp_classes">C++ classes</a> <li><a href="#Scilab_wrapping_cpp_classes">C++ classes</a>
<li><a href="#Scilab_wrapping_cpp_inheritance">C++ inheritance</a> <li><a href="#Scilab_wrapping_cpp_inheritance">C++ inheritance</a>
<li><a href="#Scilab_wrapping_cpp_overloading">C++ overloading</a></li>
<li><a href="#Scilab_wrapping_pointers_references_values_arrays">Pointers, references, values, and arrays</a> <li><a href="#Scilab_wrapping_pointers_references_values_arrays">Pointers, references, values, and arrays</a>
<li><a href="#Scilab_wrapping_cpp_templates">C++ templates</a> <li><a href="#Scilab_wrapping_cpp_templates">C++ templates</a>
<li><a href="#Scilab_wrapping_cpp_operators">C++ operators</a> <li><a href="#Scilab_wrapping_cpp_operators">C++ operators</a>
@ -752,11 +753,25 @@ typedef enum { RED, BLUE, GREEN } color;
<p> <p>
C/C++ pointers are fully supported by SWIG. They are mapped to the Scilab pointer type ("pointer", type ID: 128). Pointers are supported by SWIG. A pointer can be returned from a wrapped C/C++ function, stored in a Scilab variable, and used in input argument of another C/C++ function.
</p>
<p>
Also, thanks to the SWIG runtime which stores informations about types, pointer types are tracked between exchanges Scilab and the native code. Indeed pointer types are stored alongside the pointer adress.
A pointer is mapped to a Scilab structure (<a href="https://help.scilab.org/docs/5.5.2/en_US/tlist.html">tlist</a>), which contains as fields the pointer address and the pointer type (in fact a pointer to the type information structure in the SWIG runtime).
<br>
Why a native pointer is not mapped to a Scilab pointer (type name: "pointer", type ID: 128) ? The big advantage of mapping to a <tt>tlist</tt> is that it exposes a new type for the pointer in Scilab, type which can be acessed in Scilab with the <a href="https://help.scilab.org/docs/5.5.2/en_US/typeof.html">typeof</a> function, and manipulated using the <a href="https://help.scilab.org/docs/5.5.2/en_US/overloading.html">overloading</a> mechanism.
</p> </p>
<p> <p>
Given a wrapping of some of the C file functions: Notes:
<ul>
<li>type tracking needs the SWIG runtime to be first initialized with the appropriate function (see the <a href="#Scilab_module_initialization">Module initialization</a> section).</li>
<li>for any reason, if a wrapped pointer type is unknown (or if the SWIG runtime is not initialized), SWIG maps it to a Scilab pointer. Also, a Scilab pointer is always accepted as a pointer argument of a wrapped function. The drawaback is that pointer type is lost.</li>
</ul>
</p>
<p>
Following is an example of the wrapping of the C <tt>FILE*</tt> pointer:
</p> </p>
<div class="code"><pre> <div class="code"><pre>
@ -772,20 +787,26 @@ int fclose(FILE *);
</pre></div> </pre></div>
<p> <p>
These functions can be used in a natural way from Scilab: These functions can be used the same way as in C from Scilab:
</p> </p>
<div class="targetlang"><pre> <div class="targetlang"><pre>
--&gt; example_Init();
--&gt; f = fopen("junk", "w"); --&gt; f = fopen("junk", "w");
--&gt; typeof(f) --&gt; typeof(f)
ans = ans =
pointer _p_FILE
--&gt; fputs("Hello World", f); --&gt; fputs("Hello World", f);
--&gt; fclose(f); --&gt; fclose(f);
</pre></div> </pre></div>
<p>
Note: the type name <tt>_p_FILE</tt> which means "pointer to FILE".
</p>
<p> <p>
The user of a pointer is responsible for freeing it or, like in the example, closing any resources associated with it (just as is required in a C program). The user of a pointer is responsible for freeing it or, like in the example, closing any resources associated with it (just as is required in a C program).
</p> </p>
@ -794,7 +815,7 @@ The user of a pointer is responsible for freeing it or, like in the example, clo
<p> <p>
Most of time pointer manipulation is not needed in a scripting language such as Scilab. As a scripting language, Scilab does not provide functions to manipulate pointers.
However, in some cases it can be useful, such as for testing or debugging. However, in some cases it can be useful, such as for testing or debugging.
</p> </p>
@ -806,7 +827,11 @@ SWIG comes with two pointer utility functions:
<li><tt>SWIG_ptr()</tt>: creates a pointer from an address value</li> <li><tt>SWIG_ptr()</tt>: creates a pointer from an address value</li>
</ul> </ul>
<p>Following illustrates their use on the last example:</p> <p>
Note: a pointer created by <tt>SWIG_ptr()</tt> does not have any type and is mapped as a Scilab pointer.
</p>
<p>Following we use the utility functions on the previous example:</p>
<div class="targetlang"><pre> <div class="targetlang"><pre>
--&gt; f = fopen("junk", "w"); --&gt; f = fopen("junk", "w");
@ -817,15 +842,20 @@ SWIG comes with two pointer utility functions:
8219088. 8219088.
--&gt; p = SWIG_ptr(addr); --&gt; p = SWIG_ptr(addr);
--&gt; typeof(p)
ans =
pointer
--&gt; fputs(" World", p); --&gt; fputs(" World", p);
--&gt; fclose(f); --&gt; fclose(f);
</pre></div> </pre></div>
<H4><a name="Scilab_wrapping_pointers_null_pointers">39.3.6.2 Null pointers</a></H4>
<H4><a name="Scilab_wrapping_pointers_null_pointers">39.3.6.2 Null pointers:</a></H4>
<p>By default, Scilab does not provide a way to test or create null pointers. <p>
But it is possible to have a null pointer by using the previous functions <tt>SWIG_this()</tt> and <tt>SWIG_ptr()</tt>, like this: Using the previous <tt>SWIG_this()</tt> and <tt>SWIG_ptr()</tt>, it is possible to create and check null pointers:
</p> </p>
<div class="targetlang"><pre> <div class="targetlang"><pre>
@ -873,7 +903,7 @@ Several functions are generated:
<li>a destructor function <tt>delete_Foo()</tt> to release the struct pointer.</li> <li>a destructor function <tt>delete_Foo()</tt> to release the struct pointer.</li>
</ul> </ul>
<p>
Usage example: Usage example:
</p> </p>
@ -931,6 +961,19 @@ ans =
20. 20.
</pre></div> </pre></div>
<p>
Note: the pointer to the struct works as described in <a href="Scilab_wrapping_pointers">Pointers</a>. For example, the type of the struct pointer can be get with <tt>typeof</tt>, as following:
<p>
<div class="targetlang"><pre>
--&gt; example_Init();
--&gt; b = new_Bar();
--&gt; typeof(b)
ans =
_p_Bar
--&gt; delete_Bar(b);
</pre></div>
<H3><a name="Scilab_wrapping_cpp_classes">39.3.8 C++ classes</a></H3> <H3><a name="Scilab_wrapping_cpp_classes">39.3.8 C++ classes</a></H3>
@ -982,6 +1025,24 @@ ans =
--&gt; delete_Point(p2); --&gt; delete_Point(p2);
</pre></div> </pre></div>
<p>
Note: like structs, class pointers are mapped as described in <a href="Scilab_wrapping_pointers">Pointers</a>. Let's give an example which shows that each class pointer type is a new type in Scilab that can be used for example (through <a href="https://help.scilab.org/docs/5.5.2/en_US/overloading.html">overloading</a>) to implement a custom print for the <tt>Point</tt> class:
<p>
<div class="targetlang"><pre>
--&gt; function %_p_Point_p(p)
--&gt; mprintf('[%d, %d]\n', Point_x_get(p), Point_y_get(p));
--&gt; endfunction
--&gt; example_Init();
--&gt; p = new_Point(1, 2)
p =
[1, 2]
--&gt; delete_Point(p);
</pre></div>
<H3><a name="Scilab_wrapping_cpp_inheritance">39.3.9 C++ inheritance</a></H3> <H3><a name="Scilab_wrapping_cpp_inheritance">39.3.9 C++ inheritance</a></H3>
@ -1057,7 +1118,49 @@ But we can use either use the <tt>get_perimeter()</tt> function of the parent cl
18.84 18.84
</pre></div> </pre></div>
<H3><a name="Scilab_wrapping_pointers_references_values_arrays">39.3.10 Pointers, references, values, and arrays</a></H3> <H3><a name="Scilab_wrapping_cpp_overloading">39.3.10 C++ overloading</a></H3>
<p>
As explained in <a href="http://www.swig.org/Doc3.0/SWIGPlus.html#SWIGPlus_overloaded_methods">6.15</a> SWIG provides support for overloaded functions and constructors.
</p>
<p>As SWIG knows pointer types, the overloading works also with pointer types, here is is an example with a function <tt>magnify</tt> overloaded for the previous classes <tt>Shape</tt> and <tt>Circle</tt>:
<p>
<div class="code"><pre>
%module example
void magnify(Square *square, double factor) {
square->size *= factor;
};
void magnify(Circle *circle, double factor) {
square->radius *= factor;
};
</pre></div>
</p>
<p>
<div class="targetlang"><pre>
--&gt; example_Init();
--&gt; c = new_Circle(3);
--&gt; s = new_Square(2);
--&gt; magnify(c, 10);
--&gt; Circle_get_radius(c)
ans =
30;
--&gt; magnify(s, 10);
--&gt; Square_get_size(s)
ans =
20;
</pre></div>
</p>
<H3><a name="Scilab_wrapping_pointers_references_values_arrays">39.3.11 Pointers, references, values, and arrays</a></H3>
<p> <p>
@ -1115,7 +1218,7 @@ All these functions will return a pointer to an instance of <tt>Foo</tt>.
As the function <tt>spam7</tt> returns a value, new instance of <tt>Foo</tt> has to be allocated, and a pointer on this instance is returned. As the function <tt>spam7</tt> returns a value, new instance of <tt>Foo</tt> has to be allocated, and a pointer on this instance is returned.
</p> </p>
<H3><a name="Scilab_wrapping_cpp_templates">39.3.11 C++ templates</a></H3> <H3><a name="Scilab_wrapping_cpp_templates">39.3.12 C++ templates</a></H3>
<p> <p>
@ -1123,8 +1226,7 @@ As in other languages, function and class templates are supported in SWIG Scilab
</p> </p>
<p> <p>
You have to tell SWIG to create wrappers for a particular You have to tell SWIG to create wrappers for a particular template instantiation. The <tt>%template</tt> directive is used for this purpose.
template instantiation. The <tt>%template</tt> directive is used for this purpose.
For example: For example:
</p> </p>
@ -1175,7 +1277,7 @@ Then in Scilab:
More details on template support can be found in the <a href="SWIGPlus.html#SWIGPlus_nn30">templates</a> documentation. More details on template support can be found in the <a href="SWIGPlus.html#SWIGPlus_nn30">templates</a> documentation.
</p> </p>
<H3><a name="Scilab_wrapping_cpp_operators">39.3.12 C++ operators</a></H3> <H3><a name="Scilab_wrapping_cpp_operators">39.3.13 C++ operators</a></H3>
<p> <p>
@ -1228,7 +1330,7 @@ private:
</pre></div> </pre></div>
<H3><a name="Scilab_wrapping_cpp_namespaces">39.3.13 C++ namespaces</a></H3> <H3><a name="Scilab_wrapping_cpp_namespaces">39.3.14 C++ namespaces</a></H3>
<p> <p>
@ -1306,7 +1408,7 @@ Note: the <a href="SWIGPlus.html#SWIGPlus_nspace">nspace</a> feature is not supp
</p> </p>
<H3><a name="Scilab_wrapping_cpp_exceptions">39.3.14 C++ exceptions</a></H3> <H3><a name="Scilab_wrapping_cpp_exceptions">39.3.15 C++ exceptions</a></H3>
<p> <p>
@ -1389,7 +1491,7 @@ More complex or custom exception types require specific exception typemaps to be
See the <a href="SWIGPlus.html#SWIGPlus">SWIG C++ documentation</a> for more details. See the <a href="SWIGPlus.html#SWIGPlus">SWIG C++ documentation</a> for more details.
</p> </p>
<H3><a name="Scilab_wrapping_cpp_stl">39.3.15 C++ STL</a></H3> <H3><a name="Scilab_wrapping_cpp_stl">39.3.16 C++ STL</a></H3>
<p> <p>
@ -1448,15 +1550,9 @@ The default behaviour is for SWIG to generate code that will give a runtime erro
</ul> </ul>
<H3><a name="Scilab_typemaps_non-primitive_types">39.4.2 Default type mappings for non-primitive types</a></H3>
<p> <H3><a name="Scilab_typemaps_arrays">39.4.2 Arrays</a></H3>
The default mapped type for C/C++ non-primitive types is the Scilab pointer, for example for C structs, C++ classes, etc...
</p>
<H3><a name="Scilab_typemaps_arrays">39.4.3 Arrays</a></H3>
<p> <p>
@ -1511,7 +1607,7 @@ void printArray(int values[], int len) {
[ 0 1 2 3 ] [ 0 1 2 3 ]
</pre></div> </pre></div>
<H3><a name="Scilab_typemaps_pointer-to-pointers">39.4.4 Pointer-to-pointers</a></H3> <H3><a name="Scilab_typemaps_pointer-to-pointers">39.4.3 Pointer-to-pointers</a></H3>
<p> <p>
@ -1584,7 +1680,7 @@ void print_matrix(double **M, int nbRows, int nbCols) {
</pre></div> </pre></div>
<H3><a name="Scilab_typemaps_matrices">39.4.5 Matrices</a></H3> <H3><a name="Scilab_typemaps_matrices">39.4.4 Matrices</a></H3>
<p> <p>
@ -1677,7 +1773,7 @@ The remarks made earlier for arrays also apply here:
<li>There is no control while converting <tt>double</tt> values to integers, <tt>double</tt> values are truncated without any checking or warning.</li> <li>There is no control while converting <tt>double</tt> values to integers, <tt>double</tt> values are truncated without any checking or warning.</li>
</ul> </ul>
<H3><a name="Scilab_typemaps_stl">39.4.6 STL</a></H3> <H3><a name="Scilab_typemaps_stl">39.4.5 STL</a></H3>
<p> <p>
@ -1884,8 +1980,8 @@ ans =
The wrapped module contains an initialization function to: The wrapped module contains an initialization function to:
</p> </p>
<ul> <ul>
<li>initialize the SWIG runtime, which is necessary when working with the STL</li> <li>initialize the SWIG runtime, needed for pointer type tracking or when working with the STL</li>
<li>initialize in Scilab the module constants and enumerations declared with <tt>%scilabconst()</tt></li> <li>initialize the module constants and enumerations declared with <tt>%scilabconst()</tt></li>
</ul> </ul>
<p> <p>

View file

@ -245,7 +245,7 @@ SwigScilabPtrFromObject(void *pvApiCtx, int iVarOut, void *pvObj, swig_type_info
return SWIG_ERROR; return SWIG_ERROR;
} }
pstString = SWIG_TypePrettyName(descriptor); pstString = SWIG_TypeName(descriptor);
sciErr = createMatrixOfStringInList(pvApiCtx, SWIG_NbInputArgument(pvApiCtx) + iVarOut, piTListAddr, 1, 1, 1, &pstString); sciErr = createMatrixOfStringInList(pvApiCtx, SWIG_NbInputArgument(pvApiCtx) + iVarOut, piTListAddr, 1, 1, 1, &pstString);
if (sciErr.iErr) { if (sciErr.iErr) {
printError(&sciErr, 0); printError(&sciErr, 0);