diff --git a/std/assembly/array.ts b/std/assembly/array.ts index 059d5650..5e453f05 100644 --- a/std/assembly/array.ts +++ b/std/assembly/array.ts @@ -1,17 +1,29 @@ -import { - MAX_BLENGTH, - HEADER_SIZE, - allocateUnsafe, - reallocateUnsafe, - LOAD, - STORE -} from "./internal/arraybuffer"; +// import { +// MAX_BLENGTH, +// HEADER_SIZE, +// allocateUnsafe, +// reallocateUnsafe, +// LOAD, +// STORE +// } from "./internal/arraybuffer"; import { - allocateUnsafe as allocateUnsafeString, - freeUnsafe as freeUnsafeString, - copyUnsafe as copyUnsafeString -} from "./internal/string"; + ALLOC, + REALLOC, + REGISTER, + LINK, + ArrayBufferView +} from "./runtime"; + +import { + ArrayBuffer +} from "./arraybuffer"; + +// import { +// allocateUnsafe as allocateUnsafeString, +// freeUnsafe as freeUnsafeString, +// copyUnsafe as copyUnsafeString +// } from "./internal/string"; import { COMPARATOR, @@ -30,119 +42,114 @@ import { isArray as builtin_isArray } from "./builtins"; -export class Array { - [key: number]: T; // compatibility only - - /* @internal */ buffer_: ArrayBuffer; - /* @internal */ length_: i32; +export class Array extends ArrayBufferView { + private length_: i32; @inline static isArray(value: U): bool { return builtin_isArray(value) && value !== null; } constructor(length: i32 = 0) { - const MAX_LENGTH = MAX_BLENGTH >>> alignof(); - if (length > MAX_LENGTH) throw new RangeError("Invalid array length"); - var byteLength = length << alignof(); - var buffer = allocateUnsafe(byteLength); - this.buffer_ = buffer; + super(length, alignof()); this.length_ = length; - memory.fill( - changetype(buffer) + HEADER_SIZE, - 0, - byteLength - ); } - @inline get length(): i32 { return this.length_; } set length(length: i32) { - var buffer = this.buffer_; - var capacity = buffer.byteLength >>> alignof(); - if (length > capacity) { - const MAX_LENGTH = MAX_BLENGTH >>> alignof(); - if (length > MAX_LENGTH) throw new RangeError("Invalid array length"); - buffer = reallocateUnsafe(buffer, length << alignof()); - this.buffer_ = buffer; - } + this.resize(length); this.length_ = length; } + resize(length: i32): void { + var buffer = this.buffer; + var oldCapacity = buffer.byteLength >>> alignof(); + if (length > oldCapacity) { + const MAX_LENGTH = ArrayBuffer.MAX_BYTELENGTH >>> alignof(); + if (length > MAX_LENGTH) throw new RangeError("Invalid array length"); + let newCapacity = length << alignof(); + let newBuffer = REALLOC(changetype(buffer), newCapacity); + if (newBuffer !== changetype(buffer)) { + this.buffer = changetype(newBuffer); // links + this.dataStart = newBuffer; + this.dataEnd = newBuffer + newCapacity; + } + } + } + every(callbackfn: (element: T, index: i32, array: Array) => bool): bool { for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) { - if (!callbackfn(LOAD(this.buffer_, index), index, this)) return false; + if (!callbackfn(load(this.dataStart + (index << alignof())), index, this)) return false; } return true; } findIndex(predicate: (element: T, index: i32, array: Array) => bool): i32 { for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) { - if (predicate(LOAD(this.buffer_, index), index, this)) return index; + if (predicate(load(this.dataStart + (index << alignof())), index, this)) return index; } return -1; } - @operator("[]") - private __get(index: i32): T { - var buffer = this.buffer_; - return index < (buffer.byteLength >>> alignof()) - ? LOAD(buffer, index) - : unreachable(); - } + // @operator("[]") + // private __get(index: i32): T { + // var buffer = this.buffer_; + // return index < (buffer.byteLength >>> alignof()) + // ? LOAD(buffer, index) + // : unreachable(); + // } - @operator("{}") - private __unchecked_get(index: i32): T { - return LOAD(this.buffer_, index); - } + // @operator("{}") + // private __unchecked_get(index: i32): T { + // return LOAD(this.buffer_, index); + // } - @operator("[]=") - private __set(index: i32, value: T): void { - var buffer = this.buffer_; - var capacity = buffer.byteLength >>> alignof(); - if (index >= capacity) { - const MAX_LENGTH = MAX_BLENGTH >>> alignof(); - if (index >= MAX_LENGTH) throw new Error("Invalid array length"); - buffer = reallocateUnsafe(buffer, (index + 1) << alignof()); - this.buffer_ = buffer; - this.length_ = index + 1; - } - STORE(buffer, index, value); - if (isManaged()) __gc_link(changetype(this), changetype(value)); // tslint:disable-line - } + // @operator("[]=") + // private __set(index: i32, value: T): void { + // var buffer = this.buffer_; + // var capacity = buffer.byteLength >>> alignof(); + // if (index >= capacity) { + // const MAX_LENGTH = MAX_BLENGTH >>> alignof(); + // if (index >= MAX_LENGTH) throw new Error("Invalid array length"); + // buffer = reallocateUnsafe(buffer, (index + 1) << alignof()); + // this.buffer_ = buffer; + // this.length_ = index + 1; + // } + // STORE(buffer, index, value); + // if (isManaged()) __gc_link(changetype(this), changetype(value)); // tslint:disable-line + // } - @operator("{}=") - private __unchecked_set(index: i32, value: T): void { - STORE(this.buffer_, index, value); - if (isManaged()) __gc_link(changetype(this), changetype(value)); // tslint:disable-line - } + // @operator("{}=") + // private __unchecked_set(index: i32, value: T): void { + // STORE(this.buffer_, index, value); + // if (isManaged()) __gc_link(changetype(this), changetype(value)); // tslint:disable-line + // } fill(value: T, start: i32 = 0, end: i32 = i32.MAX_VALUE): this { - var buffer = this.buffer_; - var len = this.length_; + var base = this.dataStart; + var length = this.length_; - start = start < 0 ? max(len + start, 0) : min(start, len); - end = end < 0 ? max(len + end, 0) : min(end, len); + 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( - changetype(buffer) + start + HEADER_SIZE, + base + start, value, (end - start) ); } } else { for (; start < end; ++start) { - STORE(buffer, start, value); + store(base + (start << alignof()), value); } } return this; } - @inline includes(searchElement: T, fromIndex: i32 = 0): bool { return this.indexOf(searchElement, fromIndex) >= 0; } @@ -151,9 +158,9 @@ export class Array { var length = this.length_; if (length == 0 || fromIndex >= length) return -1; if (fromIndex < 0) fromIndex = max(length + fromIndex, 0); - var buffer = this.buffer_; + var base = this.dataStart; while (fromIndex < length) { - if (LOAD(buffer, fromIndex) == searchElement) return fromIndex; + if (load(base + (fromIndex << alignof())) == searchElement) return fromIndex; ++fromIndex; } return -1; @@ -164,50 +171,33 @@ export class Array { if (length == 0) return -1; if (fromIndex < 0) fromIndex = length + fromIndex; // no need to clamp else if (fromIndex >= length) fromIndex = length - 1; - var buffer = this.buffer_; + var base = this.dataStart; while (fromIndex >= 0) { // ^ - if (LOAD(buffer, fromIndex) == searchElement) return fromIndex; + if (load(base + (fromIndex << alignof())) == searchElement) return fromIndex; --fromIndex; } return -1; } push(element: T): i32 { - var length = this.length_; - var buffer = this.buffer_; - var capacity = buffer.byteLength >>> alignof(); - var newLength = length + 1; // safe only if length is checked - if (length >= capacity) { - const MAX_LENGTH = MAX_BLENGTH >>> alignof(); - if (length >= MAX_LENGTH) throw new Error("Invalid array length"); - buffer = reallocateUnsafe(buffer, newLength << alignof()); - this.buffer_ = buffer; - } + var newLength = this.length_ + 1; + this.resize(newLength); this.length_ = newLength; - STORE(buffer, length, element); - if (isManaged()) __gc_link(changetype(this), changetype(element)); // tslint:disable-line + store(this.dataStart + ((newLength - 1) << alignof()), element); + if (isManaged()) LINK(changetype(element), changetype(this)); return newLength; } - concat(items: Array): Array { + concat(other: Array): Array { var thisLen = this.length_; - var otherLen = select(0, items.length_, items === null); + var otherLen = select(0, other.length_, other === null); var outLen = thisLen + otherLen; var out = new Array(outLen); - if (thisLen) { - memory.copy( - changetype(out.buffer_) + HEADER_SIZE, - changetype(this.buffer_) + HEADER_SIZE, - thisLen << alignof() - ); + memory.copy(out.dataStart, this.dataStart, thisLen << alignof()); } if (otherLen) { - memory.copy( - changetype(out.buffer_) + HEADER_SIZE + (thisLen << alignof()), - changetype(items.buffer_) + HEADER_SIZE, - otherLen << alignof() - ); + memory.copy(out.dataStart + (thisLen << alignof()), other.dataStart, otherLen << alignof()); } return out; } @@ -242,23 +232,25 @@ export class Array { pop(): T { var length = this.length_; if (length < 1) throw new RangeError("Array is empty"); - var element = LOAD(this.buffer_, --length); + var element = load(this.dataStart + (--length << alignof())); this.length_ = length; return element; } forEach(callbackfn: (value: T, index: i32, array: Array) => void): void { for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) { - callbackfn(LOAD(this.buffer_, index), index, this); + callbackfn(load(this.dataStart + (index << alignof())), index, this); } } map(callbackfn: (value: T, index: i32, array: Array) => U): Array { var length = this.length_; var result = new Array(length); - var buffer = result.buffer_; + var resultStart = result.dataStart; for (let index = 0; index < min(length, this.length_); ++index) { - STORE(buffer, index, callbackfn(LOAD(this.buffer_, index), index, this)); + let element = load(this.dataStart + (index << alignof())); + store(resultStart + (index << alignof()), element); + if (isManaged()) LINK(changetype(element), changetype(result)); } return result; } @@ -266,7 +258,7 @@ export class Array { filter(callbackfn: (value: T, index: i32, array: Array) => bool): Array { var result = new Array(); for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) { - let value = LOAD(this.buffer_, index); + let value = load(this.dataStart + (index << alignof())); if (callbackfn(value, index, this)) result.push(value); } return result; @@ -278,7 +270,7 @@ export class Array { ): U { var accum = initialValue; for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) { - accum = callbackfn(accum, LOAD(this.buffer_, index), index, this); + accum = callbackfn(accum, load(this.dataStart + (index << alignof())), index, this); } return accum; } @@ -289,7 +281,7 @@ export class Array { ): U { var accum = initialValue; for (let index = this.length_ - 1; index >= 0; --index) { - accum = callbackfn(accum, LOAD(this.buffer_, index), index, this); + accum = callbackfn(accum, load(this.dataStart + (index << alignof())), index, this); } return accum; } @@ -297,87 +289,86 @@ export class Array { shift(): T { var length = this.length_; if (length < 1) throw new RangeError("Array is empty"); - var buffer = this.buffer_; - var element = LOAD(buffer, 0); + var base = this.dataStart; + var element = load(base); var lastIndex = length - 1; memory.copy( - changetype(buffer) + HEADER_SIZE, - changetype(buffer) + HEADER_SIZE + sizeof(), + base, + base + sizeof(), lastIndex << alignof() ); - STORE(buffer, lastIndex, null); + store(base + (lastIndex << alignof()), null); this.length_ = lastIndex; return element; } some(callbackfn: (element: T, index: i32, array: Array) => bool): bool { for (let index = 0, length = this.length_; index < min(length, this.length_); ++index) { - if (callbackfn(LOAD(this.buffer_, index), index, this)) return true; + if (callbackfn(load(this.dataStart + (index << alignof())), index, this)) return true; } return false; } unshift(element: T): i32 { - var buffer = this.buffer_; - var capacity = buffer.byteLength >>> alignof(); - var length = this.length_; - var newLength = length + 1; // safe only if length is checked - if (length >= capacity) { - const MAX_LENGTH = MAX_BLENGTH >>> alignof(); - if (length >= MAX_LENGTH) throw new Error("Invalid array length"); - buffer = reallocateUnsafe(buffer, newLength << alignof()); - capacity = buffer.byteLength >>> alignof(); - this.buffer_ = buffer; - } + var newLength = this.length_; + this.resize(newLength); + var base = this.dataStart; memory.copy( - changetype(buffer) + HEADER_SIZE + sizeof(), - changetype(buffer) + HEADER_SIZE, - (capacity - 1) << alignof() + base + sizeof(), + base, + (newLength - 1) << alignof() ); - STORE(buffer, 0, element); + store(base, element); + if (isManaged()) LINK(changetype(element), changetype(this)); this.length_ = newLength; - if (isManaged()) __gc_link(changetype(this), changetype(element)); // tslint:disable-line return newLength; } slice(begin: i32 = 0, end: i32 = i32.MAX_VALUE): Array { - var len = this.length_; - begin = begin < 0 ? max(begin + len, 0) : min(begin, len); - end = end < 0 ? max(end + len, 0) : min(end, len); - len = max(end - begin, 0); - var sliced = new Array(len); - if (len) { - memory.copy( - changetype(sliced.buffer_) + HEADER_SIZE, - changetype(this.buffer_) + HEADER_SIZE + (begin << alignof()), - len << alignof() - ); + var length = this.length_; + begin = begin < 0 ? max(begin + length, 0) : min(begin, length); + end = end < 0 ? max(end + length, 0) : min(end , length); + length = max(end - begin, 0); + var slice = new Array(length); + var sliceBase = slice.dataStart; + var thisBase = this.dataStart + (begin << alignof()); + for (let i = 0; i < length; ++i) { + let offset = i << alignof(); + let element = load(thisBase + offset); + store(sliceBase + offset, element); + if (isManaged()) LINK(changetype(element), changetype(slice)); } - return sliced; + return slice; } splice(start: i32, deleteCount: i32 = i32.MAX_VALUE): Array { var length = this.length_; start = start < 0 ? max(length + start, 0) : min(start, length); deleteCount = max(min(deleteCount, length - start), 0); - var buffer = this.buffer_; - var spliced = new Array(deleteCount); - var source = changetype(buffer) + HEADER_SIZE + (start << alignof()); + var splice = new Array(deleteCount); + var spliceStart = splice.dataStart; + var thisStart = this.dataStart; + var thisBase = thisStart + (start << alignof()); + for (let i = 0; i < deleteCount; ++i) { + let element = load(thisBase + (i << alignof())); + store(spliceStart + (i << alignof()), element); + if (isManaged()) LINK(changetype(element), changetype(splice)); + } memory.copy( - changetype(spliced.buffer_) + HEADER_SIZE, - source, + splice.dataStart, + thisBase, deleteCount << alignof() ); var offset = start + deleteCount; if (length != offset) { memory.copy( - source, - changetype(buffer) + HEADER_SIZE + (offset << alignof()), + thisBase, + thisStart + (offset << alignof()), (length - offset) << alignof() ); } this.length_ = length - deleteCount; - return spliced; + return splice; } reverse(): Array { diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index cdcb2b57..27d983fe 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -1020,8 +1020,6 @@ declare namespace table { declare class ArrayBuffer { /** The size, in bytes, of the array. */ readonly byteLength: i32; - /** Unsafe pointer to the start of the data in memory. */ - readonly data: usize; /** Returns true if value is one of the ArrayBuffer views, such as typed array or a DataView **/ static isView(value: T): bool; /** Constructs a new array buffer of the given length in bytes. */ diff --git a/std/assembly/internal/sort.ts b/std/assembly/internal/sort.ts index 8d50efb1..587de405 100644 --- a/std/assembly/internal/sort.ts +++ b/std/assembly/internal/sort.ts @@ -1,12 +1,3 @@ -import { - LOAD, - STORE -} from "./arraybuffer"; - -import { - compareUnsafe -} from "./string"; - /** Obtains the default comparator for the specified value type. */ @inline export function COMPARATOR(): (a: T, b: T) => i32 { @@ -42,7 +33,7 @@ export function COMPARATOR(): (a: T, b: T) => i32 { if (!alen && !blen) return 0; if (!alen) return -1; if (!blen) return 1; - return compareUnsafe(a, 0, b, 0, min(alen, blen)); + return String.cmp(a, 0, b, 0, min(alen, blen)); }; } else { return (a: T, b: T): i32 => ((a > b) - (a < b)); @@ -51,47 +42,44 @@ export function COMPARATOR(): (a: T, b: T) => i32 { @inline export function SORT( - buffer: ArrayBuffer, - byteOffset: i32, + dataStart: usize, length: i32, comparator: (a: T, b: T) => i32 ): void { if (isReference()) { // TODO replace this to faster stable sort (TimSort) when it implemented - insertionSort(buffer, byteOffset, length, comparator); + insertionSort(dataStart, length, comparator); } else { if (length < 256) { - insertionSort(buffer, byteOffset, length, comparator); + insertionSort(dataStart, length, comparator); } else { - weakHeapSort(buffer, byteOffset, length, comparator); + weakHeapSort(dataStart, length, comparator); } } } /** Sorts an Array with the 'Insertion Sort' algorithm. */ function insertionSort( - buffer: ArrayBuffer, - byteOffset: i32, + dataStart: usize, length: i32, comparator: (a: T, b: T) => i32 ): void { for (let i = 0; i < length; i++) { - let a = LOAD(buffer, i, byteOffset); // a = arr[i] + let a: T = load(dataStart + (i << alignof())); // a = arr[i] let j = i - 1; while (j >= 0) { - let b = LOAD(buffer, j, byteOffset); // b = arr[j] + let b: T = load(dataStart + (j << alignof())); // b = arr[j] if (comparator(a, b) < 0) { - STORE(buffer, j-- + 1, b, byteOffset); // arr[j + 1] = b + store(dataStart + ((j-- + 1) << alignof()), b); // arr[j + 1] = b } else break; } - STORE(buffer, j + 1, a, byteOffset); // arr[j + 1] = a + store(dataStart + ((j + 1) << alignof()), a); // arr[j + 1] = a } } /** Sorts an Array with the 'Weak Heap Sort' algorithm. */ function weakHeapSort( - buffer: ArrayBuffer, - byteOffset: i32, + dataStart: usize, length: i32, comparator: (a: T, b: T) => i32 ): void { @@ -108,37 +96,37 @@ function weakHeapSort( while ((j & 1) == (load(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1; let p = j >> 1; - let a = LOAD(buffer, p, byteOffset); // a = arr[p] - let b = LOAD(buffer, i, byteOffset); // b = arr[i] + let a: T = load(dataStart + (p << alignof())); // a = arr[p] + let b: T = load(dataStart + (i << alignof())); // b = arr[i] if (comparator(a, b) < 0) { store( bitset + (i >> 5 << shift32), load(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31)) ); - STORE(buffer, i, a, byteOffset); // arr[i] = a - STORE(buffer, p, b, byteOffset); // arr[p] = b + store(dataStart + (i << alignof()), a); // arr[i] = a + store(dataStart + (p << alignof()), b); // arr[p] = b } } for (let i = length - 1; i >= 2; i--) { - let a = LOAD(buffer, 0, byteOffset); - STORE(buffer, 0, LOAD(buffer, i, byteOffset), byteOffset); - STORE(buffer, i, a, byteOffset); + let a: T = load(dataStart); // a = arr[0] + store(dataStart, load(dataStart + (i << alignof()))); // arr[0] = arr[i] + store(dataStart + (i << alignof()), a); // arr[i] = a let x = 1, y: i32; while ((y = (x << 1) + ((load(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y; while (x > 0) { - a = LOAD(buffer, 0, byteOffset); // a = arr[0] - let b = LOAD(buffer, x, byteOffset); // b = arr[x] + a = load(dataStart); // a = arr[0] + let b: T = load(dataStart + (x << alignof())); // b = arr[x] if (comparator(a, b) < 0) { store( bitset + (x >> 5 << shift32), load(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31)) ); - STORE(buffer, x, a, byteOffset); // arr[x] = a - STORE(buffer, 0, b, byteOffset); // arr[0] = b + store(dataStart + (x << alignof()), a); // arr[x] = a + store(dataStart, b); // arr[0] = b } x >>= 1; } @@ -146,7 +134,7 @@ function weakHeapSort( memory.free(bitset); - var t = LOAD(buffer, 1, byteOffset); // t = arr[1] - STORE(buffer, 1, LOAD(buffer, 0, byteOffset), byteOffset); - STORE(buffer, 0, t, byteOffset); // arr[0] = t + var t: T = load(dataStart, sizeof()); // t = arr[1] + store(dataStart, load(dataStart), sizeof()); // arr[1] = arr[0] + store(dataStart, t); // arr[0] = t } diff --git a/std/assembly/internal/string.ts b/std/assembly/internal/string.ts index 7d903c49..2e4fd81f 100644 --- a/std/assembly/internal/string.ts +++ b/std/assembly/internal/string.ts @@ -1,3 +1,13 @@ +export function compareImpl(str1: String, index1: usize, str2: String, index2: usize, len: usize): i32 { + var result: i32 = 0; + var ptr1 = changetype(str1) + (index1 << 1); + var ptr2 = changetype(str2) + (index2 << 1); + while (len && !(result = load(ptr1) - load(ptr2))) { + --len, ptr1 += 2, ptr2 += 2; + } + return result; +} + import { MAX_SIZE_32 } from "./allocator"; import { String } from "../string"; @@ -38,16 +48,6 @@ export function copyUnsafe(dest: String, destOffset: usize, src: String, srcOffs ); } -export function compareUnsafe(str1: String, offset1: usize, str2: String, offset2: usize, len: usize): i32 { - var cmp: i32 = 0; - var ptr1 = changetype(str1) + (offset1 << 1); - var ptr2 = changetype(str2) + (offset2 << 1); - while (len && !(cmp = load(ptr1, HEADER_SIZE) - load(ptr2, HEADER_SIZE))) { - --len, ptr1 += 2, ptr2 += 2; - } - return cmp; -} - export function repeatUnsafe(dest: String, destOffset: usize, src: String, count: i32): void { var length = src.length; if (ASC_SHRINK_LEVEL > 1) { diff --git a/std/assembly/runtime.ts b/std/assembly/runtime.ts index d830bf59..746d7bc4 100644 --- a/std/assembly/runtime.ts +++ b/std/assembly/runtime.ts @@ -87,6 +87,9 @@ export function ADJUST(payloadSize: usize): usize { // free right away if not registered yet assert(ref > HEAP_BASE); // static objects aren't scratch objects memory.free(changetype(header)); + } else if (GC) { + // if previously registered, register again + gc.register(ref); } header = newHeader; ref = newRef; @@ -124,11 +127,11 @@ function unref(ref: usize): HEADER { } /** Links a managed object with its managed parent. */ -@unsafe export function LINK(ref: usize, parentRef: usize): void { - assert(ref >= HEAP_BASE + HEADER_SIZE); // must be a heap object - var header = changetype
(ref - HEADER_SIZE); +@unsafe @inline export function LINK(ref: T, parentRef: TParent): void { + assert(changetype(ref) >= HEAP_BASE + HEADER_SIZE); // must be a heap object + var header = changetype
(changetype(ref) - HEADER_SIZE); assert(header.classId != HEADER_MAGIC && header.gc1 != 0 && header.gc2 != 0); // must be registered - if (GC) gc.link(ref, parentRef); // tslint:disable-line + if (GC) gc.link(changetype(ref), changetype(parentRef)); // tslint:disable-line } /** ArrayBuffer base class. */ @@ -146,14 +149,13 @@ export abstract class ArrayBufferBase { /** Typed array base class. */ export abstract class ArrayBufferView { [key: number]: number; - readonly buffer: ArrayBuffer; + + @unsafe buffer: ArrayBuffer; @unsafe dataStart: usize; @unsafe dataEnd: usize; constructor(length: i32, alignLog2: i32) { - if (length > ArrayBufferBase.MAX_BYTELENGTH >> alignLog2) { - throw new RangeError("Invalid typed array length"); - } + if (length > ArrayBufferBase.MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length"); var byteLength = length << alignLog2; var buffer = new ArrayBuffer(byteLength); this.buffer = buffer; diff --git a/std/assembly/string.ts b/std/assembly/string.ts index adb77e95..26c8368e 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -5,42 +5,13 @@ import { } from "./runtime"; import { + compareImpl, + parse, CharCode, - parse + isWhiteSpaceOrLineTerminator } from "./internal/string"; -import { - STORE -} from "./internal/arraybuffer"; - -function compareImpl(str1: String, index1: usize, str2: String, index2: usize, len: usize): i32 { - var result: i32 = 0; - var ptr1 = changetype(str1) + (index1 << 1); - var ptr2 = changetype(str2) + (index2 << 1); - while (len && !(result = load(ptr1) - load(ptr2))) { - --len, ptr1 += 2, ptr2 += 2; - } - return result; -} - -function isWhiteSpaceOrLineTerminator(c: u16): bool { - switch (c) { - case 9: // - case 10: // - case 13: // - case 11: // - case 12: // - case 32: // - case 160: // - case 8232: // - case 8233: // - case 65279: return true; // - default: return false; - } -} - -@sealed -export class String extends StringBase { +@sealed export class String extends StringBase { // TODO Add and handle second argument static fromCharCode(code: i32): String { @@ -393,7 +364,7 @@ export class String extends StringBase { changetype(this) + (i << 1) ) ); - STORE(buffer, i, char); // FIXME: use store once AB is done as well + store(changetype(buffer) + (i << 1), char); } return result; } else if (!length) { diff --git a/std/assembly/typedarray.ts b/std/assembly/typedarray.ts index bc3e0c23..0bacb1c7 100644 --- a/std/assembly/typedarray.ts +++ b/std/assembly/typedarray.ts @@ -6,7 +6,8 @@ import { } from "./runtime"; import { - COMPARATOR + COMPARATOR, + SORT as SORT_IMPL } from "./internal/sort"; function clampToByte(value: i32): i32 { @@ -651,16 +652,15 @@ export class Float64Array extends ArrayBufferView { if (length <= 1) return array; var base = array.dataStart; if (length == 2) { - let a = load(base, sizeof()); - let b = load(base); + 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()); - store(base, a); + store(base, b, sizeof()); // arr[1] = b + store(base, a); // arr[0] = a } return array; } - // TODO - // SORT_IMPL(buffer, byteOffset, length, comparator); + SORT_IMPL(base, length, comparator); return array; } diff --git a/tests/compiler/empty.ts b/tests/compiler/empty.ts index e69de29b..25da6068 100644 --- a/tests/compiler/empty.ts +++ b/tests/compiler/empty.ts @@ -0,0 +1,9 @@ +import "allocator/arena"; + +var arr = new Uint8Array(8); +arr[0] = 10; +arr[4] = 5; +var arr2 = arr.sort(); +arr2.forEach(x => { + trace("", 1, x); +});