blob: f24f2de46b5965fda6b59fcd8286af2b782435b6 [file] [log] [blame]
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-rab-gsab --allow-natives-syntax
// Flags: --harmony-relative-indexing-methods --harmony-array-find-last
"use strict";
d8.file.execute('test/mjsunit/typedarray-helpers.js');
(function TypedArrayPrototype() {
const rab = CreateResizableArrayBuffer(40, 80);
const ab = new ArrayBuffer(80);
for (let ctor of ctors) {
const ta_rab = new ctor(rab, 0, 3);
const ta_ab = new ctor(ab, 0, 3);
assertEquals(ta_rab.__proto__, ta_ab.__proto__);
}
})();
(function TypedArrayLengthAndByteLength() {
const rab = CreateResizableArrayBuffer(40, 80);
for (let ctor of ctors) {
const ta = new ctor(rab, 0, 3);
assertEquals(rab, ta.buffer);
assertEquals(3, ta.length);
assertEquals(3 * ctor.BYTES_PER_ELEMENT, ta.byteLength);
const empty_ta = new ctor(rab, 0, 0);
assertEquals(rab, empty_ta.buffer);
assertEquals(0, empty_ta.length);
assertEquals(0, empty_ta.byteLength);
const ta_with_offset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 3);
assertEquals(rab, ta_with_offset.buffer);
assertEquals(3, ta_with_offset.length);
assertEquals(3 * ctor.BYTES_PER_ELEMENT, ta_with_offset.byteLength);
const empty_ta_with_offset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 0);
assertEquals(rab, empty_ta_with_offset.buffer);
assertEquals(0, empty_ta_with_offset.length);
assertEquals(0, empty_ta_with_offset.byteLength);
const length_tracking_ta = new ctor(rab);
assertEquals(rab, length_tracking_ta.buffer);
assertEquals(40 / ctor.BYTES_PER_ELEMENT, length_tracking_ta.length);
assertEquals(40, length_tracking_ta.byteLength);
const offset = 8;
const length_tracking_ta_with_offset = new ctor(rab, offset);
assertEquals(rab, length_tracking_ta_with_offset.buffer);
assertEquals((40 - offset) / ctor.BYTES_PER_ELEMENT,
length_tracking_ta_with_offset.length);
assertEquals(40 - offset, length_tracking_ta_with_offset.byteLength);
const empty_length_tracking_ta_with_offset = new ctor(rab, 40);
assertEquals(rab, empty_length_tracking_ta_with_offset.buffer);
assertEquals(0, empty_length_tracking_ta_with_offset.length);
assertEquals(0, empty_length_tracking_ta_with_offset.byteLength);
}
})();
(function ConstructInvalid() {
const rab = CreateResizableArrayBuffer(40, 80);
for (let ctor of ctors) {
// Length too big.
assertThrows(() => { new ctor(rab, 0, 40 / ctor.BYTES_PER_ELEMENT + 1); },
RangeError);
// Offset too close to the end.
assertThrows(() => { new ctor(rab, 40 - ctor.BYTES_PER_ELEMENT, 2); },
RangeError);
// Offset beyond end.
assertThrows(() => { new ctor(rab, 40, 1); }, RangeError);
if (ctor.BYTES_PER_ELEMENT > 1) {
// Offset not a multiple of the byte size.
assertThrows(() => { new ctor(rab, 1, 1); }, RangeError);
assertThrows(() => { new ctor(rab, 1); }, RangeError);
}
}
// Verify the error messages.
assertThrows(() => { new Int16Array(rab, 1, 1); }, RangeError,
/start offset of Int16Array should be a multiple of 2/);
assertThrows(() => { new Int16Array(rab, 38, 2); }, RangeError,
/Invalid typed array length: 2/);
})();
(function ConstructFromTypedArray() {
AllBigIntMatchedCtorCombinations((targetCtor, sourceCtor) => {
const rab = CreateResizableArrayBuffer(
4 * sourceCtor.BYTES_PER_ELEMENT,
8 * sourceCtor.BYTES_PER_ELEMENT);
const fixedLength = new sourceCtor(rab, 0, 4);
const fixedLengthWithOffset = new sourceCtor(
rab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new sourceCtor(rab, 0);
const lengthTrackingWithOffset = new sourceCtor(
rab, 2 * sourceCtor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taFull = new sourceCtor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, ...] << lengthTracking
// [3, 4, ...] << lengthTrackingWithOffset
assertEquals([1, 2, 3, 4], ToNumbers(new targetCtor(fixedLength)));
assertEquals([3, 4], ToNumbers(new targetCtor(fixedLengthWithOffset)));
assertEquals([1, 2, 3, 4], ToNumbers(new targetCtor(lengthTracking)));
assertEquals([3, 4], ToNumbers(new targetCtor(lengthTrackingWithOffset)));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * sourceCtor.BYTES_PER_ELEMENT);
// Orig. array: [1, 2, 3]
// [1, 2, 3, ...] << lengthTracking
// [3, ...] << lengthTrackingWithOffset
assertThrows(() => { new targetCtor(fixedLength); }, TypeError);
assertThrows(() => { new targetCtor(fixedLengthWithOffset); }, TypeError);
assertEquals([1, 2, 3], ToNumbers(new targetCtor(lengthTracking)));
assertEquals([3], ToNumbers(new targetCtor(lengthTrackingWithOffset)));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * sourceCtor.BYTES_PER_ELEMENT);
assertThrows(() => { new targetCtor(fixedLength); }, TypeError);
assertThrows(() => { new targetCtor(fixedLengthWithOffset); }, TypeError);
assertEquals([1], ToNumbers(new targetCtor(lengthTracking)));
assertThrows(() => { new targetCtor(lengthTrackingWithOffset); },
TypeError);
// Shrink to zero.
rab.resize(0);
assertThrows(() => { new targetCtor(fixedLength); }, TypeError);
assertThrows(() => { new targetCtor(fixedLengthWithOffset); }, TypeError);
assertEquals([], ToNumbers(new targetCtor(lengthTracking)));
assertThrows(() => { new targetCtor(lengthTrackingWithOffset); },
TypeError);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * sourceCtor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, 5, 6, ...] << lengthTracking
// [3, 4, 5, 6, ...] << lengthTrackingWithOffset
assertEquals([1, 2, 3, 4], ToNumbers(new targetCtor(fixedLength)));
assertEquals([3, 4], ToNumbers(new targetCtor(fixedLengthWithOffset)));
assertEquals([1, 2, 3, 4, 5, 6],
ToNumbers(new targetCtor(lengthTracking)));
assertEquals([3, 4, 5, 6],
ToNumbers(new targetCtor(lengthTrackingWithOffset)));
});
})();
(function TypedArrayLengthWhenResizedOutOfBounds1() {
const rab = CreateResizableArrayBuffer(16, 40);
// Create TAs which cover the bytes 0-7.
let tas_and_lengths = [];
for (let ctor of ctors) {
const length = 8 / ctor.BYTES_PER_ELEMENT;
tas_and_lengths.push([new ctor(rab, 0, length), length]);
}
for (let [ta, length] of tas_and_lengths) {
assertEquals(length, ta.length);
assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength);
}
rab.resize(2);
for (let [ta, length] of tas_and_lengths) {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
}
// Resize the rab so that it just barely covers the needed 8 bytes.
rab.resize(8);
for (let [ta, length] of tas_and_lengths) {
assertEquals(length, ta.length);
assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength);
}
rab.resize(40);
for (let [ta, length] of tas_and_lengths) {
assertEquals(length, ta.length);
assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength);
}
})();
// The previous test with offsets.
(function TypedArrayLengthWhenResizedOutOfBounds2() {
const rab = CreateResizableArrayBuffer(20, 40);
// Create TAs which cover the bytes 8-15.
let tas_and_lengths = [];
for (let ctor of ctors) {
const length = 8 / ctor.BYTES_PER_ELEMENT;
tas_and_lengths.push([new ctor(rab, 8, length), length]);
}
for (let [ta, length] of tas_and_lengths) {
assertEquals(length, ta.length);
assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength);
assertEquals(8, ta.byteOffset);
}
rab.resize(10);
for (let [ta, length] of tas_and_lengths) {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
assertEquals(0, ta.byteOffset);
}
// Resize the rab so that it just barely covers the needed 8 bytes.
rab.resize(16);
for (let [ta, length] of tas_and_lengths) {
assertEquals(length, ta.length);
assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength);
assertEquals(8, ta.byteOffset);
}
rab.resize(40);
for (let [ta, length] of tas_and_lengths) {
assertEquals(length, ta.length);
assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength);
assertEquals(8, ta.byteOffset);
}
})();
(function LengthTracking1() {
const rab = CreateResizableArrayBuffer(16, 40);
let tas = [];
for (let ctor of ctors) {
tas.push(new ctor(rab));
}
for (let ta of tas) {
assertEquals(16 / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(16, ta.byteLength);
}
rab.resize(40);
for (let ta of tas) {
assertEquals(40 / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(40, ta.byteLength);
}
// Resize to a number which is not a multiple of all byte_lengths.
rab.resize(19);
for (let ta of tas) {
const expected_length = Math.floor(19 / ta.BYTES_PER_ELEMENT);
assertEquals(expected_length, ta.length);
assertEquals(expected_length * ta.BYTES_PER_ELEMENT, ta.byteLength);
}
rab.resize(1);
for (let ta of tas) {
if (ta.BYTES_PER_ELEMENT == 1) {
assertEquals(1, ta.length);
assertEquals(1, ta.byteLength);
} else {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
}
}
rab.resize(0);
for (let ta of tas) {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
}
rab.resize(8);
for (let ta of tas) {
assertEquals(8 / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(8, ta.byteLength);
}
rab.resize(40);
for (let ta of tas) {
assertEquals(40 / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(40, ta.byteLength);
}
})();
// The previous test with offsets.
(function LengthTracking2() {
const rab = CreateResizableArrayBuffer(16, 40);
const offset = 8;
let tas = [];
for (let ctor of ctors) {
tas.push(new ctor(rab, offset));
}
for (let ta of tas) {
assertEquals((16 - offset) / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(16 - offset, ta.byteLength);
assertEquals(offset, ta.byteOffset);
}
rab.resize(40);
for (let ta of tas) {
assertEquals((40 - offset) / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(40 - offset, ta.byteLength);
assertEquals(offset, ta.byteOffset);
}
// Resize to a number which is not a multiple of all byte_lengths.
rab.resize(20);
for (let ta of tas) {
const expected_length = Math.floor((20 - offset)/ ta.BYTES_PER_ELEMENT);
assertEquals(expected_length, ta.length);
assertEquals(expected_length * ta.BYTES_PER_ELEMENT, ta.byteLength);
assertEquals(offset, ta.byteOffset);
}
// Resize so that all TypedArrays go out of bounds (because of the offset).
rab.resize(7);
for (let ta of tas) {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
assertEquals(0, ta.byteOffset);
}
rab.resize(0);
for (let ta of tas) {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
assertEquals(0, ta.byteOffset);
}
rab.resize(8);
for (let ta of tas) {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
assertEquals(offset, ta.byteOffset);
}
// Resize so that the TypedArrays which have element size > 1 go out of bounds
// (because less than 1 full element would fit).
rab.resize(offset + 1);
for (let ta of tas) {
if (ta.BYTES_PER_ELEMENT == 1) {
assertEquals(1, ta.length);
assertEquals(1, ta.byteLength);
assertEquals(offset, ta.byteOffset);
} else {
assertEquals(0, ta.length);
assertEquals(0, ta.byteLength);
assertEquals(offset, ta.byteOffset);
}
}
rab.resize(40);
for (let ta of tas) {
assertEquals((40 - offset) / ta.BYTES_PER_ELEMENT, ta.length);
assertEquals(40 - offset, ta.byteLength);
assertEquals(offset, ta.byteOffset);
}
})();
(function AccessOutOfBoundsTypedArray() {
for (let ctor of ctors) {
if (ctor.BYTES_PER_ELEMENT != 1) {
continue;
}
const rab = CreateResizableArrayBuffer(16, 40);
const array = new ctor(rab, 0, 4);
// Initial values
for (let i = 0; i < 4; ++i) {
assertEquals(0, array[i]);
}
// Within-bounds write
for (let i = 0; i < 4; ++i) {
array[i] = i;
}
// Within-bounds read
for (let i = 0; i < 4; ++i) {
assertEquals(i, array[i]);
}
rab.resize(2);
// OOB read. If the RAB isn't large enough to fit the entire TypedArray,
// the length of the TypedArray is treated as 0.
for (let i = 0; i < 4; ++i) {
assertEquals(undefined, array[i]);
}
// OOB write (has no effect)
for (let i = 0; i < 4; ++i) {
array[i] = 10;
}
rab.resize(4);
// Within-bounds read
for (let i = 0; i < 2; ++i) {
assertEquals(i, array[i]);
}
// The shrunk-and-regrown part got zeroed.
for (let i = 2; i < 4; ++i) {
assertEquals(0, array[i]);
}
rab.resize(40);
// Within-bounds read
for (let i = 0; i < 2; ++i) {
assertEquals(i, array[i]);
}
for (let i = 2; i < 4; ++i) {
assertEquals(0, array[i]);
}
}
})();
(function OutOfBoundsTypedArrayAndHas() {
for (let ctor of ctors) {
if (ctor.BYTES_PER_ELEMENT != 1) {
continue;
}
const rab = CreateResizableArrayBuffer(16, 40);
const array = new ctor(rab, 0, 4);
// Within-bounds read
for (let i = 0; i < 4; ++i) {
assertTrue(i in array);
}
rab.resize(2);
// OOB read. If the RAB isn't large enough to fit the entire TypedArray,
// the length of the TypedArray is treated as 0.
for (let i = 0; i < 4; ++i) {
assertFalse(i in array);
}
rab.resize(4);
// Within-bounds read
for (let i = 0; i < 4; ++i) {
assertTrue(i in array);
}
rab.resize(40);
// Within-bounds read
for (let i = 0; i < 4; ++i) {
assertTrue(i in array);
}
}
})();
(function LoadFromOutOfBoundsTypedArrayWithFeedback() {
function ReadElement2(ta) {
return ta[2];
}
%EnsureFeedbackVectorForFunction(ReadElement2);
const rab = CreateResizableArrayBuffer(16, 40);
const i8a = new Int8Array(rab, 0, 4);
for (let i = 0; i < 3; ++i) {
assertEquals(0, ReadElement2(i8a));
}
// Within-bounds write
for (let i = 0; i < 4; ++i) {
i8a[i] = i;
}
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertEquals(2, ReadElement2(i8a));
}
rab.resize(2);
// OOB read
for (let i = 0; i < 3; ++i) {
assertEquals(undefined, ReadElement2(i8a));
}
rab.resize(4);
// Within-bounds read (the memory got zeroed)
for (let i = 0; i < 3; ++i) {
assertEquals(0, ReadElement2(i8a));
}
i8a[2] = 3;
for (let i = 0; i < 3; ++i) {
assertEquals(3, ReadElement2(i8a));
}
rab.resize(40);
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertEquals(3, ReadElement2(i8a));
}
})();
(function HasAndOutOfBoundsTypedArrayWithFeedback() {
function HasElement2(ta) {
return 2 in ta;
}
%EnsureFeedbackVectorForFunction(HasElement2);
const rab = CreateResizableArrayBuffer(16, 40);
const i8a = new Int8Array(rab, 0, 4);
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertTrue(HasElement2(i8a));
}
rab.resize(2);
// OOB read
for (let i = 0; i < 3; ++i) {
assertFalse(HasElement2(i8a));
}
rab.resize(4);
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertTrue(HasElement2(i8a));
}
rab.resize(40);
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertTrue(HasElement2(i8a));
}
})();
(function HasWithOffsetsWithFeedback() {
function GetElements(ta) {
let result = '';
for (let i = 0; i < 8; ++i) {
result += (i in ta) + ',';
// ^ feedback will be here
}
return result;
}
%EnsureFeedbackVectorForFunction(GetElements);
const rab = CreateResizableArrayBuffer(4, 8);
const fixedLength = new Int8Array(rab, 0, 4);
const fixedLengthWithOffset = new Int8Array(rab, 1, 3);
const lengthTracking = new Int8Array(rab, 0);
const lengthTrackingWithOffset = new Int8Array(rab, 1);
assertEquals('true,true,true,true,false,false,false,false,',
GetElements(fixedLength));
assertEquals('true,true,true,false,false,false,false,false,',
GetElements(fixedLengthWithOffset));
assertEquals('true,true,true,true,false,false,false,false,',
GetElements(lengthTracking));
assertEquals('true,true,true,false,false,false,false,false,',
GetElements(lengthTrackingWithOffset));
rab.resize(2);
assertEquals('false,false,false,false,false,false,false,false,',
GetElements(fixedLength));
assertEquals('false,false,false,false,false,false,false,false,',
GetElements(fixedLengthWithOffset));
assertEquals('true,true,false,false,false,false,false,false,',
GetElements(lengthTracking));
assertEquals('true,false,false,false,false,false,false,false,',
GetElements(lengthTrackingWithOffset));
// Resize beyond the offset of the length tracking arrays.
rab.resize(1);
assertEquals('false,false,false,false,false,false,false,false,',
GetElements(fixedLength));
assertEquals('false,false,false,false,false,false,false,false,',
GetElements(fixedLengthWithOffset));
assertEquals('true,false,false,false,false,false,false,false,',
GetElements(lengthTracking));
assertEquals('false,false,false,false,false,false,false,false,',
GetElements(lengthTrackingWithOffset));
rab.resize(8);
assertEquals('true,true,true,true,false,false,false,false,',
GetElements(fixedLength));
assertEquals('true,true,true,false,false,false,false,false,',
GetElements(fixedLengthWithOffset));
assertEquals('true,true,true,true,true,true,true,true,',
GetElements(lengthTracking));
assertEquals('true,true,true,true,true,true,true,false,',
GetElements(lengthTrackingWithOffset));
})();
(function StoreToOutOfBoundsTypedArrayWithFeedback() {
function WriteElement2(ta, i) {
ta[2] = i;
}
%EnsureFeedbackVectorForFunction(WriteElement2);
const rab = CreateResizableArrayBuffer(16, 40);
const i8a = new Int8Array(rab, 0, 4);
assertEquals(0, i8a[2]);
// Within-bounds write
for (let i = 0; i < 3; ++i) {
WriteElement2(i8a, 3);
}
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertEquals(3, i8a[2]);
}
rab.resize(2);
// OOB write (has no effect)
for (let i = 0; i < 3; ++i) {
WriteElement2(i8a, 4);
}
rab.resize(4);
// Within-bounds read (the memory got zeroed)
for (let i = 0; i < 3; ++i) {
assertEquals(0, i8a[2]);
}
// Within-bounds write
for (let i = 0; i < 3; ++i) {
WriteElement2(i8a, 5);
}
rab.resize(40);
// Within-bounds read
for (let i = 0; i < 3; ++i) {
assertEquals(5, i8a[2]);
}
})();
(function OOBBehavesLikeDetached() {
function ReadElement2(ta) {
return ta[2];
}
function HasElement2(ta) {
return 2 in ta;
}
const rab = CreateResizableArrayBuffer(16, 40);
const i8a = new Int8Array(rab, 0, 4);
i8a.__proto__ = {2: 'wrong value'};
i8a[2] = 10;
assertEquals(10, ReadElement2(i8a));
assertTrue(HasElement2(i8a));
rab.resize(0);
assertEquals(undefined, ReadElement2(i8a));
assertFalse(HasElement2(i8a));
})();
(function OOBBehavesLikeDetachedWithFeedback() {
function ReadElement2(ta) {
return ta[2];
}
function HasElement2(ta) {
return 2 in ta;
}
%EnsureFeedbackVectorForFunction(ReadElement2);
%EnsureFeedbackVectorForFunction(HasElement2);
const rab = CreateResizableArrayBuffer(16, 40);
const i8a = new Int8Array(rab, 0, 4);
i8a.__proto__ = {2: 'wrong value'};
i8a[2] = 10;
for (let i = 0; i < 3; ++i) {
assertEquals(10, ReadElement2(i8a));
assertTrue(HasElement2(i8a));
}
rab.resize(0);
for (let i = 0; i < 3; ++i) {
assertEquals(undefined, ReadElement2(i8a));
assertFalse(HasElement2(i8a));
}
})();
(function EnumerateElements() {
let rab = CreateResizableArrayBuffer(100, 200);
for (let ctor of ctors) {
const ta = new ctor(rab, 0, 3);
let keys = '';
for (const key in ta) {
keys += key;
}
assertEquals('012', keys);
}
}());
(function IterateTypedArray() {
const no_elements = 10;
const offset = 2;
function TestIteration(ta, expected) {
let values = [];
for (const value of ta) {
values.push(Number(value));
}
assertEquals(expected, values);
}
for (let ctor of ctors) {
const buffer_byte_length = no_elements * ctor.BYTES_PER_ELEMENT;
// We can use the same RAB for all the TAs below, since we won't modify it
// after writing the initial values.
const rab = CreateResizableArrayBuffer(buffer_byte_length,
2 * buffer_byte_length);
const byte_offset = offset * ctor.BYTES_PER_ELEMENT;
// Write some data into the array.
let ta_write = new ctor(rab);
for (let i = 0; i < no_elements; ++i) {
WriteToTypedArray(ta_write, i, i % 128);
}
// Create various different styles of TypedArrays with the RAB as the
// backing store and iterate them.
const ta = new ctor(rab, 0, 3);
TestIteration(ta, [0, 1, 2]);
const empty_ta = new ctor(rab, 0, 0);
TestIteration(empty_ta, []);
const ta_with_offset = new ctor(rab, byte_offset, 3);
TestIteration(ta_with_offset, [2, 3, 4]);
const empty_ta_with_offset = new ctor(rab, byte_offset, 0);
TestIteration(empty_ta_with_offset, []);
const length_tracking_ta = new ctor(rab);
{
let expected = [];
for (let i = 0; i < no_elements; ++i) {
expected.push(i % 128);
}
TestIteration(length_tracking_ta, expected);
}
const length_tracking_ta_with_offset = new ctor(rab, byte_offset);
{
let expected = [];
for (let i = offset; i < no_elements; ++i) {
expected.push(i % 128);
}
TestIteration(length_tracking_ta_with_offset, expected);
}
const empty_length_tracking_ta_with_offset = new ctor(rab, buffer_byte_length);
TestIteration(empty_length_tracking_ta_with_offset, []);
}
}());
// Helpers for iteration tests.
function CreateRab(buffer_byte_length, ctor) {
const rab = CreateResizableArrayBuffer(buffer_byte_length,
2 * buffer_byte_length);
// Write some data into the array.
let ta_write = new ctor(rab);
for (let i = 0; i < buffer_byte_length / ctor.BYTES_PER_ELEMENT; ++i) {
WriteToTypedArray(ta_write, i, i % 128);
}
return rab;
}
function TestIterationAndResize(ta, expected, rab, resize_after,
new_byte_length) {
let values = [];
let resized = false;
for (const value of ta) {
if (value instanceof Array) {
// When iterating via entries(), the values will be arrays [key, value].
values.push([value[0], Number(value[1])]);
} else {
values.push(Number(value));
}
if (!resized && values.length == resize_after) {
rab.resize(new_byte_length);
resized = true;
}
}
assertEquals(expected, values);
assertTrue(resized);
}
(function IterateTypedArrayAndGrowMidIteration() {
const no_elements = 10;
const offset = 2;
for (let ctor of ctors) {
const buffer_byte_length = no_elements * ctor.BYTES_PER_ELEMENT;
const byte_offset = offset * ctor.BYTES_PER_ELEMENT;
// Create various different styles of TypedArrays with the RAB as the
// backing store and iterate them.
// Fixed-length TAs aren't affected by resizing.
let rab = CreateRab(buffer_byte_length, ctor);
const ta = new ctor(rab, 0, 3);
TestIterationAndResize(ta, [0, 1, 2], rab, 2, buffer_byte_length * 2);
rab = CreateRab(buffer_byte_length, ctor);
const ta_with_offset = new ctor(rab, byte_offset, 3);
TestIterationAndResize(ta_with_offset, [2, 3, 4], rab, 2,
buffer_byte_length * 2);
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta = new ctor(rab);
{
let expected = [];
for (let i = 0; i < no_elements; ++i) {
expected.push(i % 128);
}
// After resizing, the new memory contains zeros.
for (let i = 0; i < no_elements; ++i) {
expected.push(0);
}
TestIterationAndResize(length_tracking_ta, expected, rab, 2,
buffer_byte_length * 2);
}
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta_with_offset = new ctor(rab, byte_offset);
{
let expected = [];
for (let i = offset; i < no_elements; ++i) {
expected.push(i % 128);
}
for (let i = 0; i < no_elements; ++i) {
expected.push(0);
}
TestIterationAndResize(length_tracking_ta_with_offset, expected, rab, 2,
buffer_byte_length * 2);
}
}
}());
(function IterateTypedArrayAndGrowJustBeforeIterationWouldEnd() {
const no_elements = 10;
const offset = 2;
// We need to recreate the RAB between all TA tests, since we grow it.
for (let ctor of ctors) {
const buffer_byte_length = no_elements * ctor.BYTES_PER_ELEMENT;
const byte_offset = offset * ctor.BYTES_PER_ELEMENT;
// Create various different styles of TypedArrays with the RAB as the
// backing store and iterate them.
let rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta = new ctor(rab);
{
let expected = [];
for (let i = 0; i < no_elements; ++i) {
expected.push(i % 128);
}
// After resizing, the new memory contains zeros.
for (let i = 0; i < no_elements; ++i) {
expected.push(0);
}
TestIterationAndResize(length_tracking_ta, expected, rab, no_elements,
buffer_byte_length * 2);
}
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta_with_offset = new ctor(rab, byte_offset);
{
let expected = [];
for (let i = offset; i < no_elements; ++i) {
expected.push(i % 128);
}
for (let i = 0; i < no_elements; ++i) {
expected.push(0);
}
TestIterationAndResize(length_tracking_ta_with_offset, expected, rab,
no_elements - offset, buffer_byte_length * 2);
}
}
}());
(function IterateTypedArrayAndShrinkMidIteration() {
const no_elements = 10;
const offset = 2;
for (let ctor of ctors) {
const buffer_byte_length = no_elements * ctor.BYTES_PER_ELEMENT;
const byte_offset = offset * ctor.BYTES_PER_ELEMENT;
// Create various different styles of TypedArrays with the RAB as the
// backing store and iterate them.
// Fixed-length TAs aren't affected by shrinking if they stay in-bounds.
// They appear detached after shrinking out of bounds.
let rab = CreateRab(buffer_byte_length, ctor);
const ta1 = new ctor(rab, 0, 3);
TestIterationAndResize(ta1, [0, 1, 2], rab, 2, buffer_byte_length / 2);
rab = CreateRab(buffer_byte_length, ctor);
const ta2 = new ctor(rab, 0, 3);
assertThrows(() => { TestIterationAndResize(ta2, null, rab, 2, 1)});
rab = CreateRab(buffer_byte_length, ctor);
const ta_with_offset1 = new ctor(rab, byte_offset, 3);
TestIterationAndResize(ta_with_offset1, [2, 3, 4], rab, 2,
buffer_byte_length / 2);
rab = CreateRab(buffer_byte_length, ctor);
const ta_with_offset2 = new ctor(rab, byte_offset, 3);
assertThrows(() => {
TestIterationAndResize(ta_with_offset2, null, rab, 2, 0); });
// Length-tracking TA with offset 0 doesn't throw, but its length gracefully
// reduces too.
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta = new ctor(rab);
TestIterationAndResize(length_tracking_ta, [0, 1, 2, 3, 4], rab, 2,
buffer_byte_length / 2);
// Length-tracking TA appears detached when the buffer is resized beyond the
// offset.
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta_with_offset = new ctor(rab, byte_offset);
assertThrows(() => {
TestIterationAndResize(length_tracking_ta_with_offset, null, rab, 2,
byte_offset / 2);
// Length-tracking TA reduces its length gracefully when the buffer is
// resized to barely cover the offset.
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta_with_offset = new ctor(rab, byte_offset);
TestIterationAndResize(length_tracking_ta_with_offset, [3, 4], rab, 2,
byte_offset);
});
}
}());
(function IterateTypedArrayAndShrinkToZeroMidIteration() {
const no_elements = 10;
const offset = 2;
for (let ctor of ctors) {
const buffer_byte_length = no_elements * ctor.BYTES_PER_ELEMENT;
const byte_offset = offset * ctor.BYTES_PER_ELEMENT;
// Create various different styles of TypedArrays with the RAB as the
// backing store and iterate them.
// Fixed-length TAs appear detached after shrinking out of bounds.
let rab = CreateRab(buffer_byte_length, ctor);
const ta = new ctor(rab, 0, 3);
assertThrows(() => { TestIterationAndResize(ta, null, rab, 2, 0)});
rab = CreateRab(buffer_byte_length, ctor);
const ta_with_offset = new ctor(rab, byte_offset, 3);
assertThrows(() => {
TestIterationAndResize(ta_with_offset, null, rab, 2, 0); });
// Length-tracking TA with offset 0 doesn't throw, but its length gracefully
// goes to zero too.
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta = new ctor(rab);
TestIterationAndResize(length_tracking_ta, [0, 1], rab, 2, 0);
// Length-tracking TA which is resized beyond the offset appars detached.
rab = CreateRab(buffer_byte_length, ctor);
const length_tracking_ta_with_offset = new ctor(rab, byte_offset);
assertThrows(() => {
TestIterationAndResize(length_tracking_ta_with_offset, null, rab, 2, 0);
});
}
}());
(function Destructuring() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
let ta_write = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(ta_write, i, i);
}
{
let [a, b, c, d, e] = fixedLength;
assertEquals([0, 1, 2, 3], ToNumbers([a, b, c, d]));
assertEquals(undefined, e);
}
{
let [a, b, c] = fixedLengthWithOffset;
assertEquals([2, 3], ToNumbers([a, b]));
assertEquals(undefined, c);
}
{
let [a, b, c, d, e] = lengthTracking;
assertEquals([0, 1, 2, 3], ToNumbers([a, b, c, d]));
assertEquals(undefined, e);
}
{
let [a, b, c] = lengthTrackingWithOffset;
assertEquals([2, 3], ToNumbers([a, b]));
assertEquals(undefined, c);
}
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { let [a, b, c] = fixedLength; }, TypeError);
assertThrows(() => { let [a, b, c] = fixedLengthWithOffset; }, TypeError);
{
let [a, b, c, d] = lengthTracking;
assertEquals([0, 1, 2], ToNumbers([a, b, c]));
assertEquals(undefined, d);
}
{
let [a, b] = lengthTrackingWithOffset;
assertEquals([2], ToNumbers([a]));
assertEquals(undefined, b);
}
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { let [a, b, c] = fixedLength; }, TypeError);
assertThrows(() => { let [a, b, c] = fixedLengthWithOffset; }, TypeError);
assertThrows(() => { let [a, b, c] = lengthTrackingWithOffset; },
TypeError);
{
let [a, b] = lengthTracking;
assertEquals([0], ToNumbers([a]));
assertEquals(undefined, b);
}
// Shrink to 0.
rab.resize(0);
assertThrows(() => { let [a, b, c] = fixedLength; }, TypeError);
assertThrows(() => { let [a, b, c] = fixedLengthWithOffset; }, TypeError);
assertThrows(() => { let [a, b, c] = lengthTrackingWithOffset; },
TypeError);
{
let [a] = lengthTracking;
assertEquals(undefined, a);
}
// Grow so that all TAs are back in-bounds. The new memory is zeroed.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
{
let [a, b, c, d, e] = fixedLength;
assertEquals([0, 0, 0, 0], ToNumbers([a, b, c, d]));
assertEquals(undefined, e);
}
{
let [a, b, c] = fixedLengthWithOffset;
assertEquals([0, 0], ToNumbers([a, b]));
assertEquals(undefined, c);
}
{
let [a, b, c, d, e, f, g] = lengthTracking;
assertEquals([0, 0, 0, 0, 0, 0], ToNumbers([a, b, c, d, e, f]));
assertEquals(undefined, g);
}
{
let [a, b, c, d, e] = lengthTrackingWithOffset;
assertEquals([0, 0, 0, 0], ToNumbers([a, b, c, d]));
assertEquals(undefined, e);
}
}
}());
(function TestFill() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
assertEquals([0, 0, 0, 0], ReadDataFromBuffer(rab, ctor));
FillHelper(fixedLength, 1);
assertEquals([1, 1, 1, 1], ReadDataFromBuffer(rab, ctor));
FillHelper(fixedLengthWithOffset, 2);
assertEquals([1, 1, 2, 2], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 3);
assertEquals([3, 3, 3, 3], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTrackingWithOffset, 4);
assertEquals([3, 3, 4, 4], ReadDataFromBuffer(rab, ctor));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => FillHelper(fixedLength, 5), TypeError);
assertEquals([3, 3, 4], ReadDataFromBuffer(rab, ctor));
assertThrows(() => FillHelper(fixedLengthWithOffset, 6), TypeError);
assertEquals([3, 3, 4], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 7);
assertEquals([7, 7, 7], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTrackingWithOffset, 8);
assertEquals([7, 7, 8], ReadDataFromBuffer(rab, ctor));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => FillHelper(fixedLength, 9), TypeError);
assertEquals([7], ReadDataFromBuffer(rab, ctor));
assertThrows(() => FillHelper(fixedLengthWithOffset, 10), TypeError);
assertEquals([7], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 11);
assertEquals([11], ReadDataFromBuffer(rab, ctor));
assertThrows(() => FillHelper(lengthTrackingWithOffset, 12), TypeError);
assertEquals([11], ReadDataFromBuffer(rab, ctor));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
FillHelper(fixedLength, 13);
assertEquals([13, 13, 13, 13, 0, 0], ReadDataFromBuffer(rab, ctor));
FillHelper(fixedLengthWithOffset, 14);
assertEquals([13, 13, 14, 14, 0, 0], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 15);
assertEquals([15, 15, 15, 15, 15, 15], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTrackingWithOffset, 16);
assertEquals([15, 15, 16, 16, 16, 16], ReadDataFromBuffer(rab, ctor));
// Filling with non-undefined start & end.
FillHelper(fixedLength, 17, 1, 3);
assertEquals([15, 17, 17, 16, 16, 16], ReadDataFromBuffer(rab, ctor));
FillHelper(fixedLengthWithOffset, 18, 1, 2);
assertEquals([15, 17, 17, 18, 16, 16], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 19, 1, 3);
assertEquals([15, 19, 19, 18, 16, 16], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTrackingWithOffset, 20, 1, 2);
assertEquals([15, 19, 19, 20, 16, 16], ReadDataFromBuffer(rab, ctor));
}
})();
(function FillParameterConversionResizes() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => { rab.resize(2); return 0;}};
assertThrows(() => { FillHelper(fixedLength, evil, 1, 2); }, TypeError);
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { FillHelper(fixedLength, 3, evil, 2); }, TypeError);
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { FillHelper(fixedLength, 3, 1, evil); }, TypeError);
}
})();
(function At() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
let ta_write = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(ta_write, i, i);
}
assertEquals(3, AtHelper(fixedLength, -1));
assertEquals(3, AtHelper(lengthTracking, -1));
assertEquals(3, AtHelper(fixedLengthWithOffset, -1));
assertEquals(3, AtHelper(lengthTrackingWithOffset, -1));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { AtHelper(fixedLength, -1); });
assertThrows(() => { AtHelper(fixedLengthWithOffset, -1); });
assertEquals(2, AtHelper(lengthTracking, -1));
assertEquals(2, AtHelper(lengthTrackingWithOffset, -1));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { AtHelper(fixedLength, -1); });
assertThrows(() => { AtHelper(fixedLengthWithOffset, -1); });
assertEquals(0, AtHelper(lengthTracking, -1));
assertThrows(() => { AtHelper(lengthTrackingWithOffset, -1); });
// Grow so that all TAs are back in-bounds. New memory is zeroed.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
assertEquals(0, AtHelper(fixedLength, -1));
assertEquals(0, AtHelper(lengthTracking, -1));
assertEquals(0, AtHelper(fixedLengthWithOffset, -1));
assertEquals(0, AtHelper(lengthTrackingWithOffset, -1));
}
})();
(function AtParameterConversionResizes() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => { rab.resize(2); return 0;}};
assertEquals(undefined, AtHelper(fixedLength, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => { rab.resize(2); return -1;}};
// The TypedArray is *not* out of bounds since it's length-tracking.
assertEquals(undefined, AtHelper(lengthTracking, evil));
}
})();
(function Slice() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
const fixedLengthSlice = fixedLength.slice();
assertEquals([0, 1, 2, 3], ToNumbers(fixedLengthSlice));
assertFalse(fixedLengthSlice.buffer.resizable);
const fixedLengthWithOffsetSlice = fixedLengthWithOffset.slice();
assertEquals([2, 3], ToNumbers(fixedLengthWithOffsetSlice));
assertFalse(fixedLengthWithOffsetSlice.buffer.resizable);
const lengthTrackingSlice = lengthTracking.slice();
assertEquals([0, 1, 2, 3], ToNumbers(lengthTrackingSlice));
assertFalse(lengthTrackingSlice.buffer.resizable);
const lengthTrackingWithOffsetSlice = lengthTrackingWithOffset.slice();
assertEquals([2, 3], ToNumbers(lengthTrackingWithOffsetSlice));
assertFalse(lengthTrackingWithOffsetSlice.buffer.resizable);
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.slice(); });
assertThrows(() => { fixedLengthWithOffset.slice(); });
assertEquals([0, 1, 2], ToNumbers(lengthTracking.slice()));
assertEquals([2], ToNumbers(lengthTrackingWithOffset.slice()));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.slice(); });
assertThrows(() => { fixedLengthWithOffset.slice(); });
assertEquals([0], ToNumbers(lengthTracking.slice()));
assertThrows(() => { lengthTrackingWithOffset.slice(); });
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.slice(); });
assertThrows(() => { fixedLengthWithOffset.slice(); });
assertEquals([], ToNumbers(lengthTracking.slice()));
assertThrows(() => { lengthTrackingWithOffset.slice(); });
// Verify that the previously created slices aren't affected by the
// shrinking.
assertEquals([0, 1, 2, 3], ToNumbers(fixedLengthSlice));
assertEquals([2, 3], ToNumbers(fixedLengthWithOffsetSlice));
assertEquals([0, 1, 2, 3], ToNumbers(lengthTrackingSlice));
assertEquals([2, 3], ToNumbers(lengthTrackingWithOffsetSlice));
// Grow so that all TAs are back in-bounds. New memory is zeroed.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
assertEquals([0, 0, 0, 0], ToNumbers(fixedLength.slice()));
assertEquals([0, 0], ToNumbers(fixedLengthWithOffset.slice()));
assertEquals([0, 0, 0, 0, 0, 0], ToNumbers(lengthTracking.slice()));
assertEquals([0, 0, 0, 0], ToNumbers(lengthTrackingWithOffset.slice()));
}
})();
(function SliceSpeciesCreateResizes() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
}
};
const fixedLength = new MyArray(rab, 0, 4);
resizeWhenConstructorCalled = true;
assertThrows(() => { fixedLength.slice(); }, TypeError);
assertEquals(2 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 1);
}
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
}
};
const lengthTracking = new MyArray(rab);
resizeWhenConstructorCalled = true;
const a = lengthTracking.slice();
assertEquals(2 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
// The length of the resulting TypedArray is determined before
// TypedArraySpeciesCreate is called, and it doesn't change.
assertEquals(4, a.length);
assertEquals([1, 1, 0, 0], ToNumbers(a));
}
// Test that the (start, end) parameters are computed based on the original
// length.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 1);
}
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
}
};
const lengthTracking = new MyArray(rab);
resizeWhenConstructorCalled = true;
const a = lengthTracking.slice(-3, -1);
assertEquals(2 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
// The length of the resulting TypedArray is determined before
// TypedArraySpeciesCreate is called, and it doesn't change.
assertEquals(2, a.length);
assertEquals([1, 0], ToNumbers(a));
}
// Test where the buffer gets resized "between elements".
{
const rab = CreateResizableArrayBuffer(8, 16);
// Fill the buffer with 1-bits.
const taWrite = new Uint8Array(rab);
for (let i = 0; i < 8; ++i) {
WriteToTypedArray(taWrite, i, 255);
}
let resizeWhenConstructorCalled = false;
class MyArray extends Uint16Array {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
// Resize so that the size is not a multiple of the element size.
rab.resize(5);
}
}
};
const lengthTracking = new MyArray(rab);
assertEquals([65535, 65535, 65535, 65535], ToNumbers(lengthTracking));
resizeWhenConstructorCalled = true;
const a = lengthTracking.slice();
assertEquals(5, rab.byteLength);
assertEquals(4, a.length); // The old length is used.
assertEquals(65535, a[0]);
assertEquals(65535, a[1]);
assertEquals(0, a[2]);
assertEquals(0, a[3]);
}
})();
(function CopyWithin() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// Orig. array: [0, 1, 2, 3]
// [0, 1, 2, 3] << fixedLength
// [2, 3] << fixedLengthWithOffset
// [0, 1, 2, 3, ...] << lengthTracking
// [2, 3, ...] << lengthTrackingWithOffset
fixedLength.copyWithin(0, 2);
assertEquals([2, 3, 2, 3], ToNumbers(fixedLength));
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
fixedLengthWithOffset.copyWithin(0, 1);
assertEquals([3, 3], ToNumbers(fixedLengthWithOffset));
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
lengthTracking.copyWithin(0, 2);
assertEquals([2, 3, 2, 3], ToNumbers(lengthTracking));
lengthTrackingWithOffset.copyWithin(0, 1);
assertEquals([3, 3], ToNumbers(lengthTrackingWithOffset));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 3; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// Orig. array: [0, 1, 2]
// [0, 1, 2, ...] << lengthTracking
// [2, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.copyWithin(0, 1); });
assertThrows(() => { fixedLengthWithOffset.copyWithin(0, 1); });
lengthTracking.copyWithin(0, 1);
assertEquals([1, 2, 2], ToNumbers(lengthTracking));
lengthTrackingWithOffset.copyWithin(0, 1);
assertEquals([2], ToNumbers(lengthTrackingWithOffset));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
WriteToTypedArray(taWrite, 0, 0);
assertThrows(() => { fixedLength.copyWithin(0, 1, 1); });
assertThrows(() => { fixedLengthWithOffset.copyWithin(0, 1, 1); });
lengthTracking.copyWithin(0, 0, 1);
assertEquals([0], ToNumbers(lengthTracking));
assertThrows(() => { lengthTrackingWithOffset.copyWithin(0, 1, 1); });
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.copyWithin(0, 1, 1); });
assertThrows(() => { fixedLengthWithOffset.copyWithin(0, 1, 1); });
lengthTracking.copyWithin(0, 0, 1);
assertEquals([], ToNumbers(lengthTracking));
assertThrows(() => { lengthTrackingWithOffset.copyWithin(0, 1, 1); });
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// Orig. array: [0, 1, 2, 3, 4, 5]
// [0, 1, 2, 3] << fixedLength
// [2, 3] << fixedLengthWithOffset
// [0, 1, 2, 3, 4, 5, ...] << lengthTracking
// [2, 3, 4, 5, ...] << lengthTrackingWithOffset
fixedLength.copyWithin(0, 2);
assertEquals([2, 3, 2, 3], ToNumbers(fixedLength));
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
fixedLengthWithOffset.copyWithin(0, 1);
assertEquals([3, 3], ToNumbers(fixedLengthWithOffset));
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// [0, 1, 2, 3, 4, 5, ...] << lengthTracking
// target ^ ^ start
lengthTracking.copyWithin(0, 2);
assertEquals([2, 3, 4, 5, 4, 5], ToNumbers(lengthTracking));
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// [2, 3, 4, 5, ...] << lengthTrackingWithOffset
// target ^ ^ start
lengthTrackingWithOffset.copyWithin(0, 1);
assertEquals([3, 4, 5, 5], ToNumbers(lengthTrackingWithOffset));
}
})();
(function CopyWithinParameterConversionShrinks() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const evil = { valueOf: () => { rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 2;}};
assertThrows(() => { fixedLength.copyWithin(evil, 0, 1); }, TypeError);
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.copyWithin(0, evil, 3); }, TypeError);
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.copyWithin(0, 1, evil); }, TypeError);
}
})();
(function CopyWithinParameterConversionGrows() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, i);
}
const evil = { valueOf: () => { rab.resize(6 * ctor.BYTES_PER_ELEMENT);
WriteToTypedArray(lengthTracking, 4, 4);
WriteToTypedArray(lengthTracking, 5, 5);
return 0;} };
// Orig. array: [0, 1, 2, 3] [4, 5]
// ^ ^ ^ new elements
// target start
lengthTracking.copyWithin(evil, 2);
assertEquals([2, 3, 2, 3, 4, 5], ToNumbers(lengthTracking));
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, i);
}
// Orig. array: [0, 1, 2, 3] [4, 5]
// ^ ^ ^ new elements
// start target
lengthTracking.copyWithin(2, evil);
assertEquals([0, 1, 0, 1, 4, 5], ToNumbers(lengthTracking));
}
})();
(function EntriesKeysValues() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
assertEquals([0, 2, 4, 6], ToNumbersWithEntries(fixedLength));
assertEquals([0, 2, 4, 6], ValuesToNumbers(fixedLength));
assertEquals([0, 1, 2, 3], Keys(fixedLength));
assertEquals([4, 6], ToNumbersWithEntries(fixedLengthWithOffset));
assertEquals([4, 6], ValuesToNumbers(fixedLengthWithOffset));
assertEquals([0, 1], Keys(fixedLengthWithOffset));
assertEquals([0, 2, 4, 6], ToNumbersWithEntries(lengthTracking));
assertEquals([0, 2, 4, 6], ValuesToNumbers(lengthTracking));
assertEquals([0, 1, 2, 3], Keys(lengthTracking));
assertEquals([4, 6], ToNumbersWithEntries(lengthTrackingWithOffset));
assertEquals([4, 6], ValuesToNumbers(lengthTrackingWithOffset));
assertEquals([0, 1], Keys(lengthTrackingWithOffset));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.entries(); });
assertThrows(() => { fixedLength.values(); });
assertThrows(() => { fixedLength.keys(); });
assertThrows(() => { fixedLengthWithOffset.entries(); });
assertThrows(() => { fixedLengthWithOffset.values(); });
assertThrows(() => { fixedLengthWithOffset.keys(); });
assertEquals([0, 2, 4], ToNumbersWithEntries(lengthTracking));
assertEquals([0, 2, 4], ValuesToNumbers(lengthTracking));
assertEquals([0, 1, 2], Keys(lengthTracking));
assertEquals([4], ToNumbersWithEntries(lengthTrackingWithOffset));
assertEquals([4], ValuesToNumbers(lengthTrackingWithOffset));
assertEquals([0], Keys(lengthTrackingWithOffset));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.entries(); });
assertThrows(() => { fixedLength.values(); });
assertThrows(() => { fixedLength.keys(); });
assertThrows(() => { fixedLengthWithOffset.entries(); });
assertThrows(() => { fixedLengthWithOffset.values(); });
assertThrows(() => { fixedLengthWithOffset.keys(); });
assertThrows(() => { lengthTrackingWithOffset.entries(); });
assertThrows(() => { lengthTrackingWithOffset.values(); });
assertThrows(() => { lengthTrackingWithOffset.keys(); });
assertEquals([0], ToNumbersWithEntries(lengthTracking));
assertEquals([0], ValuesToNumbers(lengthTracking));
assertEquals([0], Keys(lengthTracking));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.entries(); });
assertThrows(() => { fixedLength.values(); });
assertThrows(() => { fixedLength.keys(); });
assertThrows(() => { fixedLengthWithOffset.entries(); });
assertThrows(() => { fixedLengthWithOffset.values(); });
assertThrows(() => { fixedLengthWithOffset.keys(); });
assertThrows(() => { lengthTrackingWithOffset.entries(); });
assertThrows(() => { lengthTrackingWithOffset.values(); });
assertThrows(() => { lengthTrackingWithOffset.keys(); });
assertEquals([], ToNumbersWithEntries(lengthTracking));
assertEquals([], ValuesToNumbers(lengthTracking));
assertEquals([], Keys(lengthTracking));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertEquals([0, 2, 4, 6], ToNumbersWithEntries(fixedLength));
assertEquals([0, 2, 4, 6], ValuesToNumbers(fixedLength));
assertEquals([0, 1, 2, 3], Keys(fixedLength));
assertEquals([4, 6], ToNumbersWithEntries(fixedLengthWithOffset));
assertEquals([4, 6], ValuesToNumbers(fixedLengthWithOffset));
assertEquals([0, 1], Keys(fixedLengthWithOffset));
assertEquals([0, 2, 4, 6, 8, 10], ToNumbersWithEntries(lengthTracking));
assertEquals([0, 2, 4, 6, 8, 10], ValuesToNumbers(lengthTracking));
assertEquals([0, 1, 2, 3, 4, 5], Keys(lengthTracking));
assertEquals([4, 6, 8, 10], ToNumbersWithEntries(lengthTrackingWithOffset));
assertEquals([4, 6, 8, 10], ValuesToNumbers(lengthTrackingWithOffset));
assertEquals([0, 1, 2, 3], Keys(lengthTrackingWithOffset));
}
})();
(function EntriesKeysValuesGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
// Iterating with entries() (the 4 loops below).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// The fixed length array is not affected by resizing.
TestIterationAndResize(fixedLength.entries(),
[[0, 0], [1, 2], [2, 4], [3, 6]],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
// The fixed length array is not affected by resizing.
TestIterationAndResize(fixedLengthWithOffset.entries(),
[[0, 4], [1, 6]],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
TestIterationAndResize(lengthTracking.entries(),
[[0, 0], [1, 2], [2, 4], [3, 6], [4, 0], [5, 0]],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
TestIterationAndResize(lengthTrackingWithOffset.entries(),
[[0, 4], [1, 6], [2, 0], [3, 0]],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
// Iterating with keys() (the 4 loops below).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// The fixed length array is not affected by resizing.
TestIterationAndResize(fixedLength.keys(),
[0, 1, 2, 3],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
// The fixed length array is not affected by resizing.
TestIterationAndResize(fixedLengthWithOffset.keys(),
[0, 1],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
TestIterationAndResize(lengthTracking.keys(),
[0, 1, 2, 3, 4, 5],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
TestIterationAndResize(lengthTrackingWithOffset.keys(),
[0, 1, 2, 3],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
// Iterating with values() (the 4 loops below).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// The fixed length array is not affected by resizing.
TestIterationAndResize(fixedLength.values(),
[0, 2, 4, 6],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
// The fixed length array is not affected by resizing.
TestIterationAndResize(fixedLengthWithOffset.values(),
[4, 6],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
TestIterationAndResize(lengthTracking.values(),
[0, 2, 4, 6, 0, 0],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
TestIterationAndResize(lengthTrackingWithOffset.values(),
[4, 6, 0, 0],
rab, 2, 6 * ctor.BYTES_PER_ELEMENT);
}
})();
(function EntriesKeysValuesShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
// Iterating with entries() (the 4 loops below).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// The fixed length array goes out of bounds when the RAB is resized.
assertThrows(() => { TestIterationAndResize(
fixedLength.entries(),
null,
rab, 2, 3 * ctor.BYTES_PER_ELEMENT); });
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
// The fixed length array goes out of bounds when the RAB is resized.
assertThrows(() => { TestIterationAndResize(
fixedLengthWithOffset.entries(),
null,
rab, 1, 3 * ctor.BYTES_PER_ELEMENT); });
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
TestIterationAndResize(lengthTracking.entries(),
[[0, 0], [1, 2], [2, 4]],
rab, 2, 3 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
TestIterationAndResize(lengthTrackingWithOffset.entries(),
[[0, 4], [1, 6]],
rab, 2, 3 * ctor.BYTES_PER_ELEMENT);
}
// Iterating with keys() (the 4 loops below).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// The fixed length array goes out of bounds when the RAB is resized.
assertThrows(() => { TestIterationAndResize(
fixedLength.keys(),
null,
rab, 2, 3 * ctor.BYTES_PER_ELEMENT); });
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
// The fixed length array goes out of bounds when the RAB is resized.
assertThrows(() => { TestIterationAndResize(
fixedLengthWithOffset.keys(),
null,
rab, 2, 3 * ctor.BYTES_PER_ELEMENT); });
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
TestIterationAndResize(lengthTracking.keys(),
[0, 1, 2],
rab, 2, 3 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
TestIterationAndResize(lengthTrackingWithOffset.keys(),
[0, 1],
rab, 2, 3 * ctor.BYTES_PER_ELEMENT);
}
// Iterating with values() (the 4 loops below).
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// The fixed length array goes out of bounds when the RAB is resized.
assertThrows(() => { TestIterationAndResize(
fixedLength.values(),
null,
rab, 2, 3 * ctor.BYTES_PER_ELEMENT); });
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
// The fixed length array goes out of bounds when the RAB is resized.
assertThrows(() => { TestIterationAndResize(
fixedLengthWithOffset.values(),
null,
rab, 2, 3 * ctor.BYTES_PER_ELEMENT); });
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
TestIterationAndResize(lengthTracking.values(),
[0, 2, 4],
rab, 2, 3 * ctor.BYTES_PER_ELEMENT);
}
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
TestIterationAndResize(lengthTrackingWithOffset.values(),
[4, 6],
rab, 2, 3 * ctor.BYTES_PER_ELEMENT);
}
})();
(function EverySome() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function div3(n) {
return Number(n) % 3 == 0;
}
function even(n) {
return Number(n) % 2 == 0;
}
function over10(n) {
return Number(n) > 10;
}
assertFalse(fixedLength.every(div3));
assertTrue(fixedLength.every(even));
assertTrue(fixedLength.some(div3));
assertFalse(fixedLength.some(over10));
assertFalse(fixedLengthWithOffset.every(div3));
assertTrue(fixedLengthWithOffset.every(even));
assertTrue(fixedLengthWithOffset.some(div3));
assertFalse(fixedLengthWithOffset.some(over10));
assertFalse(lengthTracking.every(div3));
assertTrue(lengthTracking.every(even));
assertTrue(lengthTracking.some(div3));
assertFalse(lengthTracking.some(over10));
assertFalse(lengthTrackingWithOffset.every(div3));
assertTrue(lengthTrackingWithOffset.every(even));
assertTrue(lengthTrackingWithOffset.some(div3));
assertFalse(lengthTrackingWithOffset.some(over10));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.every(div3); });
assertThrows(() => { fixedLength.some(div3); });
assertThrows(() => { fixedLengthWithOffset.every(div3); });
assertThrows(() => { fixedLengthWithOffset.some(div3); });
assertFalse(lengthTracking.every(div3));
assertTrue(lengthTracking.every(even));
assertTrue(lengthTracking.some(div3));
assertFalse(lengthTracking.some(over10));
assertFalse(lengthTrackingWithOffset.every(div3));
assertTrue(lengthTrackingWithOffset.every(even));
assertFalse(lengthTrackingWithOffset.some(div3));
assertFalse(lengthTrackingWithOffset.some(over10));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.every(div3); });
assertThrows(() => { fixedLength.some(div3); });
assertThrows(() => { fixedLengthWithOffset.every(div3); });
assertThrows(() => { fixedLengthWithOffset.some(div3); });
assertTrue(lengthTracking.every(div3));
assertTrue(lengthTracking.every(even));
assertTrue(lengthTracking.some(div3));
assertFalse(lengthTracking.some(over10));
assertThrows(() => { lengthTrackingWithOffset.every(div3); });
assertThrows(() => { lengthTrackingWithOffset.some(div3); });
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.every(div3); });
assertThrows(() => { fixedLength.some(div3); });
assertThrows(() => { fixedLengthWithOffset.every(div3); });
assertThrows(() => { fixedLengthWithOffset.some(div3); });
assertTrue(lengthTracking.every(div3));
assertTrue(lengthTracking.every(even));
assertFalse(lengthTracking.some(div3));
assertFalse(lengthTracking.some(over10));
assertThrows(() => { lengthTrackingWithOffset.every(div3); });
assertThrows(() => { lengthTrackingWithOffset.some(div3); });
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertFalse(fixedLength.every(div3));
assertTrue(fixedLength.every(even));
assertTrue(fixedLength.some(div3));
assertFalse(fixedLength.some(over10));
assertFalse(fixedLengthWithOffset.every(div3));
assertTrue(fixedLengthWithOffset.every(even));
assertTrue(fixedLengthWithOffset.some(div3));
assertFalse(fixedLengthWithOffset.some(over10));
assertFalse(lengthTracking.every(div3));
assertTrue(lengthTracking.every(even));
assertTrue(lengthTracking.some(div3));
assertFalse(lengthTracking.some(over10));
assertFalse(lengthTrackingWithOffset.every(div3));
assertTrue(lengthTrackingWithOffset.every(even));
assertTrue(lengthTrackingWithOffset.some(div3));
assertFalse(lengthTrackingWithOffset.some(over10));
}
})();
(function EveryShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return true;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertTrue(fixedLength.every(CollectValuesAndResize));
assertEquals([0, 2, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertTrue(fixedLengthWithOffset.every(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertTrue(lengthTracking.every(CollectValuesAndResize));
assertEquals([0, 2, 4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertTrue(lengthTrackingWithOffset.every(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
})();
(function EveryGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return true;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertTrue(fixedLength.every(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertTrue(fixedLengthWithOffset.every(CollectValuesAndResize));
assertEquals([4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertTrue(lengthTracking.every(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertTrue(lengthTrackingWithOffset.every(CollectValuesAndResize));
assertEquals([4, 6], values);
}
})();
(function SomeShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertFalse(fixedLength.some(CollectValuesAndResize));
assertEquals([0, 2, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertFalse(fixedLengthWithOffset.some(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertFalse(lengthTracking.some(CollectValuesAndResize));
assertEquals([0, 2, 4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertFalse(lengthTrackingWithOffset.some(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
})();
(function SomeGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values = [];
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertFalse(fixedLength.some(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertFalse(fixedLengthWithOffset.some(CollectValuesAndResize));
assertEquals([4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertFalse(lengthTracking.some(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
rab = rab;
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertFalse(lengthTrackingWithOffset.some(CollectValuesAndResize));
assertEquals([4, 6], values);
}
})();
(function FindFindIndexFindLastFindLastIndex() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function isTwoOrFour(n) {
return n == 2 || n == 4;
}
assertEquals(2, Number(fixedLength.find(isTwoOrFour)));
assertEquals(4, Number(fixedLengthWithOffset.find(isTwoOrFour)));
assertEquals(2, Number(lengthTracking.find(isTwoOrFour)));
assertEquals(4, Number(lengthTrackingWithOffset.find(isTwoOrFour)));
assertEquals(1, fixedLength.findIndex(isTwoOrFour));
assertEquals(0, fixedLengthWithOffset.findIndex(isTwoOrFour));
assertEquals(1, lengthTracking.findIndex(isTwoOrFour));
assertEquals(0, lengthTrackingWithOffset.findIndex(isTwoOrFour));
assertEquals(4, Number(fixedLength.findLast(isTwoOrFour)));
assertEquals(4, Number(fixedLengthWithOffset.findLast(isTwoOrFour)));
assertEquals(4, Number(lengthTracking.findLast(isTwoOrFour)));
assertEquals(4, Number(lengthTrackingWithOffset.findLast(isTwoOrFour)));
assertEquals(2, fixedLength.findLastIndex(isTwoOrFour));
assertEquals(0, fixedLengthWithOffset.findLastIndex(isTwoOrFour));
assertEquals(2, lengthTracking.findLastIndex(isTwoOrFour));
assertEquals(0, lengthTrackingWithOffset.findLastIndex(isTwoOrFour));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.find(isTwoOrFour); });
assertThrows(() => { fixedLength.findIndex(isTwoOrFour); });
assertThrows(() => { fixedLength.findLast(isTwoOrFour); });
assertThrows(() => { fixedLength.findLastIndex(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.find(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findIndex(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findLast(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findLastIndex(isTwoOrFour); });
assertEquals(2, Number(lengthTracking.find(isTwoOrFour)));
assertEquals(4, Number(lengthTrackingWithOffset.find(isTwoOrFour)));
assertEquals(1, lengthTracking.findIndex(isTwoOrFour));
assertEquals(0, lengthTrackingWithOffset.findIndex(isTwoOrFour));
assertEquals(4, Number(lengthTracking.findLast(isTwoOrFour)));
assertEquals(4, Number(lengthTrackingWithOffset.findLast(isTwoOrFour)));
assertEquals(2, lengthTracking.findLastIndex(isTwoOrFour));
assertEquals(0, lengthTrackingWithOffset.findLastIndex(isTwoOrFour));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.find(isTwoOrFour); });
assertThrows(() => { fixedLength.findIndex(isTwoOrFour); });
assertThrows(() => { fixedLength.findLast(isTwoOrFour); });
assertThrows(() => { fixedLength.findLastIndex(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.find(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findIndex(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findLast(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findLastIndex(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.find(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.findIndex(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.findLast(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.findLastIndex(isTwoOrFour); });
assertEquals(undefined, lengthTracking.find(isTwoOrFour));
assertEquals(-1, lengthTracking.findIndex(isTwoOrFour));
assertEquals(undefined, lengthTracking.findLast(isTwoOrFour));
assertEquals(-1, lengthTracking.findLastIndex(isTwoOrFour));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.find(isTwoOrFour); });
assertThrows(() => { fixedLength.findIndex(isTwoOrFour); });
assertThrows(() => { fixedLength.findLast(isTwoOrFour); });
assertThrows(() => { fixedLength.findLastIndex(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.find(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findIndex(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findLast(isTwoOrFour); });
assertThrows(() => { fixedLengthWithOffset.findLastIndex(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.find(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.findIndex(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.findLast(isTwoOrFour); });
assertThrows(() => { lengthTrackingWithOffset.findLastIndex(isTwoOrFour); });
assertEquals(undefined, lengthTracking.find(isTwoOrFour));
assertEquals(-1, lengthTracking.findIndex(isTwoOrFour));
assertEquals(undefined, lengthTracking.findLast(isTwoOrFour));
assertEquals(-1, lengthTracking.findLastIndex(isTwoOrFour));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 0);
}
WriteToTypedArray(taWrite, 4, 2);
WriteToTypedArray(taWrite, 5, 4);
// Orig. array: [0, 0, 0, 0, 2, 4]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, 2, 4, ...] << lengthTracking
// [0, 0, 2, 4, ...] << lengthTrackingWithOffset
assertEquals(undefined, fixedLength.find(isTwoOrFour));
assertEquals(undefined, fixedLengthWithOffset.find(isTwoOrFour));
assertEquals(2, Number(lengthTracking.find(isTwoOrFour)));
assertEquals(2, Number(lengthTrackingWithOffset.find(isTwoOrFour)));
assertEquals(-1, fixedLength.findIndex(isTwoOrFour));
assertEquals(-1, fixedLengthWithOffset.findIndex(isTwoOrFour));
assertEquals(4, lengthTracking.findIndex(isTwoOrFour));
assertEquals(2, lengthTrackingWithOffset.findIndex(isTwoOrFour));
assertEquals(undefined, fixedLength.findLast(isTwoOrFour));
assertEquals(undefined, fixedLengthWithOffset.findLast(isTwoOrFour));
assertEquals(4, Number(lengthTracking.findLast(isTwoOrFour)));
assertEquals(4, Number(lengthTrackingWithOffset.findLast(isTwoOrFour)));
assertEquals(-1, fixedLength.findLastIndex(isTwoOrFour));
assertEquals(-1, fixedLengthWithOffset.findLastIndex(isTwoOrFour));
assertEquals(5, lengthTracking.findLastIndex(isTwoOrFour));
assertEquals(3, lengthTrackingWithOffset.findLastIndex(isTwoOrFour));
}
})();
(function FindShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLength.find(CollectValuesAndResize));
assertEquals([0, 2, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLengthWithOffset.find(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTracking.find(CollectValuesAndResize));
assertEquals([0, 2, 4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTrackingWithOffset.find(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
})();
(function FindGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLength.find(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLengthWithOffset.find(CollectValuesAndResize));
assertEquals([4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTracking.find(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTrackingWithOffset.find(CollectValuesAndResize));
assertEquals([4, 6], values);
}
})();
(function FindIndexShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLength.findIndex(CollectValuesAndResize));
assertEquals([0, 2, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLengthWithOffset.findIndex(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTracking.findIndex(CollectValuesAndResize));
assertEquals([0, 2, 4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTrackingWithOffset.findIndex(CollectValuesAndResize));
assertEquals([4, undefined], values);
}
})();
(function FindIndexGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLength.findIndex(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLengthWithOffset.findIndex(CollectValuesAndResize));
assertEquals([4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTracking.findIndex(CollectValuesAndResize));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTrackingWithOffset.findIndex(CollectValuesAndResize));
assertEquals([4, 6], values);
}
})();
(function FindLastShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLength.findLast(CollectValuesAndResize));
assertEquals([6, 4, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLengthWithOffset.findLast(CollectValuesAndResize));
assertEquals([6, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTracking.findLast(CollectValuesAndResize));
assertEquals([6, 4, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTrackingWithOffset.findLast(CollectValuesAndResize));
assertEquals([6, 4], values);
}
})();
(function FindLastGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLength.findLast(CollectValuesAndResize));
assertEquals([6, 4, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, fixedLengthWithOffset.findLast(CollectValuesAndResize));
assertEquals([6, 4], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTracking.findLast(CollectValuesAndResize));
assertEquals([6, 4, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(undefined, lengthTrackingWithOffset.findLast(CollectValuesAndResize));
assertEquals([6, 4], values);
}
})();
(function FindLastIndexShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLength.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLengthWithOffset.findLastIndex(CollectValuesAndResize));
assertEquals([6, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTracking.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 1;
resizeTo = 2 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTracking.findLastIndex(CollectValuesAndResize));
assertEquals([6, undefined, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTrackingWithOffset.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4], values);
}
})();
(function FindLastIndexGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLength.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, fixedLengthWithOffset.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTracking.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4, 2, 0], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals(-1, lengthTrackingWithOffset.findLastIndex(CollectValuesAndResize));
assertEquals([6, 4], values);
}
})();
(function Filter() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// Orig. array: [0, 1, 2, 3]
// [0, 1, 2, 3] << fixedLength
// [2, 3] << fixedLengthWithOffset
// [0, 1, 2, 3, ...] << lengthTracking
// [2, 3, ...] << lengthTrackingWithOffset
function isEven(n) {
return n != undefined && Number(n) % 2 == 0;
}
assertEquals([0, 2], ToNumbers(fixedLength.filter(isEven)));
assertEquals([2], ToNumbers(fixedLengthWithOffset.filter(isEven)));
assertEquals([0, 2], ToNumbers(lengthTracking.filter(isEven)));
assertEquals([2], ToNumbers(lengthTrackingWithOffset.filter(isEven)));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 1, 2]
// [0, 1, 2, ...] << lengthTracking
// [2, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.filter(isEven); });
assertThrows(() => { fixedLengthWithOffset.filter(isEven); });
assertEquals([0, 2], ToNumbers(lengthTracking.filter(isEven)));
assertEquals([2], ToNumbers(lengthTrackingWithOffset.filter(isEven)));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.filter(isEven); });
assertThrows(() => { fixedLengthWithOffset.filter(isEven); });
assertThrows(() => { lengthTrackingWithOffset.filter(isEven); });
assertEquals([0], ToNumbers(lengthTracking.filter(isEven)));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.filter(isEven); });
assertThrows(() => { fixedLengthWithOffset.filter(isEven); });
assertThrows(() => { lengthTrackingWithOffset.filter(isEven); });
assertEquals([], ToNumbers(lengthTracking.filter(isEven)));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, i);
}
// Orig. array: [0, 1, 2, 3, 4, 5]
// [0, 1, 2, 3] << fixedLength
// [2, 3] << fixedLengthWithOffset
// [0, 1, 2, 3, 4, 5, ...] << lengthTracking
// [2, 3, 4, 5, ...] << lengthTrackingWithOffset
assertEquals([0, 2], ToNumbers(fixedLength.filter(isEven)));
assertEquals([2], ToNumbers(fixedLengthWithOffset.filter(isEven)));
assertEquals([0, 2, 4], ToNumbers(lengthTracking.filter(isEven)));
assertEquals([2, 4], ToNumbers(lengthTrackingWithOffset.filter(isEven)));
}
})();
(function FilterShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(fixedLength.filter(CollectValuesAndResize)));
assertEquals([0, 2, undefined, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(fixedLengthWithOffset.filter(CollectValuesAndResize)));
assertEquals([4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(lengthTracking.filter(CollectValuesAndResize)));
assertEquals([0, 2, 4, undefined], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(lengthTrackingWithOffset.filter(CollectValuesAndResize)));
assertEquals([4, undefined], values);
}
})();
(function FilterGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return false;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(fixedLength.filter(CollectValuesAndResize)));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(fixedLengthWithOffset.filter(CollectValuesAndResize)));
assertEquals([4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
values = [];
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(lengthTracking.filter(CollectValuesAndResize)));
assertEquals([0, 2, 4, 6], values);
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
values = [];
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([], ToNumbers(lengthTrackingWithOffset.filter(CollectValuesAndResize)));
assertEquals([4, 6], values);
}
})();
(function ForEachReduceReduceRight() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function Helper(array) {
const forEachValues = [];
const reduceValues = [];
const reduceRightValues = [];
array.forEach((n) => { forEachValues.push(n);});
array.reduce((acc, n) => {
reduceValues.push(n);
}, "initial value");
array.reduceRight((acc, n) => {
reduceRightValues.push(n);
}, "initial value");
assertEquals(reduceValues, forEachValues);
reduceRightValues.reverse();
assertEquals(reduceValues, reduceRightValues);
return ToNumbers(forEachValues);
}
assertEquals([0, 2, 4, 6], Helper(fixedLength));
assertEquals([4, 6], Helper(fixedLengthWithOffset));
assertEquals([0, 2, 4, 6], Helper(lengthTracking));
assertEquals([4, 6], Helper(lengthTrackingWithOffset));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { Helper(fixedLength); });
assertThrows(() => { Helper(fixedLengthWithOffset); });
assertEquals([0, 2, 4], Helper(lengthTracking));
assertEquals([4], Helper(lengthTrackingWithOffset));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { Helper(fixedLength); });
assertThrows(() => { Helper(fixedLengthWithOffset); });
assertThrows(() => { Helper(lengthTrackingWithOffset); });
assertEquals([0], Helper(lengthTracking));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { Helper(fixedLength); });
assertThrows(() => { Helper(fixedLengthWithOffset); });
assertThrows(() => { Helper(lengthTrackingWithOffset); });
assertEquals([], Helper(lengthTracking));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertEquals([0, 2, 4, 6], Helper(fixedLength));
assertEquals([4, 6], Helper(fixedLengthWithOffset));
assertEquals([0, 2, 4, 6, 8, 10], Helper(lengthTracking));
assertEquals([4, 6, 8, 10], Helper(lengthTrackingWithOffset));
}
})();
(function ForEachReduceReduceRightShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return true;
}
function ForEachHelper(array) {
values = [];
array.forEach(CollectValuesAndResize);
return values;
}
function ReduceHelper(array) {
values = [];
array.reduce((acc, n) => { CollectValuesAndResize(n); }, "initial value");
return values;
}
function ReduceRightHelper(array) {
values = [];
array.reduceRight((acc, n) => { CollectValuesAndResize(n); },
"initial value");
return values;
}
// Test for forEach.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, undefined, undefined], ForEachHelper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, undefined], ForEachHelper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, undefined], ForEachHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, undefined], ForEachHelper(lengthTrackingWithOffset));
}
// Tests for reduce.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, undefined, undefined], ReduceHelper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, undefined], ReduceHelper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, undefined], ReduceHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, undefined], ReduceHelper(lengthTrackingWithOffset));
}
// Tests for reduceRight.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, 4, undefined, undefined], ReduceRightHelper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, undefined], ReduceRightHelper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
// Unaffected by the shrinking, since we've already iterated past the point.
assertEquals([6, 4, 2, 0], ReduceRightHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 1;
resizeTo = 2 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, undefined, 2, 0], ReduceRightHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
// Unaffected by the shrinking, since we've already iterated past the point.
assertEquals([6, 4], ReduceRightHelper(lengthTrackingWithOffset));
}
})();
(function ForEachReduceReduceRightGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return true;
}
function ForEachHelper(array) {
values = [];
array.forEach(CollectValuesAndResize);
return values;
}
function ReduceHelper(array) {
values = [];
array.reduce((acc, n) => { CollectValuesAndResize(n); }, "initial value");
return values;
}
function ReduceRightHelper(array) {
values = [];
array.reduceRight((acc, n) => { CollectValuesAndResize(n); },
"initial value");
return values;
}
// Test for forEach.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, 6], ForEachHelper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, 6], ForEachHelper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, 6], ForEachHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, 6], ForEachHelper(lengthTrackingWithOffset));
}
// Test for reduce.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, 6], ReduceHelper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, 6], ReduceHelper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, 6], ReduceHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, 6], ReduceHelper(lengthTrackingWithOffset));
}
// Test for reduceRight.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, 4, 2, 0], ReduceRightHelper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, 4], ReduceRightHelper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, 4, 2, 0], ReduceRightHelper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([6, 4], ReduceRightHelper(lengthTrackingWithOffset));
}
})();
(function Includes() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
assertTrue(IncludesHelper(fixedLength, 2));
assertFalse(IncludesHelper(fixedLength, undefined));
assertTrue(IncludesHelper(fixedLength, 2, 1));
assertFalse(IncludesHelper(fixedLength, 2, 2));
assertTrue(IncludesHelper(fixedLength, 2, -3));
assertFalse(IncludesHelper(fixedLength, 2, -2));
assertFalse(IncludesHelper(fixedLengthWithOffset, 2));
assertTrue(IncludesHelper(fixedLengthWithOffset, 4));
assertFalse(IncludesHelper(fixedLengthWithOffset, undefined));
assertTrue(IncludesHelper(fixedLengthWithOffset, 4, 0));
assertFalse(IncludesHelper(fixedLengthWithOffset, 4, 1));
assertTrue(IncludesHelper(fixedLengthWithOffset, 4, -2));
assertFalse(IncludesHelper(fixedLengthWithOffset, 4, -1));
assertTrue(IncludesHelper(lengthTracking, 2));
assertFalse(IncludesHelper(lengthTracking, undefined));
assertTrue(IncludesHelper(lengthTracking, 2, 1));
assertFalse(IncludesHelper(lengthTracking, 2, 2));
assertTrue(IncludesHelper(lengthTracking, 2, -3));
assertFalse(IncludesHelper(lengthTracking, 2, -2));
assertFalse(IncludesHelper(lengthTrackingWithOffset, 2));
assertTrue(IncludesHelper(lengthTrackingWithOffset, 4));
assertFalse(IncludesHelper(lengthTrackingWithOffset, undefined));
assertTrue(IncludesHelper(lengthTrackingWithOffset, 4, 0));
assertFalse(IncludesHelper(lengthTrackingWithOffset, 4, 1));
assertTrue(IncludesHelper(lengthTrackingWithOffset, 4, -2));
assertFalse(IncludesHelper(lengthTrackingWithOffset, 4, -1));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { IncludesHelper(fixedLength, 2); });
assertThrows(() => { IncludesHelper(fixedLengthWithOffset, 2); });
assertTrue(IncludesHelper(lengthTracking, 2));
assertFalse(IncludesHelper(lengthTracking, undefined));
assertFalse(IncludesHelper(lengthTrackingWithOffset, 2));
assertTrue(IncludesHelper(lengthTrackingWithOffset, 4));
assertFalse(IncludesHelper(lengthTrackingWithOffset, undefined));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { IncludesHelper(fixedLength, 2); });
assertThrows(() => { IncludesHelper(fixedLengthWithOffset, 2); });
assertThrows(() => { IncludesHelper(lengthTrackingWithOffset, 2); });
// Shrink to zero.
rab.resize(0);
assertThrows(() => { IncludesHelper(fixedLength, 2); });
assertThrows(() => { IncludesHelper(fixedLengthWithOffset, 2); });
assertThrows(() => { IncludesHelper(lengthTrackingWithOffset, 2); });
assertFalse(IncludesHelper(lengthTracking, 2));
assertFalse(IncludesHelper(lengthTracking, undefined));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertTrue(IncludesHelper(fixedLength, 2));
assertFalse(IncludesHelper(fixedLength, undefined));
assertFalse(IncludesHelper(fixedLength, 8));
assertFalse(IncludesHelper(fixedLengthWithOffset, 2));
assertTrue(IncludesHelper(fixedLengthWithOffset, 4));
assertFalse(IncludesHelper(fixedLengthWithOffset, undefined));
assertFalse(IncludesHelper(fixedLengthWithOffset, 8));
assertTrue(IncludesHelper(lengthTracking, 2));
assertFalse(IncludesHelper(lengthTracking, undefined));
assertTrue(IncludesHelper(lengthTracking, 8));
assertFalse(IncludesHelper(lengthTrackingWithOffset, 2));
assertTrue(IncludesHelper(lengthTrackingWithOffset, 4));
assertFalse(IncludesHelper(lengthTrackingWithOffset, undefined));
assertTrue(IncludesHelper(lengthTrackingWithOffset, 8));
}
})();
(function IncludesParameterConversionResizes() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertFalse(IncludesHelper(fixedLength, undefined));
// The TA is OOB so it includes only "undefined".
assertTrue(IncludesHelper(fixedLength, undefined, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertTrue(IncludesHelper(fixedLength, 0));
// The TA is OOB so it includes only "undefined".
assertFalse(IncludesHelper(fixedLength, 0, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertFalse(IncludesHelper(lengthTracking, undefined));
// "includes" iterates until the original length and sees "undefined"s.
assertTrue(IncludesHelper(lengthTracking, undefined, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, 1);
}
let evil = { valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertFalse(IncludesHelper(lengthTracking, 0));
// The TA grew but we only look at the data until the original length.
assertFalse(IncludesHelper(lengthTracking, 0, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
WriteToTypedArray(lengthTracking, 0, 1);
let evil = { valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return -4;
}};
assertTrue(IncludesHelper(lengthTracking, 1, -4));
// The TA grew but the start index conversion is done based on the original
// length.
assertTrue(IncludesHelper(lengthTracking, 1, evil));
}
})();
(function IncludesSpecialValues() {
for (let ctor of floatCtors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
lengthTracking[0] = -Infinity;
lengthTracking[1] = Infinity;
lengthTracking[2] = NaN;
assertTrue(lengthTracking.includes(-Infinity));
assertTrue(lengthTracking.includes(Infinity));
assertTrue(lengthTracking.includes(NaN));
}
})();
(function IndexOfLastIndexOf() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, Math.floor(i / 2));
}
// Orig. array: [0, 0, 1, 1]
// [0, 0, 1, 1] << fixedLength
// [1, 1] << fixedLengthWithOffset
// [0, 0, 1, 1, ...] << lengthTracking
// [1, 1, ...] << lengthTrackingWithOffset
assertEquals(0, IndexOfHelper(fixedLength, 0));
assertEquals(1, IndexOfHelper(fixedLength, 0, 1));
assertEquals(-1, IndexOfHelper(fixedLength, 0, 2));
assertEquals(-1, IndexOfHelper(fixedLength, 0, -2));
assertEquals(1, IndexOfHelper(fixedLength, 0, -3));
assertEquals(2, IndexOfHelper(fixedLength, 1, 1));
assertEquals(2, IndexOfHelper(fixedLength, 1, -3));
assertEquals(2, IndexOfHelper(fixedLength, 1, -2));
assertEquals(-1, IndexOfHelper(fixedLength, undefined));
assertEquals(1, LastIndexOfHelper(fixedLength, 0));
assertEquals(1, LastIndexOfHelper(fixedLength, 0, 1));
assertEquals(1, LastIndexOfHelper(fixedLength, 0, 2));
assertEquals(1, LastIndexOfHelper(fixedLength, 0, -2));
assertEquals(1, LastIndexOfHelper(fixedLength, 0, -3));
assertEquals(-1, LastIndexOfHelper(fixedLength, 1, 1));
assertEquals(2, LastIndexOfHelper(fixedLength, 1, -2));
assertEquals(-1, LastIndexOfHelper(fixedLength, 1, -3));
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined));
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 0));
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1));
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1, -2));
assertEquals(1, IndexOfHelper(fixedLengthWithOffset, 1, -1));
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, undefined));
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 0));
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1));
assertEquals(0, LastIndexOfHelper(fixedLengthWithOffset, 1, -2));
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1, -1));
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, undefined));
assertEquals(0, IndexOfHelper(lengthTracking, 0));
assertEquals(-1, IndexOfHelper(lengthTracking, 0, 2));
assertEquals(2, IndexOfHelper(lengthTracking, 1, -3));
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
assertEquals(1, LastIndexOfHelper(lengthTracking, 0));
assertEquals(1, LastIndexOfHelper(lengthTracking, 0, 2));
assertEquals(1, LastIndexOfHelper(lengthTracking, 0, -3));
assertEquals(-1, LastIndexOfHelper(lengthTracking, 1, 1));
assertEquals(2, LastIndexOfHelper(lengthTracking, 1, 2));
assertEquals(-1, LastIndexOfHelper(lengthTracking, 1, -3));
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
assertEquals(1, IndexOfHelper(lengthTrackingWithOffset, 1, 1));
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1, -2));
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1));
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1, 1));
assertEquals(0, LastIndexOfHelper(lengthTrackingWithOffset, 1, -2));
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1, -1));
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 0, 1]
// [0, 0, 1, ...] << lengthTracking
// [1, ...] << lengthTrackingWithOffset
assertThrows(() => { IndexOfHelper(fixedLength, 1); });
assertThrows(() => { IndexOfHelper(fixedLengthWithOffset, 1); });
assertThrows(() => { LastIndexOfHelper(fixedLength, 1); });
assertThrows(() => { LastIndexOfHelper(fixedLengthWithOffset, 1); });
assertEquals(2, IndexOfHelper(lengthTracking, 1));
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
assertEquals(1, LastIndexOfHelper(lengthTracking, 0));
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
assertEquals(0, LastIndexOfHelper(lengthTrackingWithOffset, 1));
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { IndexOfHelper(fixedLength, 0); });
assertThrows(() => { IndexOfHelper(fixedLengthWithOffset, 0); });
assertThrows(() => { IndexOfHelper(lengthTrackingWithOffset, 0); });
assertThrows(() => { LastIndexOfHelper(fixedLength, 0); });
assertThrows(() => { LastIndexOfHelper(fixedLengthWithOffset, 0); });
assertThrows(() => { LastIndexOfHelper(lengthTrackingWithOffset, 0); });
assertEquals(0, IndexOfHelper(lengthTracking, 0));
assertEquals(0, LastIndexOfHelper(lengthTracking, 0));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { IndexOfHelper(fixedLength, 0); });
assertThrows(() => { IndexOfHelper(fixedLengthWithOffset, 0); });
assertThrows(() => { IndexOfHelper(lengthTrackingWithOffset, 0); });
assertThrows(() => { LastIndexOfHelper(fixedLength, 0); });
assertThrows(() => { LastIndexOfHelper(fixedLengthWithOffset, 0); });
assertThrows(() => { LastIndexOfHelper(lengthTrackingWithOffset, 0); });
assertEquals(-1, IndexOfHelper(lengthTracking, 0));
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0));
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, Math.floor(i / 2));
}
// Orig. array: [0, 0, 1, 1, 2, 2]
// [0, 0, 1, 1] << fixedLength
// [1, 1] << fixedLengthWithOffset
// [0, 0, 1, 1, 2, 2, ...] << lengthTracking
// [1, 1, 2, 2, ...] << lengthTrackingWithOffset
assertEquals(2, IndexOfHelper(fixedLength, 1));
assertEquals(-1, IndexOfHelper(fixedLength, 2));
assertEquals(-1, IndexOfHelper(fixedLength, undefined));
assertEquals(3, LastIndexOfHelper(fixedLength, 1));
assertEquals(-1, LastIndexOfHelper(fixedLength, 2));
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined));
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 0));
assertEquals(0, IndexOfHelper(fixedLengthWithOffset, 1));
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, 2));
assertEquals(-1, IndexOfHelper(fixedLengthWithOffset, undefined));
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 0));
assertEquals(1, LastIndexOfHelper(fixedLengthWithOffset, 1));
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, 2));
assertEquals(-1, LastIndexOfHelper(fixedLengthWithOffset, undefined));
assertEquals(2, IndexOfHelper(lengthTracking, 1));
assertEquals(4, IndexOfHelper(lengthTracking, 2));
assertEquals(-1, IndexOfHelper(lengthTracking, undefined));
assertEquals(3, LastIndexOfHelper(lengthTracking, 1));
assertEquals(5, LastIndexOfHelper(lengthTracking, 2));
assertEquals(-1, LastIndexOfHelper(lengthTracking, undefined));
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, 0));
assertEquals(0, IndexOfHelper(lengthTrackingWithOffset, 1));
assertEquals(2, IndexOfHelper(lengthTrackingWithOffset, 2));
assertEquals(-1, IndexOfHelper(lengthTrackingWithOffset, undefined));
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, 0));
assertEquals(1, LastIndexOfHelper(lengthTrackingWithOffset, 1));
assertEquals(3, LastIndexOfHelper(lengthTrackingWithOffset, 2));
assertEquals(-1, LastIndexOfHelper(lengthTrackingWithOffset, undefined));
}
})();
(function IndexOfParameterConversionShrinks() {
// Shrinking + fixed-length TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertEquals(0, IndexOfHelper(fixedLength, 0));
// The TA is OOB so indexOf returns -1.
assertEquals(-1, IndexOfHelper(fixedLength, 0, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertEquals(0, IndexOfHelper(fixedLength, 0));
// The TA is OOB so indexOf returns -1, also for undefined).
assertEquals(-1, IndexOfHelper(fixedLength, undefined, evil));
}
// Shrinking + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, i);
}
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertEquals(2, IndexOfHelper(lengthTracking, 2));
// 2 no longer found.
assertEquals(-1, IndexOfHelper(lengthTracking, 2, evil));
}
})();
(function LastIndexOfParameterConversionShrinks() {
// Shrinking + fixed-length TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 2;
}};
assertEquals(3, LastIndexOfHelper(fixedLength, 0));
// The TA is OOB so lastIndexOf returns -1.
assertEquals(-1, LastIndexOfHelper(fixedLength, 0, evil));
}
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 2;
}};
assertEquals(3, LastIndexOfHelper(fixedLength, 0));
// The TA is OOB so lastIndexOf returns -1, also for undefined).
assertEquals(-1, LastIndexOfHelper(fixedLength, undefined, evil));
}
// Shrinking + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, i);
}
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 2;
}};
assertEquals(2, LastIndexOfHelper(lengthTracking, 2));
// 2 no longer found.
assertEquals(-1, LastIndexOfHelper(lengthTracking, 2, evil));
}
})();
(function IndexOfParameterConversionGrows() {
// Growing + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, 1);
}
let evil = { valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertEquals(-1, IndexOfHelper(lengthTracking, 0));
// The TA grew but we only look at the data until the original length.
assertEquals(-1, IndexOfHelper(lengthTracking, 0, evil));
}
// Growing + length-tracking TA, index conversion.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
WriteToTypedArray(lengthTracking, 0, 1);
let evil = { valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return -4;
}};
assertEquals(0, IndexOfHelper(lengthTracking, 1, -4));
// The TA grew but the start index conversion is done based on the original
// length.
assertEquals(0, IndexOfHelper(lengthTracking, 1, evil));
}
})();
(function LastIndexOfParameterConversionGrows() {
// Growing + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(lengthTracking, i, 1);
}
let evil = { valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return -1;
}};
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0));
// Because lastIndexOf iterates from the given index downwards, it's not
// possible to test that "we only look at the data until the original
// length" without also testing that the index conversion happening with the
// original length.
assertEquals(-1, LastIndexOfHelper(lengthTracking, 0, evil));
}
// Growing + length-tracking TA, index conversion.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return -4;
}};
assertEquals(0, LastIndexOfHelper(lengthTracking, 0, -4));
// The TA grew but the start index conversion is done based on the original
// length.
assertEquals(0, LastIndexOfHelper(lengthTracking, 0, evil));
}
})();
(function IndexOfLastIndexOfSpecialValues() {
for (let ctor of floatCtors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
lengthTracking[0] = -Infinity;
lengthTracking[1] = -Infinity;
lengthTracking[2] = Infinity;
lengthTracking[3] = Infinity;
lengthTracking[4] = NaN;
lengthTracking[5] = NaN;
assertEquals(0, lengthTracking.indexOf(-Infinity));
assertEquals(1, lengthTracking.lastIndexOf(-Infinity));
assertEquals(2, lengthTracking.indexOf(Infinity));
assertEquals(3, lengthTracking.lastIndexOf(Infinity));
// NaN is never found.
assertEquals(-1, lengthTracking.indexOf(NaN));
assertEquals(-1, lengthTracking.lastIndexOf(NaN));
}
})();
(function JoinToLocaleString() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
assertEquals('0,2,4,6', fixedLength.join());
assertEquals('0,2,4,6', fixedLength.toLocaleString());
assertEquals('4,6', fixedLengthWithOffset.join());
assertEquals('4,6', fixedLengthWithOffset.toLocaleString());
assertEquals('0,2,4,6', lengthTracking.join());
assertEquals('0,2,4,6', lengthTracking.toLocaleString());
assertEquals('4,6', lengthTrackingWithOffset.join());
assertEquals('4,6', lengthTrackingWithOffset.toLocaleString());
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.join(); });
assertThrows(() => { fixedLength.toLocaleString(); });
assertThrows(() => { fixedLengthWithOffset.join(); });
assertThrows(() => { fixedLengthWithOffset.toLocaleString(); });
assertEquals('0,2,4', lengthTracking.join());
assertEquals('0,2,4', lengthTracking.toLocaleString());
assertEquals('4', lengthTrackingWithOffset.join());
assertEquals('4', lengthTrackingWithOffset.toLocaleString());
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { fixedLength.join(); });
assertThrows(() => { fixedLength.toLocaleString(); });
assertThrows(() => { fixedLengthWithOffset.join(); });
assertThrows(() => { fixedLengthWithOffset.toLocaleString(); });
assertThrows(() => { lengthTrackingWithOffset.join(); });
assertThrows(() => { lengthTrackingWithOffset.toLocaleString(); });
assertEquals('0', lengthTracking.join());
assertEquals('0', lengthTracking.toLocaleString());
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.join(); });
assertThrows(() => { fixedLength.toLocaleString(); });
assertThrows(() => { fixedLengthWithOffset.join(); });
assertThrows(() => { fixedLengthWithOffset.toLocaleString(); });
assertThrows(() => { lengthTrackingWithOffset.join(); });
assertThrows(() => { lengthTrackingWithOffset.toLocaleString(); });
assertEquals('', lengthTracking.join());
assertEquals('', lengthTracking.toLocaleString());
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertEquals('0,2,4,6', fixedLength.join());
assertEquals('0,2,4,6', fixedLength.toLocaleString());
assertEquals('4,6', fixedLengthWithOffset.join());
assertEquals('4,6', fixedLengthWithOffset.toLocaleString());
assertEquals('0,2,4,6,8,10', lengthTracking.join());
assertEquals('0,2,4,6,8,10', lengthTracking.toLocaleString());
assertEquals('4,6,8,10', lengthTrackingWithOffset.join());
assertEquals('4,6,8,10', lengthTrackingWithOffset.toLocaleString());
}
})();
(function JoinParameterConversionShrinks() {
// Shrinking + fixed-length TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { toString: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return '.';
}};
// We iterate 4 elements, since it was the starting length, but the TA is
// OOB right after parameter conversion, so all elements are converted to
// the empty string.
assertEquals('...', fixedLength.join(evil));
}
// Shrinking + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let evil = { toString: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return '.';
}};
// We iterate 4 elements, since it was the starting length. Elements beyond
// the new length are converted to the empty string.
assertEquals('0.0..', lengthTracking.join(evil));
}
})();
(function JoinParameterConversionGrows() {
// Growing + fixed-length TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let evil = { toString: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return '.';
}};
assertEquals('0.0.0.0', fixedLength.join(evil));
}
// Growing + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let evil = { toString: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return '.';
}};
// We iterate 4 elements, since it was the starting length.
assertEquals('0.0.0.0', lengthTracking.join(evil));
}
})();
(function ToLocaleStringNumberPrototypeToLocaleStringShrinks() {
const oldNumberPrototypeToLocaleString = Number.prototype.toLocaleString;
const oldBigIntPrototypeToLocaleString = BigInt.prototype.toLocaleString;
// Shrinking + fixed-length TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let resizeAfter = 2;
Number.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
return oldNumberPrototypeToLocaleString.call(this);
}
BigInt.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
return oldBigIntPrototypeToLocaleString.call(this);
}
// We iterate 4 elements, since it was the starting length. The TA goes
// OOB after 2 elements.
assertEquals('0,0,,', fixedLength.toLocaleString());
}
// Shrinking + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let resizeAfter = 2;
Number.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
return oldNumberPrototypeToLocaleString.call(this);
}
BigInt.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
return oldBigIntPrototypeToLocaleString.call(this);
}
// We iterate 4 elements, since it was the starting length. Elements beyond
// the new length are converted to the empty string.
assertEquals('0,0,,', lengthTracking.toLocaleString());
}
Number.prototype.toLocaleString = oldNumberPrototypeToLocaleString;
BigInt.prototype.toLocaleString = oldBigIntPrototypeToLocaleString;
})();
(function ToLocaleStringNumberPrototypeToLocaleStringGrows() {
const oldNumberPrototypeToLocaleString = Number.prototype.toLocaleString;
const oldBigIntPrototypeToLocaleString = BigInt.prototype.toLocaleString;
// Growing + fixed-length TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
let resizeAfter = 2;
Number.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
}
return oldNumberPrototypeToLocaleString.call(this);
}
BigInt.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
}
return oldBigIntPrototypeToLocaleString.call(this);
}
// We iterate 4 elements since it was the starting length. Resizing doesn't
// affect the TA.
assertEquals('0,0,0,0', fixedLength.toLocaleString());
}
// Growing + length-tracking TA.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab);
let resizeAfter = 2;
Number.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
}
return oldNumberPrototypeToLocaleString.call(this);
}
BigInt.prototype.toLocaleString = function() {
--resizeAfter;
if (resizeAfter == 0) {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
}
return oldBigIntPrototypeToLocaleString.call(this);
}
// We iterate 4 elements since it was the starting length.
assertEquals('0,0,0,0', lengthTracking.toLocaleString());
}
Number.prototype.toLocaleString = oldNumberPrototypeToLocaleString;
BigInt.prototype.toLocaleString = oldBigIntPrototypeToLocaleString;
})();
(function TestMap() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < taWrite.length; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function Helper(array) {
const values = [];
function GatherValues(n, ix) {
assertEquals(values.length, ix);
values.push(n);
if (typeof n == 'bigint') {
return n + 1n;
}
return n + 1;
}
const newValues = array.map(GatherValues);
for (let i = 0; i < values.length; ++i) {
if (typeof values[i] == 'bigint') {
assertEquals(newValues[i], values[i] + 1n);
} else {
assertEquals(newValues[i], values[i] + 1);
}
}
return ToNumbers(values);
}
assertEquals([0, 2, 4, 6], Helper(fixedLength));
assertEquals([4, 6], Helper(fixedLengthWithOffset));
assertEquals([0, 2, 4, 6], Helper(lengthTracking));
assertEquals([4, 6], Helper(lengthTrackingWithOffset));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { Helper(fixedLength); });
assertThrows(() => { Helper(fixedLengthWithOffset); });
assertEquals([0, 2, 4], Helper(lengthTracking));
assertEquals([4], Helper(lengthTrackingWithOffset));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { Helper(fixedLength); });
assertThrows(() => { Helper(fixedLengthWithOffset); });
assertThrows(() => { Helper(lengthTrackingWithOffset); });
assertEquals([0], Helper(lengthTracking));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { Helper(fixedLength); });
assertThrows(() => { Helper(fixedLengthWithOffset); });
assertThrows(() => { Helper(lengthTrackingWithOffset); });
assertEquals([], Helper(lengthTracking));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertEquals([0, 2, 4, 6], Helper(fixedLength));
assertEquals([4, 6], Helper(fixedLengthWithOffset));
assertEquals([0, 2, 4, 6, 8, 10], Helper(lengthTracking));
assertEquals([4, 6, 8, 10], Helper(lengthTrackingWithOffset));
}
})();
(function MapShrinkMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n, ix, ta) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
// We still need to return a valid BigInt / non-BigInt, even if
// n is `undefined`.
if (IsBigIntTypedArray(ta)) {
return 0n;
}
return 0;
}
function Helper(array) {
values = [];
array.map(CollectValuesAndResize);
return values;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, undefined, undefined], Helper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, undefined], Helper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, undefined], Helper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, undefined], Helper(lengthTrackingWithOffset));
}
})();
(function MapGrowMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let values;
let rab;
let resizeAfter;
let resizeTo;
function CollectValuesAndResize(n) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
if (values.length == resizeAfter) {
rab.resize(resizeTo);
}
return n;
}
function Helper(array) {
values = [];
array.map(CollectValuesAndResize);
return values;
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, 6], Helper(fixedLength));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, 6], Helper(fixedLengthWithOffset));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAfter = 2;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([0, 2, 4, 6], Helper(lengthTracking));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAfter = 1;
resizeTo = 5 * ctor.BYTES_PER_ELEMENT;
assertEquals([4, 6], Helper(lengthTrackingWithOffset));
}
})();
(function MapSpeciesCreateShrinks() {
let values;
let rab;
function CollectValues(n, ix, ta) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
// We still need to return a valid BigInt / non-BigInt, even if
// n is `undefined`.
if (IsBigIntTypedArray(ta)) {
return 0n;
}
return 0;
}
function Helper(array) {
values = [];
array.map(CollectValues);
return values;
}
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
}
};
const fixedLength = new MyArray(rab, 0, 4);
resizeWhenConstructorCalled = true;
assertEquals([undefined, undefined, undefined, undefined],
Helper(fixedLength));
assertEquals(2 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
}
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
}
}
};
const lengthTracking = new MyArray(rab);
resizeWhenConstructorCalled = true;
assertEquals([0, 1, undefined, undefined], Helper(lengthTracking));
assertEquals(2 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
}
})();
(function MapSpeciesCreateGrows() {
let values;
let rab;
function CollectValues(n, ix, ta) {
if (typeof n == 'bigint') {
values.push(Number(n));
} else {
values.push(n);
}
// We still need to return a valid BigInt / non-BigInt, even if
// n is `undefined`.
if (IsBigIntTypedArray(ta)) {
return 0n;
}
return 0;
}
function Helper(array) {
values = [];
array.map(CollectValues);
return values;
}
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
}
}
};
const fixedLength = new MyArray(rab, 0, 4);
resizeWhenConstructorCalled = true;
assertEquals([0, 1, 2, 3], Helper(fixedLength));
assertEquals(6 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
}
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, i);
}
let resizeWhenConstructorCalled = false;
class MyArray extends ctor {
constructor(...params) {
super(...params);
if (resizeWhenConstructorCalled) {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
}
}
};
const lengthTracking = new MyArray(rab);
resizeWhenConstructorCalled = true;
assertEquals([0, 1, 2, 3], Helper(lengthTracking));
assertEquals(6 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
}
})();
(function Reverse() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const wholeArrayView = new ctor(rab);
function WriteData() {
// Write some data into the array.
for (let i = 0; i < wholeArrayView.length; ++i) {
WriteToTypedArray(wholeArrayView, i, 2 * i);
}
}
WriteData();
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
fixedLength.reverse();
assertEquals([6, 4, 2, 0], ToNumbers(wholeArrayView));
fixedLengthWithOffset.reverse();
assertEquals([6, 4, 0, 2], ToNumbers(wholeArrayView));
lengthTracking.reverse();
assertEquals([2, 0, 4, 6], ToNumbers(wholeArrayView));
lengthTrackingWithOffset.reverse();
assertEquals([2, 0, 6, 4], ToNumbers(wholeArrayView));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
WriteData();
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
assertThrows(() => { fixedLength.reverse(); });
assertThrows(() => { fixedLengthWithOffset.reverse(); });
lengthTracking.reverse();
assertEquals([4, 2, 0], ToNumbers(wholeArrayView));
lengthTrackingWithOffset.reverse();
assertEquals([4, 2, 0], ToNumbers(wholeArrayView));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
WriteData();
assertThrows(() => { fixedLength.reverse(); });
assertThrows(() => { fixedLengthWithOffset.reverse(); });
assertThrows(() => { lengthTrackingWithOffset.reverse(); });
lengthTracking.reverse();
assertEquals([0], ToNumbers(wholeArrayView));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { fixedLength.reverse(); });
assertThrows(() => { fixedLengthWithOffset.reverse(); });
assertThrows(() => { lengthTrackingWithOffset.reverse(); });
lengthTracking.reverse();
assertEquals([], ToNumbers(wholeArrayView));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
WriteData();
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
fixedLength.reverse();
assertEquals([6, 4, 2, 0, 8, 10], ToNumbers(wholeArrayView));
fixedLengthWithOffset.reverse();
assertEquals([6, 4, 0, 2, 8, 10], ToNumbers(wholeArrayView));
lengthTracking.reverse();
assertEquals([10, 8, 2, 0, 4, 6], ToNumbers(wholeArrayView));
lengthTrackingWithOffset.reverse();
assertEquals([10, 8, 6, 4, 0, 2], ToNumbers(wholeArrayView));
}
})();
(function SetWithResizableTarget() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const taFull = new ctor(rab);
// Orig. array: [0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, ...] << lengthTracking
// [0, 0, ...] << lengthTrackingWithOffset
// For making sure we're not calling the source length or element getters
// if the target is OOB.
const throwingProxy = new Proxy({}, {
get(target, prop, receiver) {
throw new Error('Called getter for ' + prop);
}});
SetHelper(fixedLength, [1, 2]);
assertEquals([1, 2, 0, 0], ToNumbers(taFull));
SetHelper(fixedLength, [3, 4], 1);
assertEquals([1, 3, 4, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([1, 3, 4, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [5, 6]);
assertEquals([1, 3, 5, 6], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [7], 1);
assertEquals([1, 3, 5, 7], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0], 1)},
RangeError);
assertEquals([1, 3, 5, 7], ToNumbers(taFull));
SetHelper(lengthTracking, [8, 9]);
assertEquals([8, 9, 5, 7], ToNumbers(taFull));
SetHelper(lengthTracking, [10, 11], 1);
assertEquals([8, 10, 11, 7], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([8, 10, 11, 7], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [12, 13]);
assertEquals([8, 10, 12, 13], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [14], 1);
assertEquals([8, 10, 12, 14], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0])});
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0], 1)});
assertEquals([8, 10, 12, 14], ToNumbers(taFull));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [8, 10, 12]
// [8, 10, 12, ...] << lengthTracking
// [12, ...] << lengthTrackingWithOffset
assertThrows(() => { SetHelper(fixedLength, throwingProxy)}, TypeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, throwingProxy)},
TypeError);
assertEquals([8, 10, 12], ToNumbers(taFull));
SetHelper(lengthTracking, [15, 16]);
assertEquals([15, 16, 12], ToNumbers(taFull));
SetHelper(lengthTracking, [17, 18], 1);
assertEquals([15, 17, 18], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0])}, RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0], 1)}, RangeError);
assertEquals([15, 17, 18], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [19]);
assertEquals([15, 17, 19], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0], 1)},
RangeError);
assertEquals([15, 17, 19], ToNumbers(taFull));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { SetHelper(fixedLength, throwingProxy)}, TypeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, throwingProxy)},
TypeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, throwingProxy)},
TypeError);
assertEquals([15], ToNumbers(taFull));
SetHelper(lengthTracking, [20]);
assertEquals([20], ToNumbers(taFull));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { SetHelper(fixedLength, throwingProxy)}, TypeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, throwingProxy)},
TypeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, throwingProxy)},
TypeError);
assertThrows(() => { SetHelper(lengthTracking, [0])}, RangeError);
assertEquals([], ToNumbers(taFull));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 0, 0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, 0, 0, ...] << lengthTracking
// [0, 0, 0, 0, ...] << lengthTrackingWithOffset
SetHelper(fixedLength, [21, 22]);
assertEquals([21, 22, 0, 0, 0, 0], ToNumbers(taFull));
SetHelper(fixedLength, [23, 24], 1);
assertEquals([21, 23, 24, 0, 0, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0, 0])}, RangeError);
assertThrows(() => { SetHelper(fixedLength, [0, 0, 0, 0], 1)}, RangeError);
assertEquals([21, 23, 24, 0, 0, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [25, 26]);
assertEquals([21, 23, 25, 26, 0, 0], ToNumbers(taFull));
SetHelper(fixedLengthWithOffset, [27], 1);
assertEquals([21, 23, 25, 27, 0, 0], ToNumbers(taFull));
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(fixedLengthWithOffset, [0, 0], 1)},
RangeError);
assertEquals([21, 23, 25, 27, 0, 0], ToNumbers(taFull));
SetHelper(lengthTracking, [28, 29, 30, 31, 32, 33]);
assertEquals([28, 29, 30, 31, 32, 33], ToNumbers(taFull));
SetHelper(lengthTracking, [34, 35, 36, 37, 38], 1);
assertEquals([28, 34, 35, 36, 37, 38], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTracking, [0, 0, 0, 0, 0, 0], 1)},
RangeError);
assertEquals([28, 34, 35, 36, 37, 38], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [39, 40, 41, 42]);
assertEquals([28, 34, 39, 40, 41, 42], ToNumbers(taFull));
SetHelper(lengthTrackingWithOffset, [43, 44, 45], 1);
assertEquals([28, 34, 39, 43, 44, 45], ToNumbers(taFull));
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0, 0, 0])},
RangeError);
assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0, 0, 0], 1)},
RangeError);
assertEquals([28, 34, 39, 43, 44, 45], ToNumbers(taFull));
}
})();
(function SetSourceLengthGetterShrinksTarget() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
let resizeTo;
function CreateSourceProxy(length) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
rab.resize(resizeTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Tests where the length getter returns a non-zero value -> these are nop if
// the TA went OOB.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(1));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(1));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(1));
assertEquals([1, 2, 4], ToNumbers(lengthTracking));
assertEquals([1, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(1));
assertEquals([1], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1], ToNumbers(new ctor(rab)));
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(1));
assertEquals([0], ToNumbers(new ctor(rab)));
}
// Tests where the length getter returns a zero -> these don't throw even if
// the TA went OOB.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(0));
assertEquals([0, 2, 4], ToNumbers(new ctor(rab)));
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(0));
assertEquals([0], ToNumbers(new ctor(rab)));
}
})();
(function SetSourceLengthGetterGrowsTarget() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
let resizeTo;
function CreateSourceProxy(length) {
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
rab.resize(resizeTo);
return length;
}
return true; // Can be converted to both BigInt and Number.
}
});
}
// Test that we still throw for lengthTracking TAs if the source length is
// too large, even though we resized in the length getter (we check against
// the original length).
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTracking.set(CreateSourceProxy(6)); },
RangeError);
assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(4)); },
RangeError);
assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(rab)));
}
})();
(function SetShrinkTargetMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
// Resizing will happen when we're calling Get for the `resizeAt`:th data
// element, but we haven't yet written it to the target.
let resizeAt;
let resizeTo;
function CreateSourceProxy(length) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == resizeAt) {
rab.resize(resizeTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(4));
assertEquals([1, 2, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(2));
assertEquals([0, 2, 1], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2));
assertEquals([1, 1, 4], ToNumbers(lengthTracking));
assertEquals([1, 1, 4], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAt = 2;
resizeTo = 3 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2));
assertEquals([1], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1], ToNumbers(new ctor(rab)));
}
// Length-tracking TA goes OOB because of the offset.
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAt = 1;
resizeTo = 1 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2));
assertEquals([0], ToNumbers(new ctor(rab)));
}
})();
(function SetGrowTargetMidIteration() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
let rab;
// Resizing will happen when we're calling Get for the `resizeAt`:th data
// element, but we haven't yet written it to the target.
let resizeAt;
let resizeTo;
function CreateSourceProxy(length) {
let requestedIndices = [];
return new Proxy({}, {
get(target, prop, receiver) {
if (prop == 'length') {
return length;
}
requestedIndices.push(prop);
if (requestedIndices.length == resizeAt) {
rab.resize(resizeTo);
}
return true; // Can be converted to both BigInt and Number.
}
});
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
resizeAt = 2;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLength.set(CreateSourceProxy(4));
assertEquals([1, 1, 1, 1], ToNumbers(fixedLength));
assertEquals([1, 1, 1, 1, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
resizeAt = 1;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
fixedLengthWithOffset.set(CreateSourceProxy(2));
assertEquals([1, 1], ToNumbers(fixedLengthWithOffset));
assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
resizeAt = 2;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTracking.set(CreateSourceProxy(2));
assertEquals([1, 1, 4, 6, 0, 0], ToNumbers(lengthTracking));
assertEquals([1, 1, 4, 6, 0, 0], ToNumbers(new ctor(rab)));
}
for (let ctor of ctors) {
rab = CreateRabForTest(ctor);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
resizeAt = 1;
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
lengthTrackingWithOffset.set(CreateSourceProxy(2));
assertEquals([1, 1, 0, 0], ToNumbers(lengthTrackingWithOffset));
assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(rab)));
}
})();
(function SetWithResizableSource() {
for (let targetIsResizable of [false, true]) {
for (let targetCtor of ctors) {
for (let sourceCtor of ctors) {
const rab = CreateResizableArrayBuffer(
4 * sourceCtor.BYTES_PER_ELEMENT,
8 * sourceCtor.BYTES_PER_ELEMENT);
const fixedLength = new sourceCtor(rab, 0, 4);
const fixedLengthWithOffset = new sourceCtor(
rab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new sourceCtor(rab, 0);
const lengthTrackingWithOffset = new sourceCtor(
rab, 2 * sourceCtor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taFull = new sourceCtor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, ...] << lengthTracking
// [3, 4, ...] << lengthTrackingWithOffset
const targetAb = targetIsResizable ?
new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT) :
new ArrayBuffer(6 * targetCtor.BYTES_PER_ELEMENT,
{maxByteLength: 8 * targetCtor.BYTES_PER_ELEMENT});
const target = new targetCtor(targetAb);
if (IsBigIntTypedArray(target) != IsBigIntTypedArray(taFull)) {
// Can't mix BigInt and non-BigInt types.
continue;
}
SetHelper(target, fixedLength);
assertEquals([1, 2, 3, 4, 0, 0], ToNumbers(target));
SetHelper(target, fixedLengthWithOffset);
assertEquals([3, 4, 3, 4, 0, 0], ToNumbers(target));
SetHelper(target, lengthTracking, 1);
assertEquals([3, 1, 2, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset, 1);
assertEquals([3, 3, 4, 3, 4, 0], ToNumbers(target));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * sourceCtor.BYTES_PER_ELEMENT);
// Orig. array: [1, 2, 3]
// [1, 2, 3, ...] << lengthTracking
// [3, ...] << lengthTrackingWithOffset
assertThrows(() => { SetHelper(target, fixedLength)}, TypeError);
assertThrows(() => { SetHelper(target, fixedLengthWithOffset)},
TypeError);
assertEquals([3, 3, 4, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTracking);
assertEquals([1, 2, 3, 3, 4, 0], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset);
assertEquals([3, 2, 3, 3, 4, 0], ToNumbers(target));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * sourceCtor.BYTES_PER_ELEMENT);
assertThrows(() => { SetHelper(target, fixedLength)}, TypeError);
assertThrows(() => { SetHelper(target, fixedLengthWithOffset)},
TypeError);
assertThrows(() => { SetHelper(target, lengthTrackingWithOffset)},
TypeError);
SetHelper(target, lengthTracking, 3);
assertEquals([3, 2, 3, 1, 4, 0], ToNumbers(target));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { SetHelper(target, fixedLength)}, TypeError);
assertThrows(() => { SetHelper(target, fixedLengthWithOffset)},
TypeError);
assertThrows(() => { SetHelper(target, lengthTrackingWithOffset)},
TypeError);
SetHelper(target, lengthTracking, 4);
assertEquals([3, 2, 3, 1, 4, 0], ToNumbers(target));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * sourceCtor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taFull, i, i + 1);
}
// Orig. array: [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4] << fixedLength
// [3, 4] << fixedLengthWithOffset
// [1, 2, 3, 4, 5, 6, ...] << lengthTracking
// [3, 4, 5, 6, ...] << lengthTrackingWithOffset
SetHelper(target, fixedLength);
assertEquals([1, 2, 3, 4, 4, 0], ToNumbers(target));
SetHelper(target, fixedLengthWithOffset);
assertEquals([3, 4, 3, 4, 4, 0], ToNumbers(target));
SetHelper(target, lengthTracking, 0);
assertEquals([1, 2, 3, 4, 5, 6], ToNumbers(target));
SetHelper(target, lengthTrackingWithOffset, 1);
assertEquals([1, 3, 4, 5, 6, 6], ToNumbers(target));
}
}
}
})();
(function Subarray() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
const fixedLengthSubFull = fixedLength.subarray(0);
assertEquals([0, 2, 4, 6], ToNumbers(fixedLengthSubFull));
const fixedLengthWithOffsetSubFull = fixedLengthWithOffset.subarray(0);
assertEquals([4, 6], ToNumbers(fixedLengthWithOffsetSubFull));
const lengthTrackingSubFull = lengthTracking.subarray(0);
assertEquals([0, 2, 4, 6], ToNumbers(lengthTrackingSubFull));
const lengthTrackingWithOffsetSubFull =
lengthTrackingWithOffset.subarray(0);
assertEquals([4, 6], ToNumbers(lengthTrackingWithOffsetSubFull));
// Relative offsets
assertEquals([4, 6], ToNumbers(fixedLength.subarray(-2)));
assertEquals([6], ToNumbers(fixedLengthWithOffset.subarray(-1)));
assertEquals([4, 6], ToNumbers(lengthTracking.subarray(-2)));
assertEquals([6], ToNumbers(lengthTrackingWithOffset.subarray(-1)));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
// We can create subarrays of OOB arrays (which have length 0), as long as
// the new arrays are not OOB.
assertEquals([], ToNumbers(fixedLength.subarray(0)));
assertEquals([], ToNumbers(fixedLengthWithOffset.subarray(0)));
assertEquals([0, 2, 4], ToNumbers(lengthTracking.subarray(0)));
assertEquals([4], ToNumbers(lengthTrackingWithOffset.subarray(0)));
// Also the previously created subarrays are OOB.
assertEquals(0, fixedLengthSubFull.length);
assertEquals(0, fixedLengthWithOffsetSubFull.length);
// Relative offsets
assertEquals([2, 4], ToNumbers(lengthTracking.subarray(-2)));
assertEquals([4], ToNumbers(lengthTrackingWithOffset.subarray(-1)));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertEquals([], ToNumbers(fixedLength.subarray(0)));
assertEquals([0], ToNumbers(lengthTracking.subarray(0)));
// Even the 0-length subarray of fixedLengthWithOffset would be OOB ->
// this throws.
assertThrows(() => { fixedLengthWithOffset.subarray(0); }, RangeError);
// Also the previously created subarrays are OOB.
assertEquals(0, fixedLengthSubFull.length);
assertEquals(0, fixedLengthWithOffsetSubFull.length);
assertEquals(0, lengthTrackingWithOffsetSubFull.length);
// Shrink to zero.
rab.resize(0);
assertEquals([], ToNumbers(fixedLength.subarray(0)));
assertEquals([], ToNumbers(lengthTracking.subarray(0)));
assertThrows(() => { fixedLengthWithOffset.subarray(0); }, RangeError);
assertThrows(() => { lengthTrackingWithOffset.subarray(0); }, RangeError);
// Also the previously created subarrays are OOB.
assertEquals(0, fixedLengthSubFull.length);
assertEquals(0, fixedLengthWithOffsetSubFull.length);
assertEquals(0, lengthTrackingWithOffsetSubFull.length);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assertEquals([0, 2, 4, 6], ToNumbers(fixedLength.subarray(0)));
assertEquals([4, 6], ToNumbers(fixedLengthWithOffset.subarray(0)));
assertEquals([0, 2, 4, 6, 8, 10], ToNumbers(lengthTracking.subarray(0)));
assertEquals([4, 6, 8, 10],
ToNumbers(lengthTrackingWithOffset.subarray(0)));
// Also the previously created subarrays are no longer OOB.
assertEquals(4, fixedLengthSubFull.length);
assertEquals(2, fixedLengthWithOffsetSubFull.length);
// TODO(v8:11111): Are subarrays of length-tracking TAs also
// length-tracking? See
// https://github.com/tc39/proposal-resizablearraybuffer/issues/91
assertEquals(4, lengthTrackingSubFull.length);
assertEquals(2, lengthTrackingWithOffsetSubFull.length);
}
})();
(function SubarrayParameterConversionShrinks() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [0, 2, 4, 6, ...] << lengthTracking
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
// Fixed-length TA + first parameter conversion shrinks. The old length is
// used in the length computation, and the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertThrows(() => { fixedLength.subarray(evil); }, RangeError);
}
// Like the previous test, but now we construct a smaller subarray and it
// succeeds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertEquals([0], ToNumbers(fixedLength.subarray(evil, 1)));
}
// Fixed-length TA + second parameter conversion shrinks. The old length is
// used in the length computation, and the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 3;
}};
assertThrows(() => { fixedLength.subarray(0, evil); }, RangeError);
}
// Like the previous test, but now we construct a smaller subarray and it
// succeeds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 1;
}};
assertEquals([0], ToNumbers(fixedLength.subarray(0, evil)));
}
// Shrinking + fixed-length TA, subarray construction succeeds even though the
// TA goes OOB.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const evil = { valueOf: () => { rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;}};
assertEquals([0], ToNumbers(fixedLength.subarray(evil, 1)));
}
// Length-tracking TA + first parameter conversion shrinks. The old length is
// used in the length computation, and the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertThrows(() => { lengthTracking.subarray(evil); });
}
// Like the previous test, but now we construct a smaller subarray and it
// succeeds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertEquals([0], ToNumbers(lengthTracking.subarray(evil, 1)));
}
// Length-tracking TA + first parameter conversion shrinks. The second
// parameter is negative -> the relative index is not recomputed, and the
// subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertThrows(() => { lengthTracking.subarray(evil, -1); });
}
// Length-tracking TA + second parameter conversion shrinks. The second
// parameter is too large -> the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = { valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 3;
}};
assertThrows(() => { lengthTracking.subarray(0, evil); });
}
})();
(function SubarrayParameterConversionGrows() {
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [0, 2, 4, 6, ...] << lengthTracking
function CreateRabForTest(ctor) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
return rab;
}
// Growing a fixed length TA back in bounds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// Make `fixedLength` OOB.
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
const evil = { valueOf: () => { rab.resize(4 * ctor.BYTES_PER_ELEMENT);
return 0;}};
// The length computation is done before parameter conversion. At that
// point, the length is 0, since the TA is OOB.
assertEquals([], ToNumbers(fixedLength.subarray(evil, 0, 1)));
}
// Growing + fixed-length TA. Growing won't affect anything.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const evil = { valueOf: () => { rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;}};
assertEquals([0, 2, 4, 6], ToNumbers(fixedLength.subarray(evil)));
}
// Growing + length-tracking TA. The length computation is done with the
// original length.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const evil = { valueOf: () => { rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;}};
assertEquals([0, 2, 4, 6], ToNumbers(lengthTracking.subarray(evil)));
}
})();
(function SortWithDefaultComparison() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const taFull = new ctor(rab, 0);
function WriteUnsortedData() {
// Write some data into the array.
for (let i = 0; i < taFull.length; ++i) {
WriteToTypedArray(taFull, i, 10 - 2 * i);
}
}
// Orig. array: [10, 8, 6, 4]
// [10, 8, 6, 4] << fixedLength
// [6, 4] << fixedLengthWithOffset
// [10, 8, 6, 4, ...] << lengthTracking
// [6, 4, ...] << lengthTrackingWithOffset
WriteUnsortedData();
fixedLength.sort();
assertEquals([4, 6, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
fixedLengthWithOffset.sort();
assertEquals([10, 8, 4, 6], ToNumbers(taFull));
WriteUnsortedData();
lengthTracking.sort();
assertEquals([4, 6, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
lengthTrackingWithOffset.sort();
assertEquals([10, 8, 4, 6], ToNumbers(taFull));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [10, 8, 6]
// [10, 8, 6, ...] << lengthTracking
// [6, ...] << lengthTrackingWithOffset
WriteUnsortedData();
assertThrows(() => { fixedLength.sort(); }, TypeError);
WriteUnsortedData();
assertThrows(() => { fixedLengthWithOffset.sort(); }, TypeError);
WriteUnsortedData();
lengthTracking.sort();
assertEquals([6, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
lengthTrackingWithOffset.sort();
assertEquals([10, 8, 6], ToNumbers(taFull));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
WriteUnsortedData();
assertThrows(() => { fixedLength.sort(); }, TypeError);
WriteUnsortedData();
assertThrows(() => { fixedLengthWithOffset.sort(); }, TypeError);
WriteUnsortedData();
lengthTracking.sort();
assertEquals([10], ToNumbers(taFull));
WriteUnsortedData();
assertThrows(() => { lengthTrackingWithOffset.sort(); }, TypeError);
// Shrink to zero.
rab.resize(0);
WriteUnsortedData();
assertThrows(() => { fixedLength.sort(); }, TypeError);
WriteUnsortedData();
assertThrows(() => { fixedLengthWithOffset.sort(); }, TypeError);
WriteUnsortedData();
lengthTracking.sort();
assertEquals([], ToNumbers(taFull));
WriteUnsortedData();
assertThrows(() => { lengthTrackingWithOffset.sort(); }, TypeError);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [10, 8, 6, 4, 2, 0]
// [10, 8, 6, 4] << fixedLength
// [6, 4] << fixedLengthWithOffset
// [10, 8, 6, 4, 2, 0, ...] << lengthTracking
// [6, 4, 2, 0, ...] << lengthTrackingWithOffset
WriteUnsortedData();
fixedLength.sort();
assertEquals([4, 6, 8, 10, 2, 0], ToNumbers(taFull));
WriteUnsortedData();
fixedLengthWithOffset.sort();
assertEquals([10, 8, 4, 6, 2, 0], ToNumbers(taFull));
WriteUnsortedData();
lengthTracking.sort();
assertEquals([0, 2, 4, 6, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
lengthTrackingWithOffset.sort();
assertEquals([10, 8, 0, 2, 4, 6], ToNumbers(taFull));
}
})();
(function SortWithCustomComparison() {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
const taFull = new ctor(rab, 0);
function WriteUnsortedData() {
// Write some data into the array.
for (let i = 0; i < taFull.length; ++i) {
WriteToTypedArray(taFull, i, 10 - i);
}
}
function CustomComparison(a, b) {
// Sort all odd numbers before even numbers.
a = Number(a);
b = Number(b);
if (a % 2 == 1 && b % 2 == 0) {
return -1;
}
if (a % 2 == 0 && b % 2 == 1) {
return 1;
}
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
// Orig. array: [10, 9, 8, 7]
// [10, 9, 8, 7] << fixedLength
// [8, 7] << fixedLengthWithOffset
// [10, 9, 8, 7, ...] << lengthTracking
// [8, 7, ...] << lengthTrackingWithOffset
WriteUnsortedData();
fixedLength.sort(CustomComparison);
assertEquals([7, 9, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
fixedLengthWithOffset.sort(CustomComparison);
assertEquals([10, 9, 7, 8], ToNumbers(taFull));
WriteUnsortedData();
lengthTracking.sort(CustomComparison);
assertEquals([7, 9, 8, 10], ToNumbers(taFull));
WriteUnsortedData(CustomComparison);
lengthTrackingWithOffset.sort();
assertEquals([10, 9, 7, 8], ToNumbers(taFull));
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [10, 9, 8]
// [10, 9, 8, ...] << lengthTracking
// [8, ...] << lengthTrackingWithOffset
WriteUnsortedData();
assertThrows(() => { fixedLength.sort(CustomComparison); }, TypeError);
WriteUnsortedData();
assertThrows(() => { fixedLengthWithOffset.sort(CustomComparison); },
TypeError);
WriteUnsortedData();
lengthTracking.sort(CustomComparison);
assertEquals([9, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
lengthTrackingWithOffset.sort(CustomComparison);
assertEquals([10, 9, 8], ToNumbers(taFull));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
WriteUnsortedData();
assertThrows(() => { fixedLength.sort(CustomComparison); }, TypeError);
WriteUnsortedData();
assertThrows(() => { fixedLengthWithOffset.sort(CustomComparison); },
TypeError);
WriteUnsortedData();
lengthTracking.sort();
assertEquals([10], ToNumbers(taFull));
WriteUnsortedData();
assertThrows(() => { lengthTrackingWithOffset.sort(CustomComparison); },
TypeError);
// Shrink to zero.
rab.resize(0);
WriteUnsortedData();
assertThrows(() => { fixedLength.sort(CustomComparison); }, TypeError);
WriteUnsortedData();
assertThrows(() => { fixedLengthWithOffset.sort(CustomComparison); },
TypeError);
WriteUnsortedData();
lengthTracking.sort();
assertEquals([], ToNumbers(taFull));
WriteUnsortedData();
assertThrows(() => { lengthTrackingWithOffset.sort(CustomComparison); },
TypeError);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [10, 9, 8, 7, 6, 5]
// [10, 9, 8, 7] << fixedLength
// [8, 7] << fixedLengthWithOffset
// [10, 9, 8, 7, 6, 5, ...] << lengthTracking
// [8, 7, 6, 5, ...] << lengthTrackingWithOffset
WriteUnsortedData();
fixedLength.sort(CustomComparison);
assertEquals([7, 9, 8, 10, 6, 5], ToNumbers(taFull));
WriteUnsortedData();
fixedLengthWithOffset.sort(CustomComparison);
assertEquals([10, 9, 7, 8, 6, 5], ToNumbers(taFull));
WriteUnsortedData();
lengthTracking.sort(CustomComparison);
assertEquals([5, 7, 9, 6, 8, 10], ToNumbers(taFull));
WriteUnsortedData();
lengthTrackingWithOffset.sort(CustomComparison);
assertEquals([10, 9, 5, 7, 6, 8], ToNumbers(taFull));
}
})();
(function SortCallbackShrinks() {
function WriteUnsortedData(taFull) {
for (let i = 0; i < taFull.length; ++i) {
WriteToTypedArray(taFull, i, 10 - i);
}
}
let rab;
let resizeTo;
function CustomComparison(a, b) {
rab.resize(resizeTo);
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
// Fixed length TA.
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
resizeTo = 2 * ctor.BYTES_PER_ELEMENT;
const fixedLength = new ctor(rab, 0, 4);
const taFull = new ctor(rab, 0);
WriteUnsortedData(taFull);
fixedLength.sort(CustomComparison);
// The data is unchanged.
assertEquals([10, 9], ToNumbers(taFull));
}
// Length-tracking TA.
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
resizeTo = 2 * ctor.BYTES_PER_ELEMENT;
const lengthTracking = new ctor(rab, 0);
const taFull = new ctor(rab, 0);
WriteUnsortedData(taFull);
lengthTracking.sort(CustomComparison);
// The sort result is implementation defined, but it contains 2 elements out
// of the 4 original ones.
const newData = ToNumbers(taFull);
assertEquals(2, newData.length);
assertTrue([10, 9, 8, 7].includes(newData[0]));
assertTrue([10, 9, 8, 7].includes(newData[1]));
}
})();
(function SortCallbackGrows() {
function WriteUnsortedData(taFull) {
for (let i = 0; i < taFull.length; ++i) {
WriteToTypedArray(taFull, i, 10 - i);
}
}
let rab;
let resizeTo;
function CustomComparison(a, b) {
rab.resize(resizeTo);
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
// Fixed length TA.
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
const fixedLength = new ctor(rab, 0, 4);
const taFull = new ctor(rab, 0);
WriteUnsortedData(taFull);
fixedLength.sort(CustomComparison);
// Growing doesn't affect the sorting.
assertEquals([7, 8, 9, 10, 0, 0], ToNumbers(taFull));
}
// Length-tracking TA.
for (let ctor of ctors) {
rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
resizeTo = 6 * ctor.BYTES_PER_ELEMENT;
const lengthTracking = new ctor(rab, 0);
const taFull = new ctor(rab, 0);
WriteUnsortedData(taFull);
lengthTracking.sort(CustomComparison);
// Growing doesn't affect the sorting. Only the elements that were part of
// the original TA are sorted.
assertEquals([7, 8, 9, 10, 0, 0], ToNumbers(taFull));
}
})();
(function ObjectDefinePropertyDefineProperties() {
for (let helper of
[ObjectDefinePropertyHelper, ObjectDefinePropertiesHelper]) {
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(
rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(
rab, 2 * ctor.BYTES_PER_ELEMENT);
const taFull = new ctor(rab, 0);
// Orig. array: [0, 0, 0, 0]
// [0, 0, 0, 0] << fixedLength
// [0, 0] << fixedLengthWithOffset
// [0, 0, 0, 0, ...] << lengthTracking
// [0, 0, ...] << lengthTrackingWithOffset
helper(fixedLength, 0, 1);
assertEquals([1, 0, 0, 0], ToNumbers(taFull));
helper(fixedLengthWithOffset, 0, 2);
assertEquals([1, 0, 2, 0], ToNumbers(taFull));
helper(lengthTracking, 1, 3);
assertEquals([1, 3, 2, 0], ToNumbers(taFull));
helper(lengthTrackingWithOffset, 1, 4);
assertEquals([1, 3, 2, 4], ToNumbers(taFull));
assertThrows(() => { helper(fixedLength, 4, 8); }, TypeError);
assertThrows(() => { helper(fixedLengthWithOffset, 2, 8); }, TypeError);
assertThrows(() => { helper(lengthTracking, 4, 8); }, TypeError);
assertThrows(() => { helper(lengthTrackingWithOffset, 2, 8); },
TypeError);
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [1, 3, 2]
// [1, 3, 2, ...] << lengthTracking
// [2, ...] << lengthTrackingWithOffset
assertThrows(() => { helper(fixedLength, 0, 8); }, TypeError);
assertThrows(() => { helper(fixedLengthWithOffset, 0, 8); }, TypeError);
assertEquals([1, 3, 2], ToNumbers(taFull));
helper(lengthTracking, 0, 5);
assertEquals([5, 3, 2], ToNumbers(taFull));
helper(lengthTrackingWithOffset, 0, 6);
assertEquals([5, 3, 6], ToNumbers(taFull));
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { helper(fixedLength, 0, 8); }, TypeError);
assertThrows(() => { helper(fixedLengthWithOffset, 0, 8); }, TypeError);
assertThrows(() => { helper(lengthTrackingWithOffset, 0, 8); },
TypeError);
assertEquals([5], ToNumbers(taFull));
helper(lengthTracking, 0, 7);
assertEquals([7], ToNumbers(taFull));
// Shrink to zero.
rab.resize(0);
assertThrows(() => { helper(fixedLength, 0, 8); }, TypeError);
assertThrows(() => { helper(fixedLengthWithOffset, 0, 8); }, TypeError);
assertThrows(() => { helper(lengthTracking, 0, 8); }, TypeError);
assertThrows(() => { helper(lengthTrackingWithOffset, 0, 8); },
TypeError);
assertEquals([], ToNumbers(taFull));
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
helper(fixedLength, 0, 9);
assertEquals([9, 0, 0, 0, 0, 0], ToNumbers(taFull));
helper(fixedLengthWithOffset, 0, 10);
assertEquals([9, 0, 10, 0, 0, 0], ToNumbers(taFull));
helper(lengthTracking, 1, 11);
assertEquals([9, 11, 10, 0, 0, 0], ToNumbers(taFull));
helper(lengthTrackingWithOffset, 2, 12);
assertEquals([9, 11, 10, 0, 12, 0], ToNumbers(taFull));
// Trying to define properties out of the fixed-length bounds throws.
assertThrows(() => { helper(fixedLength, 5, 13); }, TypeError);
assertThrows(() => { helper(fixedLengthWithOffset, 3, 13); }, TypeError);
assertEquals([9, 11, 10, 0, 12, 0], ToNumbers(taFull));
helper(lengthTracking, 4, 14);
assertEquals([9, 11, 10, 0, 14, 0], ToNumbers(taFull));
helper(lengthTrackingWithOffset, 3, 15);
assertEquals([9, 11, 10, 0, 14, 15], ToNumbers(taFull));
}
}
})();
(function ObjectDefinePropertyParameterConversionShrinks() {
const helper = ObjectDefinePropertyHelper;
// Fixed length.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const evil = {toString: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
assertThrows(() => { helper(fixedLength, evil, 8); }, TypeError);
}
// Length tracking.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab, 0);
const evil = {toString: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 3; // Index too large after resize.
}};
assertThrows(() => { helper(lengthTracking, evil, 8); }, TypeError);
}
})();
(function ObjectDefinePropertyParameterConversionGrows() {
const helper = ObjectDefinePropertyHelper;
// Fixed length.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
// Make fixedLength go OOB.
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
const evil = {toString: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;
}};
helper(fixedLength, evil, 8);
assertEquals([8, 0, 0, 0], ToNumbers(fixedLength));
}
// Length tracking.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab, 0);
const evil = {toString: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 4; // Index valid after resize.
}};
helper(lengthTracking, evil, 8);
assertEquals([0, 0, 0, 0, 8, 0], ToNumbers(lengthTracking));
}
})();
(function ObjectFreeze() {
// Freezing non-OOB non-zero-length TAs throws.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(
rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(
rab, 2 * ctor.BYTES_PER_ELEMENT);
assertThrows(() => { Object.freeze(fixedLength); }, TypeError);
assertThrows(() => { Object.freeze(fixedLengthWithOffset); }, TypeError);
assertThrows(() => { Object.freeze(lengthTracking); }, TypeError);
assertThrows(() => { Object.freeze(lengthTrackingWithOffset); }, TypeError);
}
// Freezing zero-length TAs doesn't throw.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 0);
const fixedLengthWithOffset = new ctor(
rab, 2 * ctor.BYTES_PER_ELEMENT, 0);
// Zero-length because the offset is at the end:
const lengthTrackingWithOffset = new ctor(
rab, 4 * ctor.BYTES_PER_ELEMENT);
Object.freeze(fixedLength);
Object.freeze(fixedLengthWithOffset);
Object.freeze(lengthTrackingWithOffset);
}
// If the buffer has been resized to make length-tracking TAs zero-length,
// freezing them also doesn't throw.
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(rab, );
const lengthTrackingWithOffset = new ctor(
rab, 2 * ctor.BYTES_PER_ELEMENT);
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
Object.freeze(lengthTrackingWithOffset);
rab.resize(0 * ctor.BYTES_PER_ELEMENT);
Object.freeze(lengthTracking);
}
})();