Skip to content

Commit 01fe0b4

Browse files
jtennerdcodeIO
authored andcommitted
Implement TypedArray#set (#1002)
1 parent ed74b67 commit 01fe0b4

9 files changed

+18516
-1554
lines changed

std/assembly/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,8 @@ declare abstract class TypedArray<T> implements ArrayBufferView {
12901290
reverse(): this;
12911291
/** The join() method joins all elements of an array into a string. This method has the same algorithm as Array.prototype.join(). */
12921292
join(separator?: string): string;
1293+
/** The set() method stores multiple values in the typed array, reading input values from a specified array. */
1294+
set<U extends ArrayBufferView>(source: U, offset?: i32): void
12931295
/** The toString() method returns a string representing the specified array and its elements. This method has the same algorithm as Array.prototype.toString() */
12941296
toString(): string;
12951297
}

std/assembly/typedarray.ts

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort";
2-
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH } from "./util/error";
2+
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_NOTIMPLEMENTED } from "./util/error";
33
import { joinIntegerArray, joinFloatArray } from "./util/string";
44
import { idof } from "./builtins";
55
import { ArrayBufferView } from "./arraybuffer";
@@ -123,6 +123,10 @@ export class Int8Array extends ArrayBufferView {
123123
return this.join();
124124
}
125125

126+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
127+
SET<Int8Array, i8, U, valueof<U>>(this, source, offset);
128+
}
129+
126130
static wrap(buffer: ArrayBuffer, byteOffset: i32 = 0, length: i32 = -1): Int8Array {
127131
return WRAP<Int8Array, i8>(buffer, byteOffset, length);
128132
}
@@ -243,6 +247,10 @@ export class Uint8Array extends ArrayBufferView {
243247
return joinIntegerArray<u8>(this.dataStart, this.length, separator);
244248
}
245249

250+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
251+
SET<Uint8Array, u8, U, valueof<U>>(this, source, offset);
252+
}
253+
246254
toString(): string {
247255
return this.join();
248256
}
@@ -367,6 +375,10 @@ export class Uint8ClampedArray extends ArrayBufferView {
367375
return joinIntegerArray<u8>(this.dataStart, this.length, separator);
368376
}
369377

378+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
379+
SET<Uint8ClampedArray, u8, U, valueof<U>>(this, source, offset);
380+
}
381+
370382
toString(): string {
371383
return this.join();
372384
}
@@ -491,6 +503,10 @@ export class Int16Array extends ArrayBufferView {
491503
return joinIntegerArray<i16>(this.dataStart, this.length, separator);
492504
}
493505

506+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
507+
SET<Int16Array, i16, U, valueof<U>>(this, source, offset);
508+
}
509+
494510
toString(): string {
495511
return this.join();
496512
}
@@ -615,6 +631,10 @@ export class Uint16Array extends ArrayBufferView {
615631
return joinIntegerArray<u16>(this.dataStart, this.length, separator);
616632
}
617633

634+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
635+
SET<Uint16Array, u16, U, valueof<U>>(this, source, offset);
636+
}
637+
618638
toString(): string {
619639
return this.join();
620640
}
@@ -739,6 +759,10 @@ export class Int32Array extends ArrayBufferView {
739759
return joinIntegerArray<i32>(this.dataStart, this.length, separator);
740760
}
741761

762+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
763+
SET<Int32Array, i32, U, valueof<U>>(this, source, offset);
764+
}
765+
742766
toString(): string {
743767
return this.join();
744768
}
@@ -863,6 +887,10 @@ export class Uint32Array extends ArrayBufferView {
863887
return joinIntegerArray<u32>(this.dataStart, this.length, separator);
864888
}
865889

890+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
891+
SET<Uint32Array, u32, U, valueof<U>>(this, source, offset);
892+
}
893+
866894
toString(): string {
867895
return this.join();
868896
}
@@ -987,6 +1015,10 @@ export class Int64Array extends ArrayBufferView {
9871015
return joinIntegerArray<i64>(this.dataStart, this.length, separator);
9881016
}
9891017

1018+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
1019+
SET<Int64Array, i64, U, valueof<U>>(this, source, offset);
1020+
}
1021+
9901022
toString(): string {
9911023
return this.join();
9921024
}
@@ -1111,6 +1143,10 @@ export class Uint64Array extends ArrayBufferView {
11111143
return joinIntegerArray<u64>(this.dataStart, this.length, separator);
11121144
}
11131145

1146+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
1147+
SET<Uint64Array, u64, U, valueof<U>>(this, source, offset);
1148+
}
1149+
11141150
toString(): string {
11151151
return this.join();
11161152
}
@@ -1235,6 +1271,10 @@ export class Float32Array extends ArrayBufferView {
12351271
return joinFloatArray<f32>(this.dataStart, this.length, separator);
12361272
}
12371273

1274+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
1275+
SET<Float32Array, f32, U, valueof<U>>(this, source, offset);
1276+
}
1277+
12381278
toString(): string {
12391279
return this.join();
12401280
}
@@ -1359,6 +1399,10 @@ export class Float64Array extends ArrayBufferView {
13591399
return joinFloatArray<f64>(this.dataStart, this.length, separator);
13601400
}
13611401

1402+
set<U extends ArrayBufferView>(source: U, offset: i32 = 0): void {
1403+
SET<Float64Array, f64, U, valueof<U>>(this, source, offset);
1404+
}
1405+
13621406
toString(): string {
13631407
return this.join();
13641408
}
@@ -1718,3 +1762,73 @@ function WRAP<TArray extends ArrayBufferView, T>(buffer: ArrayBuffer, byteOffset
17181762
store<usize>(out, changetype<usize>(buffer) + <usize>byteOffset, offsetof<TArray>("dataStart"));
17191763
return changetype<TArray>(out); // retains
17201764
}
1765+
1766+
// @ts-ignore: decorator
1767+
@inline
1768+
function SET<TArray extends ArrayBufferView, T, UArray extends ArrayBufferView, U>(target: TArray, source: UArray, offset: i32 = 0): void {
1769+
// need to assert at compile time that U is not a reference or a function
1770+
if (isReference<U>()) {
1771+
ERROR(E_NOTIMPLEMENTED);
1772+
}
1773+
1774+
// Uncaught RangeError: offset is out of bounds
1775+
if (offset < 0) throw new RangeError(E_INDEXOUTOFRANGE);
1776+
if (source.length + offset > target.length) throw new RangeError(E_INDEXOUTOFRANGE);
1777+
1778+
// if the types align and match, use memory.copy() instead of manual loop
1779+
if (isInteger<T>() == isInteger<U>() && alignof<T>() == alignof<U>() &&
1780+
!(target instanceof Uint8ClampedArray && isSigned<U>())) {
1781+
memory.copy(
1782+
target.dataStart + (<usize>offset << alignof<T>()),
1783+
source.dataStart,
1784+
source.byteLength
1785+
);
1786+
} else {
1787+
let targetDataStart = target.dataStart + (<usize>offset << alignof<T>());
1788+
let sourceDataStart = source.dataStart;
1789+
let count = source.length;
1790+
for (let i = 0; i < count; i++) {
1791+
// if TArray is Uint8ClampedArray, then values must be clamped
1792+
if (target instanceof Uint8ClampedArray) {
1793+
if (isFloat<U>()) {
1794+
let value = load<U>(sourceDataStart + (<usize>i << alignof<U>()));
1795+
store<T>(
1796+
targetDataStart + (<usize>i << alignof<T>()),
1797+
isFinite<U>(value) ? <T>max<U>(0, min<U>(255, value)) : 0
1798+
);
1799+
} else {
1800+
let value = load<U>(sourceDataStart + (<usize>i << alignof<U>()));
1801+
if (!isSigned<U>()) {
1802+
store<T>(
1803+
targetDataStart + (<usize>i << alignof<T>()),
1804+
// @ts-ignore: cast to T is valid for numeric types here
1805+
min<U>(255, value)
1806+
);
1807+
} else if (sizeof<T>() <= 4) {
1808+
store<T>(
1809+
targetDataStart + (<usize>i << alignof<T>()),
1810+
// @ts-ignore: cast to T is valid for numeric types here
1811+
~(<i32>value >> 31) & (((255 - <i32>value) >> 31) | value)
1812+
);
1813+
} else {
1814+
store<T>(
1815+
targetDataStart + (<usize>i << alignof<T>()),
1816+
// @ts-ignore: cast to T is valid for numeric types here
1817+
~(<i64>value >> 63) & (((255 - <i64>value) >> 63) | value)
1818+
);
1819+
}
1820+
}
1821+
// if U is a float, then casting float to int must include a finite check
1822+
} else if (isFloat<U>() && !isFloat<T>()) {
1823+
let value = load<U>(sourceDataStart + (<usize>i << alignof<U>()));
1824+
// @ts-ignore: cast to T is valid for numeric types here
1825+
store<T>(targetDataStart + (<usize>i << alignof<T>()), isFinite<U>(value) ? <T>value : 0);
1826+
} else if (isFloat<T>() && !isFloat<U>()) {
1827+
// @ts-ignore: In this case the <T> conversion is required
1828+
store<T>(targetDataStart + (<usize>i << alignof<T>()), <T>load<U>(sourceDataStart + (<usize>i << alignof<U>())));
1829+
} else {
1830+
store<T>(targetDataStart + (<usize>i << alignof<T>()), load<U>(sourceDataStart + (<usize>i << alignof<U>())));
1831+
}
1832+
}
1833+
}
1834+
}

tests/compiler/resolve-elementaccess.optimized.wat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@
224224
if
225225
i32.const 128
226226
i32.const 184
227-
i32.const 1151
227+
i32.const 1187
228228
i32.const 63
229229
call $~lib/builtins/abort
230230
unreachable
@@ -248,7 +248,7 @@
248248
if
249249
i32.const 128
250250
i32.const 184
251-
i32.const 1140
251+
i32.const 1176
252252
i32.const 63
253253
call $~lib/builtins/abort
254254
unreachable

tests/compiler/resolve-elementaccess.untouched.wat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@
527527
if
528528
i32.const 128
529529
i32.const 184
530-
i32.const 1151
530+
i32.const 1187
531531
i32.const 63
532532
call $~lib/builtins/abort
533533
unreachable
@@ -551,7 +551,7 @@
551551
if
552552
i32.const 128
553553
i32.const 184
554-
i32.const 1140
554+
i32.const 1176
555555
i32.const 63
556556
call $~lib/builtins/abort
557557
unreachable

tests/compiler/std/dataview.optimized.wat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1887,7 +1887,7 @@
18871887
if
18881888
i32.const 280
18891889
i32.const 376
1890-
i32.const 159
1890+
i32.const 163
18911891
i32.const 44
18921892
call $~lib/builtins/abort
18931893
unreachable

tests/compiler/std/dataview.untouched.wat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3636,7 +3636,7 @@
36363636
if
36373637
i32.const 280
36383638
i32.const 376
3639-
i32.const 159
3639+
i32.const 163
36403640
i32.const 44
36413641
call $~lib/builtins/abort
36423642
unreachable

0 commit comments

Comments
 (0)