SWIG/python array inside structure

前端 未结 3 1759
南方客
南方客 2020-12-01 22:01

I\'ve got a structure defined inside header.h that looks like :

typedef struct {
....
    int      icntl[40];
    double   cntl[15];
    int      *irn, *jcn;         


        
相关标签:
3条回答
  • 2020-12-01 22:39

    Have you considered using SWIG carrays?

    In your header file:

    typedef struct {
        int      icntl[40];
        double   cntl[15];
    } some_struct_t;
    

    Then, in your swig file:

    %module example
    %include "carrays.i"  
    // ...
    %array_class(int, intArray);
    %array_class(double, doubleArray);
    

    The Python looks like this:

    icntl = example.intArray(40)
    cntl = example.doubleArray(15)
    for i in range(0, 40):
        icntl[i] = i
    for i in range(0, 15):
        cntl[i] = i
    st = example.some_struct_t()
    st.icntl = icntl
    st.cntl = cntl
    

    You still can't set the structs directly. I write python wrapper code to hide the boilerplate.

    array_class only works with basic types (int, double), if you need something else (e.g. uint8_t) you need to use array_functions, which have even more boilerplate, but they work.

    http://www.swig.org/Doc3.0/SWIGDocumentation.html#Library_carrays

    0 讨论(0)
  • 2020-12-01 22:44

    I would have done this in python

    ptr = int(st.icntl)
    import ctypes
    icntl = ctypes.c_int * 40
    icntl = icntl.from_address(ptr)
    
    print icntl[0]
    icntl[0] = 1
    for i in icntl:
        print i 
    
    0 讨论(0)
  • 2020-12-01 23:03

    The easiest way to do this is to wrap your arrays inside a struct, which can then provide extra methods to meet the "subscriptable" requirements.

    I've put together a small example. It assumes you're using C++, but the equivalent C version is fairly trivial to construct from this, it just requires a bit of repetition.

    First up, the C++ header that has the struct we want to wrap and a template that we use for wrapping fixed size arrays:

    template <typename Type, size_t N>
    struct wrapped_array {
      Type data[N];
    };
    
    typedef struct {
        wrapped_array<int, 40> icntl;
        wrapped_array<double, 15> cntl;
        int      *irn, *jcn;
    } Test;
    

    Our corresponding SWIG interface then looks something like:

    %module test
    
    %{
    #include "test.h"
    #include <exception>
    %}
    
    %include "test.h"
    %include "std_except.i"
    
    %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 (intArray40) wrapped_array<int, 40>;
    %template (doubleArray15) wrapped_array<double, 15>;
    

    The trick there is that we've used %extend to supply __getitem__ which is what Python uses for subscript reads and __setitem__ for the writes. (We could also have supplied a __iter__ to make the type iteratable). We also gave the specific wraped_arrays we want to use unique names to make SWIG wrap them in the output.

    With the supplied interface we can now do:

    >>> import test
    >>> foo = test.Test()
    >>> foo.icntl[30] = -654321
    >>> print foo.icntl[30]
    -654321
    >>> print foo.icntl[40]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "test.py", line 108, in __getitem__
        def __getitem__(self, *args): return _test.intArray40___getitem__(self, *args)
    IndexError: out of bounds access
    

    You might also find this approach useful/interesting as an alternative.

    0 讨论(0)
提交回复
热议问题