[Gdal-dev] Re: gdal swig interface Band.i Updated
Charlie Savage
cfis at savagexi.com
Fri Aug 4 18:41:53 EDT 2006
The proposed wrapper code is correct.
%apply (int *OUTPUT){int *blockXSize, int *blockYSize}
void GetBlockSize(int *blockXSize, int *blockYSize){
GDALGetBlockSize(self, blockXSize, blockYSize);
}
And could be further simplified to:
void GetBlockSize(int *OUTPUT, int *OUTPUT){
GDALGetBlockSize(self, blockXSize, blockYSize);
}
What's nice is that it will work with all SWIG languages. For those
interested, some more technical background below.
Charlie
------------
Three are three ways to wrap output parameters in SWIG. To show them,
let's walk through an example:
void add(int x, int y, int *result)
{
*result = x + y;
}
1. Using OUTPUT, so:
void add(int, int, int *OUTPUT);
2. Use %apply, like this:
%apply int *OUTPUT { int *result };
void add(int x, int y, int *result);
#1 is shorthand for #2. Both have SWIG generate the wrapper code for you.
3. Create the wrapper code yourself by using typemaps.
> I don't see anything obviously wrong with your formulation, but when
> I look in Band.i or the various other .i files I don't see anything
> quite analygous to your approach either. Some other functions that
> return values in variables to which passed pointers are provided just
> look like this:
>
> void GetOffset( double *val, int *hasval ) {
> *val = GDALGetRasterOffset( self, hasval );
> }
>
> I'm not sure if "val and hasval" are special names or exactly what
> makes this work. But it makes me wonder if the approach you suggest
> is appropriate.
GetOffset is an example of option #3 above. You can find the right type
map for this method in each language file. Using Python as an example,
look at line 212 in typemaps_python.i.
Part 1:
%typemap(python,in,numinputs=0) (double *val, int*hasval) ( double
tmpval, int tmphasval ) {
$1 = &tmpval;
$2 = &tmphasval;
}
Before GDalGetRasterOffset is called, define two local variable.
Pointers to these local variable will be the parameters used in the
GDalGetRasterOffset call.
Part 2:
%typemap(python,argout) (double *val, int*hasval) {
PyObject *r;
if ( !*$2 ) {
Py_INCREF(Py_None);
r = Py_None;
$result = t_output_helper($result,r);
}
else {
r = PyFloat_FromDouble( *$1 );
$result = t_output_helper($result,r);
}
}
After GDalGetRasterOffset is called, check to see if hasVal is true or
false. If false, return Py_None (null in python). If true, wrap val as
a Python double object.
The reason this typemap exists is because of the extra logic involved
needed to figure out what to do with the result.
Fake Classes
--------------
Also, a bit of backround about how the SWIG bindings are structured.
They create "fake" classes so from Python or Ruby or Java or whatever,
there is a class called GDALRasterBand which has a method called GetOffset.
Using these "fake" classes is a very unusual approach. Usually, SWIG is
used to directly wrap C++ classes so there is no need for the "fake"
classes.
However, the GDAL bindings use the c api not the c++ api. But if you
exposed the C api to python or ruby, it would create an API very foreign
to the average Python/Ruby programmer. Thus the "fake" classes make the
c api look object oriented.
The advantage of this approach is you can tightly control the exposed
api. I think the other thought was that client programs linking against
the C api would be more stable. This is true for c or c++ clients, but
I don't think is true for Python/Ruby clients. This is because they
provide APIs through which you register new methods - its not like a C++
program where the links are setup as pointers. So when you provide a
new gdal c lib, and the associated language binding libraries, a python
or ruby program is not going to care that it has changed.
The disadvantage is that its a lot of extra work and complexity, and
you're not going to find examples of how to do it out on the Web.
Anyway, hope this helps.
More information about the Gdal-dev
mailing list