3

Given is this C code:

typedef struct _B {
 /* something */
} B;

typedef struct _A {
    int numBs; /* The count of Bs in the array bellow */
    B *b;
} A;

I would like to access A.b as an array in Java

A a = new A();
B[] b = a.getB();

Do you have an Idea how to do this with SWIG? I played around with carrays.i, without success. Consider that B *b does not always have to be an array, only in this particular structure.

2
  • Create an NIO direct byte buffer using the original address, and then use the NIO Buffer methods to access the memory as an array. Commented Aug 16, 2013 at 19:22
  • Hi, thanks. Can you give an example how to achive this (the SWIG interface file)? The best result i can get is B b = a.getB() instead of B[] b = a.getB(). Commented Aug 20, 2013 at 9:59

1 Answer 1

4

We can do this with SWIG. The tricky part is that as you spotted SWIG is inclined to assume that B* is a pointer to an Object, not the start of some array.

Since the array contains many non-primitive instances each instance is going to require the creation of a Java object that is a proxy for the corresponding B instance in your C array. There are two places you could cause those to be generated. Either you could write some C that creates each Object and sticks it in a jobjectArray, or you could write some Java that takes advantage of the fact that SWIG can trivially be made to generate a specific proxy for any specific member. I think the latter solution is simpler and cleaner so I've made an example using that approach:

%module test

%ignore A_::b; // We will wrap this another way
%typemap(javacode) A %{
  public B[] getB() {
    B[] ret = new B[getNumBs()];
    for (int i = 0; i < ret.length; ++i) {
      ret[i] = getB(i);
    }
    return ret;
  }
%}

// Or %include etc.
%inline %{
typedef struct B_ {
 /* something */
} B;

typedef struct A_ {
    int numBs; /* The count of Bs in the array bellow */
    B *b;
} A;
%}

%javamethodmodifiers A_::getB(size_t pos) "private";
%extend A_ {
  // This defaults to non-owning, which is exactly what we want
  B *getB(size_t pos) {
    assert(pos < $self->numBs); // TODO: real error handling
    return $self->b+pos;
  }
}

The %extend provides one extra method in Java that gets any B in your C array of Bs. Since this is an implementation detail I made it private.

We also told SWIG not to wrap the B *b pointer - we're going to supply our own wrapping for that manually instead. This is provided via the javacode typemap. Inside that typemap we build up our Java array by calling our helper once per item in the array.

With that in place it's now sufficient for you to do:

A a = new A();
B[] b = a.getB();

Crucially because we only ignored the specific member of A it won't interfere with other uses of B *b.

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

Comments

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.