Make typemap fragments official - move the documentation in fragments.swg into Typemaps.html
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@11992 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
f9caea4b29
commit
bdea09ed83
4 changed files with 363 additions and 329 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
Version 2.0.0 (in progress)
|
Version 2.0.0 (in progress)
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
2010-04-14: wsfulton
|
||||||
|
Typemap fragments are now official and documented in Typemaps.html.
|
||||||
|
|
||||||
2010-04-09: wsfulton
|
2010-04-09: wsfulton
|
||||||
[Ruby] Fix #2048064 and #2408020.
|
[Ruby] Fix #2048064 and #2408020.
|
||||||
Apply Ubuntu patch to fix Ruby and std::vector wrappers with -minherit.
|
Apply Ubuntu patch to fix Ruby and std::vector wrappers with -minherit.
|
||||||
|
|
|
||||||
|
|
@ -349,9 +349,8 @@
|
||||||
<li><a href="Typemaps.html#Typemaps_pattern_matching">Pattern matching rules</a>
|
<li><a href="Typemaps.html#Typemaps_pattern_matching">Pattern matching rules</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn17">Basic matching rules</a>
|
<li><a href="Typemaps.html#Typemaps_nn17">Basic matching rules</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_typedef_reductions">Typedef reductions</a>
|
<li><a href="Typemaps.html#Typemaps_typedef_reductions">Typedef reductions matching</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn19">Default typemaps</a>
|
<li><a href="Typemaps.html#Typemaps_nn19">Default typemap matching rules</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_mixed_default">Mixed default typemaps</a>
|
|
||||||
<li><a href="Typemaps.html#Typemaps_multi_argument_typemaps_patterns">Multi-arguments typemaps</a>
|
<li><a href="Typemaps.html#Typemaps_multi_argument_typemaps_patterns">Multi-arguments typemaps</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_debugging_search">Debugging typemap pattern matching</a>
|
<li><a href="Typemaps.html#Typemaps_debugging_search">Debugging typemap pattern matching</a>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -390,14 +389,18 @@
|
||||||
<li><a href="Typemaps.html#Typemaps_nn43">Typemaps for multiple target languages</a>
|
<li><a href="Typemaps.html#Typemaps_nn43">Typemaps for multiple target languages</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_optimal">Optimal code generation when returning by value</a>
|
<li><a href="Typemaps.html#Typemaps_optimal">Optimal code generation when returning by value</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_multi_argument_typemaps">Multi-argument typemaps</a>
|
<li><a href="Typemaps.html#Typemaps_multi_argument_typemaps">Multi-argument typemaps</a>
|
||||||
<li><a href="Typemaps.html#runtime_type_checker">The run-time type checker</a>
|
<li><a href="Typemaps.html#Typemaps_fragments">Typemap fragments</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="Typemaps.html#Typemaps_fragment_type_specialization">Fragment type specialization</a>
|
||||||
|
<li><a href="Typemaps.html#Typemaps_automatic_specialization">Fragments and automatic typemap specialization</a>
|
||||||
|
</ul>
|
||||||
|
<li><a href="Typemaps.html#Typemaps_runtime_type_checker">The run-time type checker</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn45">Implementation</a>
|
<li><a href="Typemaps.html#Typemaps_nn45">Implementation</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_runtime_type_checker_usage">Usage</a>
|
<li><a href="Typemaps.html#Typemaps_runtime_type_checker_usage">Usage</a>
|
||||||
</ul>
|
</ul>
|
||||||
<li><a href="Typemaps.html#Typemaps_overloading">Typemaps and overloading</a>
|
<li><a href="Typemaps.html#Typemaps_overloading">Typemaps and overloading</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
|
<li><a href="Typemaps.html#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn49">Reducing wrapper code size</a>
|
|
||||||
<li><a href="Typemaps.html#Typemaps_nn47">Passing data between typemaps</a>
|
<li><a href="Typemaps.html#Typemaps_nn47">Passing data between typemaps</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn52">C++ "this" pointer</a>
|
<li><a href="Typemaps.html#Typemaps_nn52">C++ "this" pointer</a>
|
||||||
<li><a href="Typemaps.html#Typemaps_nn51">Where to go for more information?</a>
|
<li><a href="Typemaps.html#Typemaps_nn51">Where to go for more information?</a>
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,8 @@
|
||||||
<li><a href="#Typemaps_pattern_matching">Pattern matching rules</a>
|
<li><a href="#Typemaps_pattern_matching">Pattern matching rules</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#Typemaps_nn17">Basic matching rules</a>
|
<li><a href="#Typemaps_nn17">Basic matching rules</a>
|
||||||
<li><a href="#Typemaps_typedef_reductions">Typedef reductions</a>
|
<li><a href="#Typemaps_typedef_reductions">Typedef reductions matching</a>
|
||||||
<li><a href="#Typemaps_nn19">Default typemaps</a>
|
<li><a href="#Typemaps_nn19">Default typemap matching rules</a>
|
||||||
<li><a href="#Typemaps_mixed_default">Mixed default typemaps</a>
|
|
||||||
<li><a href="#Typemaps_multi_argument_typemaps_patterns">Multi-arguments typemaps</a>
|
<li><a href="#Typemaps_multi_argument_typemaps_patterns">Multi-arguments typemaps</a>
|
||||||
<li><a href="#Typemaps_debugging_search">Debugging typemap pattern matching</a>
|
<li><a href="#Typemaps_debugging_search">Debugging typemap pattern matching</a>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -72,14 +71,18 @@
|
||||||
<li><a href="#Typemaps_nn43">Typemaps for multiple target languages</a>
|
<li><a href="#Typemaps_nn43">Typemaps for multiple target languages</a>
|
||||||
<li><a href="#Typemaps_optimal">Optimal code generation when returning by value</a>
|
<li><a href="#Typemaps_optimal">Optimal code generation when returning by value</a>
|
||||||
<li><a href="#Typemaps_multi_argument_typemaps">Multi-argument typemaps</a>
|
<li><a href="#Typemaps_multi_argument_typemaps">Multi-argument typemaps</a>
|
||||||
<li><a href="#runtime_type_checker">The run-time type checker</a>
|
<li><a href="#Typemaps_fragments">Typemap fragments</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#Typemaps_fragment_type_specialization">Fragment type specialization</a>
|
||||||
|
<li><a href="#Typemaps_automatic_specialization">Fragments and automatic typemap specialization</a>
|
||||||
|
</ul>
|
||||||
|
<li><a href="#Typemaps_runtime_type_checker">The run-time type checker</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#Typemaps_nn45">Implementation</a>
|
<li><a href="#Typemaps_nn45">Implementation</a>
|
||||||
<li><a href="#Typemaps_runtime_type_checker_usage">Usage</a>
|
<li><a href="#Typemaps_runtime_type_checker_usage">Usage</a>
|
||||||
</ul>
|
</ul>
|
||||||
<li><a href="#Typemaps_overloading">Typemaps and overloading</a>
|
<li><a href="#Typemaps_overloading">Typemaps and overloading</a>
|
||||||
<li><a href="#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
|
<li><a href="#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
|
||||||
<li><a href="#Typemaps_nn49">Reducing wrapper code size</a>
|
|
||||||
<li><a href="#Typemaps_nn47">Passing data between typemaps</a>
|
<li><a href="#Typemaps_nn47">Passing data between typemaps</a>
|
||||||
<li><a href="#Typemaps_nn52">C++ "this" pointer</a>
|
<li><a href="#Typemaps_nn52">C++ "this" pointer</a>
|
||||||
<li><a href="#Typemaps_nn51">Where to go for more information?</a>
|
<li><a href="#Typemaps_nn51">Where to go for more information?</a>
|
||||||
|
|
@ -1408,7 +1411,7 @@ simpler scheme to match the current C++ template partial specialization matching
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<H3><a name="Typemaps_multi_argument_typemaps_patterns"></a>10.3.5 Multi-arguments typemaps</H3>
|
<H3><a name="Typemaps_multi_argument_typemaps_patterns"></a>10.3.4 Multi-arguments typemaps</H3>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -1438,7 +1441,7 @@ but all subsequent arguments must match exactly.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<H3><a name="Typemaps_debugging_search"></a>10.3.6 Debugging typemap pattern matching</H3>
|
<H3><a name="Typemaps_debugging_search"></a>10.3.5 Debugging typemap pattern matching</H3>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -3404,7 +3407,335 @@ with non-consecutive C/C++ arguments; a workaround such as a helper function re-
|
||||||
the arguments to make them consecutive will need to be written.
|
the arguments to make them consecutive will need to be written.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<H2><a name="runtime_type_checker"></a>10.10 The run-time type checker</H2>
|
<H2><a name="Typemaps_fragments"></a>10.10 Typemap fragments</H2>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The primary purpose of fragments is to reduce code bloat that repeated use of typemap code can lead to.
|
||||||
|
Fragments are snippets of code that can be thought of as code dependencies of a typemap.
|
||||||
|
If a fragment is used by more than one typemap, then the snippet of code within the fragment is only generated once.
|
||||||
|
Code bloat is typically reduced by moving typemap code into a support function
|
||||||
|
and then placing the support function into a fragment.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For example, if you have a very long typemap
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%typemap(in) MyClass * {
|
||||||
|
MyClass *value = 0;
|
||||||
|
|
||||||
|
... many lines of marshalling code ...
|
||||||
|
|
||||||
|
$result = value;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
the same marshalling code is often repeated in several typemaps, such as "in", "varin", "directorout", etc.
|
||||||
|
SWIG copies the code for each argument that requires the typemap code, easily leading to code bloat
|
||||||
|
in the generated code.
|
||||||
|
To eliminate this, define a fragment that includes the common marshalling code:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("AsMyClass", "header") {
|
||||||
|
MyClass *AsMyClass(PyObject *obj) {
|
||||||
|
MyClass *value = 0;
|
||||||
|
|
||||||
|
... many lines of marshalling code ...
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%typemap(in, fragment="AsMyClass") MyClass * {
|
||||||
|
$result = AsMyClass($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
%typemap(varin, fragment="AsMyClass") MyClass * {
|
||||||
|
$result = AsMyClass($input);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When the "in" or "varin" typemaps for MyClass are required, the
|
||||||
|
contents of the fragment called "AsMyClass" is added to the "header" section within the generated code, and then the
|
||||||
|
typemap code is emitted. Hence, the method <tt>AsMyClass</tt> will be
|
||||||
|
generated into the wrapper code before any typemap code that calls it.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To define a fragment you need a fragment name, a section name for generating the fragment code into, and the code itself.
|
||||||
|
See <a href="SWIG.html#SWIG_nn42">Code insertion blocks</a> for a full list of section names.
|
||||||
|
Usually the section name used is "header". Both string and curly braces can be used:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("my_name", "header") { ... }
|
||||||
|
%fragment("my_name", "header") " ... "
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following are some rules and guidelines for using fragments:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
A fragment is added to the wrapping code only once. When using the <tt>MyClass *</tt> typemaps above and wrapping the method:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
void foo(MyClass *a, MyClass *b);
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
the generated code will look something like:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
MyClass *AsMyClass(PyObject *obj) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
void _wrap_foo(...) {
|
||||||
|
....
|
||||||
|
arg1 = AsMyClass(obj1);
|
||||||
|
arg2 = AsMyClass(obj2);
|
||||||
|
...
|
||||||
|
foo(arg1, arg2);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
even as there is duplicated typemap code to process both <tt>a</tt> and
|
||||||
|
<tt>b</tt>, the <tt>AsMyClass</tt> method will be defined only once.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
A fragment should only be defined once. If there is more than
|
||||||
|
one definition, the first definition is the one used.
|
||||||
|
All other definitions are silently ignored. For example, if you have
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("AsMyClass", "header") { ...definition 1... }
|
||||||
|
....
|
||||||
|
%fragment("AsMyClass", "header") { ...definition 2... }
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
only the first definition is used. In this way
|
||||||
|
you can override the default fragments in a SWIG library by defining your fragment before the library <tt>%include</tt>.
|
||||||
|
Note that this behavior is the opposite to typemaps, where the last typemap defined/applied prevails.
|
||||||
|
Fragments follow the first-in-first-out convention since they are intended to be global,
|
||||||
|
while typemaps are intended to be locally specialized.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
Fragment names cannot contain commas.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
A fragment can use one or more additional fragments, for example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("<limits.h>", "header") {
|
||||||
|
#include <limits.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
%fragment("AsMyClass", "header", fragment="<limits.h>") {
|
||||||
|
MyClass *AsMyClass(PyObject *obj) {
|
||||||
|
MyClass *value = 0;
|
||||||
|
|
||||||
|
... some marshalling code ...
|
||||||
|
|
||||||
|
if (ival < CHAR_MIN /*defined in <limits.h>*/) {
|
||||||
|
...
|
||||||
|
} else {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
...
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
in this case, when the "AsMyClass" fragment is emitted, it also
|
||||||
|
triggers the inclusion of the "<limits.h>" fragment.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
A fragment can have dependencies on a number of other fragments, for example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("bigfragment", "header", fragment="frag1", fragment="frag2", fragment="frag3") "";
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When the "bigfragment" is used, the three dependent fragments "frag1",
|
||||||
|
"frag2" and "frag3" are also pulled in. Note that as "bigframent" is
|
||||||
|
empty (the empty string - ""), it does not add any code itself, but merely triggers the
|
||||||
|
inclusion of the other fragments.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
A typemap can also use more than one fragment, but since the
|
||||||
|
syntax is different, you need to specify the dependent fragments in a comma separated
|
||||||
|
list. Consider:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%typemap(in, fragment="frag1,frag2,frag3") {...}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
which is equivalent to:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%typemap(in, fragment="bigfragment") {...}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
when used with the "bigfragment" defined above.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
Finally, you can force the inclusion of a fragment at any point in the generated code as follows:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("bigfragment");
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
which is very useful inside a template class, for example.
|
||||||
|
</p>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Most readers will probably want to skip the next two sub-sections on advanced
|
||||||
|
fragment usage unless a desire to really get to grips
|
||||||
|
with some powerful but tricky macro and fragment usage that is used in parts of the SWIG typemap library.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<H3><a name="Typemaps_fragment_type_specialization"></a>10.10.1 Fragment type specialization</H3>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Fragments can be <i>type specialized</i>. The syntax is as follows:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("name", "header") { ...a type independent fragment... }
|
||||||
|
%fragment("name"{type}, "header") { ...a type dependent fragment... }
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
where <tt>type</tt> is a C/C++ type. Like typemaps, fragments can also be used inside templates, for example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
template <class T>
|
||||||
|
struct A {
|
||||||
|
%fragment("incode"{A<T>}, "header") {
|
||||||
|
... 'incode' specialized fragment ...
|
||||||
|
}
|
||||||
|
|
||||||
|
%typemap(in, fragment="incode"{A<T>}) {
|
||||||
|
... here we use the 'type specialized' fragment "incode"{A<T>} ...
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<H3><a name="Typemaps_automatic_specialization"></a>10.10.2 Fragments and automatic typemap specialization</H3>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Since fragments can be type specialized, they can be elegantly used
|
||||||
|
to specialize typemaps. For example, if you have something like:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%fragment("incode"{float}, "header") {
|
||||||
|
float in_method_float(PyObject *obj) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%fragment("incode"{long}, "header") {
|
||||||
|
float in_method_long(PyObject *obj) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// %my_typemaps macro definition
|
||||||
|
%define %my_typemaps(Type)
|
||||||
|
%typemap(in, fragment="incode"{Type}) Type {
|
||||||
|
value = in_method_##Type(obj);
|
||||||
|
}
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%my_typemaps(float);
|
||||||
|
%my_typemaps(long);
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
then the proper <tt>"incode"{float}</tt> or <tt>"incode"{long}</tt> fragment will be used,
|
||||||
|
and the <tt>in_method_float</tt> and <tt>in_method_long</tt> methods will be called whenever
|
||||||
|
the <tt>float</tt> or <tt>long</tt> types are used as input parameters.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This feature is used a lot in the typemaps shipped in the SWIG library for some scripting languages.
|
||||||
|
The interested (or very brave) reader can take a look at the fragments.swg file shipped with SWIG to see this in action.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H2><a name="Typemaps_runtime_type_checker"></a>10.11 The run-time type checker</H2>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -3430,7 +3761,7 @@ language modules.</li>
|
||||||
<li>Modules can be unloaded from the type system.</li>
|
<li>Modules can be unloaded from the type system.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<H3><a name="Typemaps_nn45"></a>10.10.1 Implementation</H3>
|
<H3><a name="Typemaps_nn45"></a>10.11.1 Implementation</H3>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -3616,7 +3947,7 @@ structures rather than creating new ones. These <tt>swig_module_info</tt>
|
||||||
structures are chained together in a circularly linked list.
|
structures are chained together in a circularly linked list.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<H3><a name="Typemaps_runtime_type_checker_usage"></a>10.10.2 Usage</H3>
|
<H3><a name="Typemaps_runtime_type_checker_usage"></a>10.11.2 Usage</H3>
|
||||||
|
|
||||||
|
|
||||||
<p>This section covers how to use these functions from typemaps. To learn how to
|
<p>This section covers how to use these functions from typemaps. To learn how to
|
||||||
|
|
@ -3710,7 +4041,7 @@ probably just look at the output of SWIG to get a better sense for how types are
|
||||||
managed.
|
managed.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<H2><a name="Typemaps_overloading"></a>10.11 Typemaps and overloading</H2>
|
<H2><a name="Typemaps_overloading"></a>10.12 Typemaps and overloading</H2>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -4021,7 +4352,7 @@ Subsequent "in" typemaps would then perform more extensive type-checking.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<H2><a name="Typemaps_nn48"></a>10.12 More about <tt>%apply</tt> and <tt>%clear</tt></H2>
|
<H2><a name="Typemaps_nn48"></a>10.13 More about <tt>%apply</tt> and <tt>%clear</tt></H2>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -4106,86 +4437,6 @@ example:
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<H2><a name="Typemaps_nn49"></a>10.13 Reducing wrapper code size</H2>
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Since the code supplied to a typemap is inlined directly into wrapper functions, typemaps can result
|
|
||||||
in a tremendous amount of code bloat. For example, consider this typemap for an array:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="code">
|
|
||||||
<pre>
|
|
||||||
%typemap(in) float [ANY] {
|
|
||||||
int i;
|
|
||||||
if (!PySequence_Check($input)) {
|
|
||||||
PyErr_SetString(PyExc_ValueError,"Expected a sequence");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (PySequence_Length($input) != $1_dim0) {
|
|
||||||
PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
$1 = (float) malloc($1_dim0*sizeof(float));
|
|
||||||
for (i = 0; i < $1_dim0; i++) {
|
|
||||||
PyObject *o = PySequence_GetItem($input,i);
|
|
||||||
if (PyNumber_Check(o)) {
|
|
||||||
$1[i] = (float) PyFloat_AsDouble(o);
|
|
||||||
} else {
|
|
||||||
PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
|
|
||||||
free(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If you had a large interface with hundreds of functions all accepting
|
|
||||||
array parameters, this typemap would be replicated
|
|
||||||
repeatedly--generating a huge amount of code. A better approach might
|
|
||||||
be to consolidate some of the typemap into a function. For example:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="code">
|
|
||||||
<pre>
|
|
||||||
%{
|
|
||||||
/* Define a helper function */
|
|
||||||
static float *
|
|
||||||
convert_float_array(PyObject *input, int size) {
|
|
||||||
int i;
|
|
||||||
float *result;
|
|
||||||
if (!PySequence_Check(input)) {
|
|
||||||
PyErr_SetString(PyExc_ValueError,"Expected a sequence");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (PySequence_Length(input) != size) {
|
|
||||||
PyErr_SetString(PyExc_ValueError,"Size mismatch. ");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
result = (float) malloc(size*sizeof(float));
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
PyObject *o = PySequence_GetItem(input,i);
|
|
||||||
if (PyNumber_Check(o)) {
|
|
||||||
result[i] = (float) PyFloat_AsDouble(o);
|
|
||||||
} else {
|
|
||||||
PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
|
|
||||||
free(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
%}
|
|
||||||
|
|
||||||
%typemap(in) float [ANY] {
|
|
||||||
$1 = convert_float_array($input, $1_dim0);
|
|
||||||
if (!$1) return NULL;
|
|
||||||
}
|
|
||||||
%}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<H2><a name="Typemaps_nn47"></a>10.14 Passing data between typemaps</H2>
|
<H2><a name="Typemaps_nn47"></a>10.14 Passing data between typemaps</H2>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,236 +1,13 @@
|
||||||
/*
|
/*
|
||||||
Fragments:
|
Fragments
|
||||||
==========
|
=========
|
||||||
|
See the "Typemap fragments" section in the documentation for understanding
|
||||||
|
fragments. Below is some info on how fragments and automatic type
|
||||||
|
specialization is used.
|
||||||
|
|
||||||
Second to typemaps, fragments are one the most powerful and
|
Macros that make the automatic generation of typemaps easier are provided.
|
||||||
dangerous swig features. So, if you are starting to read about them,
|
|
||||||
make sure you read all of this document.
|
|
||||||
|
|
||||||
Basics:
|
Consider the following code:
|
||||||
=======
|
|
||||||
|
|
||||||
Fragments provide a way to include or generate code into "on-demand"
|
|
||||||
as the typemaps could require.
|
|
||||||
|
|
||||||
For example, if you have a very long typemap
|
|
||||||
|
|
||||||
%typemap(in) MyClass * {
|
|
||||||
MyClass *value = 0;
|
|
||||||
|
|
||||||
<very long typemap>
|
|
||||||
....
|
|
||||||
value = somewhere_converted_from_input_object_here($input);
|
|
||||||
...
|
|
||||||
<very long typemap>
|
|
||||||
|
|
||||||
$result = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
very soon you will discover yourself copying the same long
|
|
||||||
conversion code in several typemaps, such as varin, directorout,
|
|
||||||
etc. Also, you will discover that swig copes verbatim the same very
|
|
||||||
long conversion code for every argument that requires it, making the
|
|
||||||
code very large too.
|
|
||||||
|
|
||||||
To eliminate this automatic or manual code copying, we define a
|
|
||||||
fragment that includes the common conversion code:
|
|
||||||
|
|
||||||
%fragment("AsMyClass","header") {
|
|
||||||
MyClass *AsMyClass(PyObject *obj) {
|
|
||||||
MyClass *value = 0;
|
|
||||||
<very long conversion>
|
|
||||||
....
|
|
||||||
value = somewhere_converted_from_input_object_here(obj);
|
|
||||||
...
|
|
||||||
<very long conversion>
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%typemap(in,fragment="AsMyClass") MyClass * {
|
|
||||||
$result = AsMyClass($input);
|
|
||||||
}
|
|
||||||
|
|
||||||
%typemap(varin,fragment="AsMyClass") MyClass * {
|
|
||||||
$result = AsMyClass($input);
|
|
||||||
}
|
|
||||||
|
|
||||||
When the 'in' or 'varin' typemaps for MyClass are invoked, the
|
|
||||||
fragment "AsMyClass" is added to the "header" section, and then the
|
|
||||||
typemap code is emitted. Hence, the method AsMyClass will be
|
|
||||||
included in the wrapping code and it will be available at the time
|
|
||||||
the typemap is applied.
|
|
||||||
|
|
||||||
To define a fragment then you need a name, a section where it goes,
|
|
||||||
and the code. Usually the section refers to the "header" part, and
|
|
||||||
both string and braces forms are accepted, ie:
|
|
||||||
|
|
||||||
%fragment("my_name","header") { ... }
|
|
||||||
%fragment("my_name","header") "...";
|
|
||||||
|
|
||||||
To ensure all the fragment/typemap engine works as expected, there
|
|
||||||
are some rules that fragments follow:
|
|
||||||
|
|
||||||
1.- A fragment is added to the wrapping code only once, ie, for the
|
|
||||||
method:
|
|
||||||
|
|
||||||
int foo(MyClass *a, MyClass *b);
|
|
||||||
|
|
||||||
the wrapped code will look as much as:
|
|
||||||
|
|
||||||
MyClass *AsMyClass(PyObject *obj) {
|
|
||||||
.....
|
|
||||||
}
|
|
||||||
|
|
||||||
int _wrap_foo(...) {
|
|
||||||
....
|
|
||||||
arg1 = AsMyClass(obj1);
|
|
||||||
arg2 = AsMyClass(obj2);
|
|
||||||
...
|
|
||||||
result = foo(arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
even when there will be duplicated typemap to process 'a' and
|
|
||||||
'b', the 'AsMyClass' method will be defined only once.
|
|
||||||
|
|
||||||
|
|
||||||
2.- A fragment can only defined once, and the first definition
|
|
||||||
is the only one taking in account. All other definitions of the
|
|
||||||
same fragments are silently ignored. For example, you can have
|
|
||||||
|
|
||||||
|
|
||||||
%fragment("AsMyClass","header") { <definition 1> }
|
|
||||||
....
|
|
||||||
%fragment("AsMyClass","header") { <definition 2> }
|
|
||||||
|
|
||||||
and then only the first definition is considered. In this way
|
|
||||||
you can change the 'system' fragments by including yours first.
|
|
||||||
|
|
||||||
Note that this behavior is opposite to the typemaps, where the
|
|
||||||
last typemap applied or defined prevails. Fragment follows the
|
|
||||||
first-in-first-out convention since they are intended to be
|
|
||||||
"global", while typemaps intend to be "locally" specialized.
|
|
||||||
|
|
||||||
3.- Fragments names can not contain commas.
|
|
||||||
|
|
||||||
|
|
||||||
A fragment can include one or more additional fragments, for example:
|
|
||||||
|
|
||||||
%fragment("<limits.h>", "header") {
|
|
||||||
#include <limits.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%fragment("AsMyClass", "header", fragment="<limits.h>") {
|
|
||||||
MyClass *AsMyClass(PyObject *obj) {
|
|
||||||
MyClass *value = 0;
|
|
||||||
int ival = somewhere_converted_from_input_object_here(obj)
|
|
||||||
...
|
|
||||||
if (ival < CHAR_MIN) {
|
|
||||||
value = something_from_ival(ival);
|
|
||||||
} else {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
...
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
in this case, when the "AsMyClass" fragment is emitted, it also
|
|
||||||
trigger the inclusion of the "<limits.h>" fragment.
|
|
||||||
|
|
||||||
You can add as many fragments as you want, for example
|
|
||||||
|
|
||||||
%fragment("bigfragment","header", fragment="frag1", fragment="frag2", fragment="frag3") "";
|
|
||||||
|
|
||||||
here, when the "bigfragment" is included, the three fragments "frag1",
|
|
||||||
"frag2" and "frag3" are included. Note that as "bigframent" is defined
|
|
||||||
empty, "", it does not add any code by itself, buy only trigger the
|
|
||||||
inclusion of the other fragments.
|
|
||||||
|
|
||||||
In a typemap you can also include more than one fragment, but since the
|
|
||||||
syntax is different, you need to specify them in a 'comma separated'
|
|
||||||
list, for example, considering the previous example:
|
|
||||||
|
|
||||||
%typemap(in,fragment="frag1,frag2,frag3") {...}
|
|
||||||
|
|
||||||
is equivalent to
|
|
||||||
|
|
||||||
%typemap(in,fragment="bigfragment") {...}
|
|
||||||
|
|
||||||
|
|
||||||
Finally, you can force the inclusion of a fragment at any moment as follow:
|
|
||||||
|
|
||||||
%fragment("bigfragment");
|
|
||||||
|
|
||||||
which is very useful inside a template class, for example.
|
|
||||||
|
|
||||||
|
|
||||||
Fragment type specialization
|
|
||||||
============================
|
|
||||||
|
|
||||||
Fragments can be "type specialized". The syntax is as follows
|
|
||||||
|
|
||||||
%fragment("name","header") { a type independent fragment }
|
|
||||||
%fragment("name" {Type}, "header") { a type dependent fragment }
|
|
||||||
|
|
||||||
and they can also, as typemaps, be used inside templates, for exampe:
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct A {
|
|
||||||
%fragment("incode"{A<T>},"header") {
|
|
||||||
'incode' specialized fragment
|
|
||||||
}
|
|
||||||
|
|
||||||
%typemap(in,fragment="incode"{A<T>}) {
|
|
||||||
here we use the 'type specialized'
|
|
||||||
fragment "incode"{A<T>}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
which could seems a not much interesting feature, but is
|
|
||||||
fundamental for automatic typemap and template specialization.
|
|
||||||
|
|
||||||
|
|
||||||
Fragments and automatic typemap specialization:
|
|
||||||
===============================================
|
|
||||||
|
|
||||||
Since fragments can be type specialized, they can be elegantly used
|
|
||||||
to specialized typemaps .
|
|
||||||
|
|
||||||
For example, if you have something like:
|
|
||||||
|
|
||||||
%fragment("incode"{float}, "header") {
|
|
||||||
float in_method_float(PyObject *obj) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%fragment("incode"{long}, "header") {
|
|
||||||
float in_method_long(PyObject *obj) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%define %my_typemaps(Type)
|
|
||||||
%typemaps(in,fragment="incode"{Type}) {
|
|
||||||
value = in_method_##Type(obj);
|
|
||||||
}
|
|
||||||
%enddef
|
|
||||||
|
|
||||||
%my_typemaps(float);
|
|
||||||
%my_typemaps(long);
|
|
||||||
|
|
||||||
then the proper "incode"{float,double} fragment will be included,
|
|
||||||
and the proper in_method_{float,double} will be called.
|
|
||||||
|
|
||||||
Since this is a recurrent fragment use, we provide a couple of
|
|
||||||
macros that make the automatic generation of typemaps easier:
|
|
||||||
|
|
||||||
|
|
||||||
Consider for example the following code:
|
|
||||||
|
|
||||||
%fragment(SWIG_From_frag(bool), "header") {
|
%fragment(SWIG_From_frag(bool), "header") {
|
||||||
static PyObject*
|
static PyObject*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue