Document the use of two type parameters in loadUnsafe, TypedArray etc., see #349

This commit is contained in:
dcodeIO
2018-11-30 01:12:01 +01:00
parent 3c5c2cef80
commit bf7dd1a64f
6 changed files with 71 additions and 46 deletions

View File

@ -64,18 +64,40 @@ export function reallocateUnsafe(buffer: ArrayBuffer, newByteLength: i32): Array
return buffer;
}
@inline export function loadUnsafe<T,V>(buffer: ArrayBuffer, index: i32): V {
return <V>load<T>(changetype<usize>(buffer) + (<usize>index << alignof<T>()), HEADER_SIZE);
// The helpers below use two different types in order to emit loads and stores that load respectively
// store one type to/from memory while returning/taking the desired output/input type. This allows to
// emit instructions like
//
// * `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?
@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 storeUnsafe<T,V>(buffer: ArrayBuffer, index: i32, value: V): void {
@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,V>(buffer: ArrayBuffer, index: i32, byteOffset: i32): V {
return <V>load<T>(changetype<usize>(buffer) + <usize>byteOffset + (<usize>index << alignof<T>()), 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,V>(buffer: ArrayBuffer, index: i32, value: V, byteOffset: i32): void {
@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);
}

View File

@ -12,8 +12,11 @@ import {
defaultComparator
} 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,V> {
export abstract class TypedArray<T,TNative> {
readonly buffer: ArrayBuffer;
readonly byteOffset: i32;
@ -47,19 +50,19 @@ export abstract class TypedArray<T,V> {
}
@operator("[]=")
protected __set(index: i32, value: V): void {
protected __set(index: i32, value: TNative): void {
if (<u32>index >= <u32>(this.byteLength >>> alignof<T>())) throw new Error("Index out of bounds");
storeUnsafeWithOffset<T,V>(this.buffer, index, value, this.byteOffset);
storeUnsafeWithOffset<T,TNative>(this.buffer, index, value, this.byteOffset);
}
@inline @operator("{}=")
protected __unchecked_set(index: i32, value: V): void {
storeUnsafeWithOffset<T,V>(this.buffer, index, value, this.byteOffset);
protected __unchecked_set(index: i32, value: TNative): void {
storeUnsafeWithOffset<T,TNative>(this.buffer, index, value, this.byteOffset);
}
// copyWithin(target: i32, start: i32, end: i32 = this.length): this
fill(value: V, start: i32 = 0, end: i32 = i32.MAX_VALUE): 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;
@ -75,14 +78,14 @@ export abstract class TypedArray<T,V> {
}
} else {
for (; start < end; ++start) {
storeUnsafeWithOffset<T,V>(buffer, start, value, byteOffset);
storeUnsafeWithOffset<T,TNative>(buffer, start, value, byteOffset);
}
}
return this;
}
@inline
subarray(begin: i32 = 0, end: i32 = i32.MAX_VALUE): TypedArray<T,V> {
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);