2

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 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"
Lou K
  • 1,128
  • 2
  • 12
  • 31
  • possible duplicate of [SWIG/python array inside structure](http://stackoverflow.com/questions/8114030/swig-python-array-inside-structure) – Flexo Nov 24 '11 at 09:17
  • Thanks awoodland, but I don't have control over the .h file as this comes from a vendor's distribution. If I understood that other solution correctly, I'd have to make modifications to the c source, right? I am hoping for an answer which just affects the .i file. – Lou K Dec 09 '11 at 14:56
  • You can apply it without modifying the header, it's a little trickier though. I'll put together an example later hopefully. – Flexo Dec 09 '11 at 16:15

1 Answers1

1

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.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • Flexo, I am trying to do similar things with python/swig, but in my case I want to use C. So I did something similar to Lou K's code but used a toy struct, `typdef struct { int i; int ai[10]; } mystruct;` i tried to override ai with `typdef struct { int data[10]; } wrapped_array_int_10;` and `wrapped_array_int_10* getai()`. i got the code compiled, but from python when tried `o = example.mystruct()`, i got error that mystruct don't have constructor. can you tell what am i missing? thanks... – yosukesabai Dec 14 '15 at 00:03
  • @yos are you building in C or C++? – Flexo Dec 14 '15 at 08:11
  • I am building with c. – yosukesabai Dec 14 '15 at 13:12