mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-14 15:31:31 +00:00
Implement optional type parameters (#360)
* Add a NATIVE<T> macro type to simplify use of a native WebAssembly type * Add default type parameters for internal helpers for explicit loads and stores * Unify loadUnsafe/loadUnsafeWithOffset etc. into one * Renamed loadUnsafe etc. into just LOAD, like a macro * Implement parsing of index signatures, but ignore them, for properly linting code * Refactor TypedArray<T> to use macros
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import {
|
||||
loadUnsafeWithOffset,
|
||||
storeUnsafeWithOffset
|
||||
LOAD,
|
||||
STORE
|
||||
} from "./arraybuffer";
|
||||
|
||||
import {
|
||||
@ -52,15 +52,15 @@ export function insertionSort<T>(
|
||||
comparator: (a: T, b: T) => i32
|
||||
): void {
|
||||
for (let i = 0; i < length; i++) {
|
||||
let a = loadUnsafeWithOffset<T,T>(buffer, i, byteOffset); // a = arr[i]
|
||||
let a = LOAD<T>(buffer, i, byteOffset); // a = arr[i]
|
||||
let j = i - 1;
|
||||
while (j >= 0) {
|
||||
let b = loadUnsafeWithOffset<T,T>(buffer, j, byteOffset); // b = arr[j]
|
||||
let b = LOAD<T>(buffer, j, byteOffset); // b = arr[j]
|
||||
if (comparator(a, b) < 0) {
|
||||
storeUnsafeWithOffset<T,T>(buffer, j-- + 1, b, byteOffset); // arr[j + 1] = b
|
||||
STORE<T>(buffer, j-- + 1, b, byteOffset); // arr[j + 1] = b
|
||||
} else break;
|
||||
}
|
||||
storeUnsafeWithOffset<T,T>(buffer, j + 1, a, byteOffset); // arr[j + 1] = a
|
||||
STORE<T>(buffer, j + 1, a, byteOffset); // arr[j + 1] = a
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,37 +84,37 @@ export function weakHeapSort<T>(
|
||||
while ((j & 1) == (load<u32>(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1;
|
||||
|
||||
let p = j >> 1;
|
||||
let a = loadUnsafeWithOffset<T,T>(buffer, p, byteOffset); // a = arr[p]
|
||||
let b = loadUnsafeWithOffset<T,T>(buffer, i, byteOffset); // b = arr[i]
|
||||
let a = LOAD<T>(buffer, p, byteOffset); // a = arr[p]
|
||||
let b = LOAD<T>(buffer, i, byteOffset); // b = arr[i]
|
||||
if (comparator(a, b) < 0) {
|
||||
store<u32>(
|
||||
bitset + (i >> 5 << shift32),
|
||||
load<u32>(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31))
|
||||
);
|
||||
storeUnsafeWithOffset<T,T>(buffer, i, a, byteOffset); // arr[i] = a
|
||||
storeUnsafeWithOffset<T,T>(buffer, p, b, byteOffset); // arr[p] = b
|
||||
STORE<T>(buffer, i, a, byteOffset); // arr[i] = a
|
||||
STORE<T>(buffer, p, b, byteOffset); // arr[p] = b
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = length - 1; i >= 2; i--) {
|
||||
let a = loadUnsafeWithOffset<T,T>(buffer, 0, byteOffset);
|
||||
storeUnsafeWithOffset<T,T>(buffer, 0, loadUnsafeWithOffset<T,T>(buffer, i, byteOffset), byteOffset);
|
||||
storeUnsafeWithOffset<T,T>(buffer, i, a, byteOffset);
|
||||
let a = LOAD<T>(buffer, 0, byteOffset);
|
||||
STORE<T>(buffer, 0, LOAD<T>(buffer, i, byteOffset), byteOffset);
|
||||
STORE<T>(buffer, i, a, byteOffset);
|
||||
|
||||
let x = 1, y: i32;
|
||||
while ((y = (x << 1) + ((load<u32>(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y;
|
||||
|
||||
while (x > 0) {
|
||||
a = loadUnsafeWithOffset<T,T>(buffer, 0, byteOffset); // a = arr[0]
|
||||
let b = loadUnsafeWithOffset<T,T>(buffer, x, byteOffset); // b = arr[x]
|
||||
a = LOAD<T>(buffer, 0, byteOffset); // a = arr[0]
|
||||
let b = LOAD<T>(buffer, x, byteOffset); // b = arr[x]
|
||||
|
||||
if (comparator(a, b) < 0) {
|
||||
store<u32>(
|
||||
bitset + (x >> 5 << shift32),
|
||||
load<u32>(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31))
|
||||
);
|
||||
storeUnsafeWithOffset<T,T>(buffer, x, a, byteOffset); // arr[x] = a
|
||||
storeUnsafeWithOffset<T,T>(buffer, 0, b, byteOffset); // arr[0] = b
|
||||
STORE<T>(buffer, x, a, byteOffset); // arr[x] = a
|
||||
STORE<T>(buffer, 0, b, byteOffset); // arr[0] = b
|
||||
}
|
||||
x >>= 1;
|
||||
}
|
||||
@ -122,7 +122,7 @@ export function weakHeapSort<T>(
|
||||
|
||||
memory.free(bitset);
|
||||
|
||||
var t = loadUnsafeWithOffset<T,T>(buffer, 1, byteOffset); // t = arr[1]
|
||||
storeUnsafeWithOffset<T,T>(buffer, 1, loadUnsafeWithOffset<T,T>(buffer, 0, byteOffset), byteOffset);
|
||||
storeUnsafeWithOffset<T,T>(buffer, 0, t, byteOffset); // arr[0] = t
|
||||
var t = LOAD<T>(buffer, 1, byteOffset); // t = arr[1]
|
||||
STORE<T>(buffer, 1, LOAD<T>(buffer, 0, byteOffset), byteOffset);
|
||||
STORE<T>(buffer, 0, t, byteOffset); // arr[0] = t
|
||||
}
|
||||
|
@ -71,33 +71,13 @@ export function reallocateUnsafe(buffer: ArrayBuffer, newByteLength: i32): Array
|
||||
// * `i32.load8` ^= `<i32>load<i8>(...)` that reads an i8 but returns an i32, or
|
||||
// * `i64.load32_s` ^= `<i64>load<i32>(...)`) that reads a 32-bit as a 64-bit integer
|
||||
//
|
||||
// without having to emit an additional instruction for conversion purposes. This is useful for
|
||||
// small integers only of course. When dealing with reference types like classes, both parameters
|
||||
// are usually the same, even though it looks ugly.
|
||||
//
|
||||
// TODO: is there a better way to model this?
|
||||
// without having to emit an additional instruction for conversion purposes. The second parameter
|
||||
// can be omitted for references and other loads and stores that simply return the exact type.
|
||||
|
||||
@inline export function loadUnsafe<T,TOut>(buffer: ArrayBuffer, index: i32): TOut {
|
||||
return <TOut>load<T>(changetype<usize>(buffer) + (<usize>index << alignof<T>()), HEADER_SIZE);
|
||||
@inline export function LOAD<T,TOut = T>(buffer: ArrayBuffer, index: i32, byteOffset: i32 = 0): TOut {
|
||||
return <TOut>load<T>(changetype<usize>(buffer) + (<usize>index << alignof<T>()) + <usize>byteOffset, HEADER_SIZE);
|
||||
}
|
||||
|
||||
@inline export function storeUnsafe<T,TIn>(buffer: ArrayBuffer, index: i32, value: TIn): void {
|
||||
store<T>(changetype<usize>(buffer) + (<usize>index << alignof<T>()), value, HEADER_SIZE);
|
||||
}
|
||||
|
||||
@inline export function loadUnsafeWithOffset<T,TOut>(
|
||||
buffer: ArrayBuffer,
|
||||
index: i32,
|
||||
byteOffset: i32
|
||||
): TOut {
|
||||
return <TOut>load<T>(changetype<usize>(buffer) + <usize>byteOffset + (<usize>index << alignof<T>()), HEADER_SIZE);
|
||||
}
|
||||
|
||||
@inline export function storeUnsafeWithOffset<T,TIn>(
|
||||
buffer: ArrayBuffer,
|
||||
index: i32,
|
||||
value: TIn,
|
||||
byteOffset: i32
|
||||
): void {
|
||||
store<T>(changetype<usize>(buffer) + <usize>byteOffset + (<usize>index << alignof<T>()), value, HEADER_SIZE);
|
||||
@inline export function STORE<T,TIn = T>(buffer: ArrayBuffer, index: i32, value: TIn, byteOffset: i32 = 0): void {
|
||||
store<T>(changetype<usize>(buffer) + (<usize>index << alignof<T>()) + <usize>byteOffset, value, HEADER_SIZE);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
} from "./string";
|
||||
|
||||
import {
|
||||
loadUnsafe
|
||||
LOAD
|
||||
} from "./arraybuffer";
|
||||
|
||||
export const MAX_DOUBLE_LENGTH = 28;
|
||||
@ -124,7 +124,7 @@ export function decimalCount32(value: u32): u32 {
|
||||
let t = l * 1233 >>> 12; // log10
|
||||
|
||||
let lutbuf = <ArrayBuffer>POWERS10().buffer_;
|
||||
let power = loadUnsafe<u32,u32>(lutbuf, t);
|
||||
let power = LOAD<u32>(lutbuf, t);
|
||||
t -= <u32>(value < power);
|
||||
return t + 1;
|
||||
} else {
|
||||
@ -154,7 +154,7 @@ export function decimalCount64(value: u64): u32 {
|
||||
let t = l * 1233 >>> 12; // log10
|
||||
|
||||
let lutbuf = <ArrayBuffer>POWERS10().buffer_;
|
||||
let power = loadUnsafe<u32,u64>(lutbuf, t - 10);
|
||||
let power = LOAD<u32,u64>(lutbuf, t - 10);
|
||||
t -= <u32>(value < 10000000000 * power);
|
||||
return t + 1;
|
||||
} else {
|
||||
@ -188,8 +188,8 @@ function utoa32_lut(buffer: usize, num: u32, offset: usize): void {
|
||||
let d1 = r / 100;
|
||||
let d2 = r % 100;
|
||||
|
||||
let digits1 = loadUnsafe<u32,u64>(lutbuf, d1);
|
||||
let digits2 = loadUnsafe<u32,u64>(lutbuf, d2);
|
||||
let digits1 = LOAD<u32,u64>(lutbuf, d1);
|
||||
let digits2 = LOAD<u32,u64>(lutbuf, d2);
|
||||
|
||||
offset -= 4;
|
||||
store<u64>(buffer + (offset << 1), digits1 | (digits2 << 32), STRING_HEADER_SIZE);
|
||||
@ -200,13 +200,13 @@ function utoa32_lut(buffer: usize, num: u32, offset: usize): void {
|
||||
let d1 = num % 100;
|
||||
num = t;
|
||||
offset -= 2;
|
||||
let digits = loadUnsafe<u32,u32>(lutbuf, d1);
|
||||
let digits = LOAD<u32>(lutbuf, d1);
|
||||
store<u32>(buffer + (offset << 1), digits, STRING_HEADER_SIZE);
|
||||
}
|
||||
|
||||
if (num >= 10) {
|
||||
offset -= 2;
|
||||
let digits = loadUnsafe<u32,u32>(lutbuf, num);
|
||||
let digits = LOAD<u32>(lutbuf, num);
|
||||
store<u32>(buffer + (offset << 1), digits, STRING_HEADER_SIZE);
|
||||
} else {
|
||||
offset -= 1;
|
||||
@ -231,14 +231,14 @@ function utoa64_lut(buffer: usize, num: u64, offset: usize): void {
|
||||
let c1 = c / 100;
|
||||
let c2 = c % 100;
|
||||
|
||||
let digits1 = loadUnsafe<u32,u64>(lutbuf, c1);
|
||||
let digits2 = loadUnsafe<u32,u64>(lutbuf, c2);
|
||||
let digits1 = LOAD<u32,u64>(lutbuf, c1);
|
||||
let digits2 = LOAD<u32,u64>(lutbuf, c2);
|
||||
|
||||
offset -= 4;
|
||||
store<u64>(buffer + (offset << 1), digits1 | (digits2 << 32), STRING_HEADER_SIZE);
|
||||
|
||||
digits1 = loadUnsafe<u32,u64>(lutbuf, b1);
|
||||
digits2 = loadUnsafe<u32,u64>(lutbuf, b2);
|
||||
digits1 = LOAD<u32,u64>(lutbuf, b1);
|
||||
digits2 = LOAD<u32,u64>(lutbuf, b2);
|
||||
|
||||
offset -= 4;
|
||||
store<u64>(buffer + (offset << 1), digits1 | (digits2 << 32), STRING_HEADER_SIZE);
|
||||
@ -438,8 +438,8 @@ function getCachedPower(minExp: i32): void {
|
||||
_K = 348 - (index << 3); // decimal exponent no need lookup table
|
||||
var frcPowers = <ArrayBuffer>FRC_POWERS().buffer_;
|
||||
var expPowers = <ArrayBuffer>EXP_POWERS().buffer_;
|
||||
_frc_pow = loadUnsafe<u64,u64>(frcPowers, index);
|
||||
_exp_pow = loadUnsafe<i16,i32>(expPowers, index);
|
||||
_frc_pow = LOAD<u64>(frcPowers, index);
|
||||
_exp_pow = LOAD<i16,i32>(expPowers, index);
|
||||
}
|
||||
|
||||
@inline
|
||||
@ -513,7 +513,7 @@ function genDigits(buffer: usize, w_frc: u64, w_exp: i32, mp_frc: u64, mp_exp: i
|
||||
let tmp = ((<u64>p1) << one_exp) + p2;
|
||||
if (tmp <= delta) {
|
||||
_K += kappa;
|
||||
grisuRound(buffer, len, delta, tmp, loadUnsafe<u32,u64>(powers10, kappa) << one_exp, wp_w_frc);
|
||||
grisuRound(buffer, len, delta, tmp, LOAD<u32,u64>(powers10, kappa) << one_exp, wp_w_frc);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@ -529,7 +529,7 @@ function genDigits(buffer: usize, w_frc: u64, w_exp: i32, mp_frc: u64, mp_exp: i
|
||||
--kappa;
|
||||
if (p2 < delta) {
|
||||
_K += kappa;
|
||||
wp_w_frc *= loadUnsafe<u32,u64>(powers10, -kappa);
|
||||
wp_w_frc *= LOAD<u32,u64>(powers10, -kappa);
|
||||
grisuRound(buffer, len, delta, p2, one_frc, wp_w_frc);
|
||||
return len;
|
||||
}
|
||||
|
@ -2,21 +2,18 @@ import {
|
||||
HEADER_SIZE as AB_HEADER_SIZE,
|
||||
MAX_BLENGTH as AB_MAX_BLENGTH,
|
||||
allocateUnsafe,
|
||||
loadUnsafeWithOffset,
|
||||
storeUnsafeWithOffset
|
||||
LOAD,
|
||||
STORE
|
||||
} from "./arraybuffer";
|
||||
|
||||
import {
|
||||
insertionSort,
|
||||
weakHeapSort,
|
||||
defaultComparator
|
||||
weakHeapSort
|
||||
} from "./array";
|
||||
|
||||
// The internal TypedArray class uses two type parameters for the same reason as `loadUnsafe` and
|
||||
// `storeUnsafe` in 'internal/arraybuffer.ts'. See the documentation there for details.
|
||||
|
||||
/** Typed array base class. Not a global object. */
|
||||
export abstract class TypedArray<T,TNative> {
|
||||
export abstract class TypedArray<T> {
|
||||
[key: number]: T; // compatibility only
|
||||
|
||||
readonly buffer: ArrayBuffer;
|
||||
readonly byteOffset: i32;
|
||||
@ -41,116 +38,142 @@ export abstract class TypedArray<T,TNative> {
|
||||
@operator("[]")
|
||||
protected __get(index: i32): T {
|
||||
if (<u32>index >= <u32>(this.byteLength >>> alignof<T>())) throw new Error("Index out of bounds");
|
||||
return loadUnsafeWithOffset<T,T>(this.buffer, index, this.byteOffset);
|
||||
return LOAD<T>(this.buffer, index, this.byteOffset);
|
||||
}
|
||||
|
||||
@inline @operator("{}")
|
||||
protected __unchecked_get(index: i32): T {
|
||||
return loadUnsafeWithOffset<T,T>(this.buffer, index, this.byteOffset);
|
||||
return LOAD<T>(this.buffer, index, this.byteOffset);
|
||||
}
|
||||
|
||||
@operator("[]=")
|
||||
protected __set(index: i32, value: TNative): void {
|
||||
protected __set(index: i32, value: NATIVE<T>): void {
|
||||
if (<u32>index >= <u32>(this.byteLength >>> alignof<T>())) throw new Error("Index out of bounds");
|
||||
storeUnsafeWithOffset<T,TNative>(this.buffer, index, value, this.byteOffset);
|
||||
STORE<T,NATIVE<T>>(this.buffer, index, value, this.byteOffset);
|
||||
}
|
||||
|
||||
@inline @operator("{}=")
|
||||
protected __unchecked_set(index: i32, value: TNative): void {
|
||||
storeUnsafeWithOffset<T,TNative>(this.buffer, index, value, this.byteOffset);
|
||||
protected __unchecked_set(index: i32, value: NATIVE<T>): void {
|
||||
STORE<T,NATIVE<T>>(this.buffer, index, value, this.byteOffset);
|
||||
}
|
||||
|
||||
// copyWithin(target: i32, start: i32, end: i32 = this.length): this
|
||||
}
|
||||
|
||||
fill(value: TNative, start: i32 = 0, end: i32 = i32.MAX_VALUE): this {
|
||||
var buffer = this.buffer;
|
||||
var byteOffset = this.byteOffset;
|
||||
var len = this.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(
|
||||
changetype<usize>(buffer) + start + byteOffset + AB_HEADER_SIZE,
|
||||
<u8>value,
|
||||
<usize>(end - start)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (; start < end; ++start) {
|
||||
storeUnsafeWithOffset<T,TNative>(buffer, start, value, byteOffset);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@inline
|
||||
subarray(begin: i32 = 0, end: i32 = i32.MAX_VALUE): TypedArray<T,TNative> {
|
||||
var length = this.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 slice = memory.allocate(offsetof<this>());
|
||||
store<usize>(slice, this.buffer, offsetof<this>("buffer"));
|
||||
store<i32>(slice, this.byteOffset + (begin << alignof<T>()), offsetof<this>("byteOffset"));
|
||||
store<i32>(slice, (end - begin) << alignof<T>(), offsetof<this>("byteLength"));
|
||||
return changetype<this>(slice);
|
||||
}
|
||||
|
||||
sort(comparator: (a: T, b: T) => i32 = defaultComparator<T>()): this {
|
||||
var byteOffset = this.byteOffset;
|
||||
var length = this.length;
|
||||
if (length <= 1) return this;
|
||||
var buffer = this.buffer;
|
||||
if (length == 2) {
|
||||
let a = loadUnsafeWithOffset<T,T>(buffer, 1, byteOffset);
|
||||
let b = loadUnsafeWithOffset<T,T>(buffer, 0, byteOffset);
|
||||
if (comparator(a, b) < 0) {
|
||||
storeUnsafeWithOffset<T,T>(buffer, 1, b, byteOffset);
|
||||
storeUnsafeWithOffset<T,T>(buffer, 0, a, byteOffset);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
if (isReference<T>()) {
|
||||
// TODO replace this to faster stable sort (TimSort) when it implemented
|
||||
insertionSort<T>(buffer, byteOffset, length, comparator);
|
||||
return this;
|
||||
} else {
|
||||
if (length < 256) {
|
||||
insertionSort<T>(buffer, byteOffset, length, comparator);
|
||||
} else {
|
||||
weakHeapSort<T>(buffer, byteOffset, length, comparator);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TypedArray reduce implementation. This is a method that will be called from the parent,
|
||||
* passing types down from the child class using the typed parameters TypedArrayType and
|
||||
* ReturnType respectively. This implementation requires an initial value, and the direction.
|
||||
* When direction is true, reduce will reduce from the right side.
|
||||
*/
|
||||
@inline
|
||||
protected reduce_internal<TypedArrayType, ReturnType>(
|
||||
callbackfn: (accumulator: ReturnType, value: T, index: i32, array: TypedArrayType) => ReturnType,
|
||||
array: TypedArrayType,
|
||||
initialValue: ReturnType,
|
||||
direction: bool = false,
|
||||
): ReturnType {
|
||||
var index: i32 = direction ? this.length - 1 : 0;
|
||||
var length: i32 = direction ? -1 : this.length;
|
||||
while (index != length) {
|
||||
initialValue = callbackfn(
|
||||
initialValue,
|
||||
this.__unchecked_get(index),
|
||||
index,
|
||||
array,
|
||||
@inline
|
||||
export function FILL<TArray extends TypedArray<T>, T>(
|
||||
array: TArray,
|
||||
value: NATIVE<T>,
|
||||
start: i32,
|
||||
end: i32
|
||||
): TArray {
|
||||
var buffer = array.buffer;
|
||||
var byteOffset = array.byteOffset;
|
||||
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(
|
||||
changetype<usize>(buffer) + start + byteOffset + AB_HEADER_SIZE,
|
||||
<u8>value,
|
||||
<usize>(end - start)
|
||||
);
|
||||
index = direction ? index - 1 : index + 1;
|
||||
}
|
||||
return initialValue;
|
||||
} else {
|
||||
for (; start < end; ++start) {
|
||||
STORE<T,NATIVE<T>>(buffer, start, value, byteOffset);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@inline
|
||||
export function SORT<TArray extends TypedArray<T>, T>(
|
||||
array: TArray,
|
||||
comparator: (a: T, b: T) => i32
|
||||
): TArray {
|
||||
var byteOffset = array.byteOffset;
|
||||
var length = array.length;
|
||||
if (length <= 1) return array;
|
||||
var buffer = array.buffer;
|
||||
if (length == 2) {
|
||||
let a = LOAD<T>(buffer, 1, byteOffset);
|
||||
let b = LOAD<T>(buffer, 0, byteOffset);
|
||||
if (comparator(a, b) < 0) {
|
||||
STORE<T>(buffer, 1, b, byteOffset);
|
||||
STORE<T>(buffer, 0, a, byteOffset);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
if (isReference<T>()) {
|
||||
// TODO replace this to faster stable sort (TimSort) when it implemented
|
||||
insertionSort<T>(buffer, byteOffset, length, comparator);
|
||||
return array;
|
||||
} else {
|
||||
if (length < 256) {
|
||||
insertionSort<T>(buffer, byteOffset, length, comparator);
|
||||
} else {
|
||||
weakHeapSort<T>(buffer, byteOffset, length, comparator);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
@inline
|
||||
export function SUBARRAY<TArray extends TypedArray<T>, T>(
|
||||
array: TArray,
|
||||
begin: i32,
|
||||
end: i32
|
||||
): TArray {
|
||||
var length = <i32>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 slice = memory.allocate(offsetof<TArray>());
|
||||
store<usize>(slice, array.buffer, offsetof<TArray>("buffer"));
|
||||
store<i32>(slice, <i32>array.byteOffset + (begin << alignof<T>()), offsetof<TArray>("byteOffset"));
|
||||
store<i32>(slice, (end - begin) << alignof<T>(), offsetof<TArray>("byteLength"));
|
||||
return changetype<TArray>(slice);
|
||||
}
|
||||
|
||||
@inline
|
||||
export function REDUCE<TArray extends TypedArray<T>, T, TRet>(
|
||||
array: TArray,
|
||||
callbackfn: (accumulator: TRet, value: T, index: i32, array: TArray) => TRet,
|
||||
initialValue: TRet
|
||||
): TRet {
|
||||
var index = 0;
|
||||
var length = <i32>array.length;
|
||||
while (index != length) {
|
||||
initialValue = callbackfn(
|
||||
initialValue,
|
||||
unchecked(array[index]),
|
||||
index,
|
||||
array,
|
||||
);
|
||||
++index;
|
||||
}
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
@inline
|
||||
export function REDUCE_RIGHT<TArray extends TypedArray<T>, T, TRet>(
|
||||
array: TArray,
|
||||
callbackfn: (accumulator: TRet, value: T, index: i32, array: TArray) => TRet,
|
||||
initialValue: TRet
|
||||
): TRet {
|
||||
var index = <i32>array.length - 1;
|
||||
var length = -1;
|
||||
while (index != length) {
|
||||
initialValue = callbackfn(
|
||||
initialValue,
|
||||
unchecked(array[index]),
|
||||
index,
|
||||
array,
|
||||
);
|
||||
--index;
|
||||
}
|
||||
return initialValue;
|
||||
}
|
||||
|
Reference in New Issue
Block a user