Skip to content

Commit 53b030f

Browse files
MaxGraeydcodeIO
authored andcommitted
Add Array#join and Array#toString + dtoa (AssemblyScript#275)
1 parent ff87857 commit 53b030f

16 files changed

+25711
-5305
lines changed

std/assembly/array.ts

Lines changed: 179 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,26 @@ import {
77
storeUnsafe
88
} from "./internal/arraybuffer";
99

10+
import {
11+
allocateUnsafe as allocateUnsafeString,
12+
freeUnsafe as freeUnsafeString,
13+
copyUnsafe as copyUnsafeString
14+
} from "./internal/string";
15+
1016
import {
1117
defaultComparator,
1218
insertionSort,
1319
weakHeapSort
1420
} from "./internal/array";
1521

22+
import {
23+
itoa,
24+
dtoa,
25+
itoa_stream,
26+
dtoa_stream,
27+
MAX_DOUBLE_LENGTH
28+
} from "./internal/number";
29+
1630
export class Array<T> {
1731

1832
/* @internal */ buffer_: ArrayBuffer;
@@ -118,16 +132,9 @@ export class Array<T> {
118132
return this;
119133
}
120134

135+
@inline
121136
includes(searchElement: T, fromIndex: i32 = 0): bool {
122-
var length = this.length_;
123-
if (length == 0 || fromIndex >= length) return false;
124-
if (fromIndex < 0) fromIndex = max(length + fromIndex, 0);
125-
var buffer = this.buffer_;
126-
while (fromIndex < length) {
127-
if (loadUnsafe<T,T>(buffer, fromIndex) == searchElement) return true;
128-
++fromIndex;
129-
}
130-
return false;
137+
return this.indexOf(searchElement, fromIndex) >= 0;
131138
}
132139

133140
indexOf(searchElement: T, fromIndex: i32 = 0): i32 {
@@ -356,6 +363,169 @@ export class Array<T> {
356363
}
357364
}
358365

366+
join(separator: string = ","): string {
367+
var lastIndex = this.length_ - 1;
368+
if (lastIndex < 0) return "";
369+
var result = "";
370+
var value: T;
371+
var buffer = this.buffer_;
372+
var sepLen = separator.length;
373+
var hasSeparator = sepLen != 0;
374+
if (value instanceof bool) {
375+
if (!lastIndex) {
376+
return select<string>("true", "false", loadUnsafe<T,bool>(buffer, 0));
377+
}
378+
let valueLen = 5; // max possible length of element len("false")
379+
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
380+
let result = allocateUnsafeString(estLen);
381+
let offset = 0;
382+
for (let i = 0; i < lastIndex; ++i) {
383+
value = loadUnsafe<T,bool>(buffer, i);
384+
valueLen = 4 + <i32>(!value);
385+
copyUnsafeString(result, offset, select<string>("true", "false", value), 0, valueLen);
386+
offset += valueLen;
387+
if (hasSeparator) {
388+
copyUnsafeString(result, offset, changetype<String>(separator), 0, sepLen);
389+
offset += sepLen;
390+
}
391+
}
392+
value = loadUnsafe<T,bool>(buffer, lastIndex);
393+
valueLen = 4 + <i32>(!value);
394+
copyUnsafeString(result, offset, select<string>("true", "false", value), 0, valueLen);
395+
offset += valueLen;
396+
397+
let out = result;
398+
if (estLen > offset) {
399+
out = result.substring(0, offset);
400+
freeUnsafeString(result);
401+
}
402+
return out;
403+
} else if (isInteger<T>()) {
404+
if (!lastIndex) {
405+
return changetype<string>(itoa<T>(loadUnsafe<T,T>(buffer, 0)));
406+
}
407+
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + <i32>isSigned<T>();
408+
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
409+
let result = allocateUnsafeString(estLen);
410+
let offset = 0;
411+
for (let i = 0; i < lastIndex; ++i) {
412+
value = loadUnsafe<T,T>(buffer, i);
413+
offset += itoa_stream<T>(changetype<usize>(result), offset, value);
414+
if (hasSeparator) {
415+
copyUnsafeString(result, offset, separator, 0, sepLen);
416+
offset += sepLen;
417+
}
418+
}
419+
value = loadUnsafe<T,T>(buffer, lastIndex);
420+
offset += itoa_stream<T>(changetype<usize>(result), offset, value);
421+
let out = result;
422+
if (estLen > offset) {
423+
out = result.substring(0, offset);
424+
freeUnsafeString(result);
425+
}
426+
return out;
427+
} else if (isFloat<T>()) {
428+
if (!lastIndex) {
429+
return changetype<string>(dtoa(loadUnsafe<T,f64>(buffer, 0)));
430+
}
431+
const valueLen = MAX_DOUBLE_LENGTH;
432+
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
433+
let result = allocateUnsafeString(estLen);
434+
let offset = 0;
435+
for (let i = 0; i < lastIndex; ++i) {
436+
value = loadUnsafe<T,f64>(buffer, i);
437+
offset += dtoa_stream(changetype<usize>(result), offset, value);
438+
if (hasSeparator) {
439+
copyUnsafeString(result, offset, separator, 0, sepLen);
440+
offset += sepLen;
441+
}
442+
}
443+
value = loadUnsafe<T,f64>(buffer, lastIndex);
444+
offset += dtoa_stream(changetype<usize>(result), offset, value);
445+
let out = result;
446+
if (estLen > offset) {
447+
out = result.substring(0, offset);
448+
freeUnsafeString(result);
449+
}
450+
return out;
451+
} else if (isString<T>()) {
452+
if (!lastIndex) {
453+
return loadUnsafe<T,string>(buffer, 0);
454+
}
455+
let estLen = 0;
456+
for (let i = 0, len = lastIndex + 1; i < len; ++i) {
457+
estLen += loadUnsafe<T,string>(buffer, i).length;
458+
}
459+
let offset = 0;
460+
let result = allocateUnsafeString(estLen + sepLen * lastIndex);
461+
for (let i = 0; i < lastIndex; ++i) {
462+
value = loadUnsafe<T,String>(buffer, i);
463+
if (value) {
464+
let valueLen = value.length; // tslint:disable-line:no-unsafe-any
465+
copyUnsafeString(result, offset, value, 0, valueLen); // tslint:disable-line:no-unsafe-any
466+
offset += valueLen; // tslint:disable-line:no-unsafe-any
467+
}
468+
if (hasSeparator) {
469+
copyUnsafeString(result, offset, separator, 0, sepLen);
470+
offset += sepLen;
471+
}
472+
}
473+
value = loadUnsafe<T,String>(buffer, lastIndex);
474+
if (value) {
475+
let valueLen = value.length; // tslint:disable-line:no-unsafe-any
476+
copyUnsafeString(result, offset, value, 0, valueLen); // tslint:disable-line:no-unsafe-any
477+
}
478+
return result;
479+
} else if (isArray<T>()) {
480+
if (!lastIndex) {
481+
value = loadUnsafe<T,T>(buffer, 0);
482+
return value ? value.join(separator) : ""; // tslint:disable-line:no-unsafe-any
483+
}
484+
for (let i = 0; i < lastIndex; ++i) {
485+
value = loadUnsafe<T,T>(buffer, i);
486+
if (value) result += value.join(separator); // tslint:disable-line:no-unsafe-any
487+
if (hasSeparator) result += separator;
488+
}
489+
value = loadUnsafe<T,T>(buffer, lastIndex);
490+
if (value) result += value.join(separator); // tslint:disable-line:no-unsafe-any
491+
return result;
492+
} else if (isReference<T>()) { // References
493+
if (!lastIndex) return "[object Object]";
494+
const valueLen = 15; // max possible length of element len("[object Object]")
495+
let estLen = (valueLen + sepLen) * lastIndex + valueLen;
496+
let result = allocateUnsafeString(estLen);
497+
let offset = 0;
498+
for (let i = 0; i < lastIndex; ++i) {
499+
value = loadUnsafe<T,T>(buffer, i);
500+
if (value) {
501+
copyUnsafeString(result, offset, changetype<String>("[object Object]"), 0, valueLen);
502+
offset += valueLen;
503+
}
504+
if (hasSeparator) {
505+
copyUnsafeString(result, offset, changetype<String>(separator), 0, sepLen);
506+
offset += sepLen;
507+
}
508+
}
509+
if (loadUnsafe<T,T>(buffer, lastIndex)) {
510+
copyUnsafeString(result, offset, changetype<String>("[object Object]"), 0, valueLen);
511+
offset += valueLen;
512+
}
513+
let out = result;
514+
if (estLen > offset) {
515+
out = result.substring(0, offset);
516+
freeUnsafeString(result);
517+
}
518+
return out;
519+
} else {
520+
assert(false); // Unsupported generic typename
521+
}
522+
}
523+
524+
@inline
525+
toString(): string {
526+
return this.join();
527+
}
528+
359529
private __gc(): void {
360530
var buffer = this.buffer_;
361531
__gc_mark(changetype<usize>(buffer)); // tslint:disable-line

std/assembly/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,10 @@ declare class Array<T> {
454454
unshift(element: T): i32;
455455
slice(from: i32, to?: i32): T[];
456456
splice(start: i32, deleteCount?: i32): void;
457-
reverse(): T[];
458457
sort(comparator?: (a: T, b: T) => i32): this;
458+
join(separator?: string): string;
459+
reverse(): T[];
460+
toString(): string;
459461
}
460462

461463
/** Class representing a sequence of characters. */

0 commit comments

Comments
 (0)