nested structure array access in python using SWIG
I haven't been able to figure out how to access the array elements SubStatus in the following nested structure. I do seem to be able to see the first element, but don't understand how to force indexing, e.g., as a list.
Any help is much appreciated.
status.h:
// Data Types
typedef char CHAR; // 8 bits signed
typedef short SHORT; // 16 bits signed
typedef long LONG; // 32 bits signed
typedef unsigned char UCHAR; // 8 bits unsigned
typedef unsigned short 开发者_Go百科USHORT; // 16 bits usigned
#define FUNC_TYPE // built in C, leave reference as C
#define DLL_API extern FUNC_TYPE __declspec(dllimport)
// Sub Status Data
typedef struct
{
LONG xyz;
LONG abc;
} SUB_STATUS;
// Status Info
typedef struct
{
UCHAR qrs;
UCHAR tuv;
SUB_STATUS SubStatus[4];
LONG wxy;
} STATUS;
DLL_API SHORT GetStatus( STATUS *Status );
status.i
%module status
%{
/* Includes the header in the wrapper code */
#include "status.h"
%}
/* Parse the header file to generate wrappers */
%include "windows.i"
%include "typemaps.i"
%include "status.h"
You can wrap this header without having to modify it buy doing something like:
%module status
%immutable;
%inline %{
template <typename Type, size_t N>
struct wrapped_array {
Type (&data)[N];
wrapped_array(Type (&data)[N]) : data(data) { }
};
%}
%mutable;
%{
#include "status.h"
%}
%include "typemaps.i"
%include "std_except.i"
// Only expose a reduced STATUS, without the Array:
typedef struct
{
UCHAR qrs;
UCHAR tuv;
LONG wxy;
} STATUS;
%extend wrapped_array {
inline size_t __len__() const { return N; }
inline const Type& __getitem__(size_t i) const throw(std::out_of_range) {
if (i >= N || i < 0)
throw std::out_of_range("out of bounds access");
return $self->data[i];
}
inline void __setitem__(size_t i, const Type& v) throw(std::out_of_range) {
if (i >= N || i < 0)
throw std::out_of_range("out of bounds access");
$self->data[i] = v;
}
}
%template (SubStatusArray) wrapped_array<SUB_STATUS,4>;
// Hide the real array in our helper
%extend STATUS {
wrapped_array<SUB_STATUS,4> getSubStatus() {
return wrapped_array<SUB_STATUS,4>($self->SubStatus);
}
}
%ignore STATUS; // We've specified an alternative way of wrapping this
%include "status.h"
This is basically the same as my answer here, but instead of modifying the header to use the wrapped_array
, we've used %ignore
to tell SWIG we will supply our own definition of STATUS
for it to wrap. (This is perfectly legal, the SWIG generated wrapper will still use the real definition from status.h)
We inject into this altered definition a getSubStatus()
, which returns an object that acts as a proxy to the real array in STATUS
. This proxy in turn supplies __getitem__
, __setitem__
and __len__
that python looks for to use the subscript operator.
There might be a way to do this properly in Python without needing the getSubStatus()
, making SWIG set __swig_setmethods__["SubStatus"]
and __swig_getmethods__["SubStatus"]
appropriately, but I'm not sure off the top of my head how to make SWIG python do that.
If you're using C, not using C++ you'll want to drop the template in favour of just a plain struct
and use a pointer instead of a reference to an array.
精彩评论