1

If I have a C function (see below) that returns a unsigned char pointer to an array. How would you instruct SWIG to bind to the Java ArrayList data type for getFoo(). I'm not sure an ArrayList is possible, maybe an array (String[] in this case). I want to keep the Java return type of getFoo as generic as possible since the C getFoo may return an array of int, double, char..etc.

   unsigned char * getFoo(int32_t *length){

    static unsigned char foo[44];
    foo[0]='a';
    foo[1]='b';
    foo[2]='c';
    foo[3]='d';
    return foo;
}
c12
  • 9,557
  • 48
  • 157
  • 253
  • If you're keeping it generic how will you know the length of it? Is it `NULL` terminated always? Or always a fixed length? I can think of a solution which would be very generic, but un-bounded on the Java side (and hence not an `ArrayList` or `Collection`), but it would have a sensible, usable interface still. – Flexo Dec 09 '11 at 11:46
  • @awoodland - The returned array will not always be the same length. There is a length output param passed back (getFoo(int32_t *length)), so I can get the length from there. When the pointer is pointing to an array of Strings then it would be null terminated. I had to update my C function above as I tried to be too general with it before. I added the full signature now to my original question. – c12 Dec 09 '11 at 19:43
  • I updated my answer to add an example of making the `ucArray` class iterable. – Flexo Dec 09 '11 at 20:04

1 Answers1

1

The most generic answer is to expose the result as an unbouned C array in Java:

%module test

%include "carrays.i"
%array_class(unsigned char, ucArray);

unsigned char *getFoo();

This generates a class, called ucArray, which has gets and sets for a specific index. It's unbounded, with the same semantics as C arrays, but lightweight and usable. Since it's not bounded you can invoke Undefined Behaviour from Java, and it has no bounds which makes it impossible to use as an Iterator or Collection.

If your array is NULL/0 terminated it would be reasonably easy to use %extend to implement the Java Iterable interface too, rough, untested example:

%typemap(javainterfaces) ucArray "java.lang.Iterable<Short>"
%typemap(javacode) ucArray %{
  public java.util.Iterator<Short> iterator() {
    return new java.util.Iterator<Short>() {
      private int pos = 0;
      public Short next() {
        // Mmmm autoboxing!
        return getitem(pos++);
      }
      public void remove() {
        throw new UnsupportedOperationException();
      }
      public boolean hasNext() {
        // Check if we're at the end. A NULL/0 element represents the end
        return getitem(pos) != 0;
      }
    };
  }
%}

This needs to go somewhere before the %array_class macro gets called. It says that our ucArray class will implement Iterable and then implements that interface using an anonymous inner class in the iterator() (the only method of the Iterable interface) method to implement the Iterator interface.

Flexo
  • 87,323
  • 22
  • 191
  • 272
  • I implemented the non-Iterable version (top part only) a while back with some static data (i.e. [0]='A' [1]='2'..etc). Whenever I change my C array data to things like [0]='A1' or anything other than a single letter or number I run into issues. On the Java side I'm casting the Array element from a short to a char (char chr = (char) test[i];). %array_functions(unsigned char, ucArray) creates a public static short ucArray_getitem(SWIGTYPE_p_unsigned_char ary, int index). Did I implement this wrong on the Java side or is this a limitation of my SWIG knowledge? Thanks for Helping – c12 Mar 19 '12 at 18:57
  • @c12 - my example used `%array_class` not `%array_functions`, which are slightly different (look at the generated code for the two). – Flexo Mar 19 '12 at 23:31
  • my mistake, I was trying to apply what you showed me here to http://stackoverflow.com/questions/9779435/swig-java-use-of-carrays-i-and-array-functions-for-c-array-of-strings – c12 Mar 19 '12 at 23:53