Add Array#join and Array#toString + dtoa (#275)

This commit is contained in:
Max Graey
2018-10-01 23:57:56 +03:00
committed by Daniel Wirtz
parent ff87857f40
commit 53b030fed5
16 changed files with 22635 additions and 2229 deletions

View File

@ -7,12 +7,26 @@ import {
storeUnsafe
} from "./internal/arraybuffer";
import {
allocateUnsafe as allocateUnsafeString,
freeUnsafe as freeUnsafeString,
copyUnsafe as copyUnsafeString
} from "./internal/string";
import {
defaultComparator,
insertionSort,
weakHeapSort
} from "./internal/array";
import {
itoa,
dtoa,
itoa_stream,
dtoa_stream,
MAX_DOUBLE_LENGTH
} from "./internal/number";
export class Array<T> {
/* @internal */ buffer_: ArrayBuffer;
@ -118,16 +132,9 @@ export class Array<T> {
return this;
}
@inline
includes(searchElement: T, fromIndex: i32 = 0): bool {
var length = this.length_;
if (length == 0 || fromIndex >= length) return false;
if (fromIndex < 0) fromIndex = max(length + fromIndex, 0);
var buffer = this.buffer_;
while (fromIndex < length) {
if (loadUnsafe<T,T>(buffer, fromIndex) == searchElement) return true;
++fromIndex;
}
return false;
return this.indexOf(searchElement, fromIndex) >= 0;
}
indexOf(searchElement: T, fromIndex: i32 = 0): i32 {
@ -356,6 +363,169 @@ export class Array<T> {
}
}
join(separator: string = ","): string {
var lastIndex = this.length_ - 1;
if (lastIndex < 0) return "";
var result = "";
var value: T;
var buffer = this.buffer_;
var sepLen = separator.length;
var hasSeparator = sepLen != 0;
if (value instanceof bool) {
if (!lastIndex) {
return select<string>("true", "false", loadUnsafe<T,bool>(buffer, 0));
}
let valueLen = 5; // max possible length of element len("false")
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
let result = allocateUnsafeString(estLen);
let offset = 0;
for (let i = 0; i < lastIndex; ++i) {
value = loadUnsafe<T,bool>(buffer, i);
valueLen = 4 + <i32>(!value);
copyUnsafeString(result, offset, select<string>("true", "false", value), 0, valueLen);
offset += valueLen;
if (hasSeparator) {
copyUnsafeString(result, offset, changetype<String>(separator), 0, sepLen);
offset += sepLen;
}
}
value = loadUnsafe<T,bool>(buffer, lastIndex);
valueLen = 4 + <i32>(!value);
copyUnsafeString(result, offset, select<string>("true", "false", value), 0, valueLen);
offset += valueLen;
let out = result;
if (estLen > offset) {
out = result.substring(0, offset);
freeUnsafeString(result);
}
return out;
} else if (isInteger<T>()) {
if (!lastIndex) {
return changetype<string>(itoa<T>(loadUnsafe<T,T>(buffer, 0)));
}
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + <i32>isSigned<T>();
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
let result = allocateUnsafeString(estLen);
let offset = 0;
for (let i = 0; i < lastIndex; ++i) {
value = loadUnsafe<T,T>(buffer, i);
offset += itoa_stream<T>(changetype<usize>(result), offset, value);
if (hasSeparator) {
copyUnsafeString(result, offset, separator, 0, sepLen);
offset += sepLen;
}
}
value = loadUnsafe<T,T>(buffer, lastIndex);
offset += itoa_stream<T>(changetype<usize>(result), offset, value);
let out = result;
if (estLen > offset) {
out = result.substring(0, offset);
freeUnsafeString(result);
}
return out;
} else if (isFloat<T>()) {
if (!lastIndex) {
return changetype<string>(dtoa(loadUnsafe<T,f64>(buffer, 0)));
}
const valueLen = MAX_DOUBLE_LENGTH;
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
let result = allocateUnsafeString(estLen);
let offset = 0;
for (let i = 0; i < lastIndex; ++i) {
value = loadUnsafe<T,f64>(buffer, i);
offset += dtoa_stream(changetype<usize>(result), offset, value);
if (hasSeparator) {
copyUnsafeString(result, offset, separator, 0, sepLen);
offset += sepLen;
}
}
value = loadUnsafe<T,f64>(buffer, lastIndex);
offset += dtoa_stream(changetype<usize>(result), offset, value);
let out = result;
if (estLen > offset) {
out = result.substring(0, offset);
freeUnsafeString(result);
}
return out;
} else if (isString<T>()) {
if (!lastIndex) {
return loadUnsafe<T,string>(buffer, 0);
}
let estLen = 0;
for (let i = 0, len = lastIndex + 1; i < len; ++i) {
estLen += loadUnsafe<T,string>(buffer, i).length;
}
let offset = 0;
let result = allocateUnsafeString(estLen + sepLen * lastIndex);
for (let i = 0; i < lastIndex; ++i) {
value = loadUnsafe<T,String>(buffer, i);
if (value) {
let valueLen = value.length; // tslint:disable-line:no-unsafe-any
copyUnsafeString(result, offset, value, 0, valueLen); // tslint:disable-line:no-unsafe-any
offset += valueLen; // tslint:disable-line:no-unsafe-any
}
if (hasSeparator) {
copyUnsafeString(result, offset, separator, 0, sepLen);
offset += sepLen;
}
}
value = loadUnsafe<T,String>(buffer, lastIndex);
if (value) {
let valueLen = value.length; // tslint:disable-line:no-unsafe-any
copyUnsafeString(result, offset, value, 0, valueLen); // tslint:disable-line:no-unsafe-any
}
return result;
} else if (isArray<T>()) {
if (!lastIndex) {
value = loadUnsafe<T,T>(buffer, 0);
return value ? value.join(separator) : ""; // tslint:disable-line:no-unsafe-any
}
for (let i = 0; i < lastIndex; ++i) {
value = loadUnsafe<T,T>(buffer, i);
if (value) result += value.join(separator); // tslint:disable-line:no-unsafe-any
if (hasSeparator) result += separator;
}
value = loadUnsafe<T,T>(buffer, lastIndex);
if (value) result += value.join(separator); // tslint:disable-line:no-unsafe-any
return result;
} else if (isReference<T>()) { // References
if (!lastIndex) return "[object Object]";
const valueLen = 15; // max possible length of element len("[object Object]")
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
let result = allocateUnsafeString(estLen);
let offset = 0;
for (let i = 0; i < lastIndex; ++i) {
value = loadUnsafe<T,T>(buffer, i);
if (value) {
copyUnsafeString(result, offset, changetype<String>("[object Object]"), 0, valueLen);
offset += valueLen;
}
if (hasSeparator) {
copyUnsafeString(result, offset, changetype<String>(separator), 0, sepLen);
offset += sepLen;
}
}
if (loadUnsafe<T,T>(buffer, lastIndex)) {
copyUnsafeString(result, offset, changetype<String>("[object Object]"), 0, valueLen);
offset += valueLen;
}
let out = result;
if (estLen > offset) {
out = result.substring(0, offset);
freeUnsafeString(result);
}
return out;
} else {
assert(false); // Unsupported generic typename
}
}
@inline
toString(): string {
return this.join();
}
private __gc(): void {
var buffer = this.buffer_;
__gc_mark(changetype<usize>(buffer)); // tslint:disable-line