доступ к массиву вложенных структур в Python с использованием SWIG - PullRequest
2 голосов
/ 10 октября 2011

Мне не удалось выяснить, как получить доступ к элементам массива SubStatus в следующей вложенной структуре. Мне кажется, я вижу первый элемент, но не понимаю, как принудительно индексировать, например, в виде списка.

Любая помощь очень ценится.

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"

1 Ответ

1 голос
/ 09 декабря 2011

Вы можете обернуть этот заголовок, не изменяя его, купив что-то вроде:

%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"

Это в основном то же самое, что и мой ответ , но вместо изменения заголовка наиспользуйте wrapped_array, мы использовали %ignore, чтобы сообщить SWIG, что мы предоставим наше собственное определение STATUS для его переноса.(Это совершенно законно, оболочка, сгенерированная SWIG, будет по-прежнему использовать реальное определение из status.h)

Мы вводим в это измененное определение getSubStatus(), который возвращает объект, который действует как прокси для реальногомассив в STATUS.Этот прокси, в свою очередь, предоставляет __getitem__, __setitem__ и __len__, которые Python ищет, чтобы использовать оператор индекса.

Может быть способ сделать это правильно в Python без необходимости getSubStatus(),чтобы SWIG установил __swig_setmethods__["SubStatus"] и __swig_getmethods__["SubStatus"] соответствующим образом, но я не совсем уверен, как заставить SWIG python делать это.

Если вы используете C, вы не используете C ++ 'Я хочу отбросить шаблон в пользу простого struct и использовать указатель вместо ссылки на массив.

...