Added section on typemaps and overloading.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@4668 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Dave Beazley 2003-04-05 01:44:57 +00:00
commit c25cbb1fda

View file

@ -413,6 +413,7 @@ int foo(<b><font color="#ff0000">int x, double y, char *s</font></b>);
<p>
<ul>
<li>Input argument conversion ("in" typemap).
<li>Input argument type checking ("typecheck" typemap).
<li>Output argument handling ("argout" typemap).
<li>Input argument value checking ("check" typemap).
<li>Input argument initialization ("arginit" typemap).
@ -1653,6 +1654,26 @@ At this time, only zero or one arguments may be converted.
<b>Compatibility note: </b> Specifying <tt>numinputs=0</tt>
is the same as the old "ignore" typemap.
<h3>"typecheck" typemap</h3>
The "typecheck" typemap is used to support overloaded functions and methods. It merely checks an argument
to see whether or not it matches a specific type. For example:
<blockquote>
<pre>
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) int {
$1 = PyInt_Check($input) ? 1 : 0;
}
</pre>
</blockquote>
For typechecking, the $1 variable is always a simple integer that is set to 1 or 0 depending on whether or not
the input argument is the correct type.
<p>
If you define new "in" typemaps <em>and</em> your program uses overloaded methods, you should also define a collection of
"typecheck" typemaps. More details about this follow in a later section on "Typemaps and Overloading."
<a name="n27"></a><H3>8.5.2 "out" typemap</H3>
@ -2562,6 +2583,289 @@ type-checking. This code is also included in every generated wrapped file so yo
probably just look at the output of SWIG to get a better sense for how types are
managed.
<h2>Typemaps and overloading</h2>
In many target languages, SWIG fully supports C++ overloaded methods and functions. For example,
if you have a collection of functions like this:
<blockquote>
<pre>
int foo(int x);
int foo(double x);
int foo(char *s, int y);
</pre>
</blockquote>
You can access the functions in a normal way from the scripting interpreter:
<blockquote>
<pre>
# Python
foo(3) # foo(int)
foo(3.5) # foo(double)
foo("hello",5) # foo(char *, int)
# Tcl
foo 3 # foo(int)
foo 3.5 # foo(double)
foo hello 5 # foo(char *, int)
</pre>
</blockquote>
To implement overloading, SWIG generates a separate wrapper function for each overloaded method.
For example, the above functions would produce something roughly like this:
<blockquote>
<pre>
// wrapper pseudocode
_wrap_foo_0(argc, args[]) { // foo(int)
int arg1;
int result;
...
arg1 = FromInteger(args[0]);
result = foo(arg1);
return ToInteger(result);
}
_wrap_foo_1(argc, args[]) { // foo(double)
double arg1;
int result;
...
arg1 = FromDouble(args[0]);
result = foo(arg1);
return ToInteger(result);
}
_wrap_foo_2(argc, args[]) { // foo(char *, int)
char *arg1;
int arg2;
int result;
...
arg1 = FromString(args[0]);
arg2 = FromInteger(args[1]);
result = foo(arg1,arg2);
return ToInteger(result);
}
</pre>
</blockquote>
Next, a dynamic dispatch function is generated:
<blockquote>
<pre>
_wrap_foo(argc, args[]) {
if (argc == 1) {
if (IsInteger(args[0])) {
return _wrap_foo_0(argc,args);
}
if (IsDouble(args[0])) {
return _wrap_foo_1(argc,args);
}
}
if (argc == 2) {
if (IsString(args[0]) && IsInteger(args[1])) {
return _wrap_foo_2(argc,args);
}
}
error("No matching function!\n");
}
</pre>
</blockquote>
The purpose of the dynamic dispatch function is to select the appropriate C++ function based on
argument types---a task that must be performed at runtime in most of SWIG's target languages.
<p>
The generation of the dynamic dispatch function is a relatively tricky affair. Not only must input typemaps
be taken into account (these typemaps can radically change the types of arguments accepted), but overloaded
methods must also be sorted and checked in a very specific order to resolve potential ambiguity. A high-level
overview of this ranking process is found in the "<a href="SWIGPlus.html">SWIG and C++</a>" chapter. What isn't mentioned in that chapter
is the mechanism by which it is implemented---as a collection of typemaps.
<p>
To support dynamic dispatch, SWIG first defines a general purpose type hierarchy as follows:
<blockquote>
<pre>
Symbolic Name Precedence Value
------------------------------ ------------------
SWIG_TYPECHECK_POINTER 0
SWIG_TYPECHECK_VOIDPTR 10
SWIG_TYPECHECK_BOOL 15
SWIG_TYPECHECK_UINT8 20
SWIG_TYPECHECK_INT8 25
SWIG_TYPECHECK_UINT16 30
SWIG_TYPECHECK_INT16 35
SWIG_TYPECHECK_UINT32 40
SWIG_TYPECHECK_INT32 45
SWIG_TYPECHECK_UINT64 50
SWIG_TYPECHECK_INT64 55
SWIG_TYPECHECK_UINT128 60
SWIG_TYPECHECK_INT128 65
SWIG_TYPECHECK_INTEGER 70
SWIG_TYPECHECK_FLOAT 80
SWIG_TYPECHECK_DOUBLE 90
SWIG_TYPECHECK_COMPLEX 100
SWIG_TYPECHECK_UNICHAR 110
SWIG_TYPECHECK_UNISTRING 120
SWIG_TYPECHECK_CHAR 130
SWIG_TYPECHECK_STRING 140
SWIG_TYPECHECK_BOOL_ARRAY 1015
SWIG_TYPECHECK_INT8_ARRAY 1025
SWIG_TYPECHECK_INT16_ARRAY 1035
SWIG_TYPECHECK_INT32_ARRAY 1045
SWIG_TYPECHECK_INT64_ARRAY 1055
SWIG_TYPECHECK_INT128_ARRAY 1065
SWIG_TYPECHECK_FLOAT_ARRAY 1080
SWIG_TYPECHECK_DOUBLE_ARRAY 1090
SWIG_TYPECHECK_CHAR_ARRAY 1130
SWIG_TYPECHECK_STRING_ARRAY 1140
</pre>
</blockquote>
(These precedence levels are defined in <tt>swig.swg</tt>, a library file that's included by all target language modules.)
<p>
In this table, the precedence-level determines the order in which types are going to be checked. Low values
are always checked before higher values. For example, integers are checked before floats, single values are checked
before arrays, and so forth.
<p>
Using the above table as a guide, each target language defines a collection of "typecheck" typemaps.
The follow excerpt from the Python module illustrates this:
<blockquote>
<pre>
/* Python type checking rules */
/* Note: %typecheck(X) is a macro for %typemap(typecheck,precedence=X) */
%typecheck(SWIG_TYPECHECK_INTEGER)
int, short, long,
unsigned int, unsigned short, unsigned long,
signed char, unsigned char,
long long, unsigned long long,
const int &, const short &, const long &,
const unsigned int &, const unsigned short &, const unsigned long &,
const long long &, const unsigned long long &,
enum SWIGTYPE,
bool, const bool &
{
$1 = (PyInt_Check($input) || PyLong_Check($input)) ? 1 : 0;
}
%typecheck(SWIG_TYPECHECK_DOUBLE)
float, double,
const float &, const double &
{
$1 = (PyFloat_Check($input) || PyInt_Check($input) || PyLong_Check($input)) ? 1 : 0;
}
%typecheck(SWIG_TYPECHECK_CHAR) char {
$1 = (PyString_Check($input) && (PyString_Size($input) == 1)) ? 1 : 0;
}
%typecheck(SWIG_TYPECHECK_STRING) char * {
$1 = PyString_Check($input) ? 1 : 0;
}
%typecheck(SWIG_TYPECHECK_POINTER) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [] {
void *ptr;
if (SWIG_ConvertPtr($input, (void **) &ptr, $1_descriptor, 0) == -1) {
$1 = 0;
PyErr_Clear();
} else {
$1 = 1;
}
}
%typecheck(SWIG_TYPECHECK_POINTER) SWIGTYPE {
void *ptr;
if (SWIG_ConvertPtr($input, (void **) &ptr, $&1_descriptor, 0) == -1) {
$1 = 0;
PyErr_Clear();
} else {
$1 = 1;
}
}
%typecheck(SWIG_TYPECHECK_VOIDPTR) void * {
void *ptr;
if (SWIG_ConvertPtr($input, (void **) &ptr, 0, 0) == -1) {
$1 = 0;
PyErr_Clear();
} else {
$1 = 1;
}
}
%typecheck(SWIG_TYPECHECK_POINTER) PyObject *
{
$1 = ($input != 0);
}
</pre>
</blockquote>
It might take a bit of contemplation, but this code has merely organized all of the basic C++ types, provided some simple type-checking
code, and assigned each type a precedence value.
<p>
Finally, to generate the dynamic dispatch function, SWIG uses the following algorithm:
<ul>
<li>Overloaded methods are first sorted by the number of required arguments.
<li>Methods with the same number of arguments are then sorted by precedence values of argument types.
<li>Typecheck typemaps are then emitted to produce a dispatch function that checks arguments in the correct order.
</ul>
If you haven't written any typemaps of your own, it is unnecessary to worry about the typechecking rules.
However, if you have written new input typemaps, you might have to supply a typechecking rule as well.
An easy way to do this is to simply copy one of the existing typechecking rules.
Here is an example,
<blockquote>
<pre>
// Typemap for a C++ string
%typemap(in) std::string {
if (PyString_Check($input)) {
$1 = std::string(PyString_AsString($input));
} else {
SWIG_exception(SWIG_TypeError, "string expected");
}
}
// Copy the typecheck code for "char *".
%typemap(typecheck) std::string = char *;
</pre>
</blockquote>
The bottom line: If you are writing new typemaps and you are using overloaded methods, you will probably
have to write typecheck code or copy existing code. Since this is a relatively new SWIG feature, there are
few examples to work with. However, you might look at some of the existing library files likes 'typemaps.i' for
a guide.
<p>
<b>Notes:</b>
<ul>
<li>Typecheck typemaps are not used for non-overloaded methods. Because of this, it is
still always necessary to check types in any "in" typemaps.
<p>
<li>The dynamic dispatch process is only meant to be a heuristic. There are many corner
cases where SWIG simply can't disambiguate types to the same degree as C++. The only way to
resolve this ambiguity is to use the %rename directive to rename one of the overloaded methods (effectively
eliminating overloading).
<p>
<li>
Typechecking may be partial. For example, if working with arrays, the typecheck code might
simply check the type of the first array element and use that to dispatch to the correct function.
Subsequent "in" typemaps would then perform more extensive type-checking.
<p>
<Li>Make sure you read the section on overloading in the "<a href="SWIGPlus.html">SWIG and C++</a>" chapter.
</ul>
<a name="n42"></a><H2>8.9 More about <tt>%apply</tt> and <tt>%clear</tt></H2>
@ -2711,7 +3015,7 @@ convert_float_array(PyObject *input, int size) {
</pre>
</blockquote>
<a name="n44"></a><H3>8.10.1 Passing data between typemaps</H3>
<a name="n44"></a><H2>8.10.1 Passing data between typemaps</H2>
<p>