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)
|
||||
============================
|
||||
|
||||
2010-04-14: wsfulton
|
||||
Typemap fragments are now official and documented in Typemaps.html.
|
||||
|
||||
2010-04-09: wsfulton
|
||||
[Ruby] Fix #2048064 and #2408020.
|
||||
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>
|
||||
<ul>
|
||||
<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_nn19">Default typemaps</a>
|
||||
<li><a href="Typemaps.html#Typemaps_mixed_default">Mixed default typemaps</a>
|
||||
<li><a href="Typemaps.html#Typemaps_typedef_reductions">Typedef reductions matching</a>
|
||||
<li><a href="Typemaps.html#Typemaps_nn19">Default typemap matching rules</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>
|
||||
</ul>
|
||||
|
|
@ -390,14 +389,18 @@
|
|||
<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_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>
|
||||
<li><a href="Typemaps.html#Typemaps_nn45">Implementation</a>
|
||||
<li><a href="Typemaps.html#Typemaps_runtime_type_checker_usage">Usage</a>
|
||||
</ul>
|
||||
<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_nn49">Reducing wrapper code size</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_nn51">Where to go for more information?</a>
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@
|
|||
<li><a href="#Typemaps_pattern_matching">Pattern matching rules</a>
|
||||
<ul>
|
||||
<li><a href="#Typemaps_nn17">Basic matching rules</a>
|
||||
<li><a href="#Typemaps_typedef_reductions">Typedef reductions</a>
|
||||
<li><a href="#Typemaps_nn19">Default typemaps</a>
|
||||
<li><a href="#Typemaps_mixed_default">Mixed default typemaps</a>
|
||||
<li><a href="#Typemaps_typedef_reductions">Typedef reductions matching</a>
|
||||
<li><a href="#Typemaps_nn19">Default typemap matching rules</a>
|
||||
<li><a href="#Typemaps_multi_argument_typemaps_patterns">Multi-arguments typemaps</a>
|
||||
<li><a href="#Typemaps_debugging_search">Debugging typemap pattern matching</a>
|
||||
</ul>
|
||||
|
|
@ -72,14 +71,18 @@
|
|||
<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_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>
|
||||
<li><a href="#Typemaps_nn45">Implementation</a>
|
||||
<li><a href="#Typemaps_runtime_type_checker_usage">Usage</a>
|
||||
</ul>
|
||||
<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_nn49">Reducing wrapper code size</a>
|
||||
<li><a href="#Typemaps_nn47">Passing data between typemaps</a>
|
||||
<li><a href="#Typemaps_nn52">C++ "this" pointer</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>
|
||||
|
||||
|
||||
<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>
|
||||
|
|
@ -1438,7 +1441,7 @@ but all subsequent arguments must match exactly.
|
|||
</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>
|
||||
|
|
@ -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.
|
||||
</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>
|
||||
|
|
@ -3430,7 +3761,7 @@ language modules.</li>
|
|||
<li>Modules can be unloaded from the type system.</li>
|
||||
</ul>
|
||||
|
||||
<H3><a name="Typemaps_nn45"></a>10.10.1 Implementation</H3>
|
||||
<H3><a name="Typemaps_nn45"></a>10.11.1 Implementation</H3>
|
||||
|
||||
|
||||
<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.
|
||||
</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
|
||||
|
|
@ -3710,7 +4041,7 @@ probably just look at the output of SWIG to get a better sense for how types are
|
|||
managed.
|
||||
</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>
|
||||
|
|
@ -4021,7 +4352,7 @@ Subsequent "in" typemaps would then perform more extensive type-checking.
|
|||
</li>
|
||||
</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>
|
||||
|
|
@ -4106,86 +4437,6 @@ example:
|
|||
</pre>
|
||||
</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>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,238 +1,15 @@
|
|||
/*
|
||||
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
|
||||
dangerous swig features. So, if you are starting to read about them,
|
||||
make sure you read all of this document.
|
||||
Macros that make the automatic generation of typemaps easier are provided.
|
||||
|
||||
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*
|
||||
SWIG_From_dec(bool)(bool value)
|
||||
{
|
||||
|
|
@ -242,7 +19,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
%typemap(out,fragment=SWIG_From_frag(bool)) bool {
|
||||
%typemap(out, fragment=SWIG_From_frag(bool)) bool {
|
||||
$result = SWIG_From(bool)($1));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue