Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vector<struct> as returntype: possible? Mapping correct? #24

Open
ochafik opened this issue Mar 18, 2015 · 1 comment
Open

vector<struct> as returntype: possible? Mapping correct? #24

ochafik opened this issue Mar 18, 2015 · 1 comment
Labels

Comments

@ochafik
Copy link
Member

ochafik commented Mar 18, 2015

From @apiening on September 25, 2012 22:37

Hi bridj users,

after a successful hello world test, I'm running more and more in problems using BridJ in my "real world" app. I wonder if I'm doing something wrong, my type of mapping is not supported or my platform support (Mac OS X, Mountain Lion) is still buggy.

I want to return a container with structs from a C++ function. I used vector but I'm not specifically bound to this container.
I created a simple demo project and a mapping with JNAerator which compiles, but fails with this error:

Exception in thread "main" java.lang.RuntimeException: Invalid return value type !
    at bridjtest_java.bridj.Test.getStruct(Native Method)
    at bridjtest_java.BridJTest_Java.main(BridJTest_Java.java:35)
Java Result: 1

Here is my C++ header that feeds JNAerator:

#include <vector>

struct SimpleStruct {
    int number;
};

class Test {
public:
    Test();
    Test(const Test& orig);
    virtual ~Test();

    std::vector<SimpleStruct> getStruct();
private:

};

This is the mapping I get from JNAerator:

package bridjtest_java.bridj;
import org.bridj.Pointer;
import org.bridj.ann.Library;
import org.bridj.ann.Name;
import org.bridj.cpp.CPPObject;
import org.bridj.cpp.std.vector;

@Library("test")
public class Test extends CPPObject {
    public Test() {
        super();
    }
    /// Original signature : <code>int Test()</code>
    @Name("Test")
    public native int Test$2();
    /// Original signature : <code>int Test(const Test&)</code>
    public native int Test(Pointer<Test > orig);
    /**
     * char* getGaps(const char* outfile);<br>
     * Original signature : <code>std::vector getStruct()</code><br>
     * <i>native declaration : line 50</i>
     */
    public native vector<SimpleStruct> getStruct();
}

And here's the mapping class for the struct:

package bridjtest_java.bridj;
import org.bridj.Pointer;
import org.bridj.StructObject;
import org.bridj.ann.Field;
import org.bridj.ann.Library;

@Library("test")
public class SimpleStruct extends StructObject {
    public SimpleStruct() {
        super();
    }
    @Field(0)
    public int number() {
        return this.io.getIntField(this, 0);
    }
    @Field(0)
    public SimpleStruct number(int number) {
        this.io.setIntField(this, 0, number);
        return this;
    }
    public SimpleStruct(Pointer pointer) {
        super(pointer);
    }
}

Can someone please confirm if this mapping is supported/possible and if it should work or not?
What may cause my error? How can I dig into that?

Thank you very much!

Andreas Piening

Copied from original issue: nativelibs4java/nativelibs4java#341

@ochafik
Copy link
Member Author

ochafik commented Mar 18, 2015

Hi @apiening ,

Returning a vector by value is not recommended in C++ (might incur a copy upon return), people usually pass it by reference:

void getValues(std::vector& out);

BridJ's org.bridj.cpp.std.vector support is currently very flaky at best (STL has different layouts on each platform / runtime library, which even changes between release and debug modes), but you might manage to use it if you provide creation / destruction methods (vector newSimpleStructVector(); void deleteSimpleStructVector(vector);).

The other alternative is to use the C style:

void getValues(SimpleStruct* out, size_t outSize, size_t *elementCount);

Which you first call with:

Pointer pElementCount = allocateSizeT();
getValues(null, 0, pElementCount);

Then:

long elementCount = pElementCount.getSizeT();
Pointer pStructs = allocateArray(SimpleStruct.class, elementCount);
getValues(pStructs, elementCount, null);

Hope it helps :-)

Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant