The official flutter tutorial on C/C++ interop through ffi only touches on calling a C++ function and getting a single return value.
Goal
What if I have a data buffer created on C/C++ side, but want to deliver to dart/flutter-side to show?
Problem
With #MilesBudnek 's tip, I'm testing Dart's FFI by trying to have safe memory deallocation from Dart to C/C++. The test reuses the official struct sample .
I could get the Array as a dart Pointer, but it's unclear to me how to iterate the array as a collection easily.
Code
I'm implementing a Dart-side C array binding like this:
In struct.h
struct Array
{
int* array;
int len;
};
and a pair of simple allocation/deallocation test functions:
struct Array* get_array();
int del_array(struct Array* arr);
Then on Dart side in structs.dart:
typedef get_array_func = Pointer<Array> Function();
typedef del_array_func = void Function(int arrAddress);
...
final getArrayPointer = dylib.lookup<NativeFunction<get_array_func>>('get_array');
final getArray = getArrayPointer.asFunction<get_array_func>();
final arrayPointer = getArray();
final array = arrayPointer.ref.array;
print('array.array: $array');
This gives me the print out
array.array: Pointer<Int32>: address=0x7fb0a5900000
Question
Can I convert the array pointer to a List easily? Something like:
final array = arrayPointer.ref.array.toList();
array.forEach(index, elem) => print("array[$idx]: $elem");
======
Old Question (you can skip this)
Problem
It's unclear to me how to retrieve this kind of vector data from C/C++ by dart/flutter.
Possible solutions
More importantly, how to push data from C++ side from various threads?
If there is no builtin support, off the top of my head I'd need to implement some communication schemes.
Option #1: Networking
I could do network through TCP sockets. But I'm reluctant to go there if there are easier solutions.
Option #2: file I/O
Write data to file with C/C++, and let dart/flutter poll on the file and stream data over. This is not realtime friendly.
So, are there better options?
Solved it.
According to this issue, the API asTypedList is the way to go.
Here is the code that works for me
final getArrayPointer = dylib.lookup<NativeFunction<get_array_func>>('get_array');
final getArray = getArrayPointer.asFunction<get_array_func>();
final arrayPointer = getArray();
final arr = arrayPointer.ref.arr;
print('array.array: $arr');
final arrReal = arr.asTypedList(10);
final arrType = arrReal.runtimeType;
print('arrReal: $arrReal, $arrType');
arrReal.forEach((elem) => print("array: $elem"));
This gives me:
array.array: Pointer<Int32>: address=0x7f9eebb02870
arrReal: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], Int32List
array: 0
array: 1
array: 2
array: 3
array: 4
array: 5
array: 6
array: 7
array: 8
array: 9
asTypedList will only work with pointers that relate to TypedData.
there are other cases where, for example, you want to convert an Pointer<UnsignedChar> to a Uint8List, in this case you can:
use an extension and then either cast the Pointer<UnsignedChar to a Pointer<Uint8> and then use asTypedList. In this case you have to make sure the pointer is not freed while the Uint8List is still referenced.
extension UnsignedCharPointerExtension on Pointer<UnsignedChar> {
Uint8List? toUint8List(int length) {
if (this == nullptr) {
return null;
}
return cast<Uint8>().asTypedList(length);
}
}
use an extension and don't cast the pointer but copy it manually. In this case you can free the pointer after you get the Uint8List
extension UnsignedCharPointerExtension on Pointer<UnsignedChar> {
Uint8List? toUint8List(int length) {
if (this == nullptr) {
return null;
}
final Uint8List list = Uint8List(length);
for (int i = 0; i < length; i++) {
list[i] = this[i];
}
return list;
}
}
Related
How would one get a view of a PyArrayObject* similar to the following python code?
# n-column array x
# d is the length of each column
print(x.shape) # => (d, n)
by_column = [x[::,i] for i in range(x.shape[1])]
assert len(by_column) == n
print(by_column[n-1].shape) # => (d,)
So far my code is this:
// my_array is a PyArrayObject*
std::vector<PyArrayObject*> columns = {};
npy_intp* dims = my_array->dimensions;
npy_intp* strides = my_array->strides;
std::vector<int> shape = {};
for (int i = 0; &dims[i] != strides; i++){
shape.push_back(dims[i]);
}
switch (shape.size()) {
case 1: {
// handle 1D array by simply iterating
}
case 2: {
int columns = shape[1];
// What now?
}
}
I'm having trouble finding any reference to do this in C/C++ in both the documentation and the source code, could you give an example of how one would do this?
The C/C++ API for numpy seems really convoluted when compared to something like std::vector, and the documentation isn't very beginner-friendly either, so any references to easier guides would be appreciated too.
You should access the internal structure of PyArrayObject via the PyArray_XXX functions like PyArray_NDIM. To get the contents of a sequence, you use PyObject_GetItem with a tuple key, where in your use case the tuple will have a PySliceObject as the first element.
I am trying to port a JS algorithm to C++, to see if I can improve the perfs, but I'm facing a huge performance bottleneck on populating v8 arrays.
Here is a snippet that reproduce just the array populating. I create an array of 800k items, each item being an array of 17 numbers. This algo takes 3secs to execute on my machine, which is quite huge.
Is there anyway to speed it up?
#include <node.h>
namespace demo {
using namespace v8; // just for lisibility of the example
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Array> array = Array::New(isolate, 800000);
for (int i = 0; i < 800000; ++i) {
Local<Array> line = Array::New(isolate, 17);
for (int j = 0; j < 17; ++j) {
line->Set(j, Number::New(isolate, i * 100 + j));
}
array->Set(i, line);
}
args.GetReturnValue().Set(array);
}
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(parser, Init)
}
Creating JS objects (and interacting with them) from C++ is more expensive than doing it from JS. This can easily offset performance gains from the rest of the C++ code.
You can work around this by communicating via a Buffer (the serialization overhead will typically be lower than the above). More importantly, this will also let you do the work off the main v8 thread.
If you're only dealing with numbers, this should be relatively straightforward using Buffer.readIntLE (or similar methods). You could also encode the array's length into the first few bytes of the buffer. Here's what the JS side of things could look like:
var buf = new Buffer(/* Large enough to contain your serialized data. */);
// Function defined in your C++ addon.
addon.populate(buf, function (err) {
if (err) {
// Handle C++ error.
return;
}
// At this point, `buf` contains the serialized data. Deserialization
// will depend on the chosen serialization format but a reasonable
// option could be the following:
var arr = [];
var pos = 4;
var size = buf.readInt32LE(0);
while (size--) {
var subarr = new Array(17);
for (var i = 0; i < 17; i++) {
subarr[i] = buf.readInt32LE(pos);
pos += 4;
}
arr.push(subarr);
}
// `arr` now contains your decoded data.
});
The C++ part of the code would keep a reference to buf's data (a char *) and populate it inside a worker thread (see nan's AsyncWorker for a convenient helper).
As mtth said, working with JS arrays in C++ is expensive. Using a buffer would work, but you can also use TypedArrays. These are accessible from C++ as pointers to contiguous, aligned blocks of memory, which makes them easy to work with and fast to iterate over.
See https://stackoverflow.com/a/31712512/1218408 for some info on how to access their contents.
I am working on bridging between a C++ class and Swift. I know I can only interface with c and Objective C so I am writing a wrapping function in c.
I need to return some data that I have packaged in a structure and with the structure holding an array of unknown length. All this needs to be done with only c to interface with Swift.
My structure looks as follows:
struct Output {
double DataA;
long DataArrayLength;
double *DataArray;
};
I have written the following function in c to package the data:
struct Output* GetData( double InputA) {
struct Output output;
output.DataArrayLength = 100; // The length will only be known at run time and
// once I get into this function.
output.DataArray = new double[output.DataArrayLength];
///
Fill in the data array - some complicated calculations behind this.
output.DataArray[0] = 12345.0;
output.DataArray[99] = 98761.0;
///
return &output; // Getting warning Address of stack associated with local variable 'output' returned.
}
From Swift I can then call
var swoutput = GetData( 1.0)
var count = swoutput.memory.DataArrayLength
My questions are:
Is there a better way do do this? How?
How should I allocate, pass, return the Output struct? I realize the problem with the current method but not sure the best fix.
I still need to release the memory from DataArray. I think I need to do this from the Swift code. How do I do this?
You have to do:
Output* GetData( double InputA) {
Output* output = new Output;
output->DataArrayLength = 100; // The length will only be known at run time and
// once I get into this function.
output->DataArray = new double[output->DataArrayLength];
/// Fill in the data array - some complicated calculations behind this.
output->DataArray[0] = 12345.0;
output->DataArray[99] = 98761.0;
///
return output;
}
And don't forget:
void DeleteOutput(Output* output)
{
if (output == nullptr) {
return;
}
delete [] output->DataArray;
delete output;
}
I created a function that returns an error code (ErrCode enum) and pass two output parameters. But when I print the result of the function, I don't get the correct values in the array.
// .. some codes here ..
ErrCode err;
short lstCnt;
short lstArr[] = {};
err = getTrimmedList(lstArr, &lstCnt);
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d", i, lstArr[i]);
// .. some codes here ..
The getTrimmedList function is like this:
ErrCode getTrimmedList(short* vList, short* vCnt)
{
short cnt;
ErrCode err = foo.getListCount(FOO_TYPE_1, &cnt);
if (NoError!=err) return err;
short* list = new short [cnt];
short total = 0;
for (short i=0; i<cnt; ++i)
{
FooBar bar = foo.getEntryByIndex(FOO_TYPE_1, i);
if (bar.isDeleted) continue;
list[total] = i;
++total;
}
*vCnt = total;
//vList = (short*)realloc(index, sizeof(short)*total);
vList = (short*)malloc(sizeof(short)*total);
memcpy(vList, list, sizeof(short)*total)
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d", i, lstArr[i]);
return NoError;
}
where:
foo is an object that holds arrays of FooBar objects
foo.getListCount() returns the number of objects with type FOO_TYPE_1
FOO_TYPE_1 is the type of object we want to take/list
foo.getEntryByIndex() returns the ith FooBar object with type FOO_TYPE_1
bar.isDeleted is a flag that tells if bar is considered as 'deleted' or not
What's my error?
Edit:
Sorry, I copied a wrong line. I commented it above and put the correct line.
Edit 2
I don't have control over the returns of foo and bar. All their function returns are ErrCode and the outputs are passed through parameter.
Couple of questions before I can answer your post...
Where is "index" defined in:
vList = (short*)realloc(index, sizeof(short)*total);
Are you leaking the memory associated with:
short* list = new short [cnt];
Is it possible you have accidentally confused your pointers in memory allocation? In any case, here is an example to go from. You have a whole host of problems, but you should be able to use this as a guide to answer this question as it was originally asked.
WORKING EXAMPLE:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int getTrimmedList(short** vList, short* vCnt);
int main ()
{
// .. some codes here ..
int err;
short lstCnt;
short *lstArr = NULL;
err = getTrimmedList(&lstArr, &lstCnt);
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d\n", i, lstArr[i]);
// .. some codes here ..
return 0;
}
int getTrimmedList(short** vList, short* vCnt)
{
short cnt = 5;
short* list = new short [cnt];
short* newList = NULL;
short total = 0;
list[0] = 0;
list[1] = 3;
list[2] = 4;
list[3] = 6;
total = 4;
*vCnt = total;
newList = (short*)realloc(*vList, sizeof(short)*total);
if ( newList ) {
memcpy(newList, list, sizeof(short)*total);
*vList = newList;
} else {
memcpy(*vList, list, sizeof(short)*total);
}
delete list;
return 0;
}
You have serious problems.
For starters, your function has only one output param as you use it: vCnt.
vList you use as just a local variable.
realloc is called with some index that we kow nothing about, not likely good. It must be something got from malloc() or realloc().
The allocated memory in vList is leaked as soon as you exit getTrimmedList.
Where you call the function you pass the local lstArr array as first argument that is not used for anything. Then print the original, unchanged array, to bounds in cnt, while it has 0 size still -- behavior is undefined.
Even if you managed to pass that array by ref, you could not reassign it to a different value -- C-style arrays can't do that.
You better use std::vector that you can actually pass by reference and fill in the called function. eliminating the redundant size and importantly the mess with memory handling.
You should use std::vector instead of raw c-style arrays, and pass-by-reference using "&" instead of "*" here. Right now, you are not properly setting your out parameter (a pointer to an array would look like "short **arr_ptr" not "short *arr_ptr", if you want to be return a new array to your caller -- this API is highly error-prone, however, as you're finding out.)
Your getTrimmedList function, therefore, should have this signature:
ErrCode getTrimmedList(std::vector<short> &lst);
Now you no longer require your "count" parameters, as well -- C++'s standard containers all have ways of querying the size of their contents.
C++11 also lets you be more specific about space requirements for ints, so if you're looking for a 16-bit "short", you probably want int16_t.
ErrCode getTrimmedList(std::vector<int16_t> &lst);
It may also be reasonable to avoid requiring your caller to create the "out" array, since we're using smarter containers here:
std::vector<int16_t> getTrimmedList(); // not a reference in the return here
In this style, we would likely manage errors using exceptions rather than return-codes, however, so other things about your interface would evolve, as well, most likely.
I have the following structure
typedef struct DeviceInfo
{
char[30] name;
char[30] serial Number;
}DeviceInfo;
I am doing this
DeviceInfo* m_DeviceInfo = new DeviceInfo[4];
// Populate m_DeviceInfo
Then I wanted to re size m_DeviceInfo to 6 and want to preserve the
Previous 4 Value as well.
How to do it in c++ ?
You can't do that with regular arrays. I suggest you to use vector which is able to grow as you add more elements to it (so you don't even have to specify initial size).
The good C++ way is to use an appropriate container for that. Apparently, you should use the std::vector container, e.g:
std::vector<DeviceInfo> m_DeviceInfo;
m_DeviceInfo.resize(4);
This requires some constraints on your DeviceInfo. In particular, it should have a constructor without arguments, and copy constructors...
And your question is badly phrased. You certainly don't change sizeof(DeviceInfo*) which is probably 4 bytes on a 32 bits machine, and 8 bytes on a 64 bits one.
m_DeviceInfo points to an array of DeviceInfo of 4 elements. There is no resizing with arrays. Instead you should delete and create it with 6 elements.
DeviceInfo * m_DeviceInfo2 = new DeviceInfo[6];
memcopy( m_DeviceInfo,m_DeviceInfo2, 4 );
delete[] m_DeviceInfo;
But you should use a vector.
std::vector<DeviceInfo> m_DeviceInfo;
// or
std::vector<std::shared_ptr<DeviceInfo>> m_DeviceInfo;
To resize it
m_DeviceInfo.resize(m_DeviceInfo.size()+ 2);
You have two options in your problem and it depends if you want to use STL or not.
typedef struct DeviceInfo
{
char[30] name;
char[30] serial Number;
} DeviceInfo;
With STL:
//requires vector.h
vector<DeviceInfo> m_deviceInfo;
DeviceInfo dummy;
dummy.name = "dummyName";
dummy.serialNumber = "1234";
m_deviceInfo.insert(m_deviceInfo.begin(), dummy);
//add as many DeviceInfo instance you need the same way
or without STL:
//implement this
DeviceInfo* reallocArray(DeviceInfo* arr, int curItemNum, int newItemNumber)
{
DeviceInfo* buf = new DeviceInfo[newItemNumber];
for(int i = 0; i < curItemNum; i++)
buf[i] = arr[i];
for(int i = curItemNum; i < newItemNumber; i++)
buf[i] = null;
}
//and in your main code
DeviceInfo m_DeviceInfo = new DeviceInfo[4];
m_DeviceInfo = reallocArray( m_DeviceInfo, 4, 6 );
1) Make a new array of size that fits, and copy all elements of the old array to the new one.
2) Use the std::vector (my recommendation).
The best possible solution is using vector in your program.
Refer this site http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html#VECTOR
This site will help you to solve your problem.
Here you can push the data.No need to bother about the size of structure.
Your syntax is wrong:
DeviceInfo m_DeviceInfo = new DeviceInfo[4];
should be:
DeviceInfo* m_DeviceInfo = new DeviceInfo[4];
A better alternative would be the use of std::vector.
std::vector<DeviceInfo> vec;
//populate:
DeviceInfo inf;
vec.push_back(inf);
vec.push_back(inf);
//....
well there are several ways to do this, but
you should use the realloc function in c++. it will reallocate contiguous memory and also copies the value of previous memory into the new ones. for example:
temp_DevInfo = (DeviceInfo*) realloc (m_DeviceInfo, (2) * sizeof(struct DeviceInfo));
free(m_DeviceInfo);
m_deviceInfo = temp_DevInfo;
you do 2 * sizeof(DeviceInfo) because you want to add 2 more, plus the previous 4 is 6.
then you should free/delete the previous object.
and finally set old pointer to point to the new object you just allocated.
that should be the gist of it
look at the documentation of realloc.