// 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 gsab = CreateGrowableSharedArrayBuffer(40, 80); const sab = new SharedArrayBuffer(80); for (let ctor of ctors) { const ta_gsab = new ctor(gsab, 0, 3); const ta_sab = new ctor(sab, 0, 3); assertEquals(ta_gsab.__proto__, ta_sab.__proto__); } })(); (function TypedArrayLengthAndByteLength() { const gsab = CreateGrowableSharedArrayBuffer(40, 80); for (let ctor of ctors) { const ta = new ctor(gsab, 0, 3); assertEquals(gsab, ta.buffer); assertEquals(3, ta.length); assertEquals(3 * ctor.BYTES_PER_ELEMENT, ta.byteLength); const empty_ta = new ctor(gsab, 0, 0); assertEquals(gsab, empty_ta.buffer); assertEquals(0, empty_ta.length); assertEquals(0, empty_ta.byteLength); const ta_with_offset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 3); assertEquals(gsab, 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(gsab, 2 * ctor.BYTES_PER_ELEMENT, 0); assertEquals(gsab, 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(gsab); assertEquals(gsab, 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(gsab, offset); assertEquals(gsab, 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 length_tracking_ta_zero = new ctor(gsab, 40); assertEquals(gsab, length_tracking_ta_zero.buffer); assertEquals(0, length_tracking_ta_zero.length); assertEquals(0, length_tracking_ta_zero.byteLength); } })(); (function ConstructInvalid() { const gsab = CreateGrowableSharedArrayBuffer(40, 80); for (let ctor of ctors) { // Length too big. assertThrows(() => { new ctor(gsab, 0, 40 / ctor.BYTES_PER_ELEMENT + 1); }, RangeError); // Offset too close to the end. assertThrows(() => { new ctor(gsab, 40 - ctor.BYTES_PER_ELEMENT, 2); }, RangeError); // Offset beyond end. assertThrows(() => { new ctor(gsab, 40, 1); }, RangeError); if (ctor.BYTES_PER_ELEMENT > 1) { // Offset not a multiple of ctor.BYTES_PER_ELEMENT. assertThrows(() => { new ctor(gsab, 1, 1); }, RangeError); assertThrows(() => { new ctor(gsab, 1); }, RangeError); } } // Verify the error messages. assertThrows(() => { new Int16Array(gsab, 1, 1); }, RangeError, /start offset of Int16Array should be a multiple of 2/); assertThrows(() => { new Int16Array(gsab, 38, 2); }, RangeError, /Invalid typed array length: 2/); })(); (function ConstructFromTypedArray() { AllBigIntMatchedCtorCombinations((targetCtor, sourceCtor) => { const gsab = CreateGrowableSharedArrayBuffer( 4 * sourceCtor.BYTES_PER_ELEMENT, 8 * sourceCtor.BYTES_PER_ELEMENT); const fixedLength = new sourceCtor(gsab, 0, 4); const fixedLengthWithOffset = new sourceCtor( gsab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2); const lengthTracking = new sourceCtor(gsab, 0); const lengthTrackingWithOffset = new sourceCtor( gsab, 2 * sourceCtor.BYTES_PER_ELEMENT); // Write some data into the array. const taFull = new sourceCtor(gsab); 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))); // Grow. gsab.grow(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 ConstructFromTypedArraySpeciesConstructorNotCalled() { class MySharedArrayBuffer extends SharedArrayBuffer { constructor(...params) { super(...params); } static get [Symbol.species]() { throw new Error('This should not be called!'); } }; AllBigIntMatchedCtorCombinations((targetCtor, sourceCtor) => { const gsab = new MySharedArrayBuffer( 4 * sourceCtor.BYTES_PER_ELEMENT, {maxByteLength: 8 * sourceCtor.BYTES_PER_ELEMENT}); // Write some data into the array. const taWrite = new sourceCtor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } const fixedLength = new sourceCtor(gsab, 0, 4); assertEquals([0, 2, 4, 6], ToNumbers(new targetCtor(fixedLength))); const fixedLengthWithOffset = new sourceCtor( gsab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2); assertEquals([4, 6], ToNumbers(new targetCtor(fixedLengthWithOffset))); const lengthTracking = new sourceCtor(gsab, 0); assertEquals([0, 2, 4, 6], ToNumbers(new targetCtor(lengthTracking))); const lengthTrackingWithOffset = new sourceCtor( gsab, 2 * sourceCtor.BYTES_PER_ELEMENT); assertEquals([4, 6], ToNumbers(new targetCtor(lengthTrackingWithOffset))); }); })(); (function TypedArrayLengthWhenGrown1() { const gsab = CreateGrowableSharedArrayBuffer(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(gsab, 0, length), length]); } for (let [ta, length] of tas_and_lengths) { assertEquals(length, ta.length); assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength); } gsab.grow(20); for (let [ta, length] of tas_and_lengths) { assertEquals(length, ta.length); assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength); } gsab.grow(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 TypedArrayLengthWhenGrown2() { const gsab = CreateGrowableSharedArrayBuffer(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(gsab, 8, length), length]); } for (let [ta, length] of tas_and_lengths) { assertEquals(length, ta.length); assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength); } gsab.grow(20); for (let [ta, length] of tas_and_lengths) { assertEquals(length, ta.length); assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength); } gsab.grow(40); for (let [ta, length] of tas_and_lengths) { assertEquals(length, ta.length); assertEquals(length * ta.BYTES_PER_ELEMENT, ta.byteLength); } })(); (function LengthTracking1() { const gsab = CreateGrowableSharedArrayBuffer(16, 40); let tas = []; for (let ctor of ctors) { tas.push(new ctor(gsab)); } for (let ta of tas) { assertEquals(16 / ta.BYTES_PER_ELEMENT, ta.length); assertEquals(16, ta.byteLength); } gsab.grow(24); for (let ta of tas) { assertEquals(24 / ta.BYTES_PER_ELEMENT, ta.length); assertEquals(24, ta.byteLength); } // Grow to a number which is not a multiple of all byte_lengths. gsab.grow(26); for (let ta of tas) { const expected_length = Math.floor(26 / ta.BYTES_PER_ELEMENT); assertEquals(expected_length, ta.length); assertEquals(expected_length * ta.BYTES_PER_ELEMENT, ta.byteLength); } gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(16, 40); const offset = 8; let tas = []; for (let ctor of ctors) { tas.push(new ctor(gsab, offset)); } for (let ta of tas) { assertEquals((16 - offset) / ta.BYTES_PER_ELEMENT, ta.length); assertEquals(16 - offset, ta.byteLength); } gsab.grow(24); for (let ta of tas) { assertEquals((24 - offset) / ta.BYTES_PER_ELEMENT, ta.length); assertEquals(24 - offset, ta.byteLength); } // Grow to a number which is not a multiple of all byte_lengths. gsab.grow(26); for (let ta of tas) { const expected_length = Math.floor((26 - offset)/ ta.BYTES_PER_ELEMENT); assertEquals(expected_length, ta.length); assertEquals(expected_length * ta.BYTES_PER_ELEMENT, ta.byteLength); } gsab.grow(40); for (let ta of tas) { assertEquals((40 - offset) / ta.BYTES_PER_ELEMENT, ta.length); assertEquals(40 - offset, ta.byteLength); } })(); (function LoadWithFeedback() { function ReadElement2(ta) { return ta[2]; } %EnsureFeedbackVectorForFunction(ReadElement2); const gsab = CreateGrowableSharedArrayBuffer(16, 40); const i8a = new Int8Array(gsab, 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)); } gsab.grow(20); // Within-bounds read for (let i = 0; i < 3; ++i) { assertEquals(2, ReadElement2(i8a)); } gsab.grow(40); // Within-bounds read for (let i = 0; i < 3; ++i) { assertEquals(2, ReadElement2(i8a)); } })(); (function LoadAndStoreWithFeedback() { function ReadElement(ta, i) { return ta[i]; } function HasElement(ta, i) { return i in ta; } function WriteElement(ta, i, v) { ta[i] = v; } %EnsureFeedbackVectorForFunction(ReadElement); %EnsureFeedbackVectorForFunction(HasElement); %EnsureFeedbackVectorForFunction(WriteElement); const gsab = CreateGrowableSharedArrayBuffer(16, 40); const i8a = new Int8Array(gsab); // length-tracking assertEquals(16, i8a.length); // Within-bounds read for (let i = 0; i < i8a.length; ++i) { assertEquals(0, ReadElement(i8a, i)); assertTrue(HasElement(i8a, i)); } assertFalse(HasElement(i8a, 17)); // Within-bounds write for (let i = 0; i < i8a.length; ++i) { WriteElement(i8a, i, i); } // Within-bounds read for (let i = 0; i < i8a.length; ++i) { assertEquals(i, ReadElement(i8a, i)); } let old_length = i8a.length; gsab.grow(20); assertEquals(20, i8a.length); for (let i = 0; i < i8a.length; ++i) { if (i < old_length) { assertEquals(i, ReadElement(i8a, i)); } else { assertEquals(0, ReadElement(i8a, i)); } assertTrue(HasElement(i8a, i)); } assertFalse(HasElement(i8a, 21)); // Within-bounds write for (let i = 0; i < i8a.length; ++i) { WriteElement(i8a, i, i + 1); } // Within-bounds read for (let i = 0; i < i8a.length; ++i) { assertEquals(i + 1, ReadElement(i8a, i)); } })(); (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 gsab = CreateGrowableSharedArrayBuffer(4, 8); const fixedLength = new Int8Array(gsab, 0, 4); const fixedLengthWithOffset = new Int8Array(gsab, 1, 3); const lengthTracking = new Int8Array(gsab, 0); const lengthTrackingWithOffset = new Int8Array(gsab, 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)); gsab.grow(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 EnumerateElements() { let gsab = CreateGrowableSharedArrayBuffer(100, 200); for (let ctor of ctors) { const ta = new ctor(gsab, 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 GSAB for all the TAs below, since we won't modify it // after writing the initial values. const gsab = CreateGrowableSharedArrayBuffer(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(gsab); for (let i = 0; i < no_elements; ++i) { WriteToTypedArray(ta_write, i, i % 128); } // Create various different styles of TypedArrays with the GSAB as the // backing store and iterate them. const ta = new ctor(gsab, 0, 3); TestIteration(ta, [0, 1, 2]); const empty_ta = new ctor(gsab, 0, 0); TestIteration(empty_ta, []); const ta_with_offset = new ctor(gsab, byte_offset, 3); TestIteration(ta_with_offset, [2, 3, 4]); const empty_ta_with_offset = new ctor(gsab, byte_offset, 0); TestIteration(empty_ta_with_offset, []); const length_tracking_ta = new ctor(gsab); { 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(gsab, 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(gsab, buffer_byte_length); TestIteration(empty_length_tracking_ta_with_offset, []); } }()); // Helpers for iteration tests. function CreateGsab(buffer_byte_length, ctor) { const gsab = CreateGrowableSharedArrayBuffer(buffer_byte_length, 2 * buffer_byte_length); // Write some data into the array. let ta_write = new ctor(gsab); for (let i = 0; i < buffer_byte_length / ctor.BYTES_PER_ELEMENT; ++i) { WriteToTypedArray(ta_write, i, i % 128); } return gsab; } function TestIterationAndGrow(ta, expected, gsab, grow_after, new_byte_length) { let values = []; let grown = 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 (!grown && values.length == grow_after) { gsab.grow(new_byte_length); grown = true; } } assertEquals(expected, values); assertTrue(grown); } (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 gsab as the // backing store and iterate them. // Fixed-length TAs aren't affected by resizing. let gsab = CreateGsab(buffer_byte_length, ctor); const ta = new ctor(gsab, 0, 3); TestIterationAndGrow(ta, [0, 1, 2], gsab, 2, buffer_byte_length * 2); gsab = CreateGsab(buffer_byte_length, ctor); const ta_with_offset = new ctor(gsab, byte_offset, 3); TestIterationAndGrow(ta_with_offset, [2, 3, 4], gsab, 2, buffer_byte_length * 2); gsab = CreateGsab(buffer_byte_length, ctor); const length_tracking_ta = new ctor(gsab); { 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); } TestIterationAndGrow(length_tracking_ta, expected, gsab, 2, buffer_byte_length * 2); } gsab = CreateGsab(buffer_byte_length, ctor); const length_tracking_ta_with_offset = new ctor(gsab, 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); } TestIterationAndGrow(length_tracking_ta_with_offset, expected, gsab, 2, buffer_byte_length * 2); } } }()); (function IterateTypedArrayAndGrowJustBeforeIterationWouldEnd() { const no_elements = 10; const offset = 2; // We need to recreate the gsab 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 gsab as the // backing store and iterate them. let gsab = CreateGsab(buffer_byte_length, ctor); const length_tracking_ta = new ctor(gsab); { 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); } TestIterationAndGrow(length_tracking_ta, expected, gsab, no_elements, buffer_byte_length * 2); } gsab = CreateGsab(buffer_byte_length, ctor); const length_tracking_ta_with_offset = new ctor(gsab, 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); } TestIterationAndGrow(length_tracking_ta_with_offset, expected, gsab, no_elements - offset, buffer_byte_length * 2); } } }()); (function Destructuring() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. let ta_write = new ctor(gsab); 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); } // Grow. The new memory is zeroed. gsab.grow(6 * ctor.BYTES_PER_ELEMENT); { 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, f, g] = lengthTracking; assertEquals([0, 1, 2, 3, 0, 0], ToNumbers([a, b, c, d, e, f])); assertEquals(undefined, g); } { let [a, b, c, d, e] = lengthTrackingWithOffset; assertEquals([2, 3, 0, 0], ToNumbers([a, b, c, d])); assertEquals(undefined, e); } } }()); (function TestFill() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); assertEquals([0, 0, 0, 0], ReadDataFromBuffer(gsab, ctor)); FillHelper(fixedLength, 1); assertEquals([1, 1, 1, 1], ReadDataFromBuffer(gsab, ctor)); FillHelper(fixedLengthWithOffset, 2); assertEquals([1, 1, 2, 2], ReadDataFromBuffer(gsab, ctor)); FillHelper(lengthTracking, 3); assertEquals([3, 3, 3, 3], ReadDataFromBuffer(gsab, ctor)); FillHelper(lengthTrackingWithOffset, 4); assertEquals([3, 3, 4, 4], ReadDataFromBuffer(gsab, ctor)); gsab.grow(6 * ctor.BYTES_PER_ELEMENT); FillHelper(fixedLength, 13); assertEquals([13, 13, 13, 13, 0, 0], ReadDataFromBuffer(gsab, ctor)); FillHelper(fixedLengthWithOffset, 14); assertEquals([13, 13, 14, 14, 0, 0], ReadDataFromBuffer(gsab, ctor)); FillHelper(lengthTracking, 15); assertEquals([15, 15, 15, 15, 15, 15], ReadDataFromBuffer(gsab, ctor)); FillHelper(lengthTrackingWithOffset, 16); assertEquals([15, 15, 16, 16, 16, 16], ReadDataFromBuffer(gsab, ctor)); // Filling with non-undefined start & end. FillHelper(fixedLength, 17, 1, 3); assertEquals([15, 17, 17, 16, 16, 16], ReadDataFromBuffer(gsab, ctor)); FillHelper(fixedLengthWithOffset, 18, 1, 2); assertEquals([15, 17, 17, 18, 16, 16], ReadDataFromBuffer(gsab, ctor)); FillHelper(lengthTracking, 19, 1, 3); assertEquals([15, 19, 19, 18, 16, 16], ReadDataFromBuffer(gsab, ctor)); FillHelper(lengthTrackingWithOffset, 20, 1, 2); assertEquals([15, 19, 19, 20, 16, 16], ReadDataFromBuffer(gsab, ctor)); } })(); (function At() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. let ta_write = new ctor(gsab); 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)); // Grow. New memory is zeroed. gsab.grow(6 * ctor.BYTES_PER_ELEMENT); assertEquals(3, AtHelper(fixedLength, -1)); assertEquals(0, AtHelper(lengthTracking, -1)); assertEquals(3, AtHelper(fixedLengthWithOffset, -1)); assertEquals(0, AtHelper(lengthTrackingWithOffset, -1)); } })(); (function Slice() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, i); } const fixedLengthSlice = fixedLength.slice(); assertEquals([0, 1, 2, 3], ToNumbers(fixedLengthSlice)); assertTrue(fixedLengthSlice.buffer instanceof ArrayBuffer); assertFalse(fixedLengthSlice.buffer instanceof SharedArrayBuffer); assertFalse(fixedLengthSlice.buffer.resizable); const fixedLengthWithOffsetSlice = fixedLengthWithOffset.slice(); assertEquals([2, 3], ToNumbers(fixedLengthWithOffsetSlice)); assertTrue(fixedLengthWithOffsetSlice.buffer instanceof ArrayBuffer); assertFalse(fixedLengthWithOffsetSlice.buffer instanceof SharedArrayBuffer); assertFalse(fixedLengthWithOffsetSlice.buffer.resizable); const lengthTrackingSlice = lengthTracking.slice(); assertEquals([0, 1, 2, 3], ToNumbers(lengthTrackingSlice)); assertTrue(lengthTrackingSlice.buffer instanceof ArrayBuffer); assertFalse(lengthTrackingSlice.buffer instanceof SharedArrayBuffer); assertFalse(lengthTrackingSlice.buffer.resizable); const lengthTrackingWithOffsetSlice = lengthTrackingWithOffset.slice(); assertEquals([2, 3], ToNumbers(lengthTrackingWithOffsetSlice)); assertTrue(lengthTrackingWithOffsetSlice.buffer instanceof ArrayBuffer); assertFalse(lengthTrackingWithOffsetSlice.buffer instanceof SharedArrayBuffer); assertFalse(lengthTrackingWithOffsetSlice.buffer.resizable); gsab.grow(6 * ctor.BYTES_PER_ELEMENT); assertEquals([0, 1, 2, 3], ToNumbers(fixedLength.slice())); assertEquals([2, 3], ToNumbers(fixedLengthWithOffset.slice())); assertEquals([0, 1, 2, 3, 0, 0], ToNumbers(lengthTracking.slice())); assertEquals([2, 3, 0, 0], ToNumbers(lengthTrackingWithOffset.slice())); // Verify that the previously created slices aren't affected by the growing. assertEquals([0, 1, 2, 3], ToNumbers(fixedLengthSlice)); assertEquals([2, 3], ToNumbers(fixedLengthWithOffsetSlice)); assertEquals([0, 1, 2, 3], ToNumbers(lengthTrackingSlice)); assertEquals([2, 3], ToNumbers(lengthTrackingWithOffsetSlice)); } })(); (function SliceSpeciesCreateResizes() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 1); } let resizeWhenConstructorCalled = false; class MyArray extends ctor { constructor(...params) { super(...params); if (resizeWhenConstructorCalled) { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); } } }; const fixedLength = new MyArray(gsab, 0, 4); resizeWhenConstructorCalled = true; const a = fixedLength.slice(); assertEquals(4, a.length); assertEquals([1, 1, 1, 1], ToNumbers(a)); assertEquals(6 * ctor.BYTES_PER_ELEMENT, gsab.byteLength); } for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 1); } let resizeWhenConstructorCalled = false; class MyArray extends ctor { constructor(...params) { super(...params); if (resizeWhenConstructorCalled) { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); } } }; const lengthTracking = new MyArray(gsab); resizeWhenConstructorCalled = true; const a = lengthTracking.slice(); assertEquals(6 * ctor.BYTES_PER_ELEMENT, gsab.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, 1, 1], ToNumbers(a)); } })(); (function CopyWithin() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); gsab.grow(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 CopyWithinParameterConversionGrows() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(lengthTracking, i, i); } const evil = { valueOf: () => { gsab.grow(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)); } })(); (function EntriesKeysValues() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); // Grow. gsab.grow(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 CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } // Iterating with entries() (the 4 loops below). for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); // The fixed length array is not affected by resizing. TestIterationAndGrow(fixedLength.entries(), [[0, 0], [1, 2], [2, 4], [3, 6]], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); // The fixed length array is not affected by resizing. TestIterationAndGrow(fixedLengthWithOffset.entries(), [[0, 4], [1, 6]], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); TestIterationAndGrow(lengthTracking.entries(), [[0, 0], [1, 2], [2, 4], [3, 6], [4, 0], [5, 0]], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); TestIterationAndGrow(lengthTrackingWithOffset.entries(), [[0, 4], [1, 6], [2, 0], [3, 0]], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } // Iterating with keys() (the 4 loops below). for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); // The fixed length array is not affected by resizing. TestIterationAndGrow(fixedLength.keys(), [0, 1, 2, 3], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); // The fixed length array is not affected by resizing. TestIterationAndGrow(fixedLengthWithOffset.keys(), [0, 1], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); TestIterationAndGrow(lengthTracking.keys(), [0, 1, 2, 3, 4, 5], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); TestIterationAndGrow(lengthTrackingWithOffset.keys(), [0, 1, 2, 3], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } // Iterating with values() (the 4 loops below). for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); // The fixed length array is not affected by resizing. TestIterationAndGrow(fixedLength.values(), [0, 2, 4, 6], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); // The fixed length array is not affected by resizing. TestIterationAndGrow(fixedLengthWithOffset.values(), [4, 6], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); TestIterationAndGrow(lengthTracking.values(), [0, 2, 4, 6, 0, 0], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); TestIterationAndGrow(lengthTrackingWithOffset.values(), [4, 6, 0, 0], gsab, 2, 6 * ctor.BYTES_PER_ELEMENT); } })(); (function EverySome() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); // Grow. gsab.grow(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 EveryGrowMidIteration() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [4, 6] << fixedLengthWithOffset // [0, 2, 4, 6, ...] << lengthTracking // [4, 6, ...] << lengthTrackingWithOffset function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return true; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertTrue(fixedLength.every(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertTrue(fixedLengthWithOffset.every(CollectValuesAndGrow)); assertEquals([4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertTrue(lengthTracking.every(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertTrue(lengthTrackingWithOffset.every(CollectValuesAndGrow)); assertEquals([4, 6], 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 CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return false; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertFalse(fixedLength.some(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; gsab = gsab; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertFalse(fixedLengthWithOffset.some(CollectValuesAndGrow)); assertEquals([4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertFalse(lengthTracking.some(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertFalse(lengthTrackingWithOffset.some(CollectValuesAndGrow)); assertEquals([4, 6], values); } })(); (function FindFindIndexFindLastFindLastIndex() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); // Grow. gsab.grow(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 FindGrowMidIteration() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [4, 6] << fixedLengthWithOffset // [0, 2, 4, 6, ...] << lengthTracking // [4, 6, ...] << lengthTrackingWithOffset function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return false; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, fixedLength.find(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, fixedLengthWithOffset.find(CollectValuesAndGrow)); assertEquals([4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, lengthTracking.find(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, lengthTrackingWithOffset.find(CollectValuesAndGrow)); assertEquals([4, 6], 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 CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return false; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, fixedLength.findIndex(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, fixedLengthWithOffset.findIndex(CollectValuesAndGrow)); assertEquals([4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, lengthTracking.findIndex(CollectValuesAndGrow)); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, lengthTrackingWithOffset.findIndex(CollectValuesAndGrow)); assertEquals([4, 6], 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 CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return false; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, fixedLength.findLast(CollectValuesAndGrow)); assertEquals([6, 4, 2, 0], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, fixedLengthWithOffset.findLast(CollectValuesAndGrow)); assertEquals([6, 4], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, lengthTracking.findLast(CollectValuesAndGrow)); assertEquals([6, 4, 2, 0], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(undefined, lengthTrackingWithOffset.findLast(CollectValuesAndGrow)); 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 CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return false; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, fixedLength.findLastIndex(CollectValuesAndGrow)); assertEquals([6, 4, 2, 0], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, fixedLengthWithOffset.findLastIndex(CollectValuesAndGrow)); assertEquals([6, 4], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, lengthTracking.findLastIndex(CollectValuesAndGrow)); assertEquals([6, 4, 2, 0], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals(-1, lengthTrackingWithOffset.findLastIndex(CollectValuesAndGrow)); assertEquals([6, 4], values); } })(); (function Filter() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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))); // Grow. gsab.grow(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 FilterGrowMidIteration() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [4, 6] << fixedLengthWithOffset // [0, 2, 4, 6, ...] << lengthTracking // [4, 6, ...] << lengthTrackingWithOffset function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndGrow(n) { if (n == undefined) { values.push(n); } else { values.push(Number(n)); } if (values.length == growAfter) { gsab.grow(growTo); } return false; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([], ToNumbers(fixedLength.filter(CollectValuesAndGrow))); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([], ToNumbers(fixedLengthWithOffset.filter(CollectValuesAndGrow))); assertEquals([4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); values = []; growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([], ToNumbers(lengthTracking.filter(CollectValuesAndGrow))); assertEquals([0, 2, 4, 6], values); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); values = []; growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([], ToNumbers(lengthTrackingWithOffset.filter(CollectValuesAndGrow))); assertEquals([4, 6], values); } })(); (function ForEachReduceReduceRight() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); // Grow. gsab.grow(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 ForEachReduceReduceRightGrowMidIteration() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [4, 6] << fixedLengthWithOffset // [0, 2, 4, 6, ...] << lengthTracking // [4, 6, ...] << lengthTrackingWithOffset function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndResize(n) { if (typeof n == 'bigint') { values.push(Number(n)); } else { values.push(n); } if (values.length == growAfter) { gsab.grow(growTo); } 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) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([0, 2, 4, 6], ForEachHelper(fixedLength)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([4, 6], ForEachHelper(fixedLengthWithOffset)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([0, 2, 4, 6], ForEachHelper(lengthTracking)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([4, 6], ForEachHelper(lengthTrackingWithOffset)); } // Test for reduce. for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([0, 2, 4, 6], ReduceHelper(fixedLength)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([4, 6], ReduceHelper(fixedLengthWithOffset)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([0, 2, 4, 6], ReduceHelper(lengthTracking)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([4, 6], ReduceHelper(lengthTrackingWithOffset)); } // Test for reduceRight. for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([6, 4, 2, 0], ReduceRightHelper(fixedLength)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([6, 4], ReduceRightHelper(fixedLengthWithOffset)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([6, 4, 2, 0], ReduceRightHelper(lengthTracking)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([6, 4], ReduceRightHelper(lengthTrackingWithOffset)); } })(); (function Includes() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); // Grow. gsab.grow(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 IncludesParameterConversionGrows() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(lengthTracking, i, 1); } let evil = { valueOf: () => { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); WriteToTypedArray(lengthTracking, 0, 1); let evil = { valueOf: () => { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); 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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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)); // Grow. gsab.grow(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 IndexOfParameterConversionGrows() { // Growing + length-tracking TA. for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(lengthTracking, i, 1); } let evil = { valueOf: () => { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); WriteToTypedArray(lengthTracking, 0, 1); let evil = { valueOf: () => { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(lengthTracking, i, 1); } let evil = { valueOf: () => { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); let evil = { valueOf: () => { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); 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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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()); // Grow. gsab.grow(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 JoinParameterConversionGrows() { // Growing + fixed-length TA. for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); let evil = { toString: () => { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); return '.'; }}; assertEquals('0.0.0.0', fixedLength.join(evil)); } // Growing + length-tracking TA. for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); let evil = { toString: () => { gsab.grow(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 ToLocaleStringNumberPrototypeToLocaleStringGrows() { const oldNumberPrototypeToLocaleString = Number.prototype.toLocaleString; const oldBigIntPrototypeToLocaleString = BigInt.prototype.toLocaleString; // Growing + fixed-length TA. for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); let growAfter = 2; Number.prototype.toLocaleString = function() { --growAfter; if (growAfter == 0) { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); } return oldNumberPrototypeToLocaleString.call(this); } BigInt.prototype.toLocaleString = function() { --growAfter; if (growAfter == 0) { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const lengthTracking = new ctor(gsab); let growAfter = 2; Number.prototype.toLocaleString = function() { --growAfter; if (growAfter == 0) { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); } return oldNumberPrototypeToLocaleString.call(this); } BigInt.prototype.toLocaleString = function() { --growAfter; if (growAfter == 0) { gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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 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)); // Grow. gsab.grow(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 MapGrowMidIteration() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [4, 6] << fixedLengthWithOffset // [0, 2, 4, 6, ...] << lengthTracking // [4, 6, ...] << lengthTrackingWithOffset function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let values; let gsab; let growAfter; let growTo; function CollectValuesAndResize(n) { if (typeof n == 'bigint') { values.push(Number(n)); } else { values.push(n); } if (values.length == growAfter) { gsab.grow(growTo); } return n; } function Helper(array) { values = []; array.map(CollectValuesAndResize); return values; } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([0, 2, 4, 6], Helper(fixedLength)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([4, 6], Helper(fixedLengthWithOffset)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); growAfter = 2; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([0, 2, 4, 6], Helper(lengthTracking)); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); growAfter = 1; growTo = 5 * ctor.BYTES_PER_ELEMENT; assertEquals([4, 6], Helper(lengthTrackingWithOffset)); } })(); (function MapSpeciesCreateGrows() { let values; let gsab; 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) { gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, i); } let resizeWhenConstructorCalled = false; class MyArray extends ctor { constructor(...params) { super(...params); if (resizeWhenConstructorCalled) { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); } } }; const fixedLength = new MyArray(gsab, 0, 4); resizeWhenConstructorCalled = true; assertEquals([0, 1, 2, 3], Helper(fixedLength)); assertEquals(6 * ctor.BYTES_PER_ELEMENT, gsab.byteLength); } for (let ctor of ctors) { gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, i); } let resizeWhenConstructorCalled = false; class MyArray extends ctor { constructor(...params) { super(...params); if (resizeWhenConstructorCalled) { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); } } }; const lengthTracking = new MyArray(gsab); resizeWhenConstructorCalled = true; assertEquals([0, 1, 2, 3], Helper(lengthTracking)); assertEquals(6 * ctor.BYTES_PER_ELEMENT, gsab.byteLength); } })(); (function Reverse() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); const wholeArrayView = new ctor(gsab); 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)); // Grow. gsab.grow(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 SetWithGrowableTarget() { for (let ctor of ctors) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taFull = new ctor(gsab); // Orig. array: [0, 0, 0, 0] // [0, 0, 0, 0] << fixedLength // [0, 0] << fixedLengthWithOffset // [0, 0, 0, 0, ...] << lengthTracking // [0, 0, ...] << lengthTrackingWithOffset 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])}, RangeError); assertThrows(() => { SetHelper(lengthTrackingWithOffset, [0, 0], 1)}, RangeError); assertEquals([8, 10, 12, 14], ToNumbers(taFull)); // Grow. gsab.grow(6 * ctor.BYTES_PER_ELEMENT); // Orig. array: [8, 10, 12, 14, 0, 0] // [8, 10, 12, 14] << fixedLength // [12, 14] << fixedLengthWithOffset // [8, 10, 12, 14, 0, 0, ...] << lengthTracking // [12, 14, 0, 0, ...] << lengthTrackingWithOffset SetHelper(fixedLength, [21, 22]); assertEquals([21, 22, 12, 14, 0, 0], ToNumbers(taFull)); SetHelper(fixedLength, [23, 24], 1); assertEquals([21, 23, 24, 14, 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, 14, 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 SetSourceLengthGetterGrowsTarget() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [4, 6] << fixedLengthWithOffset // [0, 2, 4, 6, ...] << lengthTracking // [4, 6, ...] << lengthTrackingWithOffset function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let gsab; let growTo; function CreateSourceProxy(length) { return new Proxy({}, { get(target, prop, receiver) { if (prop == 'length') { gsab.grow(growTo); 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) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); growTo = 6 * ctor.BYTES_PER_ELEMENT; assertThrows(() => { lengthTracking.set(CreateSourceProxy(6)); }, RangeError); assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(gsab))); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); growTo = 6 * ctor.BYTES_PER_ELEMENT; assertThrows(() => { lengthTrackingWithOffset.set(CreateSourceProxy(6)); }, RangeError); assertEquals([0, 2, 4, 6, 0, 0], ToNumbers(new ctor(gsab))); } })(); (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 CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } let gsab; // Growing will happen when we're calling Get for the `growAt`:th data // element, but we haven't yet written it to the target. let growAt; let growTo; function CreateSourceProxy(length) { let requestedIndices = []; return new Proxy({}, { get(target, prop, receiver) { if (prop == 'length') { return length; } requestedIndices.push(prop); if (requestedIndices.length == growAt) { gsab.grow(growTo); } return true; // Can be converted to both BigInt and Number. } }); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); growAt = 2; growTo = 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(gsab))); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); growAt = 1; growTo = 6 * ctor.BYTES_PER_ELEMENT; fixedLengthWithOffset.set(CreateSourceProxy(2)); assertEquals([1, 1], ToNumbers(fixedLengthWithOffset)); assertEquals([0, 2, 1, 1, 0, 0], ToNumbers(new ctor(gsab))); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); growAt = 2; growTo = 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(gsab))); } for (let ctor of ctors) { gsab = CreateGsabForTest(ctor); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); growAt = 1; growTo = 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(gsab))); } })(); (function SetWithGrowableSource() { for (let targetIsGrowable of [false, true]) { for (let targetCtor of ctors) { for (let sourceCtor of ctors) { const gsab = CreateGrowableSharedArrayBuffer( 4 * sourceCtor.BYTES_PER_ELEMENT, 8 * sourceCtor.BYTES_PER_ELEMENT); const fixedLength = new sourceCtor(gsab, 0, 4); const fixedLengthWithOffset = new sourceCtor( gsab, 2 * sourceCtor.BYTES_PER_ELEMENT, 2); const lengthTracking = new sourceCtor(gsab, 0); const lengthTrackingWithOffset = new sourceCtor( gsab, 2 * sourceCtor.BYTES_PER_ELEMENT); // Write some data into the array. const taFull = new sourceCtor(gsab); 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 = targetIsGrowable ? 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)); // Grow. gsab.grow(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 gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); const fixedLength = new ctor(gsab, 0, 4); const fixedLengthWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT, 2); const lengthTracking = new ctor(gsab, 0); const lengthTrackingWithOffset = new ctor(gsab, 2 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); 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))); // Grow. gsab.grow(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))); 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 SubarrayParameterConversionGrows() { // Orig. array: [0, 2, 4, 6] // [0, 2, 4, 6] << fixedLength // [0, 2, 4, 6, ...] << lengthTracking function CreateGsabForTest(ctor) { const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT); // Write some data into the array. const taWrite = new ctor(gsab); for (let i = 0; i < 4; ++i) { WriteToTypedArray(taWrite, i, 2 * i); } return gsab; } // Growing + fixed-length TA. Growing won't affect anything. for (let ctor of ctors) { const gsab = CreateGsabForTest(ctor); const fixedLength = new ctor(gsab, 0, 4); const evil = { valueOf: () => { gsab.grow(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 gsab = CreateGsabForTest(ctor); const lengthTracking = new ctor(gsab, 0); const evil = { valueOf: () => { gsab.grow(6 * ctor.BYTES_PER_ELEMENT); return 0;}}; assertEquals([0, 2, 4, 6], ToNumbers(lengthTracking.subarray(evil))); } })();