Skip to content

Commit

Permalink
Add TypedArray#includes/indexOf/lastIndexOf (#660)
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxGraey authored and dcodeIO committed Jun 16, 2019
1 parent a4e5857 commit f48f3c9
Show file tree
Hide file tree
Showing 7 changed files with 15,635 additions and 2,041 deletions.
16 changes: 8 additions & 8 deletions std/assembly/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1115,18 +1115,18 @@ declare abstract class TypedArray<T> implements ArrayBufferView<T> {
readonly byteLength: i32;
/** The length (in elements). */
readonly length: i32;
/** The includes() method determines whether a typed array includes a certain element, returning true or false as appropriate. */
includes(searchElement: T, fromIndex?: i32): bool;
/** The indexOf() method returns the first index at which a given element can be found in the typed array, or -1 if it is not present. */
indexOf(searchElement: T, fromIndex?: i32): i32;
/** The lastIndexOf() method returns the last index at which a given element can be found in the typed array, or -1 if it is not present. The typed array is searched backwards, starting at fromIndex. */
lastIndexOf(searchElement: T, fromIndex?: i32): i32;
/** Returns a new TypedArray of this type on the same ArrayBuffer from begin inclusive to end exclusive. */
subarray(begin?: i32, end?: i32): this;
/** The reduce() method applies a function against an accumulator and each value of the typed array (from left-to-right) has to reduce it to a single value. This method has the same algorithm as Array.prototype.reduce(). */
reduce<W>(
callbackfn: (accumulator: W, value: T, index: i32, self: this) => W,
initialValue: W,
): W;
reduce<W>(callbackfn: (accumulator: W, value: T, index: i32, self: this) => W, initialValue: W): W;
/** The reduceRight() method applies a function against an accumulator and each value of the typed array (from left-to-right) has to reduce it to a single value, starting from the end of the array. This method has the same algorithm as Array.prototype.reduceRight(). */
reduceRight<W>(
callbackfn: (accumulator: W, value: T, index: i32, self: this) => W,
initialValue: W,
): W;
reduceRight<W>(callbackfn: (accumulator: W, value: T, index: i32, self: this) => W, initialValue: W): W;
/** The some() method tests whether some element in the typed array passes the test implemented by the provided function. This method has the same algorithm as Array.prototype.some().*/
some(callbackfn: (value: T, index: i32, self: this) => bool): bool;
/** The map() method creates a new typed array with the results of calling a provided function on every element in this typed array. This method has the same algorithm as Array.prototype.map().*/
Expand Down
187 changes: 184 additions & 3 deletions std/assembly/typedarray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ export class Int8Array extends ArrayBufferView {
store<i8>(this.dataStart + <usize>index, value);
}

includes(searchElement: i8, fromIndex: i32 = 0): bool {
return INCLUDES<Int8Array, i8>(this, searchElement, fromIndex);
}

indexOf(searchElement: i8, fromIndex: i32 = 0): i32 {
return INDEX_OF<Int8Array, i8>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: i8, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Int8Array, i8>(this, searchElement, fromIndex);
}

fill(value: i32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int8Array {
return FILL<Int8Array, i8>(this, value, start, end);
}
Expand Down Expand Up @@ -116,6 +128,18 @@ export class Uint8Array extends ArrayBufferView {
store<u8>(this.dataStart + <usize>index, value);
}

includes(searchElement: u8, fromIndex: i32 = 0): bool {
return INCLUDES<Uint8Array, u8>(this, searchElement, fromIndex);
}

indexOf(searchElement: u8, fromIndex: i32 = 0): i32 {
return INDEX_OF<Uint8Array, u8>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: u8, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Uint8Array, u8>(this, searchElement, fromIndex);
}

fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint8Array {
return FILL<Uint8Array, u8>(this, value, start, end);
}
Expand Down Expand Up @@ -198,6 +222,18 @@ export class Uint8ClampedArray extends ArrayBufferView {
store<u8>(this.dataStart + <usize>index, ~(<i32>value >> 31) & (((255 - value) >> 31) | value));
}

includes(searchElement: u8, fromIndex: i32 = 0): bool {
return INCLUDES<Uint8ClampedArray, u8>(this, searchElement, fromIndex);
}

indexOf(searchElement: u8, fromIndex: i32 = 0): i32 {
return INDEX_OF<Uint8ClampedArray, u8>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: u8, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Uint8ClampedArray, u8>(this, searchElement, fromIndex);
}

fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint8ClampedArray {
return FILL<Uint8ClampedArray, u8>(this, value, start, end);
}
Expand Down Expand Up @@ -280,6 +316,18 @@ export class Int16Array extends ArrayBufferView {
store<i16>(this.dataStart + (<usize>index << alignof<i16>()), value);
}

includes(searchElement: i16, fromIndex: i32 = 0): bool {
return INCLUDES<Int16Array, i16>(this, searchElement, fromIndex);
}

indexOf(searchElement: i16, fromIndex: i32 = 0): i32 {
return INDEX_OF<Int16Array, i16>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: i16, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Int16Array, i16>(this, searchElement, fromIndex);
}

fill(value: i32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int16Array {
return FILL<Int16Array, i16>(this, value, start, end);
}
Expand Down Expand Up @@ -362,6 +410,18 @@ export class Uint16Array extends ArrayBufferView {
store<u16>(this.dataStart + (<usize>index << alignof<u16>()), value);
}

includes(searchElement: u16, fromIndex: i32 = 0): bool {
return INCLUDES<Uint16Array, u16>(this, searchElement, fromIndex);
}

indexOf(searchElement: u16, fromIndex: i32 = 0): i32 {
return INDEX_OF<Uint16Array, u16>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: u16, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Uint16Array, u16>(this, searchElement, fromIndex);
}

fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint16Array {
return FILL<Uint16Array, u16>(this, value, start, end);
}
Expand Down Expand Up @@ -444,6 +504,18 @@ export class Int32Array extends ArrayBufferView {
store<i32>(this.dataStart + (<usize>index << alignof<i32>()), value);
}

includes(searchElement: i32, fromIndex: i32 = 0): bool {
return INCLUDES<Int32Array, i32>(this, searchElement, fromIndex);
}

indexOf(searchElement: i32, fromIndex: i32 = 0): i32 {
return INDEX_OF<Int32Array, i32>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: i32, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Int32Array, i32>(this, searchElement, fromIndex);
}

fill(value: i32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int32Array {
return FILL<Int32Array, i32>(this, value, start, end);
}
Expand Down Expand Up @@ -526,6 +598,18 @@ export class Uint32Array extends ArrayBufferView {
store<u32>(this.dataStart + (<usize>index << alignof<u32>()), value);
}

includes(searchElement: u32, fromIndex: i32 = 0): bool {
return INCLUDES<Uint32Array, u32>(this, searchElement, fromIndex);
}

indexOf(searchElement: u32, fromIndex: i32 = 0): i32 {
return INDEX_OF<Uint32Array, u32>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: u32, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Uint32Array, u32>(this, searchElement, fromIndex);
}

fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint32Array {
return FILL<Uint32Array, u32>(this, value, start, end);
}
Expand Down Expand Up @@ -608,6 +692,18 @@ export class Int64Array extends ArrayBufferView {
store<i64>(this.dataStart + (<usize>index << alignof<i64>()), value);
}

includes(searchElement: i64, fromIndex: i32 = 0): bool {
return INCLUDES<Int64Array, i64>(this, searchElement, fromIndex);
}

indexOf(searchElement: i64, fromIndex: i32 = 0): i32 {
return INDEX_OF<Int64Array, i64>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: i64, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Int64Array, i64>(this, searchElement, fromIndex);
}

fill(value: i64, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int64Array {
return FILL<Int64Array, i64>(this, value, start, end);
}
Expand Down Expand Up @@ -690,6 +786,18 @@ export class Uint64Array extends ArrayBufferView {
store<u64>(this.dataStart + (<usize>index << alignof<u64>()), value);
}

includes(searchElement: u64, fromIndex: i32 = 0): bool {
return INCLUDES<Uint64Array, u64>(this, searchElement, fromIndex);
}

indexOf(searchElement: u64, fromIndex: i32 = 0): i32 {
return INDEX_OF<Uint64Array, u64>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: u64, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Uint64Array, u64>(this, searchElement, fromIndex);
}

fill(value: u64, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint64Array {
return FILL<Uint64Array, u64>(this, value, start, end);
}
Expand Down Expand Up @@ -772,6 +880,18 @@ export class Float32Array extends ArrayBufferView {
store<f32>(this.dataStart + (<usize>index << alignof<f32>()), value);
}

includes(searchElement: f32, fromIndex: i32 = 0): bool {
return INCLUDES<Float32Array, f32>(this, searchElement, fromIndex);
}

indexOf(searchElement: f32, fromIndex: i32 = 0): i32 {
return INDEX_OF<Float32Array, f32>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: f32, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Float32Array, f32>(this, searchElement, fromIndex);
}

fill(value: f32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Float32Array {
return FILL<Float32Array, f32>(this, value, start, end);
}
Expand Down Expand Up @@ -854,6 +974,18 @@ export class Float64Array extends ArrayBufferView {
store<f64>(this.dataStart + (<usize>index << alignof<f64>()), value);
}

includes(searchElement: f64, fromIndex: i32 = 0): bool {
return INCLUDES<Float64Array, f64>(this, searchElement, fromIndex);
}

indexOf(searchElement: f64, fromIndex: i32 = 0): i32 {
return INDEX_OF<Float64Array, f64>(this, searchElement, fromIndex);
}

lastIndexOf(searchElement: f64, fromIndex: i32 = this.length): i32 {
return LAST_INDEX_OF<Float64Array, f64>(this, searchElement, fromIndex);
}

fill(value: f64, start: i32 = 0, end: i32 = i32.MAX_VALUE): Float64Array {
return FILL<Float64Array, f64>(this, value, start, end);
}
Expand Down Expand Up @@ -1027,6 +1159,55 @@ function FIND_INDEX<TArray extends ArrayBufferView, T>(
return -1;
}

// @ts-ignore: decorator
@inline
function INCLUDES<TArray extends ArrayBufferView, T>(
array: TArray,
searchElement: T,
fromIndex: i32,
): bool {
return INDEX_OF<TArray, T>(array, searchElement, fromIndex) >= 0;
}

// @ts-ignore: decorator
@inline
function INDEX_OF<TArray extends ArrayBufferView, T>(
array: TArray,
searchElement: 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 dataStart = array.dataStart;
while (index < length) {
if (load<T>(dataStart + (index << alignof<T>())) == searchElement) return <i32>index;
++index;
}
return -1;
}

// @ts-ignore: decorator
@inline
function LAST_INDEX_OF<TArray extends ArrayBufferView, T>(
array: TArray,
searchElement: 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 dataStart = array.dataStart;
while (index >= 0) {
if (load<T>(dataStart + (index << alignof<T>())) == searchElement) return <i32>index;
--index;
}
return -1;
}

// @ts-ignore: decorator
@inline
function SOME<TArray extends ArrayBufferView, T>(
Expand Down Expand Up @@ -1070,9 +1251,9 @@ function FOREACH<TArray extends ArrayBufferView, T>(
@inline
export function REVERSE<TArray extends ArrayBufferView, T>(array: TArray): TArray {
var dataStart = array.dataStart;
for (let front = 0, back = array.length - 1; front < back; ++front, --back) {
let frontPtr = dataStart + (<usize>front << alignof<T>());
let backPtr = dataStart + (<usize>back << alignof<T>());
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 temp = load<T>(frontPtr);
store<T>(frontPtr, load<T>(backPtr));
store<T>(backPtr, temp);
Expand Down
2 changes: 1 addition & 1 deletion tests/compiler/std/dataview.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1609,7 +1609,7 @@
if
i32.const 280
i32.const 376
i32.const 115
i32.const 127
i32.const 44
call $~lib/builtins/abort
unreachable
Expand Down
2 changes: 1 addition & 1 deletion tests/compiler/std/dataview.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -3302,7 +3302,7 @@
if
i32.const 280
i32.const 376
i32.const 115
i32.const 127
i32.const 44
call $~lib/builtins/abort
unreachable
Expand Down

0 comments on commit f48f3c9

Please sign in to comment.