blob: 520ea9cbbe06cdd355a70de210b7a68ae2d49aca [file] [edit]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'dart:ffi';
import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:ffi/ffi.dart';
import 'jni.dart';
import 'jobject.dart';
import 'jreference.dart';
import 'types.dart';
part 'primitive_jarrays.dart';
final class _$JArray$Type$<E extends JObject?> extends JType<JArray<E>> {
_$JArray$Type$(JType<E> elementType)
: signature = '[${elementType.signature}';
@override
final String signature;
}
extension type JArray<E extends JObject?>._(JObject _$this) implements JObject {
/// The type which includes information such as the signature of this class.
static JType<JArray<$E>> type<$E extends JObject?>(JType<$E> innerType) =>
_$JArray$Type$<$E>(innerType);
/// Creates a [JArray] of the given length from the given [elementType].
///
/// The [length] must be a non-negative integer.
static JArray<$E?> withLength<$E extends JObject?>(
JType<$E> elementType, int length) {
RangeError.checkNotNegative(length);
return _newArray<$E>(elementType.jClass, length);
}
static JArray<$E> _newArray<$E extends JObject?>(JClass jClass, int length,
[$E? fill]) {
final classRef = jClass.reference;
final fillRef = fill?.reference ?? jNullReference;
final array = JObject.fromReference(
JGlobalReference(Jni.env.NewObjectArray(
length,
classRef.pointer,
fillRef.pointer,
)),
) as JArray<$E>;
classRef.release();
return array;
}
/// Creates a [JArray] of the given length with [fill] at each position.
///
/// The [length] must be a non-negative integer.
static JArray<$E> filled<$E extends JObject>(int length, $E fill,
{JType<$E>? elementType}) {
RangeError.checkNotNegative(length);
final jClass = elementType == null ? fill.jClass : elementType.jClass;
return _newArray<$E>(jClass, length, fill);
}
/// Creates a [JArray] from `elements`.
static JArray<$E> of<$E extends JObject?>(
JType<$E> elementType, Iterable<$E> elements) {
final len = elements.length;
return _newArray<$E>(elementType.jClass, len)..setRange(0, len, elements);
}
/// The number of elements in this array.
int get length => Jni.env.GetArrayLength(reference.pointer);
E _elementAt(int index) {
RangeError.checkValueInInterval(index, 0, length - 1);
final pointer = Jni.env.GetObjectArrayElement(reference.pointer, index);
if (pointer == nullptr) {
return null as E;
}
return JObject.fromReference(JGlobalReference(pointer)) as E;
}
E operator [](int index) {
return _elementAt(index);
}
void operator []=(int index, E value) {
RangeError.checkValueInInterval(index, 0, length - 1);
final valueRef = value?.reference ?? jNullReference;
Jni.env.SetObjectArrayElement(reference.pointer, index, valueRef.pointer);
}
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
RangeError.checkValidRange(start, end, length);
final rangeLength = end - start;
final it = iterable.skip(skipCount).take(rangeLength);
for (final (index, element) in it.indexed) {
this[index] = element;
}
}
}
final class _JArrayListView<E extends JObject?>
with ListMixin<E>, NonGrowableListMixin<E> {
final JArray<E> _jarray;
_JArrayListView(this._jarray);
@override
int get length => _jarray.length;
@override
E operator [](int index) {
return _jarray[index];
}
@override
void operator []=(int index, E value) {
_jarray[index] = value;
}
}
extension JArrayToList<E extends JObject?> on JArray<E> {
/// Returns a [List] view into this array.
///
/// Any changes to this list will reflect in the original array as well.
List<E> asDart() => _JArrayListView<E>(this);
}
void _allocate<T extends NativeType>(
int byteCount,
void Function(Pointer<T> ptr) use,
) {
using((arena) {
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,
};
}
}