07. Flutter FFI array

 
Flutter FFI Study Notes Series

  1. "The Simplest Example of Flutter FFI"
  2. "Flutter FFI Basic Data Type"
  3. "Flutter FFI Function"
  4. "Flutter FFI String"
  5. "Flutter FFI Structure"
  6. "Flutter FFI Class"
  7. "Flutter FFI Array"
  8. "Flutter FFI Memory Management"
  9. 《Flutter FFI Dart Native API》
      
     

In the previous chapters, basic data types, strings, structures, etc. were introduced, and then the arrays in FFI are introduced.
  
 

1. Array representation

  Arrays in C language can be int[]represented by or by int*. In Dart, is generally used to Pointer<T extends NativeType>represent an array in C language.
  If a pointer is used to represent an array in C language, the length of the array generally needs to be specified. For example:

typedef struct {
    
    
    int32_t *data;
    int32_t length;
} IntArray;

IntArray *createIntArray() {
    
    
    auto *result = (IntArray *) malloc(sizeof(IntArray));
    result->length = 5;
    result->data = (int32_t *) malloc(result->length * sizeof(int32_t));
    for (int i = 0; i < result->length; i++) {
    
    
        result->data[i] = i * 2;
    }
    return result;
}

  Code description:

  • In the above code, an integer array is represented by defining IntArraya structure , datarepresenting data and lengthlength;
     

  In Dart, arrays are Pointer<T extends NativeType>represented , for example, int32_tarrays are Pointer<Int32>represented by .
  dart:ffiSome extension functions are defined in to help us use it Pointer<T extends NativeType>as an array, for example Pointer<Int32>:

extension Int32Pointer on Pointer<Int32> {
    
    
    //通过下标读取数组元素
    external int operator [](int index);
    
    //通过下标改写数组元素
    external void operator []=(int index, int value);
    
    //将指针数组转为List,可以像List一样使用各种便捷函数,例如:forEach
    //需要注意的是,使用时不能超出数组范围
    external Int32List asTypedList(int length);
}

  illustrate:

  • Int32Pointer[]In the extension function, the and []=operator functions are defined , which are used to read or rewrite the value of the specified index of the array;
  • asTypedList()Functions can convert arrays to Dart Listso that Listvarious .
     

2. Example of array usage

  The following example demonstrates basic usage of arrays.
  First, define the array structure, methods for creating arrays, and methods for accessing arrays in C:

#include <malloc.h>
#include <cstring>

#define DART_API extern "C" __attribute__((visibility("default"))) __attribute__((used))

//定义IntArray结构体
typedef struct {
    
    
    int32_t *data;
    int32_t length;
} IntArray;

//创建数组
DART_API IntArray *createIntArray() {
    
    
    auto *result = (IntArray *) malloc(sizeof(IntArray));
    result->length = 5;
    result->data = (int32_t *) malloc(result->length * sizeof(int32_t));
    for (int i = 0; i < result->length; i++) {
    
    
        result->data[i] = i * 2;
    }
    return result;
}

//获取数组最大值
DART_API int32_t getMaxInt(const int32_t *intArray, int32_t length) {
    
    
    int32_t max = intArray[0];
    for (int i = 1; i < length; i++) {
    
    
        if (intArray[i] > max) {
    
    
            max = intArray[i];
        }
    }
    return max;
}

//定义结构体Point,表示平面上的一点
typedef struct {
    
    
    int32_t x;
    int32_t y;
} Point;

//获取若干几点
DART_API Point *getPoints(int32_t length) {
    
    
    auto *points = (Point *) malloc(length * sizeof(Point));
    for (int i = 0; i < length; ++i) {
    
    
        points[i].x = 100 * (i + 1) + i;
        points[i].y = 200 * (i + 1) + (i + 1);
    }
    return points;
}

  Then, define the corresponding structure and function types in Dart:

//对应C中的IntArray结构体
class IntArray extends Struct {
    
    
  external Pointer<Int32> data;

  @Int32()
  external int length;
}

//对应C中的Point结构体
class Point extends Struct {
    
    
  @Int32()
  external int x;

  @Int32()
  external int y;

  String toDebugString() => "{x=$x, y=$y}";
}

typedef Native_createIntArray = Pointer<IntArray> Function();
typedef FFI_createIntArray = Pointer<IntArray> Function();

typedef Native_getMaxInt = Int32 Function(Pointer<Int32>, Int32);
typedef FFI_getMaxInt = int Function(Pointer<Int32>, int);

typedef Native_getPoints = Pointer<Point> Function(Int32 length);
typedef FFI_getPoints = Pointer<Point> Function(int length);

  Finally, write the interface that calls the array in Dart:

//加载符号
DynamicLibrary nativeApi = Platform.isAndroid
    ? DynamicLibrary.open("libnative_ffi.so")
    : DynamicLibrary.process();

//查找函数符号 - createIntArray
FFI_createIntArray createIntArrayFunc =
    nativeApi.lookupFunction<Native_createIntArray, FFI_createIntArray>(
        "createIntArray");

//查找函数符号 - getMaxInt
FFI_getMaxInt getMaxIntFunc =
    nativeApi.lookupFunction<Native_getMaxInt, FFI_getMaxInt>("getMaxInt");

//查找函数符号 - getPoints
FFI_getPoints getPointsFunc =
    nativeApi.lookupFunction<Native_getPoints, FFI_getPoints>("getPoints");

//创建IntArray
Pointer<IntArray> pIntArray = createIntArrayFunc();
IntArray intArray = pIntArray.ref;

//打印数组元素
for (int i = 0; i < intArray.length; i++) {
    
    
  print("intArray[$i]=${intArray.data[i]}");
}

//获取数组中的最大值
int max = getMaxIntFunc(intArray.data, intArray.length);
print("max of intArray=$max");

//将Int数组转为List使用
Int32List int32list = intArray.data.asTypedList(intArray.length);
int32list.forEach((it) => print("int32list=$it"));

//创建结构体数组
int length = 3;
Pointer<Point> pPointArray = getPointsFunc(length);
for (int i = 0; i < length; i++) {
    
    
  print("points[$i]=${pPointArray[i].toDebugString()}");
}

//释放内存
calloc.free(intArray.data);
calloc.free(pIntArray);
calloc.free(pPointArray);

  The output of the above code is as follows:

I/flutter ( 9388): intArray[0]=0
I/flutter ( 9388): intArray[1]=2
I/flutter ( 9388): intArray[2]=4
I/flutter ( 9388): intArray[3]=6
I/flutter ( 9388): intArray[4]=8
I/flutter ( 9388): max of intArray=8
I/flutter ( 9388): int32list=0
I/flutter ( 9388): int32list=2
I/flutter ( 9388): int32list=4
I/flutter ( 9388): int32list=6
I/flutter ( 9388): int32list=8
I/flutter ( 9388): points[0]={x=100, y=201}
I/flutter ( 9388): points[1]={x=201, y=402}
I/flutter ( 9388): points[2]={x=302, y=603}

 

3. Arrays of other types

  
Int32The array   and array are demonstrated above Struct, and other types of arrays, such as: Double, Float, Int8... are almost the same in usage.
 

 

4. Processing of zero-length dynamic arrays

  
   The interaction between C language zero-length dynamic array and Dart directly gives the code:
  
  C code:

#include "dart_api/dart_api.h"
#include "dart_api/dart_native_api.h"
#include "dart_api/dart_api_dl.h"

typedef struct {
    
    
    int len;
    int buffer[0];
} DynamicArray;

// 该函数用于创建一个 DynamicArray,给 Dart 使用。
DART_EXPORT DynamicArray *createArray(int len) {
    
    
    auto arr = (DynamicArray *) calloc(sizeof(DynamicArray) + sizeof(int) * len, 1);
    arr->len = len;
    return arr;
}

  Dart code:


void main() {
    
     runApp(Demo()); }

class Demo extends StatefulWidget {
    
    
  const Demo({
    
    Key? key}) : super(key: key);

  @override
  _DemoState createState() => _DemoState();
}

const int intMaxValue = 9223372036854775807;

class DynamicArray extends Struct {
    
    
  @Int32()
  external int len;

  ///给 dimension1 参数赋一个很大的值,绕过 ffi-patch.dart 的 _checkIndex() 的检查
  @Array(intMaxValue)
  external Array<Int32> data;
}

typedef Native_Dart_CreatArray = Pointer<DynamicArray> Function(Int32);
typedef FFI_Dart_CreatArray = Pointer<DynamicArray> Function(int);

class _DemoState extends State<Demo> {
    
    
  late DynamicLibrary nativeApi;

  @override
  void initState() {
    
    
    super.initState();
    testNative();
  }

  @override
  Widget build(BuildContext context) {
    
    
    return MaterialApp(home: Scaffold(body: Center(child: Text("FFI Demo"))));
  }

  void testNative() {
    
    
    nativeApi = Platform.isAndroid
        ? DynamicLibrary.open("libnative_ffi.so")
        : DynamicLibrary.process();

    FFI_Dart_CreatArray createArray =
        nativeApi.lookupFunction<Native_Dart_CreatArray, FFI_Dart_CreatArray>(
            "createArray");

    Pointer<DynamicArray> array = createArray(10);
    print("array len=${array.ref.len}");

    for (int i = 0; i < array.ref.len; i++) {
    
    
      array.ref.data[i] = i * 2;
    }

    for (int i = 0; i < array.ref.len; i++) {
    
    
      final int a = array.ref.data[i];
      print("i=$a");
    }
  }
}

illustrate

  • ArrayWhen defining in dart , the length of the array must be specified, and it must be a positive number. If it is, an error will be 0reported and the compilation will fail;
  • The problem lies in how to solve the problem that the data length is dynamically changing. The solution here is to dimension1set a large value for to bypass the check that bypasses theffi-patch.dart ._checkIndex()
  • But in this way, arrays cannot be created in Dart, and C needs to provide a function to create arrays—— createArray();

  Program running result:

I/flutter (25532): array len=10
I/flutter (25532): i=0
I/flutter (25532): i=2
I/flutter (25532): i=4
I/flutter (25532): i=6
I/flutter (25532): i=8
I/flutter (25532): i=10
I/flutter (25532): i=12
I/flutter (25532): i=14
I/flutter (25532): i=16
I/flutter (25532): i=18

  
 

5. Summary

  The mutual calls between arrays in Dart and C are introduced above. It needs to be explained: there is actually another way to create an array, which is to use mallocand calloc. In the next chapter, I will introduce FFI memory management, and also introduce how mallocDart calloccreates arrays through and, welcome to pay attention.

  
 

Guess you like

Origin blog.csdn.net/eieihihi/article/details/119599375