diff --git a/polyfill.d.ts b/polyfill.d.ts
index 45a5f97..1c024b8 100644
--- a/polyfill.d.ts
+++ b/polyfill.d.ts
@@ -78,5 +78,19 @@ declare global {
toSorted(compareFn?: (a: number, b: number) => number): this;
toSpliced(start: number, deleteCount?: number, ...values: number[]): this;
}
+
+ interface BigInt64Array {
+ with(index: number, value: bigint): this;
+ toReversed(): this;
+ toSorted(compareFn?: (a: bigint, b: bigint) => number | bigint): this;
+ toSpliced(start: number, deleteCount?: number, ...values: bigint[]): this;
+ }
+
+ interface BigUint64Array {
+ with(index: number, value: bigint): this;
+ toReversed(): this;
+ toSorted(compareFn?: (a: bigint, b: bigint) => number | bigint): this;
+ toSpliced(start: number, deleteCount?: number, ...values: bigint[]): this;
+ }
}
export {};
diff --git a/polyfill.js b/polyfill.js
index 75cc749..0829ffd 100644
--- a/polyfill.js
+++ b/polyfill.js
@@ -1,5 +1,6 @@
// @ts-check
///
+///
((arrayPrototype, typedArrayPrototype) => {
"use strict";
@@ -44,7 +45,7 @@
return Math.max(0, Math.min(len, Number.MAX_SAFE_INTEGER));
}
- /** @typedef {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} TypedArray */
+ /** @typedef {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array|BigInt64Array|BigUint64Array} TypedArray */
/**
* @param {unknown} v
@@ -92,6 +93,10 @@
return new Float32Array(length);
case 'Float64Array':
return new Float64Array(length);
+ case 'BigInt64Array':
+ return new BigInt64Array(length);
+ case 'BigUint64Array':
+ return new BigUint64Array(length);
default:
/** @type {never} */
const n = arrayName;
@@ -99,6 +104,21 @@
}
}
+ /**
+ * @param {TypedArray} example
+ * @returns {boolean}
+ */
+ function isBigIntArray(example) {
+ assertTypedArray(example);
+ const arrayName = typedArrayNameInternalSlot(example);
+ switch (arrayName) {
+ case 'BigInt64Array':
+ case 'BigUint64Array':
+ return true;
+ }
+ return false;
+ }
+
function transfer({ count, src, srcStart, srcStep = 1, target, targetStart, targetStep = srcStep }) {
let from = srcStart;
let to = targetStart;
@@ -249,12 +269,22 @@
const len = typedArrayLength(o);
const relativeIndex = toIntegerOrInfinity(index);
const actualIndex = relativeIndex < 0 ? len + relativeIndex : relativeIndex;
+ let asNumber;
+ {
+ if (isBigIntArray(o)) {
+ asNumber = 0n;
+ } else {
+ asNumber = -0; // important to use `-0` and not `0`
+ }
+ // @ts-ignore : using `+=` to emulate ToBigInt or ToNumber
+ asNumber += value;
+ }
if (actualIndex < 0 || actualIndex >= len) {
throw new RangeError();
}
const a = typedArrayCreate(o, len);
for (let k = 0; k < len; k++) {
- const v = k === actualIndex ? value : o[k];
+ const v = k === actualIndex ? asNumber : o[k];
a[k] = v;
}
return a;
diff --git a/polyfill.test.js b/polyfill.test.js
index d6b8b06..55e79f1 100644
--- a/polyfill.test.js
+++ b/polyfill.test.js
@@ -259,6 +259,29 @@ tape("Array.prototype[Symbol.unscopables]", (t) => {
t.end();
});
+ tape(`${TypedArray.name}.prototype.with executes 'user code' before starting copy`, (t) => {
+ const orig = new TypedArray([1, 2, 3]);
+ const idx = 1;
+ const valueUserCodeWillInsert = 4;
+ const userCodeReturnValue = 5;
+ const expected = new TypedArray([valueUserCodeWillInsert, userCodeReturnValue, 3]);
+ let userCodeExecuted = false;
+ /** @type any */
+ const val = {
+ valueOf() {
+ userCodeExecuted = true;
+ orig[0] = valueUserCodeWillInsert;
+ return userCodeReturnValue;
+ }
+ };
+
+ const copy = orig.with(idx, val);
+ t.assert(userCodeExecuted);
+ t.deepEqual(copy, expected);
+
+ t.end();
+ });
+
tape(`${TypedArray.name} does not use Symbol.species for the new methods`, (t) => {
class SubClass extends TypedArray { }
@@ -279,3 +302,158 @@ tape("Array.prototype[Symbol.unscopables]", (t) => {
t.end();
});
});
+
+[
+ BigInt64Array,
+ BigUint64Array
+].forEach((TypedArray) => {
+ tape(`${TypedArray.name}.prototype.toReversed`, (t) => {
+ const orig = new TypedArray([3n, 2n, 1n]);
+ const expected = new TypedArray([1n, 2n, 3n]);
+
+ const copy = orig.toReversed();
+
+ t.deepEqual(copy, expected);
+ t.notEqual(orig, copy);
+ t.notDeepEqual(orig, copy);
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.toSorted`, (t) => {
+ const orig = new TypedArray([3n, 1n, 2n]);
+ const expected = new TypedArray([1n, 2n, 3n]);
+
+ const copy = orig.toSorted();
+
+ t.deepEqual(copy, expected);
+ t.notEqual(orig, copy);
+ t.notDeepEqual(orig, copy);
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.toSorted(compareFn)`, (t) => {
+ const orig = new TypedArray([3n, 1n, 2n]);
+ const expected = new TypedArray([3n, 2n, 1n]);
+ function compareFn(a, b) {
+ return a > b ? -1 : 1;
+ }
+
+ const copy = orig.toSorted(compareFn);
+
+ t.deepEqual(copy, expected);
+ t.notEqual(orig, copy);
+ t.notDeepEqual(orig, copy);
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.toSpliced`, (t) => {
+ const orig = new TypedArray([1n, -1n, 0n, -1n, 4n]);
+ const expected = new TypedArray([1n, 2n, 3n, 4n]);
+ const idx = 1;
+ const delNum = 3;
+ const ins = [2n, 3n];
+
+ const copy = orig.toSpliced(idx, delNum, ...ins);
+
+ t.deepEqual(copy, expected);
+ t.notEqual(orig, copy);
+ t.notDeepEqual(orig, copy);
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.with`, (t) => {
+ const orig = new TypedArray([1n, 1n, 3n]);
+ const expected = new TypedArray([1n, 2n, 3n]);
+ const idx = 1;
+ const val = 2n;
+
+ const copy = orig.with(idx, val);
+
+ t.deepEqual(copy, expected);
+ t.notEqual(orig, copy);
+ t.notDeepEqual(orig, copy);
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.with non bigint throws`, (t) => {
+ const orig = new TypedArray([1n, 2n, 2n]);
+ const idx = 3;
+ const val = 4;
+
+ t.throws(() => {
+ // @ts-expect-error inserting number instead of bigint
+ orig.with(idx, val);
+ }, TypeError);
+
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.with negativeIndex`, (t) => {
+ const orig = new TypedArray([1n, 2n, 2n]);
+ const expected = new TypedArray([1n, 2n, 3n]);
+ const idx = -1;
+ const val = 3n;
+
+ const copy = orig.with(idx, val);
+
+ t.deepEqual(copy, expected);
+ t.notEqual(orig, copy);
+ t.notDeepEqual(orig, copy);
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.with out of bounds`, (t) => {
+ const orig = new TypedArray([1n, 2n, 2n]);
+ const idx = 3;
+ const val = 4n;
+
+ t.throws(() => {
+ orig.with(idx, val);
+ }, RangeError);
+
+ t.end();
+ });
+
+ tape(`${TypedArray.name}.prototype.with executes 'user code' before starting copy`, (t) => {
+ const orig = new TypedArray([1n, 2n, 3n]);
+ const idx = 1;
+ const valueUserCodeWillInsert = 4n;
+ const userCodeReturnValue = 5n;
+ const expected = new TypedArray([valueUserCodeWillInsert, userCodeReturnValue, 3n]);
+ let userCodeExecuted = false;
+ /** @type any */
+ const val = {
+ valueOf() {
+ userCodeExecuted = true;
+ orig[0] = valueUserCodeWillInsert;
+ return userCodeReturnValue;
+ }
+ };
+
+ const copy = orig.with(idx, val);
+ t.assert(userCodeExecuted);
+ t.deepEqual(copy, expected);
+
+ t.end();
+ });
+
+ tape(`${TypedArray.name} does not use Symbol.species for the new methods`, (t) => {
+ class SubClass extends TypedArray { }
+
+ function assertType(arr) {
+ t.equal(arr instanceof SubClass, false);
+ t.equal(arr instanceof TypedArray, true);
+ }
+
+ /** @type {BigInt64Array} */
+ // @ts-ignore
+ const orig = new SubClass([1n, 2n, 3n]);
+
+ assertType(orig.with(0, 0n));
+ assertType(orig.toReversed());
+ assertType(orig.toSorted());
+ assertType(orig.toSpliced(0, 0));
+
+ t.end();
+ });
+});