import { ALLOC, REGISTER, LINK, ArrayBufferView } from "./runtime"; import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort"; function clampToByte(value: i32): i32 { return ~(value >> 31) & (((255 - value) >> 31) | value); // & 255 } export class Int8Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength; } fill(value: i32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int8Array { return FILL(this, value, start, end); } sort(comparator: (a: i8, b: i8) => i32 = COMPARATOR()): Int8Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Int8Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: i8, index: i32, array: Int8Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: i8, index: i32, array: Int8Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: i8, index: i32, self: Int8Array) => i8): Int8Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: i8, index: i32, self: Int8Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: i8, index: i32, self: Int8Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: i8, index: i32, self: Int8Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: i8, index: i32, self: Int8Array) => void): void { FOREACH(this, callbackfn); } } export class Uint8Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get length(): i32 { return this.byteLength; } fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint8Array { return FILL(this, value, start, end); } sort(comparator: (a: u8, b: u8) => i32 = COMPARATOR()): Uint8Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Uint8Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: u8, index: i32, array: Uint8Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: u8, index: i32, array: Uint8Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: u8, index: i32, self: Uint8Array) => u8): Uint8Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: u8, index: i32, self: Uint8Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: u8, index: i32, self: Uint8Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: u8, index: i32, self: Uint8Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: u8, index: i32, self: Uint8Array) => void): void { FOREACH(this, callbackfn); } } export class Uint8ClampedArray extends Uint8Array { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint8ClampedArray { return changetype(super.fill(value, start, end)); // safe because '.fill' reuses 'this' } sort(comparator: (a: u8, b: u8) => i32 = COMPARATOR()): Uint8ClampedArray { return changetype(super.sort(comparator)); // safe because '.sort' reuses 'this' } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Uint8ClampedArray { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: u8, index: i32, array: Uint8ClampedArray) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: u8, index: i32, array: Uint8ClampedArray) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: u8, index: i32, self: Uint8ClampedArray) => u8): Uint8ClampedArray { return MAP(this, callbackfn); } findIndex(callbackfn: (value: u8, index: i32, self: Uint8ClampedArray) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: u8, index: i32, self: Uint8ClampedArray) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: u8, index: i32, self: Uint8ClampedArray) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: u8, index: i32, self: Uint8ClampedArray) => void): void { FOREACH(this, callbackfn); } } export class Int16Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 1; } fill(value: i32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int16Array { return FILL(this, value, start, end); } sort(comparator: (a: i16, b: i16) => i32 = COMPARATOR()): Int16Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Int16Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: i16, index: i32, array: Int16Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: i16, index: i32, array: Int16Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: i16, index: i32, self: Int16Array) => i16): Int16Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: i16, index: i32, self: Int16Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: i16, index: i32, self: Int16Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: i16, index: i32, self: Int16Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: i16, index: i32, self: Int16Array) => void): void { FOREACH(this, callbackfn); } } export class Uint16Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 1; } fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint16Array { return FILL(this, value, start, end); } sort(comparator: (a: u16, b: u16) => i32 = COMPARATOR()): Uint16Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Uint16Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: u16, index: i32, array: Uint16Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: u16, index: i32, array: Uint16Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: u16, index: i32, self: Uint16Array) => u16): Uint16Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: u16, index: i32, self: Uint16Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: u16, index: i32, self: Uint16Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: u16, index: i32, self: Uint16Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: u16, index: i32, self: Uint16Array) => void): void { FOREACH(this, callbackfn); } } export class Int32Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 2; } fill(value: i32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int32Array { return FILL(this, value, start, end); } sort(comparator: (a: i32, b: i32) => i32 = COMPARATOR()): Int32Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Int32Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: i32, index: i32, array: Int32Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: i32, index: i32, array: Int32Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: i32, index: i32, self: Int32Array) => i32): Int32Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: i32, index: i32, self: Int32Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: i32, index: i32, self: Int32Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: i32, index: i32, self: Int32Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: i32, index: i32, self: Int32Array) => void): void { FOREACH(this, callbackfn); } } export class Uint32Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 2; } fill(value: u32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint32Array { return FILL(this, value, start, end); } sort(comparator: (a: u32, b: u32) => i32 = COMPARATOR()): Uint32Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Uint32Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: u32, index: i32, array: Uint32Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: u32, index: i32, array: Uint32Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: u32, index: i32, self: Uint32Array) => u32): Uint32Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: u32, index: i32, self: Uint32Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: u32, index: i32, self: Uint32Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: u32, index: i32, self: Uint32Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: u32, index: i32, self: Uint32Array) => void): void { FOREACH(this, callbackfn); } } export class Int64Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 3; } fill(value: i64, start: i32 = 0, end: i32 = i32.MAX_VALUE): Int64Array { return FILL(this, value, start, end); } sort(comparator: (a: i64, b: i64) => i32 = COMPARATOR()): Int64Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Int64Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: i64, index: i32, array: Int64Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: i64, index: i32, array: Int64Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: i64, index: i32, self: Int64Array) => i64): Int64Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: i64, index: i32, self: Int64Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: i64, index: i32, self: Int64Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: i64, index: i32, self: Int64Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: i64, index: i32, self: Int64Array) => void): void { FOREACH(this, callbackfn); } } export class Uint64Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 3; } fill(value: u64, start: i32 = 0, end: i32 = i32.MAX_VALUE): Uint64Array { return FILL(this, value, start, end); } sort(comparator: (a: u64, b: u64) => i32 = COMPARATOR()): Uint64Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Uint64Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: u64, index: i32, array: Uint64Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: u64, index: i32, array: Uint64Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: u64, index: i32, self: Uint64Array) => u64): Uint64Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: u64, index: i32, self: Uint64Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: u64, index: i32, self: Uint64Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: u64, index: i32, self: Uint64Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: u64, index: i32, self: Uint64Array) => void): void { FOREACH(this, callbackfn); } } export class Float32Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 2; } fill(value: f32, start: i32 = 0, end: i32 = i32.MAX_VALUE): Float32Array { return FILL(this, value, start, end); } sort(comparator: (a: f32, b: f32) => i32 = COMPARATOR()): Float32Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Float32Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: f32, index: i32, array: Float32Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: f32, index: i32, array: Float32Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: f32, index: i32, self: Float32Array) => f32): Float32Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: f32, index: i32, self: Float32Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: f32, index: i32, self: Float32Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: f32, index: i32, self: Float32Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: f32, index: i32, self: Float32Array) => void): void { FOREACH(this, callbackfn); } } export class Float64Array extends ArrayBufferView { @lazy static readonly BYTES_PER_ELEMENT: usize = sizeof(); constructor(length: i32) { super(length, alignof()); } get buffer(): ArrayBuffer { return this.data; } get length(): i32 { return this.byteLength >>> 3; } fill(value: f64, start: i32 = 0, end: i32 = i32.MAX_VALUE): Float64Array { return FILL(this, value, start, end); } sort(comparator: (a: f64, b: f64) => i32 = COMPARATOR()): Float64Array { return SORT(this, comparator); } subarray(begin: i32 = 0, end: i32 = 0x7fffffff): Float64Array { return SUBARRAY(this, begin, end); } reduce( callbackfn: (accumulator: T, value: f64, index: i32, array: Float64Array) => T, initialValue: T, ): T { return REDUCE(this, callbackfn, initialValue); } reduceRight( callbackfn: (accumulator: T, value: f64, index: i32, array: Float64Array) => T, initialValue: T, ): T { return REDUCE_RIGHT(this, callbackfn, initialValue); } map(callbackfn: (value: f64, index: i32, self: Float64Array) => f64): Float64Array { return MAP(this, callbackfn); } findIndex(callbackfn: (value: f64, index: i32, self: Float64Array) => bool): i32 { return FIND_INDEX(this, callbackfn); } some(callbackfn: (value: f64, index: i32, self: Float64Array) => bool): bool { return SOME(this, callbackfn); } every(callbackfn: (value: f64, index: i32, self: Float64Array) => bool): bool { return EVERY(this, callbackfn); } forEach(callbackfn: (value: f64, index: i32, self: Float64Array) => void): void { FOREACH(this, callbackfn); } } @inline function FILL( array: TArray, value: native, start: i32, end: i32 ): TArray { var dataStart = array.dataStart; var length = array.length; start = start < 0 ? max(length + start, 0) : min(start, length); end = end < 0 ? max(length + end, 0) : min(end, length); if (sizeof() == 1) { if (start < end) memory.fill(dataStart + start, value, (end - start)); } else { for (; start < end; ++start) { store(dataStart + (start << alignof()), value); } } return array; } @inline function SORT( array: TArray, comparator: (a: T, b: T) => i32 ): TArray { var length = array.length; if (length <= 1) return array; var base = array.dataStart; if (length == 2) { let a: T = load(base, sizeof()); // a = arr[1] let b: T = load(base); // b = arr[0] if (comparator(a, b) < 0) { store(base, b, sizeof()); // arr[1] = b store(base, a); // arr[0] = a } return array; } SORT_IMPL(base, length, comparator); return array; } @inline function SUBARRAY( array: TArray, begin: i32, end: i32 ): TArray { var buffer = array.data; var length = array.length; if (begin < 0) begin = max(length + begin, 0); else begin = min(begin, length); if (end < 0) end = max(length + end, begin); else end = max(min(end, length), begin); var out = ALLOC(offsetof()); store(out, buffer, offsetof("buffer")); store(out, array.dataStart + (begin << alignof()) , offsetof("dataStart")); store(out, array.dataEnd + ((end - begin) << alignof()), offsetof("dataEnd")); LINK(buffer, REGISTER(out)); // register first, then link return changetype(out); } @inline function REDUCE( array: TArray, callbackfn: (accumulator: TRet, value: T, index: i32, array: TArray) => TRet, initialValue: TRet ): TRet { var dataStart = array.dataStart; for (let i = 0, k = array.length; i < k; i++) { initialValue = callbackfn(initialValue, load(dataStart + (i << alignof())), i, array); } return initialValue; } @inline function REDUCE_RIGHT( array: TArray, callbackfn: (accumulator: TRet, value: T, index: i32, array: TArray) => TRet, initialValue: TRet ): TRet { var dataStart = array.dataStart; for (let i = array.length - 1; i >= 0; i--) { initialValue = callbackfn(initialValue, load(dataStart + (i << alignof())), i, array); } return initialValue; } @inline function MAP( array: TArray, callbackfn: (value: T, index: i32, self: TArray) => T, ): TArray { var length = array.length; var dataStart = array.dataStart; var out = instantiate(length); var outDataStart = out.dataStart; for (let i = 0; i < length; i++) { store( outDataStart + (i << alignof()), callbackfn(load(dataStart + (i << alignof())), i, array) ); } return out; } @inline function FIND_INDEX( array: TArray, callbackfn: (value: T, index: i32, array: TArray) => bool, ): i32 { var dataStart = array.dataStart; for (let i = 0, k = array.length; i < k; i++) { if (callbackfn(load(dataStart + (i << alignof())), i, array)) return i; } return -1; } @inline function SOME( array: TArray, callbackfn: (value: T, index: i32, array: TArray) => bool, ): bool { var dataStart = array.dataStart; for (let i = 0, k = array.length; i < k; i++) { if (callbackfn(load(dataStart + (i << alignof())), i, array)) return true; } return false; } @inline function EVERY( array: TArray, callbackfn: (value: T, index: i32, array: TArray) => bool, ): bool { var dataStart = array.dataStart; for (let i = 0, k = array.length; i < k; i++) { if (callbackfn(load(dataStart + (i << alignof())), i, array)) continue; return false; } return true; } @inline function FOREACH( array: TArray, callbackfn: (value: T, index: i32, array: TArray) => void, ): void { var dataStart = array.dataStart; for (let i = 0, k = array.length; i < k; i++) { callbackfn(load(dataStart + (i << alignof())), i, array); } }