1

Say I have the following static constexpr array of c struct:

#include <cstdint>

namespace ns1::ns2 {
    struct Person {
        char name[32];
        uint8_t age;    
    };
    static constexpr Person PERSONS[] = {
        {"Ken", 8},
        {"Cat", 27}
    };
}

How can I access elements in ns1::ns2::PERSONS in python by using swig?

One way I can think of is to create a accessor like const Person& get(uint32_t index) in the swig interface file. Tho, I wonder whether there is a more elegant way that I don't have to create an accessor function for each array of c struct.

Thanks!

1 Answer 1

3

One way I can think of is to create a accessor like const Person& get(uint32_t index) in the swig interface file.

According to 5.4.5 Arrays in the SWIG documentation, that's the way to do it:

%module test

%include <stdint.i>

%inline %{
#include <cstdint>

namespace ns1::ns2 {
    struct Person {
        char name[32];
        uint8_t age;
    };
    static constexpr Person PERSONS[] = {
        {"Ken", 8},
        {"Cat", 27}
    };
}

// helper function
const ns1::ns2::Person* Person_get(size_t index) {
    if(index < sizeof(ns1::ns2::PERSONS) / sizeof(ns1::ns2::Person))  // protection
        return ns1::ns2::PERSONS + index;
    else
        return nullptr;
}
%}

Demo:

>>> import test
>>> test.PERSONS.name # can only access the first element
'Ken'
>>> test.Person_get(1).name
'Cat'
>>> test.Person_get(2).name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'name'

SWIG can also generate array wrappers for you with 11.2.2 carrays.i, but there is no bounds checking:

%module test

%include <stdint.i>

%inline %{
#include <cstdint>

namespace ns1::ns2 {
    struct Person {
        char name[32];
        uint8_t age;
    };
    static constexpr Person PERSONS[] = {
        {"Ken", 8},
        {"Cat", 27}
    };
}
%}

%include <carrays.i>
%array_functions(ns1::ns2::Person,arrayPerson);

Demo:

>>> import test
>>> test.arrayPerson_getitem(test.PERSONS,1).name
'Cat'
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. I wish one day, swig can offer something more "natural" that user can just access element like test.PERSONS[0]...
Actually, one more question related to the same code snippet above. If I add a const cv-qualifier to member variables name and age, it seems like SWIG generates some invalid code (the cv-qualifier in this case is valid tho) that I got this error, error: use of deleted function ‘ns1::ns2::Person::Person()’ and 3096 | return (new ns1::ns2::Person[nelements]()); Seems like SWIG always tries to allocate a new object when returning even though I requested for returning a reference.
@HCSF if you want more natural try using a std::vector instead of an array.

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.