Skip to content

Commit

Permalink
[jnigen] Add getRange method to JArray<JPrimitive> and change the…
Browse files Browse the repository at this point in the history
… 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 []=`
  • Loading branch information
HosseinYousefi authored Apr 24, 2024
1 parent d7d9229 commit 880ca30
Show file tree
Hide file tree
Showing 7 changed files with 420 additions and 134 deletions.
8 changes: 7 additions & 1 deletion pkgs/jni/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
## 0.9.0-wip

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

## 0.8.0

Expand Down
241 changes: 146 additions & 95 deletions pkgs/jni/lib/src/jarray.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// ignore_for_file: unnecessary_cast, overridden_fields

import 'dart:ffi';
import 'dart:typed_data';

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

extension NativeArray<E extends JPrimitive> on JArray<E> {
void _allocate<T extends NativeType>(
int size,
int byteCount,
void Function(Pointer<T> ptr) use,
) {
using((arena) {
final ptr = arena.allocate<T>(size);
final ptr = arena.allocate<T>(byteCount);
use(ptr);
}, malloc);
}
}

extension on Allocator {
Pointer<NativeFinalizerFunction>? get _nativeFree {
return switch (this) {
malloc => malloc.nativeFree,
calloc => calloc.nativeFree,
_ => null,
};
}
}

extension BoolArray on JArray<jboolean> {
bool operator [](int index) {
return _elementAt(index, JniCallType.booleanType).boolean;
}

void operator []=(int index, bool value) {
RangeError.checkValidIndex(index, this);
_allocate<JBooleanMarker>(sizeOf<JBooleanMarker>(), (ptr) {
ptr.value = value ? 1 : 0;
Jni.env.SetBooleanArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors
.setBooleanArrayElement(reference.pointer, index, value ? 1 : 0);
}

Uint8List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator
.allocate<JBooleanMarker>(sizeOf<JBooleanMarker>() * rangeLength);
Jni.env
.GetBooleanArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<bool> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JBooleanMarker>(sizeOf<JBooleanMarker>() * size, (ptr) {
final rangeLength = end - start;
final it = iterable.skip(skipCount).take(rangeLength);
_allocate<JBooleanMarker>(sizeOf<JBooleanMarker>() * rangeLength, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element ? 1 : 0;
});
Jni.env.SetBooleanArrayRegion(reference.pointer, start, size, ptr);
Jni.env.SetBooleanArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -175,51 +194,61 @@ extension ByteArray on JArray<jbyte> {

void operator []=(int index, int value) {
RangeError.checkValidIndex(index, this);
_allocate<JByteMarker>(sizeOf<JByteMarker>(), (ptr) {
ptr.value = value;
Jni.env.SetByteArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors.setByteArrayElement(reference.pointer, index, value).check();
}

Int8List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JByteMarker>(rangeLength);
Jni.env.GetByteArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<int> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JByteMarker>(sizeOf<JByteMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element;
});
Jni.env.SetByteArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JByteMarker>(sizeOf<JByteMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetByteArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}

/// `JArray<jchar>` is a 16-bit integer array.
///
/// Due to variable length encoding, the number of code units is not equal to
/// the number of characters.
extension CharArray on JArray<jchar> {
String operator [](int index) {
return String.fromCharCode(
_elementAt(index, JniCallType.charType).char,
);
int operator [](int index) {
return _elementAt(index, JniCallType.charType).char;
}

void operator []=(int index, String value) {
void operator []=(int index, int value) {
RangeError.checkValidIndex(index, this);
_allocate<JCharMarker>(sizeOf<JCharMarker>(), (ptr) {
ptr.value = value.codeUnits.first;
Jni.env.SetCharArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors.setCharArrayElement(reference.pointer, index, value).check();
}

Uint16List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JCharMarker>(rangeLength);
Jni.env.GetCharArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<String> iterable,
void setRange(int start, int end, Iterable<int> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JCharMarker>(sizeOf<JCharMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element.codeUnits.first;
});
Jni.env.SetCharArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JCharMarker>(sizeOf<JCharMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetCharArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -231,22 +260,26 @@ extension ShortArray on JArray<jshort> {

void operator []=(int index, int value) {
RangeError.checkValidIndex(index, this);
_allocate<JShortMarker>(sizeOf<JShortMarker>(), (ptr) {
ptr.value = value;
Jni.env.SetShortArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors.setShortArrayElement(reference.pointer, index, value).check();
}

Int16List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JShortMarker>(rangeLength);
Jni.env.GetShortArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<int> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JShortMarker>(sizeOf<JShortMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element;
});
Jni.env.SetShortArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JShortMarker>(sizeOf<JShortMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetShortArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -258,22 +291,26 @@ extension IntArray on JArray<jint> {

void operator []=(int index, int value) {
RangeError.checkValidIndex(index, this);
_allocate<JIntMarker>(sizeOf<JIntMarker>(), (ptr) {
ptr.value = value;
Jni.env.SetIntArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors.setIntArrayElement(reference.pointer, index, value).check();
}

Int32List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JIntMarker>(rangeLength);
Jni.env.GetIntArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<int> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JIntMarker>(sizeOf<JIntMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element;
});
Jni.env.SetIntArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JIntMarker>(sizeOf<JIntMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetIntArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -285,22 +322,26 @@ extension LongArray on JArray<jlong> {

void operator []=(int index, int value) {
RangeError.checkValidIndex(index, this);
_allocate<JLongMarker>(sizeOf<JLongMarker>(), (ptr) {
ptr.value = value;
Jni.env.SetLongArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors.setLongArrayElement(reference.pointer, index, value).check();
}

Int64List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JLongMarker>(rangeLength);
Jni.env.GetLongArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<int> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JLongMarker>(sizeOf<JLongMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element;
});
Jni.env.SetLongArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JLongMarker>(sizeOf<JLongMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetLongArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -312,22 +353,26 @@ extension FloatArray on JArray<jfloat> {

void operator []=(int index, double value) {
RangeError.checkValidIndex(index, this);
_allocate<JFloatMarker>(sizeOf<JFloatMarker>(), (ptr) {
ptr.value = value;
Jni.env.SetFloatArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors.setFloatArrayElement(reference.pointer, index, value).check();
}

Float32List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JFloatMarker>(rangeLength);
Jni.env.GetFloatArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<double> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JFloatMarker>(sizeOf<JFloatMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element;
});
Jni.env.SetFloatArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JFloatMarker>(sizeOf<JFloatMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetFloatArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -339,22 +384,28 @@ extension DoubleArray on JArray<jdouble> {

void operator []=(int index, double value) {
RangeError.checkValidIndex(index, this);
_allocate<JDoubleMarker>(sizeOf<JDoubleMarker>(), (ptr) {
ptr.value = value;
Jni.env.SetDoubleArrayRegion(reference.pointer, index, 1, ptr);
});
Jni.accessors
.setDoubleArrayElement(reference.pointer, index, value)
.check();
}

Float64List getRange(int start, int end, {Allocator allocator = malloc}) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final buffer = allocator<JDoubleMarker>(rangeLength);
Jni.env.GetDoubleArrayRegion(reference.pointer, start, rangeLength, buffer);
return buffer.asTypedList(rangeLength, finalizer: allocator._nativeFree);
}

void setRange(int start, int end, Iterable<double> iterable,
[int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
_allocate<JDoubleMarker>(sizeOf<JDoubleMarker>() * size, (ptr) {
it.forEachIndexed((index, element) {
ptr[index] = element;
});
Jni.env.SetDoubleArrayRegion(reference.pointer, start, size, ptr);
final rangeLength = end - start;
_allocate<JDoubleMarker>(sizeOf<JDoubleMarker>() * rangeLength, (ptr) {
ptr
.asTypedList(rangeLength)
.setRange(0, rangeLength, iterable, skipCount);
Jni.env.SetDoubleArrayRegion(reference.pointer, start, rangeLength, ptr);
});
}
}
Expand All @@ -373,8 +424,8 @@ extension ObjectArray<T extends JObject> on JArray<T> {

void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final size = end - start;
final it = iterable.skip(skipCount).take(size);
final rangeLength = end - start;
final it = iterable.skip(skipCount).take(rangeLength);
it.forEachIndexed((index, element) {
this[index] = element;
});
Expand Down
Loading

0 comments on commit 880ca30

Please sign in to comment.