My c++ function is defined as follows:
std::vector<std::array<std::array<float, 160>, 160>> get_masks(float *img_pixels) {...}
I would request the community to help out by mapping this function to dart so it can be consumed.
I even tried ffigen & Chatgpt but the results were unsatisfactory.
Also is there any good resource from where I can learn this concept?
You can use this code as a start, BUT DON'T FORGET TO FREE THE ALLOCATED MEMORY (AND EVEN OPTIMIZE IT MORE TO YOUR SPECIFIC CASE, AS IT MAY NOT BE OPTIMIZED AND IT IS JUST FOR DEMONSTRATION):
FFI_PLUGIN_EXPORT float **createDoubleArrayFromVectorOfDoubleArrays(void *vector) {
std::vector<std::array<std::array<float, 160>, 160>> *vectorOfDoubleArrays = (std::vector<std::array<std::array<float, 160>, 160>> *) vector;
float **array = new float *[vectorOfDoubleArrays->size()];
for (int i = 0; i < vectorOfDoubleArrays->size(); i++) {
array[i] = new float[160 * 160];
for (int j = 0; j < 160; j++) {
for (int k = 0; k < 160; k++) {
array[i][j * 160 + k] = (*vectorOfDoubleArrays)[i][j][k];
}
}
}
return array;
}
List<List<Float64List>> generateRandomArrayOfDoubleArrays(int count){
Pointer<Void> nativeVector = _bindings.createRandomVectorOfDoubleArrays(count); // create a vector of double arrays in native code and return a pointer to it (casted to void*)
final Pointer<Pointer<Float>> nativeGeneratedArray = _bindings.createDoubleArrayFromVectorOfDoubleArrays(nativeVector); // generate a list of list of double arrays from nativeVector, each double array is a Float64List of length 160
// now we convert them to dart lists by iterating and copying the data
final List<List<Float64List>> generatedArray = [];
for (int i = 0; i < count; i++) {
final List<Float64List> generatedArrayRow = [];
for (int j = 0; j < 160; j++) {
final Pointer<Float> nativeGeneratedArrayRow = nativeGeneratedArray.elementAt(i).value.elementAt(j);
final Float64List generatedArrayRowElement = Float64List.fromList(nativeGeneratedArrayRow.asTypedList(160));
generatedArrayRow.add(generatedArrayRowElement);
}
generatedArray.add(generatedArrayRow);
}
return generatedArray;
}
flutter create --template=plugin_ffi --platforms=android,ios,windows,macos,linux sample_ffi_plugin
sample_ffi_plugin.c
in src/
to sample_ffi_plugin.cpp
(and rename it also in CMakeLists.txt
sample_ffi_plugin.cpp
with these:#include "sample_ffi_plugin.h"
FFI_PLUGIN_EXPORT float **createDoubleArrayFromVectorOfDoubleArrays(void *vector) {
std::vector<std::array<std::array<float, 160>, 160>> *vectorOfDoubleArrays = (std::vector<std::array<std::array<float, 160>, 160>> *) vector;
float **array = new float *[vectorOfDoubleArrays->size()];
for (int i = 0; i < vectorOfDoubleArrays->size(); i++) {
array[i] = new float[160 * 160];
for (int j = 0; j < 160; j++) {
for (int k = 0; k < 160; k++) {
array[i][j * 160 + k] = (*vectorOfDoubleArrays)[i][j][k];
}
}
}
return array;
}
FFI_PLUGIN_EXPORT void* createRandomVectorOfDoubleArrays(int count){
std::vector<std::array<std::array<float, 160>, 160>> *vector = new std::vector<std::array<std::array<float, 160>, 160>>;
for (int i = 0; i < count; i++) {
std::array<std::array<float, 160>, 160> array;
for (int j = 0; j < 160; j++) {
for (int k = 0; k < 160; k++) {
array[j][k] = j * 160 + k;
}
}
vector->push_back(array);
}
return vector;
}
sample_ffi_plugin.h
with these:#if _WIN32
#define FFI_PLUGIN_EXPORT __declspec(dllexport)
#else
#define FFI_PLUGIN_EXPORT
#endif
#ifdef __cplusplus
#include <vector>
#include <array>
extern "C" {
#endif
FFI_PLUGIN_EXPORT void* createRandomVectorOfDoubleArrays(int count);
FFI_PLUGIN_EXPORT float** createDoubleArrayFromVectorOfDoubleArrays(void* vector);
#ifdef __cplusplus
}
#endif
flutter pub run ffigen --config ffigen.yaml
sample_ffi_plugin.dart
in /lib/
with this:
import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'dart:typed_data';
import 'sample_ffi_plugin_bindings_generated.dart';
const String _libName = 'sample_ffi_plugin';
/// The dynamic library in which the symbols for [SampleFfiPluginBindings] can be found.
final DynamicLibrary _dylib = () {
if (Platform.isMacOS || Platform.isIOS) {
return DynamicLibrary.open('$_libName.framework/$_libName');
}
if (Platform.isAndroid || Platform.isLinux) {
return DynamicLibrary.open('lib$_libName.so');
}
if (Platform.isWindows) {
return DynamicLibrary.open('$_libName.dll');
}
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}();
/// The bindings to the native functions in [_dylib].
final SampleFfiPluginBindings _bindings = SampleFfiPluginBindings(_dylib);
extension Float64ListExtension on Float64List {
/// Creates a `double` array from this list by copying the list's
/// data, and returns a pointer to it.
///
/// `nullptr` is returned if the list is empty.
Pointer<Double> toDoubleArrayPointer({required Allocator allocator}) {
if (isEmpty) {
return nullptr;
}
final Pointer<Double> ptr = allocator(sizeOf<Double>() * length);
for (int i = 0; i < length; i++) {
ptr[i] = this[i];
}
return ptr;
}
}
List<List<Float64List>> generateRandomArrayOfDoubleArrays(int count){
Pointer<Void> nativeVector = _bindings.createRandomVectorOfDoubleArrays(count); // create a vector of double arrays in native code and return a pointer to it (casted to void*)
final Pointer<Pointer<Float>> nativeGeneratedArray = _bindings.createDoubleArrayFromVectorOfDoubleArrays(nativeVector); // generate a list of list of double arrays from nativeVector, each double array is a Float64List of length 160
// now we convert them to dart lists by iterating and copying the data
final List<List<Float64List>> generatedArray = [];
for (int i = 0; i < count; i++) {
final List<Float64List> generatedArrayRow = [];
for (int j = 0; j < 160; j++) {
final Pointer<Float> nativeGeneratedArrayRow = nativeGeneratedArray.elementAt(i).value.elementAt(j);
final Float64List generatedArrayRowElement = Float64List.fromList(nativeGeneratedArrayRow.asTypedList(160));
generatedArrayRow.add(generatedArrayRowElement);
}
generatedArray.add(generatedArrayRow);
}
return generatedArray;
}
/example
and replace main.dart
with this:import 'package:flutter/material.dart';
import 'dart:async';
import 'package:sample_ffi_plugin/sample_ffi_plugin.dart' as sample_ffi_plugin;
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
const textStyle = TextStyle(fontSize: 25);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Native Packages'),
),
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(10),
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'First 100 elements of each of first 10 generated arrays:',
style: textStyle,
),
for(int i=0;i<10;i++)
Text(
'${sample_ffi_plugin.generateRandomArrayOfDoubleArrays(1)[0][i].take(100)}',
style: textStyle),
],
),
),
),
),
);
}
}