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

Commit

Permalink
Merge pull request #87 from acutmore/match-latest-spec-and-support-bi…
Browse files Browse the repository at this point in the history
…gint

update pollyfill after #85 and support bigint
  • Loading branch information
Robin Ricard committed Jun 10, 2022
2 parents 0cd4150 + e95267a commit 435df6c
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 2 deletions.
14 changes: 14 additions & 0 deletions polyfill.d.ts
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
@@ -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
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();
});
});

0 comments on commit 435df6c

Please sign in to comment.