This document is a continuation of the previous one.
In This document, I introduce to how to use ponter and buffer at ffi and wasm.
How to use Pointer and Buffer
Create clang function
#include <stdio.h>
#include <stdlib.h>
// [Linux]
// find . -name "*.o" | xargs rm
// gcc -Wall -Werror -fpic -I. -c ky.c -o ky.o
// gcc -shared -o libky.so ky.o
// [Wasm]
// find . -name "*.o" | xargs rm
// find . -name "*.wasm" | xargs rm
// emcc ky.c -o ky.o
// emcc ky.o -o libky.js -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -s EXPORTED_FUNCTIONS="['_new_buffer','_init_buffer','_destroy_buffer']"
// cp libky.js ../web/libky.js
// cp libky.wasm ../web/libky.wasm
char* new_buffer(int size) {
char* ret = malloc(sizeof(char)*size);
return ret;
}
char* init_buffer(char* buffer, int size) {
for(int i=0;i<size;i++) {
buffer[i] = i;
}
return buffer;
}
void destroy_buffer(char* p) {
free(p);
}
Call from linux server at dart:ffi
import 'dart:ffi' as ffi;
import 'dart:typed_data' as typed;
// dart ./bin/main.dart
ffi.DynamicLibrary dylib = ffi.DynamicLibrary.open('/app/libc/libky.so');
// char* new_buffer(int size)
typedef NewBufferFunc = ffi.Pointer<ffi.Uint8> Function(ffi.Int32 size);
typedef NewBuffer = ffi.Pointer<ffi.Uint8> Function(int size);
NewBuffer _new_buffer = dylib
.lookup<ffi.NativeFunction<NewBufferFunc>>('new_buffer')
.asFunction<NewBuffer>();
ffi.Pointer<ffi.Uint8> newBuffer(int length) {
return _new_buffer(length);
}
// char* init_buffer(char*, int size)
typedef InitBufferFunc = ffi.Pointer<ffi.Uint8> Function(ffi.Pointer<ffi.Uint8> buffer, ffi.Int32 size);
typedef InitBuffer = ffi.Pointer<ffi.Uint8> Function(ffi.Pointer<ffi.Uint8> buffer, int size);
InitBuffer _init_buffer = dylib
.lookup<ffi.NativeFunction<InitBufferFunc>>('init_buffer')
.asFunction<InitBuffer>();
ffi.Pointer<ffi.Uint8> initBuffer(ffi.Pointer<ffi.Uint8> buffer, int length) {
return _init_buffer(buffer, length);
}
// void destroy_buffer(char* p)
typedef DestroyBufferFunc = ffi.Void Function(ffi.Pointer<ffi.Uint8> buffer);
typedef DestroyBuffer = void Function(ffi.Pointer<ffi.Uint8> buffer);
DestroyBuffer _destroy_buffer = dylib
.lookup<ffi.NativeFunction<DestroyBufferFunc>>('init_buffer')
.asFunction<DestroyBuffer>();
void destroyBuffer(ffi.Pointer<ffi.Uint8> buffer) {
_destroy_buffer(buffer);
}
void main(List<String> args) {
// pointer and buffer
var buffer = newBuffer(20);
// new pointer
for(var i=0;i<20;i++){
print(buffer.elementAt(i).value); // random value or 0
}
// pointer -> pointer
buffer = initBuffer(buffer, 20);
for(var i=0;i<20;i++){
print(buffer.elementAt(i).value); // 0, 1, 2, 3, 4, ....19
}
// pointer -> uint8slist // 0, 1, 2, 3, 4, ....19
typed.Uint8List bufferAsUint8List = buffer.asTypedList(20);
for(var i=0;i<bufferAsUint8List.length;i++){
print(bufferAsUint8List[i]);
}
// set value into buffer
bufferAsUint8List[0] = 110;
print(buffer.elementAt(0).value); // 110
}
Call from web browser at dart:js
import 'dart:js' as js;
import 'dart:typed_data' as typed;
// webdev serve --hostname=0.0.0.0
js.JsObject Module = js.context['Module'];
var HEAP8 = Module['HEAP8'];
js.JsFunction _new_buffer = Module.callMethod('cwrap',['new_buffer','number',['number']]);
int newBuffer(int length) {
return _new_buffer.apply([length]);
}
js.JsFunction _init_buffer = Module.callMethod('cwrap',['init_buffer','number',['number','number']]);
int initBuffer(int buffer, int length) {
return _init_buffer.apply([buffer, length]);
}
js.JsFunction _destroy_buffer = Module.callMethod('cwrap',['destroy_buffer','void',['number']]);
int destroyBuffer(int buffer) {
return _destroy_buffer.apply([buffer]);
}
js.JsFunction _to_uint8list= js.context['to_uint8list'];// from util.js
typed.Uint8List toUint8List(int buffer, int length) {
return _to_uint8list.apply([buffer, length]);
}
void main() {
// hello
printHello(); // Hello!!
// int
print('${sumInt(10, 100)}'); // 110
// double
print('${sumDouble(10.1, 100.2)}'); // 110.3
//
// new pointer
var buffer = newBuffer(20);
for(var i=0;i<20;i++){
print('${HEAP8[i+buffer]}'); // random value or 0
}
// pointer -> pointer
buffer = initBuffer(buffer, 20);
for(var i=0;i<20;i++){
print('${HEAP8[i+buffer]}'); // random value or 0
}
// pointer -> uint8slist // 0, 1, 2, 3, 4, ....19
typed.Uint8List bufferAsUint8List = toUint8List(buffer, 20);
for(var i=0;i<bufferAsUint8List.length;i++){
print(bufferAsUint8List[i]);
}
// set value into buffer
bufferAsUint8List[0] = 110;
print('${HEAP8[buffer]}'); // 110
print("${HEAP8.runtimeType}");//
typed.Uint8List bufferAsUint8List2 = (HEAP8 as typed.Int8List).buffer.asUint8List(buffer, 20);
for(var i=0;i<bufferAsUint8List2.length;i++){
print(bufferAsUint8List2[i]);
}
}
to_uint8list = function(index, len) {
var v = new Uint8Array(Module.HEAP8.buffer, index, len);
return v;
}
Explanation
Pointer
Clang's pointer is used as Pointer object in dart:ffi. Clang's pointer is used as number object in dart:js.
If you want to use the value of the pointer
buffer.elementAt(i).value
js.JsObject Module = js.context['Module'];
var HEAP8 = Module['HEAP8'];
typed.Uint8List bufferAsUint8List2 = (HEAP8 as typed.Int8List).buffer.asUint8List(buffer, 20);
bufferAsUint8List2[i]
But I couldn't find any documentation to back this up about dart:js's code
I recommend the following code to use js function
to_uint8list = function(index, len) {
var v = new Uint8Array(Module.HEAP8.buffer, index, len);
return v;
}
About Uint8List
You can handle the Buffer as Uint8List
In the case of dart:io, buffer.asTypedList(20)
.
In the case of daer:js, (HEAP8 as typed.Int8List).buffer.asUint8List(buffer, 20)
And, if you change Uint8List, the C language Buffer will also change.
Note!!
Clang's buffer is released by free function.
but, it is not recommended to access released buffer.
Next Time
About Clang's Object
PS
Here's the code for this one
https://github.com/kyorohiro/dart_clang_codeserver/tree/03_buffer_int_double
Top comments (0)