Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 435df6c

Browse files
author
Robin Ricard
authored
Merge pull request #87 from acutmore/match-latest-spec-and-support-bigint
update pollyfill after #85 and support bigint
2 parents 0cd4150 + e95267a commit 435df6c

File tree

3 files changed

+224
-2
lines changed

3 files changed

+224
-2
lines changed

polyfill.d.ts

+14
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,19 @@ declare global {
7878
toSorted(compareFn?: (a: number, b: number) => number): this;
7979
toSpliced(start: number, deleteCount?: number, ...values: number[]): this;
8080
}
81+
82+
interface BigInt64Array {
83+
with(index: number, value: bigint): this;
84+
toReversed(): this;
85+
toSorted(compareFn?: (a: bigint, b: bigint) => number | bigint): this;
86+
toSpliced(start: number, deleteCount?: number, ...values: bigint[]): this;
87+
}
88+
89+
interface BigUint64Array {
90+
with(index: number, value: bigint): this;
91+
toReversed(): this;
92+
toSorted(compareFn?: (a: bigint, b: bigint) => number | bigint): this;
93+
toSpliced(start: number, deleteCount?: number, ...values: bigint[]): this;
94+
}
8195
}
8296
export {};

polyfill.js

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-check
22
/// <reference path="./polyfill.d.ts" />
3+
/// <reference lib="es2020" />
34

45
((arrayPrototype, typedArrayPrototype) => {
56
"use strict";
@@ -44,7 +45,7 @@
4445
return Math.max(0, Math.min(len, Number.MAX_SAFE_INTEGER));
4546
}
4647

47-
/** @typedef {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} TypedArray */
48+
/** @typedef {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array|BigInt64Array|BigUint64Array} TypedArray */
4849

4950
/**
5051
* @param {unknown} v
@@ -92,13 +93,32 @@
9293
return new Float32Array(length);
9394
case 'Float64Array':
9495
return new Float64Array(length);
96+
case 'BigInt64Array':
97+
return new BigInt64Array(length);
98+
case 'BigUint64Array':
99+
return new BigUint64Array(length);
95100
default:
96101
/** @type {never} */
97102
const n = arrayName;
98103
throw new Error(`Unexpected TypedArray name ${n}`);
99104
}
100105
}
101106

107+
/**
108+
* @param {TypedArray} example
109+
* @returns {boolean}
110+
*/
111+
function isBigIntArray(example) {
112+
assertTypedArray(example);
113+
const arrayName = typedArrayNameInternalSlot(example);
114+
switch (arrayName) {
115+
case 'BigInt64Array':
116+
case 'BigUint64Array':
117+
return true;
118+
}
119+
return false;
120+
}
121+
102122
function transfer({ count, src, srcStart, srcStep = 1, target, targetStart, targetStep = srcStep }) {
103123
let from = srcStart;
104124
let to = targetStart;
@@ -249,12 +269,22 @@
249269
const len = typedArrayLength(o);
250270
const relativeIndex = toIntegerOrInfinity(index);
251271
const actualIndex = relativeIndex < 0 ? len + relativeIndex : relativeIndex;
272+
let asNumber;
273+
{
274+
if (isBigIntArray(o)) {
275+
asNumber = 0n;
276+
} else {
277+
asNumber = -0; // important to use `-0` and not `0`
278+
}
279+
// @ts-ignore : using `+=` to emulate ToBigInt or ToNumber
280+
asNumber += value;
281+
}
252282
if (actualIndex < 0 || actualIndex >= len) {
253283
throw new RangeError();
254284
}
255285
const a = typedArrayCreate(o, len);
256286
for (let k = 0; k < len; k++) {
257-
const v = k === actualIndex ? value : o[k];
287+
const v = k === actualIndex ? asNumber : o[k];
258288
a[k] = v;
259289
}
260290
return a;

polyfill.test.js

+178
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,29 @@ tape("Array.prototype[Symbol.unscopables]", (t) => {
259259
t.end();
260260
});
261261

262+
tape(`${TypedArray.name}.prototype.with executes 'user code' before starting copy`, (t) => {
263+
const orig = new TypedArray([1, 2, 3]);
264+
const idx = 1;
265+
const valueUserCodeWillInsert = 4;
266+
const userCodeReturnValue = 5;
267+
const expected = new TypedArray([valueUserCodeWillInsert, userCodeReturnValue, 3]);
268+
let userCodeExecuted = false;
269+
/** @type any */
270+
const val = {
271+
valueOf() {
272+
userCodeExecuted = true;
273+
orig[0] = valueUserCodeWillInsert;
274+
return userCodeReturnValue;
275+
}
276+
};
277+
278+
const copy = orig.with(idx, val);
279+
t.assert(userCodeExecuted);
280+
t.deepEqual(copy, expected);
281+
282+
t.end();
283+
});
284+
262285
tape(`${TypedArray.name} does not use Symbol.species for the new methods`, (t) => {
263286
class SubClass extends TypedArray { }
264287

@@ -279,3 +302,158 @@ tape("Array.prototype[Symbol.unscopables]", (t) => {
279302
t.end();
280303
});
281304
});
305+
306+
[
307+
BigInt64Array,
308+
BigUint64Array
309+
].forEach((TypedArray) => {
310+
tape(`${TypedArray.name}.prototype.toReversed`, (t) => {
311+
const orig = new TypedArray([3n, 2n, 1n]);
312+
const expected = new TypedArray([1n, 2n, 3n]);
313+
314+
const copy = orig.toReversed();
315+
316+
t.deepEqual(copy, expected);
317+
t.notEqual(orig, copy);
318+
t.notDeepEqual(orig, copy);
319+
t.end();
320+
});
321+
322+
tape(`${TypedArray.name}.prototype.toSorted`, (t) => {
323+
const orig = new TypedArray([3n, 1n, 2n]);
324+
const expected = new TypedArray([1n, 2n, 3n]);
325+
326+
const copy = orig.toSorted();
327+
328+
t.deepEqual(copy, expected);
329+
t.notEqual(orig, copy);
330+
t.notDeepEqual(orig, copy);
331+
t.end();
332+
});
333+
334+
tape(`${TypedArray.name}.prototype.toSorted(compareFn)`, (t) => {
335+
const orig = new TypedArray([3n, 1n, 2n]);
336+
const expected = new TypedArray([3n, 2n, 1n]);
337+
function compareFn(a, b) {
338+
return a > b ? -1 : 1;
339+
}
340+
341+
const copy = orig.toSorted(compareFn);
342+
343+
t.deepEqual(copy, expected);
344+
t.notEqual(orig, copy);
345+
t.notDeepEqual(orig, copy);
346+
t.end();
347+
});
348+
349+
tape(`${TypedArray.name}.prototype.toSpliced`, (t) => {
350+
const orig = new TypedArray([1n, -1n, 0n, -1n, 4n]);
351+
const expected = new TypedArray([1n, 2n, 3n, 4n]);
352+
const idx = 1;
353+
const delNum = 3;
354+
const ins = [2n, 3n];
355+
356+
const copy = orig.toSpliced(idx, delNum, ...ins);
357+
358+
t.deepEqual(copy, expected);
359+
t.notEqual(orig, copy);
360+
t.notDeepEqual(orig, copy);
361+
t.end();
362+
});
363+
364+
tape(`${TypedArray.name}.prototype.with`, (t) => {
365+
const orig = new TypedArray([1n, 1n, 3n]);
366+
const expected = new TypedArray([1n, 2n, 3n]);
367+
const idx = 1;
368+
const val = 2n;
369+
370+
const copy = orig.with(idx, val);
371+
372+
t.deepEqual(copy, expected);
373+
t.notEqual(orig, copy);
374+
t.notDeepEqual(orig, copy);
375+
t.end();
376+
});
377+
378+
tape(`${TypedArray.name}.prototype.with non bigint throws`, (t) => {
379+
const orig = new TypedArray([1n, 2n, 2n]);
380+
const idx = 3;
381+
const val = 4;
382+
383+
t.throws(() => {
384+
// @ts-expect-error inserting number instead of bigint
385+
orig.with(idx, val);
386+
}, TypeError);
387+
388+
t.end();
389+
});
390+
391+
tape(`${TypedArray.name}.prototype.with negativeIndex`, (t) => {
392+
const orig = new TypedArray([1n, 2n, 2n]);
393+
const expected = new TypedArray([1n, 2n, 3n]);
394+
const idx = -1;
395+
const val = 3n;
396+
397+
const copy = orig.with(idx, val);
398+
399+
t.deepEqual(copy, expected);
400+
t.notEqual(orig, copy);
401+
t.notDeepEqual(orig, copy);
402+
t.end();
403+
});
404+
405+
tape(`${TypedArray.name}.prototype.with out of bounds`, (t) => {
406+
const orig = new TypedArray([1n, 2n, 2n]);
407+
const idx = 3;
408+
const val = 4n;
409+
410+
t.throws(() => {
411+
orig.with(idx, val);
412+
}, RangeError);
413+
414+
t.end();
415+
});
416+
417+
tape(`${TypedArray.name}.prototype.with executes 'user code' before starting copy`, (t) => {
418+
const orig = new TypedArray([1n, 2n, 3n]);
419+
const idx = 1;
420+
const valueUserCodeWillInsert = 4n;
421+
const userCodeReturnValue = 5n;
422+
const expected = new TypedArray([valueUserCodeWillInsert, userCodeReturnValue, 3n]);
423+
let userCodeExecuted = false;
424+
/** @type any */
425+
const val = {
426+
valueOf() {
427+
userCodeExecuted = true;
428+
orig[0] = valueUserCodeWillInsert;
429+
return userCodeReturnValue;
430+
}
431+
};
432+
433+
const copy = orig.with(idx, val);
434+
t.assert(userCodeExecuted);
435+
t.deepEqual(copy, expected);
436+
437+
t.end();
438+
});
439+
440+
tape(`${TypedArray.name} does not use Symbol.species for the new methods`, (t) => {
441+
class SubClass extends TypedArray { }
442+
443+
function assertType(arr) {
444+
t.equal(arr instanceof SubClass, false);
445+
t.equal(arr instanceof TypedArray, true);
446+
}
447+
448+
/** @type {BigInt64Array} */
449+
// @ts-ignore
450+
const orig = new SubClass([1n, 2n, 3n]);
451+
452+
assertType(orig.with(0, 0n));
453+
assertType(orig.toReversed());
454+
assertType(orig.toSorted());
455+
assertType(orig.toSpliced(0, 0));
456+
457+
t.end();
458+
});
459+
});

0 commit comments

Comments
 (0)