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

update pollyfill after #85 and support bigint #87

Merged
merged 1 commit into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions polyfill.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
34 changes: 32 additions & 2 deletions polyfill.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
/// <reference path="./polyfill.d.ts" />
/// <reference lib="es2020" />

((arrayPrototype, typedArrayPrototype) => {
"use strict";
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -92,13 +93,32 @@
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;
throw new Error(`Unexpected TypedArray name ${n}`);
}
}

/**
* @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;
Expand Down Expand Up @@ -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;
Expand Down
178 changes: 178 additions & 0 deletions polyfill.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 { }

Expand All @@ -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();
});
});