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"
3
  • possible duplicate of SWIG/python array inside structure Commented Nov 24, 2011 at 9: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. Commented Dec 9, 2011 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. Commented Dec 9, 2011 at 16:15

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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...
@yos are you building in C or C++?
I am building with c.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.