I know one way - using memcpy on C++ side:
C++ method:
void CopyData(void* buffer, int size)
{
memcpy(buffer, source, size);
}
JNR mapping:
void CopyData(@Pinned @Out ByteBuffer byteBuffer, @Pinned @In int size);
Java invocation:
ByteBuffer buffer = ByteBuffer.allocateDirect(size);
adapter.CopyData(buffer, size);
But I would like to handle case when native code does not copy data, but only returns pointer to the memory which is to be copied:
C++ methods:
void* GetData1()
{
return source;
}
// or
struct Data
{
void* data;
};
void* GetData2(Data* outData)
{
outData->data = source;
}
I know how to write JNR mapping to be able to copy data to HeapByteBuffer:
Pointer GetData1();
// or
void GetData2(@Pinned @Out Data outData);
final class Data extends Struct {
public final Struct.Pointer data;
public DecodeResult(Runtime runtime) {
super(runtime);
data = new Struct.Pointer();
}
}
Java invocation:
ByteBuffer buffer = ByteBuffer.allocate(size);
Pointer dataPtr = adapter.GetData1();
dataPtr.get(0, buffer.array(), 0, buffer.array().length);
// or
ByteBuffer buffer = ByteBuffer.allocate(size);
Data outData = new Data(runtime);
adapter.GetData2(outData);
Pointer dataPtr = outData.data.get();
dataPtr.get(0, buffer.array(), 0, buffer.array().length);
But I have not found a way to copy memory to DirectByteBuffer instead of HeapByteBuffer. The above snippet of code does not work for DirectByteBuffer because buffer.array() is null for such a buffer, as it is backed by native memory area.
Please help.
I have found several ways to perform copying of JNR native memory to
DirectByteBuffer. They differ in efficiency. Currently I use the following aproach, I don't know whether is it the best or intended by JNR authors:or
It is important that the assert clause above is fulfilled. It guarantees that pointers are
jnr.ffi.provider.jffi.DirectMemoryIOinstances, and the efficientmemcpymethod is used for copying (check implementation ofDirectMemoryIO.transferTo()).The alternative is to wrap
DirectByteBufferusing the following method:or
but no:
Pointer destPtr = Pointer.wrap(runtime, buffer);The first and second pointers are backed by
DirectMemoryIO, but the third pointer is backed byByteBufferMemoryIOand it involves slow byte-by-byte copying.The one drawback is that
DirectMemoryIOinstance is quite heavyweight. It allocates 32 bytes on JVM heap, so in case of plenty of JNR invocations, allDirectMemoryIOinstances consume big part of memory.