From 04ff988195aea1c2115aa64b095f5730f5c285fe Mon Sep 17 00:00:00 2001 From: Jasm Sison <jasm.sison@gmail.com> Date: Wed, 4 Sep 2019 17:22:25 +0200 Subject: [PATCH 1/3] added utf8 support --- lib/src/box.dart | 10 +++++----- lib/src/common.dart | 2 +- lib/src/ffi/cstring.dart | 32 ++++++++++++++++++++++---------- pubspec.yaml | 3 ++- test/test.dart | 12 +++++++++--- 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/lib/src/box.dart b/lib/src/box.dart index 32e9776a1..8f2e6164e 100644 --- a/lib/src/box.dart +++ b/lib/src/box.dart @@ -125,25 +125,25 @@ class Box<T> { } // transform flatbuffers byte array into memory area for C, with a length of a multiple of four - Pointer<Uint8> bufferPtr = allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4); + Pointer<Uint8> bufferPtr = Pointer<Uint8>.allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4); for(int i = 0; i < buffer.length; ++i) bufferPtr.elementAt(i).store(buffer[i] as int); // put object into box and free the buffer - checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], fromAddress(bufferPtr.address), buffer.length, putMode)); + checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], Pointer<Void>.fromAddress(bufferPtr.address), buffer.length, putMode)); bufferPtr.free(); } getById(int id) { - Pointer<Pointer<Void>> dataPtr = allocate(); - Pointer<Int32> sizePtr = allocate(); + Pointer<Pointer<Void>> dataPtr = Pointer<Pointer<Void>>.allocate(); + Pointer<Int32> sizePtr = Pointer<Int32>.allocate(); // get element with specified id from database Pointer<Void> txn = bindings.obx_txn_read(_store.ptr); check(txn != null && txn.address != 0); checkObx(bindings.obx_box_get(_objectboxBox, id, dataPtr, sizePtr)); checkObx(bindings.obx_txn_close(txn)); - Pointer<Uint8> data = fromAddress(dataPtr.load<Pointer<Void>>().address); + Pointer<Uint8> data = Pointer<Uint8>.fromAddress(dataPtr.load<Pointer<Void>>().address); var size = sizePtr.load<int>(); // transform bytes from memory to Dart byte list diff --git a/lib/src/common.dart b/lib/src/common.dart index 36d2217a0..3dbe50520 100644 --- a/lib/src/common.dart +++ b/lib/src/common.dart @@ -5,7 +5,7 @@ import "ffi/cstring.dart"; class Common { static List<int> version() { - Pointer<Int32> majorPtr = allocate(), minorPtr = allocate(), patchPtr = allocate(); + Pointer<Int32> majorPtr = Pointer<Int32>.allocate(), minorPtr = Pointer<Int32>.allocate(), patchPtr = Pointer<Int32>.allocate(); bindings.obx_version(majorPtr, minorPtr, patchPtr); var ret = [majorPtr.load<int>(), minorPtr.load<int>(), patchPtr.load<int>()]; majorPtr.free(); diff --git a/lib/src/ffi/cstring.dart b/lib/src/ffi/cstring.dart index 6f04cdc84..2a637845f 100644 --- a/lib/src/ffi/cstring.dart +++ b/lib/src/ffi/cstring.dart @@ -1,24 +1,36 @@ import "dart:ffi"; +import "dart:typed_data"; +import "package:utf/src/utf8.dart"; +import "package:utf/src/utf16.dart"; +// TODO check if revamp structs are relevant (https://github.com/dart-lang/sdk/issues/37229) // wrapper for a null-terminated array of characters in memory ("c-style string") class CString { Pointer<Uint8> _ptr; - CString(String dartStr) { // if this constructor is used, ".free" needs to be called on this instance - _ptr = allocate(count: dartStr.length + 1); - for(int i = 0; i < dartStr.length; ++i) - _ptr.elementAt(i).store(dartStr.codeUnitAt(i)); - _ptr.elementAt(dartStr.length).store(0); + // if this constructor is used, ".free" needs to be called on this instance + CString(String dartStr) { + List<int> ints = encodeUtf8(dartStr); + var utf8Str = Uint8List.fromList(ints); + _ptr = Pointer<Uint8>.allocate(count: utf8Str.length + 1); + for(int i = 0; i < utf8Str.length; ++i) + _ptr.elementAt(i).store(utf8Str.elementAt(i)); + _ptr.elementAt(utf8Str.length).store(0); } CString.fromPtr(this._ptr); String get val { - String ret = "", c; - int i = 0; - while((c = String.fromCharCode(_ptr.elementAt(i++).load<int>())).codeUnitAt(0) != 0) // TODO: unicode support - ret += c; - return ret; + List<int> utf8CodePoints = new List<int>(); + + int element; + + for (int i=0; element != 0; i++) { + element = _ptr.elementAt(i).load<int>(); + utf8CodePoints.add(element); + } + + return decodeUtf8(utf8CodePoints); } String toString() => val; diff --git a/pubspec.yaml b/pubspec.yaml index e53166272..ff901d14e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,9 @@ name: objectbox -version: 0.0.1 +version: 0.0.2 description: >- ObjectBox binding for Dart. environment: sdk: '>=2.2.2 <3.0.0' dependencies: flat_buffers: ^1.11.0 + utf: ^0.9.0 diff --git a/test/test.dart b/test/test.dart index 70068f746..6507bf1a2 100644 --- a/test/test.dart +++ b/test/test.dart @@ -1,4 +1,5 @@ import "../lib/objectbox.dart"; +import "package:utf/src/utf8.dart"; @Entity(id: 1, uid: 1) class Note { @@ -17,11 +18,16 @@ class Note { main() { var store = Store([Note]); var box = Box<Note>(store); + insertNote(box, decodeUtf8([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])); + insertNote(box, decodeUtf8([228, 189, 160, 229, 165, 189, 228, 184, 150, 231, 149, 140, 33])); + insertNote(box, decodeUtf8([65, 104, 111, 106, 32, 115, 118, 196, 155, 116, 101, 33])); + store.close(); +} - var note = Note.construct("Hello"); +insertNote(Box<Note> box, String str) { + var note = Note.construct(str); box.put(note); + print("new note got id ${note.id}"); print("refetched note: ${box.getById(note.id)}"); - - store.close(); } From 9026bc466f5a06e058d4c62ff8d17dc64bb52b4f Mon Sep 17 00:00:00 2001 From: Jasm Sison <jasm.sison@gmail.com> Date: Thu, 5 Sep 2019 15:31:02 +0200 Subject: [PATCH 2/3] I tried explicitly casting with `x as Uint8` and `(Uint) x` this triggered some weird compiler errors. Then I tried this without explicitly casting, evidently there's some type polymorphism going on, or some casting by the compiler. In any case, the Uint8List has been removed. --- lib/src/ffi/cstring.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/ffi/cstring.dart b/lib/src/ffi/cstring.dart index 2a637845f..898f26e4b 100644 --- a/lib/src/ffi/cstring.dart +++ b/lib/src/ffi/cstring.dart @@ -10,12 +10,12 @@ class CString { // if this constructor is used, ".free" needs to be called on this instance CString(String dartStr) { - List<int> ints = encodeUtf8(dartStr); - var utf8Str = Uint8List.fromList(ints); - _ptr = Pointer<Uint8>.allocate(count: utf8Str.length + 1); - for(int i = 0; i < utf8Str.length; ++i) - _ptr.elementAt(i).store(utf8Str.elementAt(i)); - _ptr.elementAt(utf8Str.length).store(0); + final ints = encodeUtf8(dartStr); + _ptr = Pointer<Uint8>.allocate(count: ints.length + 1); + for(int i = 0; i < ints.length; ++i) { + _ptr.elementAt(i).store(ints.elementAt(i)); + } + _ptr.elementAt(ints.length).store(0); } CString.fromPtr(this._ptr); From c77e1b8414c68e7011744ec7ad0059ed79b8dcb0 Mon Sep 17 00:00:00 2001 From: Jasm Sison <jasm.sison@gmail.com> Date: Thu, 5 Sep 2019 15:52:37 +0200 Subject: [PATCH 3/3] Maintain support for 2.4's ffi TODO Revert and test this commit when 2.5 is released as stable --- lib/src/box.dart | 10 +++++----- lib/src/common.dart | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/box.dart b/lib/src/box.dart index 8f2e6164e..32e9776a1 100644 --- a/lib/src/box.dart +++ b/lib/src/box.dart @@ -125,25 +125,25 @@ class Box<T> { } // transform flatbuffers byte array into memory area for C, with a length of a multiple of four - Pointer<Uint8> bufferPtr = Pointer<Uint8>.allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4); + Pointer<Uint8> bufferPtr = allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4); for(int i = 0; i < buffer.length; ++i) bufferPtr.elementAt(i).store(buffer[i] as int); // put object into box and free the buffer - checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], Pointer<Void>.fromAddress(bufferPtr.address), buffer.length, putMode)); + checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], fromAddress(bufferPtr.address), buffer.length, putMode)); bufferPtr.free(); } getById(int id) { - Pointer<Pointer<Void>> dataPtr = Pointer<Pointer<Void>>.allocate(); - Pointer<Int32> sizePtr = Pointer<Int32>.allocate(); + Pointer<Pointer<Void>> dataPtr = allocate(); + Pointer<Int32> sizePtr = allocate(); // get element with specified id from database Pointer<Void> txn = bindings.obx_txn_read(_store.ptr); check(txn != null && txn.address != 0); checkObx(bindings.obx_box_get(_objectboxBox, id, dataPtr, sizePtr)); checkObx(bindings.obx_txn_close(txn)); - Pointer<Uint8> data = Pointer<Uint8>.fromAddress(dataPtr.load<Pointer<Void>>().address); + Pointer<Uint8> data = fromAddress(dataPtr.load<Pointer<Void>>().address); var size = sizePtr.load<int>(); // transform bytes from memory to Dart byte list diff --git a/lib/src/common.dart b/lib/src/common.dart index 3dbe50520..36d2217a0 100644 --- a/lib/src/common.dart +++ b/lib/src/common.dart @@ -5,7 +5,7 @@ import "ffi/cstring.dart"; class Common { static List<int> version() { - Pointer<Int32> majorPtr = Pointer<Int32>.allocate(), minorPtr = Pointer<Int32>.allocate(), patchPtr = Pointer<Int32>.allocate(); + Pointer<Int32> majorPtr = allocate(), minorPtr = allocate(), patchPtr = allocate(); bindings.obx_version(majorPtr, minorPtr, patchPtr); var ret = [majorPtr.load<int>(), minorPtr.load<int>(), patchPtr.load<int>()]; majorPtr.free();