@@ -35,7 +35,7 @@ class _OBXFBEntityReader extends fb.TableReader<_OBXFBEntity> {
35
35
new _OBXFBEntity ._(bc, offset);
36
36
}
37
37
38
- class _IDArray {
38
+ class _IDArray { // wrapper for "struct OBX_id_array"
39
39
Pointer <Uint64 > _idsPtr, _structPtr;
40
40
41
41
_IDArray (List <int > ids) {
@@ -55,6 +55,80 @@ class _IDArray {
55
55
}
56
56
}
57
57
58
+ class _ByteBuffer {
59
+ Pointer <Uint8 > _ptr;
60
+ int _size;
61
+
62
+ _ByteBuffer (this ._ptr, this ._size);
63
+
64
+ _ByteBuffer .allocate (Uint8List dartData, [bool align = true ]) {
65
+ _ptr = Pointer <Uint8 >.allocate (count: align ? ((dartData.length + 3.0 ) ~ / 4.0 ) * 4 : dartData.length);
66
+ for (int i = 0 ; i < dartData.length; ++ i)
67
+ _ptr.elementAt (i).store (dartData[i]);
68
+ _size = dartData.length;
69
+ }
70
+
71
+ _ByteBuffer .fromOBXBytes (Pointer <Uint64 > obxPtr) { // extract fields from "struct OBX_bytes"
72
+ _ptr = Pointer <Uint8 >.fromAddress (obxPtr.load <int >());
73
+ _size = obxPtr.elementAt (1 ).load <int >();
74
+ }
75
+
76
+ get ptr => _ptr;
77
+ get voidPtr => Pointer <Void >.fromAddress (_ptr.address);
78
+ get address => _ptr.address;
79
+ get size => _size;
80
+
81
+ Uint8List get data {
82
+ var buffer = new Uint8List (size);
83
+ for (int i = 0 ; i < size; ++ i)
84
+ buffer[i] = _ptr.elementAt (i).load <int >();
85
+ return buffer;
86
+ }
87
+
88
+ free () => _ptr.free ();
89
+ }
90
+
91
+ class _SerializedByteBufferArray {
92
+ Pointer <Uint64 > _outerPtr, _innerPtr; // outerPtr points to the instance itself, innerPtr points to the respective OBX_bytes_array.bytes
93
+
94
+ _SerializedByteBufferArray (this ._outerPtr, this ._innerPtr);
95
+ get ptr => _outerPtr;
96
+
97
+ free () {
98
+ _innerPtr.free ();
99
+ _outerPtr.free ();
100
+ }
101
+ }
102
+
103
+ class _ByteBufferArray {
104
+ List <_ByteBuffer > _buffers;
105
+
106
+ _ByteBufferArray (this ._buffers);
107
+
108
+ _ByteBufferArray .fromOBXBytesArray (Pointer <Uint64 > bytesArray) {
109
+ _buffers = [];
110
+ Pointer <Uint64 > bufferPtrs = Pointer <Uint64 >.fromAddress (bytesArray.load <int >()); // bytesArray.bytes
111
+ int numBuffers = bytesArray.elementAt (1 ).load <int >(); // bytesArray.count
112
+ for (int i = 0 ; i < numBuffers; ++ i) // loop through instances of "struct OBX_bytes"
113
+ _buffers.add (_ByteBuffer .fromOBXBytes (bufferPtrs.elementAt (2 * i))); // 2 * i, because each instance of "struct OBX_bytes" has .data and .size
114
+ }
115
+
116
+ _SerializedByteBufferArray toOBXBytesArray () {
117
+ Pointer <Uint64 > bufferPtrs = Pointer <Uint64 >.allocate (count: _buffers.length * 2 );
118
+ for (int i = 0 ; i < _buffers.length; ++ i) {
119
+ bufferPtrs.elementAt (2 * i).store (_buffers[i].ptr.address);
120
+ bufferPtrs.elementAt (2 * i + 1 ).store (_buffers[i].size);
121
+ }
122
+
123
+ Pointer <Uint64 > outerPtr = Pointer <Uint64 >.allocate (count: 2 );
124
+ outerPtr.store (bufferPtrs.address);
125
+ outerPtr.elementAt (1 ).store (_buffers.length);
126
+ return _SerializedByteBufferArray (outerPtr, bufferPtrs);
127
+ }
128
+
129
+ get buffers => _buffers;
130
+ }
131
+
58
132
class Box <T > {
59
133
Store _store;
60
134
Pointer <Void > _objectboxBox;
@@ -69,7 +143,7 @@ class Box<T> {
69
143
checkObxPtr (_objectboxBox, "failed to create box" );
70
144
}
71
145
72
- _marshal (propVals) {
146
+ _ByteBuffer _marshal (propVals) {
73
147
var builder = new fb.Builder (initialSize: 1024 );
74
148
75
149
// write all strings
@@ -98,12 +172,14 @@ class Box<T> {
98
172
});
99
173
100
174
var endOffset = builder.endTable ();
101
- return builder.finish (endOffset);
175
+ return _ByteBuffer . allocate ( builder.finish (endOffset) );
102
176
}
103
-
104
- _unmarshal (buffer) {
177
+
178
+ T _unmarshal (_ByteBuffer buffer) {
179
+ if (buffer.size == 0 || buffer.address == 0 )
180
+ return null ;
105
181
Map <String , dynamic > propVals = {};
106
- var entity = new _OBXFBEntity (buffer);
182
+ var entity = new _OBXFBEntity (buffer.data );
107
183
108
184
_entityDefinition["properties" ].forEach ((p) {
109
185
var propReader;
@@ -124,48 +200,76 @@ class Box<T> {
124
200
return _entityBuilder (propVals);
125
201
}
126
202
127
- _unmarshalArray (Pointer <Uint64 > bytesArray) { // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h)
128
- List <T > ret = [];
129
- int numObjects = bytesArray.elementAt (1 ).load <int >(); // bytesArray.count
130
- Pointer <Uint64 > objectsPtrs = Pointer <Uint64 >.fromAddress (bytesArray.load <int >()); // bytesArray.bytes
131
- for (int i = 0 ; i < numObjects; ++ i) { // loop through instances of OBX_bytes
132
- Pointer <Uint8 > data = Pointer <Uint8 >.fromAddress (objectsPtrs.elementAt (2 * i).load <int >()); // bytesArray.bytes[i].data
133
- int size = objectsPtrs.elementAt (2 * i + 1 ).load <int >(); // bytesArray.bytes[i].size
134
- if (data.address == 0 || size == 0 ) {
135
- ret.add (null );
136
- continue ;
137
- }
138
- ret.add (_unmarshal (loadMemory (data, size)));
203
+ // expects pointer to OBX_bytes_array and manually resolves its contents (see objectbox.h)
204
+ _unmarshalArray (Pointer <Uint64 > bytesArray) {
205
+ return _ByteBufferArray .fromOBXBytesArray (bytesArray).buffers.map (_unmarshal).toList ();
206
+ }
207
+
208
+ _getOBXPutMode (PutMode mode) {
209
+ switch (mode) {
210
+ case PutMode .Put : return OBXPutMode .PUT ;
211
+ case PutMode .Insert : return OBXPutMode .INSERT ;
212
+ case PutMode .Update : return OBXPutMode .UPDATE ;
139
213
}
140
- return ret;
141
214
}
142
215
143
- put (T inst, {PutMode mode = PutMode .Put }) { // if the respective ID property is given as null or 0, a newly assigned ID is returned, otherwise the existing ID is returned
216
+ // if the respective ID property is given as null or 0, a newly assigned ID is returned, otherwise the existing ID is returned
217
+ int put (T inst, {PutMode mode = PutMode .Put }) {
144
218
var propVals = _entityReader (inst);
145
219
var idPropName = _entityDefinition["idPropertyName" ];
146
220
if (propVals[idPropName] == null || propVals[idPropName] == 0 ) {
147
221
final id = bindings.obx_box_id_for_put (_objectboxBox, 0 );
148
222
propVals[idPropName] = id;
149
223
}
150
- var buffer = _marshal (propVals);
224
+
225
+ // put object into box and free the buffer
226
+ _ByteBuffer buffer = _marshal (propVals);
227
+ checkObx (bindings.obx_box_put (_objectboxBox, propVals[idPropName], buffer.voidPtr, buffer.size, _getOBXPutMode (mode)));
228
+ buffer.free ();
229
+ return propVals[idPropName];
230
+ }
231
+
232
+ // only instances whose ID property ot null or 0 will be given a new, valid number for that. A list of the final IDs is returned
233
+ List <int > putMany (List <T > insts, {PutMode mode = PutMode .Put }) {
234
+ if (insts.length == 0 )
235
+ return [];
151
236
152
- // determine internal put mode from given enum
153
- var putMode;
154
- switch (mode) {
155
- case PutMode .Put : putMode = OBXPutMode .PUT ; break ;
156
- case PutMode .Insert : putMode = OBXPutMode .INSERT ; break ;
157
- case PutMode .Update : putMode = OBXPutMode .UPDATE ; break ;
237
+ // read all property values and find number of instances where ID is missing
238
+ var allPropVals = insts.map (_entityReader).toList ();
239
+ var idPropName = _entityDefinition["idPropertyName" ];
240
+ int numInstsMissingId = 0 ;
241
+ for (var instPropVals in allPropVals)
242
+ if (instPropVals[idPropName] == null || instPropVals[idPropName] == 0 )
243
+ ++ numInstsMissingId;
244
+
245
+ // generate new IDs for these instances and set them
246
+ Pointer <Uint64 > instIdsMemory;
247
+ if (numInstsMissingId != 0 ) {
248
+ instIdsMemory = Pointer <Uint64 >.allocate (count: numInstsMissingId);
249
+ checkObx (bindings.obx_box_ids_for_put (_objectboxBox, numInstsMissingId, instIdsMemory));
250
+ int newIdIndex = 0 ;
251
+ for (var instPropVals in allPropVals)
252
+ if (instPropVals[idPropName] == null || instPropVals[idPropName] == 0 )
253
+ instPropVals[idPropName] = instIdsMemory.elementAt (newIdIndex++ ).load <int >();
254
+
158
255
}
159
256
160
- // transform flatbuffers byte array into memory area for C, with a length of a multiple of four
161
- Pointer <Uint8 > bufferPtr = Pointer <Uint8 >.allocate (count: ((buffer.length + 3.0 ) / 4.0 ).toInt () * 4 );
162
- for (int i = 0 ; i < buffer.length; ++ i)
163
- bufferPtr.elementAt (i).store (buffer[i] as int );
257
+ // because obx_box_put_many also needs a list of all IDs of the elements to be put into the box, generate this list now (only needed if not all IDs have been generated)
258
+ if (numInstsMissingId != insts.length) {
259
+ if (instIdsMemory != null )
260
+ instIdsMemory.free ();
261
+ instIdsMemory = Pointer <Uint64 >.allocate (count: insts.length);
262
+ for (int i = 0 ; i < allPropVals.length; ++ i)
263
+ instIdsMemory.elementAt (i).store (allPropVals[i][idPropName]);
264
+ }
164
265
165
- // put object into box and free the buffer
166
- checkObx (bindings.obx_box_put (_objectboxBox, propVals[idPropName], Pointer <Void >.fromAddress (bufferPtr.address), buffer.length, putMode));
167
- bufferPtr.free ();
168
- return propVals[idPropName];
266
+ // marshal all objects to be put into the box
267
+ var putObjects = _ByteBufferArray (allPropVals.map (_marshal).toList ()).toOBXBytesArray ();
268
+
269
+ checkObx (bindings.obx_box_put_many (_objectboxBox, putObjects.ptr, instIdsMemory, _getOBXPutMode (mode)));
270
+ putObjects.free ();
271
+ instIdsMemory.free ();
272
+ return allPropVals.map ((p) => p[idPropName] as int ).toList ();
169
273
}
170
274
171
275
_inReadTransaction (fn) {
@@ -186,7 +290,7 @@ class Box<T> {
186
290
var size = sizePtr.load <int >();
187
291
188
292
// transform bytes from memory to Dart byte list
189
- var buffer = loadMemory (data, size);
293
+ var buffer = _ByteBuffer (data, size);
190
294
dataPtr.free ();
191
295
sizePtr.free ();
192
296
0 commit comments