Skip to content

Commit 02c656a

Browse files
authored
Merge pull request objectbox#1 from vaind/dev-query
id-array FFI struct & TestEnv
2 parents 13e8c0e + b1fae6a commit 02c656a

File tree

10 files changed

+127
-124
lines changed

10 files changed

+127
-124
lines changed

lib/src/bindings/bindings.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import "dart:ffi";
22
import "dart:io" show Platform;
33

44
import "signatures.dart";
5+
import "structs.dart";
56

67
// bundles all C functions to be exposed to Dart
78
class _ObjectBoxBindings {
@@ -11,10 +12,11 @@ class _ObjectBoxBindings {
1112
void Function(Pointer<Int32> major, Pointer<Int32> minor, Pointer<Int32> patch) obx_version;
1213
Pointer<Uint8> Function() obx_version_string;
1314
void Function(Pointer<Uint64> structPtr)
14-
obx_bytes_array_free, obx_id_array_free, obx_string_array_free,
15+
obx_bytes_array_free, obx_string_array_free,
1516
obx_int64_array_free, obx_int32_array_free,
1617
obx_int16_array_free, obx_int8_array_free,
1718
obx_double_array_free, obx_float_array_free;
19+
obx_free_t<OBX_id_array> obx_id_array_free;
1820

1921
// error info
2022
int Function() obx_last_error_code;
@@ -55,7 +57,7 @@ class _ObjectBoxBindings {
5557
int Function(Pointer<Void> box, int id, Pointer<Int8> out_contains) obx_box_contains;
5658
int Function(Pointer<Void> box, Pointer<Uint64> ids, Pointer<Int8> out_contains) obx_box_contains_many;
5759
int Function(Pointer<Void> box, int id, Pointer<Pointer<Void>> data, Pointer<Int32> size) obx_box_get;
58-
Pointer<Uint64> Function(Pointer<Void> box, Pointer<Uint64> ids) obx_box_get_many;
60+
Pointer<Uint64> Function(Pointer<Void> box, Pointer<OBX_id_array> ids) obx_box_get_many;
5961
Pointer<Uint64> Function(Pointer<Void> box) obx_box_get_all;
6062
int Function(Pointer<Void> box, int id_or_zero) obx_box_id_for_put;
6163
int Function(Pointer<Void> box, int count, Pointer<Uint64> out_first_id) obx_box_ids_for_put;
@@ -106,7 +108,7 @@ class _ObjectBoxBindings {
106108
obx_query_t obx_query_create;
107109
obx_query_close_dart_t obx_query_close;
108110
obx_query_find_t<int> obx_query_find;
109-
obx_query_find_t<int> obx_query_find_ids;
111+
obx_query_find_ids_t<int> obx_query_find_ids;
110112

111113
obx_query_count_dart_t obx_query_count, obx_query_remove;
112114

@@ -135,7 +137,7 @@ class _ObjectBoxBindings {
135137
obx_version = _fn<obx_version_native_t>("obx_version").asFunction();
136138
obx_version_string = _fn<obx_version_string_native_t>("obx_version_string").asFunction();
137139
obx_bytes_array_free = _fn<obx_free_struct_native_t>("obx_bytes_array_free").asFunction();
138-
obx_id_array_free = _fn<obx_free_struct_native_t>("obx_id_array_free").asFunction();
140+
obx_id_array_free = _fn<obx_free_t<OBX_id_array>>("obx_id_array_free").asFunction();
139141
obx_string_array_free = _fn<obx_free_struct_native_t>("obx_string_array_free").asFunction();
140142
obx_int64_array_free = _fn<obx_free_struct_native_t>("obx_int64_array_free").asFunction();
141143
obx_int32_array_free = _fn<obx_free_struct_native_t>("obx_int32_array_free").asFunction();
@@ -244,7 +246,7 @@ class _ObjectBoxBindings {
244246
obx_query_create = _fn<obx_query_t>("obx_query").asFunction();
245247
obx_query_close = _fn<obx_query_close_native_t>("obx_query_close").asFunction();
246248

247-
obx_query_find_ids = _fn<obx_query_find_t<Uint64>>("obx_query_find_ids").asFunction();
249+
obx_query_find_ids = _fn<obx_query_find_ids_t<Uint64>>("obx_query_find_ids").asFunction();
248250
obx_query_find = _fn<obx_query_find_t<Uint64>>("obx_query_find").asFunction();
249251

250252
obx_query_count = _fn<obx_query_count_native_t>("obx_query_count").asFunction();

lib/src/bindings/helpers.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ checkObx(errorCode) {
99
if (errorCode != OBXError.OBX_SUCCESS) throw ObjectBoxException(lastObxErrorString(errorCode));
1010
}
1111

12-
checkObxPtr(Pointer ptr, String msg, [bool hasLastError = false]) {
12+
Pointer<T> checkObxPtr<T extends NativeType>(Pointer<T> ptr, String msg, [bool hasLastError = false]) {
1313
if (ptr == null || ptr.address == 0) throw ObjectBoxException("$msg: ${hasLastError ? lastObxErrorString() : ""}");
1414
return ptr;
1515
}

lib/src/bindings/signatures.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import "dart:ffi";
2+
import 'structs.dart';
23

34
// common functions
45
typedef obx_version_native_t = Void Function(Pointer<Int32> major, Pointer<Int32> minor, Pointer<Int32> patch);
56
typedef obx_version_string_native_t = Pointer<Uint8> Function();
7+
typedef obx_free_t<T extends NativeType> = Void Function(Pointer<T> ptr);
68
typedef obx_free_struct_native_t = Void Function(Pointer<Uint64> structPtr);
79

810
// error info
@@ -47,7 +49,7 @@ typedef obx_box_contains_many_native_t = Int32 Function(
4749
Pointer<Void> box, Pointer<Uint64> ids, Pointer<Int8> out_contains);
4850
typedef obx_box_get_native_t = Int32 Function(
4951
Pointer<Void> box, Uint64 id, Pointer<Pointer<Void>> data, Pointer<Int32> size);
50-
typedef obx_box_get_many_native_t = Pointer<Uint64> Function(Pointer<Void> box, Pointer<Uint64> ids);
52+
typedef obx_box_get_many_native_t = Pointer<Uint64> Function(Pointer<Void> box, Pointer<OBX_id_array> ids);
5153
typedef obx_box_get_all_native_t = Pointer<Uint64> Function(Pointer<Void> box);
5254
typedef obx_box_id_for_put_native_t = Uint64 Function(Pointer<Void> box, Uint64 id_or_zero);
5355
typedef obx_box_ids_for_put_native_t = Int32 Function(Pointer<Void> box, Uint64 count, Pointer<Uint64> out_first_id);
@@ -114,6 +116,7 @@ typedef obx_query_close_native_t = Int32 Function(Pointer<Void> query);
114116
typedef obx_query_close_dart_t = int Function(Pointer<Void> query);
115117

116118
typedef obx_query_find_t<T> = Pointer<Uint64> Function(Pointer<Void> query, T offset, T limit);
119+
typedef obx_query_find_ids_t<T> = Pointer<OBX_id_array> Function(Pointer<Void> query, T offset, T limit);
117120

118121
typedef obx_query_count_native_t = Int32 Function(Pointer<Void> query, Pointer<Uint64> count);
119122
typedef obx_query_count_dart_t = int Function(Pointer<Void> query, Pointer<Uint64> count);

lib/src/bindings/structs.dart

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,44 @@ import 'dart:ffi';
22
import 'dart:convert';
33
import "dart:typed_data" show Uint8List, Uint64List;
44

5-
// TODO reimplement as ffi.Struct
6-
class IDArray {
7-
// wrapper for "struct OBX_id_array"
8-
Pointer<Uint64> _idsPtr, _structPtr;
9-
10-
IDArray(List<int> ids) {
11-
_idsPtr = Pointer<Uint64>.allocate(count: ids.length);
12-
for (int i = 0; i < ids.length; ++i) _idsPtr.elementAt(i).store(ids[i]);
13-
_structPtr = Pointer<Uint64>.allocate(count: 2);
14-
_structPtr.store(_idsPtr.address);
15-
_structPtr.elementAt(1).store(ids.length);
16-
}
17-
18-
List<int> _ids; // obx_id === uint64_t
19-
20-
IDArray.fromAddress(int address) {
21-
_structPtr = Pointer<Uint64>.fromAddress(address); // bootstrap
22-
_idsPtr = Pointer<Uint64>.fromAddress(_structPtr.load()); // 1st memory location contains vector obx_id*
23-
int count = _structPtr.elementAt(1).load<int>(); // 2nd mem loc contains the scalar count
24-
final idsPtrBuffer = _idsPtr.asExternalTypedData(count: count).buffer;
25-
// Is the ExternalTypedData just referring to the base type of Uint64List?
26-
_ids = Uint64List.view(idsPtrBuffer).toList();
27-
}
28-
29-
get ids => _ids;
30-
31-
get ptr => _structPtr;
32-
33-
free() {
34-
_idsPtr.free();
35-
_structPtr.free();
5+
// Note: IntPtr seems to be the the correct representation for size_t: "Represents a native pointer-sized integer in C."
6+
7+
class OBX_id_array extends Struct<OBX_id_array> {
8+
/*
9+
typedef struct OBX_id_array {
10+
obx_id* ids;
11+
size_t count;
12+
};
13+
*/
14+
15+
Pointer<Uint64> _itemsPtr;
16+
17+
@IntPtr() // size_t
18+
int length;
19+
20+
/// Get a copy of the list
21+
List<int> items() => Uint64List.view(_itemsPtr.asExternalTypedData(count: length).buffer).toList();
22+
23+
/// Execute the given function, managing the resources consistently
24+
static R executeWith<R>(List<int> items, R Function(Pointer<OBX_id_array>) fn) {
25+
// allocate a temporary structure
26+
final ptr = Pointer<OBX_id_array>.allocate();
27+
28+
// fill it with data
29+
OBX_id_array array = ptr.load();
30+
array.length = items.length;
31+
array._itemsPtr = Pointer<Uint64>.allocate(count: array.length);
32+
for (int i = 0; i < items.length; ++i) {
33+
array._itemsPtr.elementAt(i).store(items[i]);
34+
}
35+
36+
// call the function with the structure and free afterwards
37+
try {
38+
return fn(ptr);
39+
} finally {
40+
array._itemsPtr.free();
41+
ptr.free();
42+
}
3643
}
3744
}
3845

@@ -55,8 +62,11 @@ class ByteBuffer {
5562
}
5663

5764
get ptr => _ptr;
65+
5866
get voidPtr => Pointer<Void>.fromAddress(_ptr.address);
67+
5968
get address => _ptr.address;
69+
6070
get size => _size;
6171

6272
Uint8List get data {
@@ -73,6 +83,7 @@ class _SerializedByteBufferArray {
7383
_innerPtr; // outerPtr points to the instance itself, innerPtr points to the respective OBX_bytes_array.bytes
7484

7585
_SerializedByteBufferArray(this._outerPtr, this._innerPtr);
86+
7687
get ptr => _outerPtr;
7788

7889
free() {
@@ -109,4 +120,4 @@ class ByteBufferArray {
109120
}
110121

111122
get buffers => _buffers;
112-
}
123+
}

lib/src/box.dart

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,9 @@ class Box<T> {
140140
List<T> getMany(List<int> ids) {
141141
if (ids.length == 0) return [];
142142

143-
// write ids in buffer for FFI call
144-
var idArray = new IDArray(ids);
145-
146-
try {
147-
return _getMany(() =>
148-
checkObxPtr(bindings.obx_box_get_many(_cBox, idArray.ptr), "failed to get many objects from box", true));
149-
} finally {
150-
idArray.free();
151-
}
143+
return OBX_id_array.executeWith(ids, (ptr) => _getMany(() =>
144+
checkObxPtr(bindings.obx_box_get_many(_cBox, ptr), "failed to get many objects from box", true))
145+
);
152146
}
153147

154148
List<T> getAll() {

lib/src/query/query.dart

Lines changed: 36 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -374,60 +374,42 @@ class IntegerCondition extends Condition<int> {
374374
}
375375

376376
int apply(Pointer<Void> cBuilder, int propertyId) {
377-
switch (_type) {
378-
integer:
379-
case OBXPropertyType.Int: // 4 bytes
380-
switch (_op) {
381-
case ConditionOp.eq:
382-
return _op1(
383-
cBuilder, propertyId, bindings.obx_qb_int_equal);
384-
case ConditionOp.not_eq:
385-
return _op1(
386-
cBuilder, propertyId, bindings.obx_qb_int_not_equal);
387-
case ConditionOp.gt:
388-
return _op1(
389-
cBuilder, propertyId, bindings.obx_qb_int_greater);
390-
case ConditionOp.lt:
391-
return _op1(
392-
cBuilder, propertyId, bindings.obx_qb_int_less);
393-
case ConditionOp.tween:
394-
return bindings.obx_qb_int_between(
395-
cBuilder, propertyId, _value, _value2);
396-
}
397-
break;
398-
case OBXPropertyType.Long:
399-
continue integer;
400-
case OBXPropertyType.Byte:
401-
continue integer;
402-
case OBXPropertyType.Short:
403-
continue integer;
404-
case OBXPropertyType.Char:
405-
continue integer;
406-
case OBXPropertyType.Bool:
407-
continue integer;
408-
}
409-
410377
switch (_op) {
378+
case ConditionOp.eq:
379+
return _op1(
380+
cBuilder, propertyId, bindings.obx_qb_int_equal);
381+
case ConditionOp.not_eq:
382+
return _op1(
383+
cBuilder, propertyId, bindings.obx_qb_int_not_equal);
384+
case ConditionOp.gt:
385+
return _op1(
386+
cBuilder, propertyId, bindings.obx_qb_int_greater);
387+
case ConditionOp.lt:
388+
return _op1(
389+
cBuilder, propertyId, bindings.obx_qb_int_less);
390+
case ConditionOp.tween:
391+
return bindings.obx_qb_int_between(
392+
cBuilder, propertyId, _value, _value2);
411393
case ConditionOp.inside:
412-
{
413-
switch (_type) {
414-
case OBXPropertyType.Int:
415-
return _opList32(cBuilder, propertyId, bindings.obx_qb_int32_in);
416-
case OBXPropertyType.Long:
417-
return _opList64(cBuilder, propertyId, bindings.obx_qb_int64_in);
418-
}
419-
break;
394+
switch (_type) {
395+
case OBXPropertyType.Int:
396+
return _opList32(cBuilder, propertyId, bindings.obx_qb_int32_in);
397+
case OBXPropertyType.Long:
398+
return _opList64(cBuilder, propertyId, bindings.obx_qb_int64_in);
399+
default:
400+
throw Exception("Unsupported type for IN: ${_type}");
420401
}
402+
break;
421403
case ConditionOp.not_in:
422-
{
423-
switch (_type) {
424-
case OBXPropertyType.Int:
425-
return _opList32(cBuilder, propertyId, bindings.obx_qb_int32_not_in);
426-
case OBXPropertyType.Long:
427-
return _opList64(cBuilder, propertyId, bindings.obx_qb_int64_not_in);
428-
}
429-
break;
404+
switch (_type) {
405+
case OBXPropertyType.Int:
406+
return _opList32(cBuilder, propertyId, bindings.obx_qb_int32_not_in);
407+
case OBXPropertyType.Long:
408+
return _opList64(cBuilder, propertyId, bindings.obx_qb_int64_not_in);
409+
default:
410+
throw Exception("Unsupported type for IN: ${_type}");
430411
}
412+
break;
431413
default:
432414
throw Exception("Unsupported operation ${_op.toString()}");
433415
}
@@ -535,16 +517,16 @@ class Query<T> {
535517

536518
T findFirst() {
537519
final list = find(offset:0, limit:1);
538-
return ((list == null || list.length == 0) ? null : list[0]) as T;
520+
return (list.length == 0 ? null : list[0]) as T;
539521
}
540522

541523
List<int> findIds({int offset=0, int limit=0}) {
542-
final structPtr = checkObxPtr(bindings.obx_query_find_ids(_cQuery, offset, limit), "find ids");
524+
final idArrayPtr = checkObxPtr(bindings.obx_query_find_ids(_cQuery, offset, limit), "find ids");
543525
try {
544-
final idArray = IDArray.fromAddress(structPtr.address);
545-
return idArray.ids.length == 0 ? null : idArray.ids;
526+
OBX_id_array idArray = idArrayPtr.load();
527+
return idArray.length == 0 ? List<int>() : idArray.items();
546528
}finally {
547-
bindings.obx_id_array_free(structPtr);
529+
bindings.obx_id_array_free(idArrayPtr);
548530
}
549531
}
550532

test/box_test.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import "package:test/test.dart";
22
import "package:objectbox/objectbox.dart";
33
import "entity.dart";
4-
import "util.dart";
4+
import 'test_env.dart';
55

66
void main() {
7-
Store store;
7+
TestEnv env;
88
Box box;
99

1010
group("box", () {
1111
setUp(() {
12-
store = Store([TestEntity_OBXDefs]);
13-
box = Box<TestEntity>(store);
12+
env = TestEnv("box");
13+
box = env.box;
1414
});
1515

1616
test(".put() returns a valid id", () {
@@ -82,5 +82,5 @@ void main() {
8282
});
8383
});
8484

85-
tearDown(tearDownStorage(store, box));
85+
tearDown(() {env.close();});
8686
}

test/query_test.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import "package:test/test.dart";
22
import "package:objectbox/objectbox.dart";
33
import "entity.dart";
4-
import "util.dart";
4+
import 'test_env.dart';
55

66
void main() {
7-
Store store;
7+
TestEnv env;
88
Box box;
99

1010
group("query", () {
1111
setUp(() {
12-
store = Store([TestEntity_OBXDefs]);
13-
box = Box<TestEntity>(store);
12+
env = TestEnv("query");
13+
box = env.box;
1414
});
1515

1616
test(".null and .notNull", () {
@@ -164,7 +164,7 @@ void main() {
164164

165165
expect(result0.length, 7); // TODO off by one bug?
166166
expect(result2.length, 1);
167-
expect(result3, null);
167+
expect(result3.length, 0);
168168

169169
q0.close();
170170
q2.close();
@@ -321,5 +321,5 @@ void main() {
321321
});
322322
});
323323

324-
tearDown(tearDownStorage(store, box));
324+
tearDown(() {env.close();});
325325
}

0 commit comments

Comments
 (0)