Skip to content

Commit

Permalink
feat: Add findLastIndex for Array and TypedArray (Stage 3) (AssemblyS…
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxGraey authored Jul 23, 2021
1 parent 20a0635 commit a0307d8
Show file tree
Hide file tree
Showing 43 changed files with 24,144 additions and 20,072 deletions.
223 changes: 115 additions & 108 deletions std/assembly/array.ts

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion std/assembly/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,8 @@ declare abstract class TypedArray<T> implements ArrayBufferView {
fill(value: T, start?: i32, end?: i32): this;
/** The findIndex() method returns an index in the typed array, if an element in the typed array satisfies the provided testing function. Otherwise -1 is returned. See also the find() [not implemented] method, which returns the value of a found element in the typed array instead of its index. */
findIndex(callbackfn: (value: T, index: i32, self: this) => bool): i32;
/** The findLastIndex() method returns an index start searching from the end in the typed array, if an element in the typed array satisfies the provided testing function. Otherwise -1 is returned. See also the find() [not implemented] method, which returns the value of a found element in the typed array instead of its index. */
findLastIndex(callbackfn: (value: T, index: i32, self: this) => bool): i32;
/** The every() method tests whether all elements in the typed array pass the test implemented by the provided function. This method has the same algorithm as Array.prototype.every(). */
every(callbackfn: (value: T, index: i32, self: this) => bool): bool;
/** The forEach() method executes a provided function once per array element. This method has the same algorithm as Array.prototype.forEach().*/
Expand Down Expand Up @@ -1688,7 +1690,8 @@ declare class Array<T> {
at(index: i32): T;
fill(value: T, start?: i32, end?: i32): this;
every(callbackfn: (element: T, index: i32, array?: Array<T>) => bool): bool;
findIndex(predicate: (element: T, index: i32, array?: Array<T>) => bool): i32;
findIndex(callbackfn: (element: T, index: i32, array?: Array<T>) => bool): i32;
findLastIndex(callbackfn: (element: T, index: i32, array?: Array<T>) => bool): i32;
includes(searchElement: T, fromIndex?: i32): bool;
indexOf(searchElement: T, fromIndex?: i32): i32;
lastIndexOf(searchElement: T, fromIndex?: i32): i32;
Expand Down
135 changes: 96 additions & 39 deletions std/assembly/typedarray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export class Int8Array extends ArrayBufferView {
return FIND_INDEX<Int8Array, i8>(this, fn);
}

findLastIndex(fn: (value: i8, index: i32, self: Int8Array) => bool): i32 {
return FIND_LAST_INDEX<Int8Array, i8>(this, fn);
}

some(fn: (value: i8, index: i32, self: Int8Array) => bool): bool {
return SOME<Int8Array, i8>(this, fn);
}
Expand Down Expand Up @@ -243,6 +247,10 @@ export class Uint8Array extends ArrayBufferView {
return FIND_INDEX<Uint8Array, u8>(this, fn);
}

findLastIndex(fn: (value: u8, index: i32, self: Uint8Array) => bool): i32 {
return FIND_LAST_INDEX<Uint8Array, u8>(this, fn);
}

some(fn: (value: u8, index: i32, self: Uint8Array) => bool): bool {
return SOME<Uint8Array, u8>(this, fn);
}
Expand Down Expand Up @@ -379,6 +387,10 @@ export class Uint8ClampedArray extends ArrayBufferView {
return FIND_INDEX<Uint8ClampedArray, u8>(this, fn);
}

findLastIndex(fn: (value: u8, index: i32, self: Uint8ClampedArray) => bool): i32 {
return FIND_LAST_INDEX<Uint8ClampedArray, u8>(this, fn);
}

some(fn: (value: u8, index: i32, self: Uint8ClampedArray) => bool): bool {
return SOME<Uint8ClampedArray, u8>(this, fn);
}
Expand Down Expand Up @@ -515,6 +527,10 @@ export class Int16Array extends ArrayBufferView {
return FIND_INDEX<Int16Array, i16>(this, fn);
}

findLastIndex(fn: (value: i16, index: i32, self: Int16Array) => bool): i32 {
return FIND_LAST_INDEX<Int16Array, i16>(this, fn);
}

some(fn: (value: i16, index: i32, self: Int16Array) => bool): bool {
return SOME<Int16Array, i16>(this, fn);
}
Expand Down Expand Up @@ -651,6 +667,10 @@ export class Uint16Array extends ArrayBufferView {
return FIND_INDEX<Uint16Array, u16>(this, fn);
}

findLastIndex(fn: (value: u16, index: i32, self: Uint16Array) => bool): i32 {
return FIND_LAST_INDEX<Uint16Array, u16>(this, fn);
}

some(fn: (value: u16, index: i32, self: Uint16Array) => bool): bool {
return SOME<Uint16Array, u16>(this, fn);
}
Expand Down Expand Up @@ -787,6 +807,10 @@ export class Int32Array extends ArrayBufferView {
return FIND_INDEX<Int32Array, i32>(this, fn);
}

findLastIndex(fn: (value: i32, index: i32, self: Int32Array) => bool): i32 {
return FIND_LAST_INDEX<Int32Array, i32>(this, fn);
}

some(fn: (value: i32, index: i32, self: Int32Array) => bool): bool {
return SOME<Int32Array, i32>(this, fn);
}
Expand Down Expand Up @@ -923,6 +947,10 @@ export class Uint32Array extends ArrayBufferView {
return FIND_INDEX<Uint32Array, u32>(this, fn);
}

findLastIndex(fn: (value: u32, index: i32, self: Uint32Array) => bool): i32 {
return FIND_LAST_INDEX<Uint32Array, u32>(this, fn);
}

some(fn: (value: u32, index: i32, self: Uint32Array) => bool): bool {
return SOME<Uint32Array, u32>(this, fn);
}
Expand Down Expand Up @@ -1059,6 +1087,10 @@ export class Int64Array extends ArrayBufferView {
return FIND_INDEX<Int64Array, i64>(this, fn);
}

findLastIndex(fn: (value: i64, index: i32, self: Int64Array) => bool): i32 {
return FIND_LAST_INDEX<Int64Array, i64>(this, fn);
}

some(fn: (value: i64, index: i32, self: Int64Array) => bool): bool {
return SOME<Int64Array, i64>(this, fn);
}
Expand Down Expand Up @@ -1195,6 +1227,10 @@ export class Uint64Array extends ArrayBufferView {
return FIND_INDEX<Uint64Array, u64>(this, fn);
}

findLastIndex(fn: (value: u64, index: i32, self: Uint64Array) => bool): i32 {
return FIND_LAST_INDEX<Uint64Array, u64>(this, fn);
}

some(fn: (value: u64, index: i32, self: Uint64Array) => bool): bool {
return SOME<Uint64Array, u64>(this, fn);
}
Expand Down Expand Up @@ -1331,6 +1367,10 @@ export class Float32Array extends ArrayBufferView {
return FIND_INDEX<Float32Array, f32>(this, fn);
}

findLastIndex(fn: (value: f32, index: i32, self: Float32Array) => bool): i32 {
return FIND_LAST_INDEX<Float32Array, f32>(this, fn);
}

some(fn: (value: f32, index: i32, self: Float32Array) => bool): bool {
return SOME<Float32Array, f32>(this, fn);
}
Expand Down Expand Up @@ -1467,6 +1507,10 @@ export class Float64Array extends ArrayBufferView {
return FIND_INDEX<Float64Array, f64>(this, fn);
}

findLastIndex(fn: (value: f64, index: i32, self: Float64Array) => bool): i32 {
return FIND_LAST_INDEX<Float64Array, f64>(this, fn);
}

some(fn: (value: f64, index: i32, self: Float64Array) => bool): bool {
return SOME<Float64Array, f64>(this, fn);
}
Expand Down Expand Up @@ -1508,15 +1552,15 @@ function FILL<TArray extends ArrayBufferView, T extends number>(
start: i32,
end: i32
): TArray {
var dataStart = array.dataStart;
var ptr = array.dataStart;
var len = array.length;
start = start < 0 ? max(len + start, 0) : min(start, len);
end = end < 0 ? max(len + end, 0) : min(end, len);
if (sizeof<T>() == 1) {
if (start < end) memory.fill(dataStart + <usize>start, <u8>value, <usize>(end - start));
if (start < end) memory.fill(ptr + <usize>start, <u8>value, <usize>(end - start));
} else {
for (; start < end; ++start) {
store<T>(dataStart + (<usize>start << alignof<T>()), value);
store<T>(ptr + (<usize>start << alignof<T>()), value);
}
}
return array;
Expand Down Expand Up @@ -1572,7 +1616,7 @@ function COPY_WITHIN<TArray extends ArrayBufferView, T>(
end: i32
): TArray {
var len = array.length;
var dataStart = array.dataStart;
var ptr = array.dataStart;

end = min<i32>(end, len);
var to = target < 0 ? max(len + target, 0) : min(target, len);
Expand All @@ -1581,8 +1625,8 @@ function COPY_WITHIN<TArray extends ArrayBufferView, T>(
var count = min(last - from, len - to);

memory.copy(
dataStart + (<usize>to << alignof<T>()),
dataStart + (<usize>from << alignof<T>()),
ptr + (<usize>to << alignof<T>()),
ptr + (<usize>from << alignof<T>()),
<usize>count << alignof<T>()
);
return array;
Expand All @@ -1595,9 +1639,9 @@ function REDUCE<TArray extends ArrayBufferView, T, TRet>(
fn: (accumulator: TRet, value: T, index: i32, array: TArray) => TRet,
initialValue: TRet
): TRet {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let i = 0, k = array.length; i < k; i++) {
initialValue = fn(initialValue, load<T>(dataStart + (<usize>i << alignof<T>())), i, array);
initialValue = fn(initialValue, load<T>(ptr + (<usize>i << alignof<T>())), i, array);
}
return initialValue;
}
Expand All @@ -1609,9 +1653,9 @@ function REDUCE_RIGHT<TArray extends ArrayBufferView, T, TRet>(
fn: (accumulator: TRet, value: T, index: i32, array: TArray) => TRet,
initialValue: TRet
): TRet {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let i = array.length - 1; i >= 0; i--) {
initialValue = fn(initialValue, load<T>(dataStart + (<usize>i << alignof<T>())), i, array);
initialValue = fn(initialValue, load<T>(ptr + (<usize>i << alignof<T>())), i, array);
}
return initialValue;
}
Expand All @@ -1623,15 +1667,15 @@ function MAP<TArray extends ArrayBufferView, T>(
fn: (value: T, index: i32, self: TArray) => T,
): TArray {
var len = array.length;
var dataStart = array.dataStart;
var ptr = array.dataStart;

var byteLength = len << alignof<T>();
var out = changetype<TArray>(__new(offsetof<TArray>(), idof<TArray>()));
var buf = changetype<ArrayBuffer>(__new(byteLength, idof<ArrayBuffer>()));
for (let i = 0; i < len; i++) {
store<T>(
changetype<usize>(buf) + (<usize>i << alignof<T>()),
fn(load<T>(dataStart + (<usize>i << alignof<T>())), i, array)
fn(load<T>(ptr + (<usize>i << alignof<T>())), i, array)
);
}
store<usize>(changetype<usize>(out), changetype<usize>(buf), offsetof<TArray>("buffer"));
Expand Down Expand Up @@ -1677,9 +1721,22 @@ function FIND_INDEX<TArray extends ArrayBufferView, T>(
array: TArray,
fn: (value: T, index: i32, array: TArray) => bool,
): i32 {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let i = 0, k = array.length; i < k; i++) {
if (fn(load<T>(dataStart + (<usize>i << alignof<T>())), i, array)) return i;
if (fn(load<T>(ptr + (<usize>i << alignof<T>())), i, array)) return i;
}
return -1;
}

// @ts-ignore: decorator
@inline
function FIND_LAST_INDEX<TArray extends ArrayBufferView, T>(
array: TArray,
fn: (value: T, index: i32, array: TArray) => bool,
): i32 {
var ptr = array.dataStart;
for (let i = array.length - 1; i >= 0; --i) {
if (fn(load<T>(ptr + (<usize>i << alignof<T>())), i, array)) return i;
}
return -1;
}
Expand All @@ -1693,11 +1750,11 @@ function INCLUDES<TArray extends ArrayBufferView, T>(
): bool {
if (isFloat<T>()) {
let index: isize = fromIndex;
let length: isize = array.length;
if (length == 0 || index >= length) return false;
if (index < 0) index = max(length + index, 0);
let len: isize = array.length;
if (len == 0 || index >= len) return false;
if (index < 0) index = max(len + index, 0);
let dataStart = array.dataStart;
while (index < length) {
while (index < len) {
let elem = load<T>(dataStart + (index << alignof<T>()));
// @ts-ignore
if (elem == searchElement || isNaN(elem) & isNaN(searchElement)) return true;
Expand All @@ -1717,11 +1774,11 @@ function INDEX_OF<TArray extends ArrayBufferView, T>(
fromIndex: i32,
): i32 {
var index: isize = fromIndex;
var length: isize = array.length;
if (length == 0 || index >= length) return -1;
if (index < 0) index = max(length + index, 0);
var len: isize = array.length;
if (len == 0 || index >= len) return -1;
if (index < 0) index = max(len + index, 0);
var dataStart = array.dataStart;
while (index < length) {
while (index < len) {
if (load<T>(dataStart + (index << alignof<T>())) == searchElement) return <i32>index;
++index;
}
Expand All @@ -1736,10 +1793,10 @@ function LAST_INDEX_OF<TArray extends ArrayBufferView, T>(
fromIndex: i32,
): i32 {
var index: isize = fromIndex;
var length: isize = array.length;
if (length == 0) return -1;
if (index < 0) index = length + index; // no need to clamp
else if (index >= length) index = length - 1;
var len: isize = array.length;
if (len == 0) return -1;
if (index < 0) index = len + index; // no need to clamp
else if (index >= len) index = len - 1;
var dataStart = array.dataStart;
while (index >= 0) {
if (load<T>(dataStart + (index << alignof<T>())) == searchElement) return <i32>index;
Expand All @@ -1754,9 +1811,9 @@ function SOME<TArray extends ArrayBufferView, T>(
array: TArray,
fn: (value: T, index: i32, array: TArray) => bool,
): bool {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let i = 0, k = array.length; i < k; i++) {
if (fn(load<T>(dataStart + (<usize>i << alignof<T>())), i, array)) return true;
if (fn(load<T>(ptr + (<usize>i << alignof<T>())), i, array)) return true;
}
return false;
}
Expand All @@ -1767,9 +1824,9 @@ function EVERY<TArray extends ArrayBufferView, T>(
array: TArray,
fn: (value: T, index: i32, array: TArray) => bool,
): bool {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let i = 0, k = array.length; i < k; i++) {
if (fn(load<T>(dataStart + (<usize>i << alignof<T>())), i, array)) continue;
if (fn(load<T>(ptr + (<usize>i << alignof<T>())), i, array)) continue;
return false;
}
return true;
Expand All @@ -1781,19 +1838,19 @@ function FOREACH<TArray extends ArrayBufferView, T>(
array: TArray,
fn: (value: T, index: i32, array: TArray) => void,
): void {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let i = 0, k = array.length; i < k; i++) {
fn(load<T>(dataStart + (<usize>i << alignof<T>())), i, array);
fn(load<T>(ptr + (<usize>i << alignof<T>())), i, array);
}
}

// @ts-ignore: decorator
@inline
function REVERSE<TArray extends ArrayBufferView, T>(array: TArray): TArray {
var dataStart = array.dataStart;
var ptr = array.dataStart;
for (let front: usize = 0, back: usize = array.length - 1; front < back; ++front, --back) {
let frontPtr = dataStart + (front << alignof<T>());
let backPtr = dataStart + (back << alignof<T>());
let frontPtr = ptr + (front << alignof<T>());
let backPtr = ptr + (back << alignof<T>());
let temp = load<T>(frontPtr);
store<T>(frontPtr, load<T>(backPtr));
store<T>(backPtr, temp);
Expand All @@ -1806,16 +1863,16 @@ function REVERSE<TArray extends ArrayBufferView, T>(array: TArray): TArray {
function WRAP<TArray extends ArrayBufferView, T>(
buffer: ArrayBuffer,
byteOffset: i32 = 0,
length: i32 = -1
len: i32 = -1
): TArray {
var byteLength: i32;
var bufferByteLength = buffer.byteLength;
const mask: u32 = sizeof<T>() - 1;
if (i32(<u32>byteOffset > <u32>bufferByteLength) | (byteOffset & mask)) {
throw new RangeError(E_INDEXOUTOFRANGE);
}
if (length < 0) {
if (length == -1) {
if (len < 0) {
if (len == -1) {
if (bufferByteLength & mask) {
throw new RangeError(E_INVALIDLENGTH);
}
Expand All @@ -1824,7 +1881,7 @@ function WRAP<TArray extends ArrayBufferView, T>(
throw new RangeError(E_INVALIDLENGTH);
}
} else {
byteLength = length << alignof<T>();
byteLength = len << alignof<T>();
if (byteOffset + byteLength > bufferByteLength) {
throw new RangeError(E_INVALIDLENGTH);
}
Expand Down
Loading

0 comments on commit a0307d8

Please sign in to comment.