Skip to content

Commit 880ca30

Browse files
[jnigen] Add getRange method to JArray<JPrimitive> and change the dart equivalent type for JArray<jchar> to int (#1095)
* Close #990 * Convert the return type of `operator []` of `JArray<jchar>` to `int`, to be more consistent with the `getRange` return type. Similarly `operator []=` gets an `int` now * Remove some unused functions in `dartjni.c` * Use `.asTypedList(len).setRange` in `setRange` to be more efficient * Close #1097 – Improve the performance of`JArray`'s `operator []=`
1 parent d7d9229 commit 880ca30

File tree

7 files changed

+420
-134
lines changed

7 files changed

+420
-134
lines changed

pkgs/jni/CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
## 0.9.0-wip
22

3-
- No changes yet.
3+
- **Breaking Change**
4+
([#1004](https://github.com/dart-lang/native/issues/1004)): Changed the return
5+
type `operator []` of `JArray<jchar>` to `int` instead of `String`. Similarly,
6+
change the argument type of `operator []=` to accept `int`.
7+
- Added `getRange` method to `JArray` of primitive types that returns a
8+
`TypedData` list depending on the kind of the array.
9+
- Improved the performance of `JArray`'s `setRange` and `operator []=`.
410

511
## 0.8.0
612

pkgs/jni/lib/src/jarray.dart

Lines changed: 146 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// ignore_for_file: unnecessary_cast, overridden_fields
66

77
import 'dart:ffi';
8+
import 'dart:typed_data';
89

910
import 'package:collection/collection.dart';
1011
import 'package:ffi/ffi.dart';
@@ -131,39 +132,57 @@ class JArray<E> extends JObject {
131132

132133
extension NativeArray<E extends JPrimitive> on JArray<E> {
133134
void _allocate<T extends NativeType>(
134-
int size,
135+
int byteCount,
135136
void Function(Pointer<T> ptr) use,
136137
) {
137138
using((arena) {
138-
final ptr = arena.allocate<T>(size);
139+
final ptr = arena.allocate<T>(byteCount);
139140
use(ptr);
140141
}, malloc);
141142
}
142143
}
143144

145+
extension on Allocator {
146+
Pointer<NativeFinalizerFunction>? get _nativeFree {
147+
return switch (this) {
148+
malloc => malloc.nativeFree,
149+
calloc => calloc.nativeFree,
150+
_ => null,
151+
};
152+
}
153+
}
154+
144155
extension BoolArray on JArray<jboolean> {
145156
bool operator [](int index) {
146157
return _elementAt(index, JniCallType.booleanType).boolean;
147158
}
148159

149160
void operator []=(int index, bool value) {
150161
RangeError.checkValidIndex(index, this);
151-
_allocate<JBooleanMarker>(sizeOf<JBooleanMarker>(), (ptr) {
152-
ptr.value = value ? 1 : 0;
153-
Jni.env.SetBooleanArrayRegion(reference.pointer, index, 1, ptr);
154-
});
162+
Jni.accessors
163+
.setBooleanArrayElement(reference.pointer, index, value ? 1 : 0);
164+
}
165+
166+
Uint8List getRange(int start, int end, {Allocator allocator = malloc}) {
167+
RangeError.checkValidRange(start, end, length);
168+
final rangeLength = end - start;
169+
final buffer = allocator
170+
.allocate<JBooleanMarker>(sizeOf<JBooleanMarker>() * rangeLength);
171+
Jni.env
172+
.GetBooleanArrayRegion(reference.pointer, start, rangeLength, buffer);
173+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
155174
}
156175

157176
void setRange(int start, int end, Iterable<bool> iterable,
158177
[int skipCount = 0]) {
159178
RangeError.checkValidRange(start, end, length);
160-
final size = end - start;
161-
final it = iterable.skip(skipCount).take(size);
162-
_allocate<JBooleanMarker>(sizeOf<JBooleanMarker>() * size, (ptr) {
179+
final rangeLength = end - start;
180+
final it = iterable.skip(skipCount).take(rangeLength);
181+
_allocate<JBooleanMarker>(sizeOf<JBooleanMarker>() * rangeLength, (ptr) {
163182
it.forEachIndexed((index, element) {
164183
ptr[index] = element ? 1 : 0;
165184
});
166-
Jni.env.SetBooleanArrayRegion(reference.pointer, start, size, ptr);
185+
Jni.env.SetBooleanArrayRegion(reference.pointer, start, rangeLength, ptr);
167186
});
168187
}
169188
}
@@ -175,51 +194,61 @@ extension ByteArray on JArray<jbyte> {
175194

176195
void operator []=(int index, int value) {
177196
RangeError.checkValidIndex(index, this);
178-
_allocate<JByteMarker>(sizeOf<JByteMarker>(), (ptr) {
179-
ptr.value = value;
180-
Jni.env.SetByteArrayRegion(reference.pointer, index, 1, ptr);
181-
});
197+
Jni.accessors.setByteArrayElement(reference.pointer, index, value).check();
198+
}
199+
200+
Int8List getRange(int start, int end, {Allocator allocator = malloc}) {
201+
RangeError.checkValidRange(start, end, length);
202+
final rangeLength = end - start;
203+
final buffer = allocator<JByteMarker>(rangeLength);
204+
Jni.env.GetByteArrayRegion(reference.pointer, start, rangeLength, buffer);
205+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
182206
}
183207

184208
void setRange(int start, int end, Iterable<int> iterable,
185209
[int skipCount = 0]) {
186210
RangeError.checkValidRange(start, end, length);
187-
final size = end - start;
188-
final it = iterable.skip(skipCount).take(size);
189-
_allocate<JByteMarker>(sizeOf<JByteMarker>() * size, (ptr) {
190-
it.forEachIndexed((index, element) {
191-
ptr[index] = element;
192-
});
193-
Jni.env.SetByteArrayRegion(reference.pointer, start, size, ptr);
211+
final rangeLength = end - start;
212+
_allocate<JByteMarker>(sizeOf<JByteMarker>() * rangeLength, (ptr) {
213+
ptr
214+
.asTypedList(rangeLength)
215+
.setRange(0, rangeLength, iterable, skipCount);
216+
Jni.env.SetByteArrayRegion(reference.pointer, start, rangeLength, ptr);
194217
});
195218
}
196219
}
197220

221+
/// `JArray<jchar>` is a 16-bit integer array.
222+
///
223+
/// Due to variable length encoding, the number of code units is not equal to
224+
/// the number of characters.
198225
extension CharArray on JArray<jchar> {
199-
String operator [](int index) {
200-
return String.fromCharCode(
201-
_elementAt(index, JniCallType.charType).char,
202-
);
226+
int operator [](int index) {
227+
return _elementAt(index, JniCallType.charType).char;
203228
}
204229

205-
void operator []=(int index, String value) {
230+
void operator []=(int index, int value) {
206231
RangeError.checkValidIndex(index, this);
207-
_allocate<JCharMarker>(sizeOf<JCharMarker>(), (ptr) {
208-
ptr.value = value.codeUnits.first;
209-
Jni.env.SetCharArrayRegion(reference.pointer, index, 1, ptr);
210-
});
232+
Jni.accessors.setCharArrayElement(reference.pointer, index, value).check();
233+
}
234+
235+
Uint16List getRange(int start, int end, {Allocator allocator = malloc}) {
236+
RangeError.checkValidRange(start, end, length);
237+
final rangeLength = end - start;
238+
final buffer = allocator<JCharMarker>(rangeLength);
239+
Jni.env.GetCharArrayRegion(reference.pointer, start, rangeLength, buffer);
240+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
211241
}
212242

213-
void setRange(int start, int end, Iterable<String> iterable,
243+
void setRange(int start, int end, Iterable<int> iterable,
214244
[int skipCount = 0]) {
215245
RangeError.checkValidRange(start, end, length);
216-
final size = end - start;
217-
final it = iterable.skip(skipCount).take(size);
218-
_allocate<JCharMarker>(sizeOf<JCharMarker>() * size, (ptr) {
219-
it.forEachIndexed((index, element) {
220-
ptr[index] = element.codeUnits.first;
221-
});
222-
Jni.env.SetCharArrayRegion(reference.pointer, start, size, ptr);
246+
final rangeLength = end - start;
247+
_allocate<JCharMarker>(sizeOf<JCharMarker>() * rangeLength, (ptr) {
248+
ptr
249+
.asTypedList(rangeLength)
250+
.setRange(0, rangeLength, iterable, skipCount);
251+
Jni.env.SetCharArrayRegion(reference.pointer, start, rangeLength, ptr);
223252
});
224253
}
225254
}
@@ -231,22 +260,26 @@ extension ShortArray on JArray<jshort> {
231260

232261
void operator []=(int index, int value) {
233262
RangeError.checkValidIndex(index, this);
234-
_allocate<JShortMarker>(sizeOf<JShortMarker>(), (ptr) {
235-
ptr.value = value;
236-
Jni.env.SetShortArrayRegion(reference.pointer, index, 1, ptr);
237-
});
263+
Jni.accessors.setShortArrayElement(reference.pointer, index, value).check();
264+
}
265+
266+
Int16List getRange(int start, int end, {Allocator allocator = malloc}) {
267+
RangeError.checkValidRange(start, end, length);
268+
final rangeLength = end - start;
269+
final buffer = allocator<JShortMarker>(rangeLength);
270+
Jni.env.GetShortArrayRegion(reference.pointer, start, rangeLength, buffer);
271+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
238272
}
239273

240274
void setRange(int start, int end, Iterable<int> iterable,
241275
[int skipCount = 0]) {
242276
RangeError.checkValidRange(start, end, length);
243-
final size = end - start;
244-
final it = iterable.skip(skipCount).take(size);
245-
_allocate<JShortMarker>(sizeOf<JShortMarker>() * size, (ptr) {
246-
it.forEachIndexed((index, element) {
247-
ptr[index] = element;
248-
});
249-
Jni.env.SetShortArrayRegion(reference.pointer, start, size, ptr);
277+
final rangeLength = end - start;
278+
_allocate<JShortMarker>(sizeOf<JShortMarker>() * rangeLength, (ptr) {
279+
ptr
280+
.asTypedList(rangeLength)
281+
.setRange(0, rangeLength, iterable, skipCount);
282+
Jni.env.SetShortArrayRegion(reference.pointer, start, rangeLength, ptr);
250283
});
251284
}
252285
}
@@ -258,22 +291,26 @@ extension IntArray on JArray<jint> {
258291

259292
void operator []=(int index, int value) {
260293
RangeError.checkValidIndex(index, this);
261-
_allocate<JIntMarker>(sizeOf<JIntMarker>(), (ptr) {
262-
ptr.value = value;
263-
Jni.env.SetIntArrayRegion(reference.pointer, index, 1, ptr);
264-
});
294+
Jni.accessors.setIntArrayElement(reference.pointer, index, value).check();
295+
}
296+
297+
Int32List getRange(int start, int end, {Allocator allocator = malloc}) {
298+
RangeError.checkValidRange(start, end, length);
299+
final rangeLength = end - start;
300+
final buffer = allocator<JIntMarker>(rangeLength);
301+
Jni.env.GetIntArrayRegion(reference.pointer, start, rangeLength, buffer);
302+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
265303
}
266304

267305
void setRange(int start, int end, Iterable<int> iterable,
268306
[int skipCount = 0]) {
269307
RangeError.checkValidRange(start, end, length);
270-
final size = end - start;
271-
final it = iterable.skip(skipCount).take(size);
272-
_allocate<JIntMarker>(sizeOf<JIntMarker>() * size, (ptr) {
273-
it.forEachIndexed((index, element) {
274-
ptr[index] = element;
275-
});
276-
Jni.env.SetIntArrayRegion(reference.pointer, start, size, ptr);
308+
final rangeLength = end - start;
309+
_allocate<JIntMarker>(sizeOf<JIntMarker>() * rangeLength, (ptr) {
310+
ptr
311+
.asTypedList(rangeLength)
312+
.setRange(0, rangeLength, iterable, skipCount);
313+
Jni.env.SetIntArrayRegion(reference.pointer, start, rangeLength, ptr);
277314
});
278315
}
279316
}
@@ -285,22 +322,26 @@ extension LongArray on JArray<jlong> {
285322

286323
void operator []=(int index, int value) {
287324
RangeError.checkValidIndex(index, this);
288-
_allocate<JLongMarker>(sizeOf<JLongMarker>(), (ptr) {
289-
ptr.value = value;
290-
Jni.env.SetLongArrayRegion(reference.pointer, index, 1, ptr);
291-
});
325+
Jni.accessors.setLongArrayElement(reference.pointer, index, value).check();
326+
}
327+
328+
Int64List getRange(int start, int end, {Allocator allocator = malloc}) {
329+
RangeError.checkValidRange(start, end, length);
330+
final rangeLength = end - start;
331+
final buffer = allocator<JLongMarker>(rangeLength);
332+
Jni.env.GetLongArrayRegion(reference.pointer, start, rangeLength, buffer);
333+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
292334
}
293335

294336
void setRange(int start, int end, Iterable<int> iterable,
295337
[int skipCount = 0]) {
296338
RangeError.checkValidRange(start, end, length);
297-
final size = end - start;
298-
final it = iterable.skip(skipCount).take(size);
299-
_allocate<JLongMarker>(sizeOf<JLongMarker>() * size, (ptr) {
300-
it.forEachIndexed((index, element) {
301-
ptr[index] = element;
302-
});
303-
Jni.env.SetLongArrayRegion(reference.pointer, start, size, ptr);
339+
final rangeLength = end - start;
340+
_allocate<JLongMarker>(sizeOf<JLongMarker>() * rangeLength, (ptr) {
341+
ptr
342+
.asTypedList(rangeLength)
343+
.setRange(0, rangeLength, iterable, skipCount);
344+
Jni.env.SetLongArrayRegion(reference.pointer, start, rangeLength, ptr);
304345
});
305346
}
306347
}
@@ -312,22 +353,26 @@ extension FloatArray on JArray<jfloat> {
312353

313354
void operator []=(int index, double value) {
314355
RangeError.checkValidIndex(index, this);
315-
_allocate<JFloatMarker>(sizeOf<JFloatMarker>(), (ptr) {
316-
ptr.value = value;
317-
Jni.env.SetFloatArrayRegion(reference.pointer, index, 1, ptr);
318-
});
356+
Jni.accessors.setFloatArrayElement(reference.pointer, index, value).check();
357+
}
358+
359+
Float32List getRange(int start, int end, {Allocator allocator = malloc}) {
360+
RangeError.checkValidRange(start, end, length);
361+
final rangeLength = end - start;
362+
final buffer = allocator<JFloatMarker>(rangeLength);
363+
Jni.env.GetFloatArrayRegion(reference.pointer, start, rangeLength, buffer);
364+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
319365
}
320366

321367
void setRange(int start, int end, Iterable<double> iterable,
322368
[int skipCount = 0]) {
323369
RangeError.checkValidRange(start, end, length);
324-
final size = end - start;
325-
final it = iterable.skip(skipCount).take(size);
326-
_allocate<JFloatMarker>(sizeOf<JFloatMarker>() * size, (ptr) {
327-
it.forEachIndexed((index, element) {
328-
ptr[index] = element;
329-
});
330-
Jni.env.SetFloatArrayRegion(reference.pointer, start, size, ptr);
370+
final rangeLength = end - start;
371+
_allocate<JFloatMarker>(sizeOf<JFloatMarker>() * rangeLength, (ptr) {
372+
ptr
373+
.asTypedList(rangeLength)
374+
.setRange(0, rangeLength, iterable, skipCount);
375+
Jni.env.SetFloatArrayRegion(reference.pointer, start, rangeLength, ptr);
331376
});
332377
}
333378
}
@@ -339,22 +384,28 @@ extension DoubleArray on JArray<jdouble> {
339384

340385
void operator []=(int index, double value) {
341386
RangeError.checkValidIndex(index, this);
342-
_allocate<JDoubleMarker>(sizeOf<JDoubleMarker>(), (ptr) {
343-
ptr.value = value;
344-
Jni.env.SetDoubleArrayRegion(reference.pointer, index, 1, ptr);
345-
});
387+
Jni.accessors
388+
.setDoubleArrayElement(reference.pointer, index, value)
389+
.check();
390+
}
391+
392+
Float64List getRange(int start, int end, {Allocator allocator = malloc}) {
393+
RangeError.checkValidRange(start, end, length);
394+
final rangeLength = end - start;
395+
final buffer = allocator<JDoubleMarker>(rangeLength);
396+
Jni.env.GetDoubleArrayRegion(reference.pointer, start, rangeLength, buffer);
397+
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
346398
}
347399

348400
void setRange(int start, int end, Iterable<double> iterable,
349401
[int skipCount = 0]) {
350402
RangeError.checkValidRange(start, end, length);
351-
final size = end - start;
352-
final it = iterable.skip(skipCount).take(size);
353-
_allocate<JDoubleMarker>(sizeOf<JDoubleMarker>() * size, (ptr) {
354-
it.forEachIndexed((index, element) {
355-
ptr[index] = element;
356-
});
357-
Jni.env.SetDoubleArrayRegion(reference.pointer, start, size, ptr);
403+
final rangeLength = end - start;
404+
_allocate<JDoubleMarker>(sizeOf<JDoubleMarker>() * rangeLength, (ptr) {
405+
ptr
406+
.asTypedList(rangeLength)
407+
.setRange(0, rangeLength, iterable, skipCount);
408+
Jni.env.SetDoubleArrayRegion(reference.pointer, start, rangeLength, ptr);
358409
});
359410
}
360411
}
@@ -373,8 +424,8 @@ extension ObjectArray<T extends JObject> on JArray<T> {
373424

374425
void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) {
375426
RangeError.checkValidRange(start, end, length);
376-
final size = end - start;
377-
final it = iterable.skip(skipCount).take(size);
427+
final rangeLength = end - start;
428+
final it = iterable.skip(skipCount).take(rangeLength);
378429
it.forEachIndexed((index, element) {
379430
this[index] = element;
380431
});

0 commit comments

Comments
 (0)