1

I'm trying to figure out what SWIG Interface file change is needed in order to handle the getFoo returns a pointer that points to an array of a custom structure (sender_id_t). Without any special SWIG Interface code, I get just the pointer on the Java side. How can I turn that pointer into something I can loop or iterate over (in Java) so that I can get each sender_id_t id value? Appreciate any suggestions.

C Structure:

typedef unsigned char id_v1_t[32];
typedef id_v1_t id_t;
%rename (Sample) sender_id_t_;
struct sender_id_t_ {
    id_t       id;
    uint32_t   phy_idx;
};

C Function:

//This will return a pointer to an array of sender_id_t data.  The number of elements is retrieved from a separate call. 
sender_id_t* getFoo(resultset_t* resultset);

Exception:

 [exec] test_wrap.c: In function `new_foo_array':
 [exec] test_wrap.c:785: error: invalid application of `sizeof' to incomplete type `sender_id_t_' 
 [exec] test_wrap.c: At top level:
 [exec] test_wrap.c:792: error: return type is an incomplete type
 [exec] test_wrap.c: In function `foo_array_getitem':
 [exec] test_wrap.c:793: error: invalid use of undefined type `struct sender_id_t_'
 [exec] test_wrap.c:793: error: dereferencing pointer to incomplete type
 [exec] test_wrap.c:793: warning: `return' with a value, in function returning void
 [exec] test_wrap.c: At top level:
 [exec] test_wrap.c:795: error: parameter `value' has incomplete type
 [exec] test_wrap.c: In function `foo_array_setitem':
c12
  • 9,557
  • 48
  • 157
  • 253

1 Answers1

2

The simplest solution to this doesn't involve writing any JNI at all - in effect it's method 2. So what I did was use carrays.i to expose a very basic interface and then written a small bit of Java to make the public view of it more usable/intuitive. The key thing is you need to supply a way of bringing together the knowledge of the array and the length of it. I've put together a minimal complete example to illustrate, it returns a Java array, but it could equally work for an ArrayList or any collection you like.

Firstly a header file, with an inline implementation for compactness:

#ifndef TEST_H
#define TEST_H

struct Foo {
   int v;
};

inline static struct Foo *getFoo() {
  static struct Foo r[] = {{0},{1},{2}};
  return r;
}

inline static unsigned short numFoo() {
  return 3;
}

#endif

This is then wrapped with:

%module test

%{
#include "test.h"
%}

%include <carrays.i>
%array_functions(struct Foo, foo_array);

%rename(getFooImpl) getFoo;
%javamethodmodifiers getFoo() "private";
%javamethodmodifiers numFoo() "private";
%include "test.h"

%pragma(java) modulecode=%{
  public static Foo[] getFoo() {
    final int num = numFoo();
    Foo ret[] = new Foo[num];
    Foo result = getFooImpl();
    for (int i = 0; i < num; ++i) {
      ret[i] = foo_array_getitem(result, i);
    }
    return ret;
  }  
%}

Where we make rename the getFoo() from the header file and make it and the corresponding numFoo() private, i.e. implementation details.

Using these two private functions we can then write a real, public Foo[] getFoo(), that calls these two and then copies the results into an actual array of known size.

I tested this with:

public class main {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    Foo[] foos = test.getFoo();
    System.out.println(foos[2].getV());
  }
}

In my view this solution is cleaner than the corresponding JNI based example - it's simpler to write and harder to introduce bugs which makes it more maintainable. Any Java or C programmer that looks at it can pretty much see what's going on. It's probably not much worse in terms of performance and probably not going to be a big chunk of time on some critical path - if benchmarks show it to be a problem then it's still easy to go down the JNI road later.

For completeness on the "making it private" aspect you might also want to do something like:

%javamethodmodifiers foo_array_getitem "private";
%ignore foo_array_setitem;
%ignore delete_foo_array;
%ignore new_foo_array;
%include <carrays.i>
%array_functions(struct Foo, foo_array);

To hide all of the functions which get generated by the %array_functions macro.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • thanks for such a complete example. I was able to compile your sample code fine. When I tried to use my structure (sender_id_t_) I ran into issue with applying the sizeof to the sender_id_t_.id property. I pasted the compile errors in the question above. Any ideas? – c12 Dec 19 '11 at 03:03
  • @c12 - it looks like you need an extra `#include` inside the `%{ %}` bit at the top that includes the fil that defines `sender_id_t_`. – Flexo Dec 19 '11 at 13:18
  • I removed the %rename on the sender_id_t_ (see initial question) and everything worked. For some reason the way I'm using the %rename (question now edited to include it) is causing the "sizeof" error. – c12 Dec 20 '11 at 03:10
  • I've come back to this example several times trying to figure out my issue with converting a c array pointer to a java array and it seems that the above implementation doesn't quite work the same for a nonstatic return value. It may be an implementation issue on my part, but does your answer change if C is returning a non static pointer to an array? – c12 Mar 16 '12 at 18:00
  • @c12 not really, I'll try and look later. Only the ownership will change to avoid leaking. The static part just changes the function linkage, which was because I was being lazy and putting it all in a header file :) – Flexo Mar 16 '12 at 18:08
  • When I use `typedef struct Foo Foo;` in the header file, the generated getFooImpl() method returns SWIGTYPE_p_Foo instead of Foo. Is there any workaround except to remove `typedef struct Foo Foo;` ? – Svetoslav Marinov Aug 14 '12 at 07:06
  • 1
    @SvetoslavMarinov - you need to have a (any) definition of `struct Foo` available in the SWIG interface. Even `typedef struct Foo {} Foo;` in the SWIG interface works. See [this answer](http://stackoverflow.com/a/10008434/168175), ignore the `%extend` part of it. – Flexo Aug 14 '12 at 07:44
  • Thank you. This is the solution of the problem. – Svetoslav Marinov Aug 14 '12 at 08:47