Commit a863c4d3 authored by dehrenberg's avatar dehrenberg Committed by Commit bot

TypedArray.prototype.copyWithin method

This patch adds the copyWithin method to TypedArrays. For the first
pass, the internals of Array.copyWithin are used. Eventually, a more
efficient form based on memcpy could be used instead.

BUG=v8:3578
LOG=Y
R=adamk@chromium.org, arv@chromium.org, caitpotter88@gmail.com

Review URL: https://codereview.chromium.org/1131113002

Cr-Commit-Position: refs/heads/master@{#28381}
parent 0b620ad5
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var $innerArrayCopyWithin;
(function(global, exports) {
'use strict';
......@@ -13,13 +15,7 @@ var GlobalSymbol = global.Symbol;
// -------------------------------------------------------------------
// ES6 draft 03-17-15, section 22.1.3.3
function ArrayCopyWithin(target, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
var array = TO_OBJECT_INLINE(this);
var length = $toLength(array.length);
function InnerArrayCopyWithin(target, start, end, array, length) {
target = TO_INTEGER(target);
var to;
if (target < 0) {
......@@ -65,6 +61,17 @@ function ArrayCopyWithin(target, start, end) {
return array;
}
$innerArrayCopyWithin = InnerArrayCopyWithin;
// ES6 draft 03-17-15, section 22.1.3.3
function ArrayCopyWithin(target, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
var array = TO_OBJECT_INLINE(this);
var length = $toLength(array.length);
return InnerArrayCopyWithin(target, start, end, array, length);
}
// ES6 draft 07-15-13, section 15.4.3.23
function ArrayFind(predicate /* thisArg */) { // length == 1
......
......@@ -29,6 +29,16 @@ TYPED_ARRAYS(DECLARE_GLOBALS)
// -------------------------------------------------------------------
function TypedArrayCopyWithin(target, start, end) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
// TODO(dehrenberg): Replace with a memcpy for better performance
return $innerArrayCopyWithin(target, start, end, this, length);
}
%FunctionSetLength(TypedArrayCopyWithin, 2);
// ES6 draft 05-05-15, section 22.2.3.7
function TypedArrayEvery(f, receiver) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
......@@ -67,6 +77,7 @@ macro EXTEND_TYPED_ARRAY(NAME)
// Set up non-enumerable functions on the prototype object.
$installFunctions(GlobalNAME.prototype, DONT_ENUM, [
"copyWithin", TypedArrayCopyWithin,
"every", TypedArrayEvery,
"forEach", TypedArrayForEach
]);
......
// Copyright 2015 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-arrays
var typedArrayConstructors = [
Uint8Array,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
Uint8ClampedArray,
Float32Array,
Float64Array];
function CheckEachTypedArray(fn) {
typedArrayConstructors.forEach(fn);
}
CheckEachTypedArray(function copyWithinArity(constructor) {
assertEquals(new constructor([]).copyWithin.length, 2);
});
CheckEachTypedArray(function copyWithinTargetAndStart(constructor) {
// works with two arguments
assertArrayEquals([4, 5, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, 3));
assertArrayEquals([1, 4, 5, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(1, 3));
assertArrayEquals([1, 3, 4, 5, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(1, 2));
assertArrayEquals([1, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(2, 2));
});
CheckEachTypedArray(function copyWithinTargetStartAndEnd(constructor) {
// works with three arguments
assertArrayEquals(new constructor([1, 2, 3, 4, 5]).copyWithin(0, 3, 4),
[4, 2, 3, 4, 5]);
assertArrayEquals(new constructor([1, 2, 3, 4, 5]).copyWithin(1, 3, 4),
[1, 4, 3, 4, 5]);
assertArrayEquals(new constructor([1, 2, 3, 4, 5]).copyWithin(1, 2, 4),
[1, 3, 4, 4, 5]);
});
CheckEachTypedArray(function copyWithinNegativeRelativeOffsets(constructor) {
// works with negative arguments
assertArrayEquals([4, 5, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, -2));
assertArrayEquals([4, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, -2, -1));
assertArrayEquals([1, 3, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(-4, -3, -2));
assertArrayEquals([1, 3, 4, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(-4, -3, -1));
assertArrayEquals([1, 3, 4, 5, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(-4, -3));
// test with arguments equal to -this.length
assertArrayEquals([1, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(-5, 0));
});
CheckEachTypedArray(function mustBeTypedArray(constructor) {
// throws on non-TypedArray values
assertThrows(function() {
return constructor.prototype.copyWithin.call(null, 0, 3);
}, TypeError);
assertThrows(function() {
return constructor.prototype.copyWithin.call(undefined, 0, 3);
}, TypeError);
assertThrows(function() {
return constructor.prototype.copyWithin.call(34, 0, 3);
}, TypeError);
assertThrows(function() {
return constructor.prototype.copyWithin.call([1, 2, 3, 4, 5], 0, 3);
}, TypeError);
});
CheckEachTypedArray(function copyWithinStartLessThanTarget(constructor) {
// test with target > start on 2 arguments
assertArrayEquals([1, 2, 3, 1, 2],
new constructor([1, 2, 3, 4, 5]).copyWithin(3, 0));
// test with target > start on 3 arguments
assertArrayEquals([1, 2, 3, 1, 2],
new constructor([1, 2, 3, 4, 5]).copyWithin(3, 0, 4));
});
CheckEachTypedArray(function copyWithinNonIntegerRelativeOffsets(constructor) {
// test on fractional arguments
assertArrayEquals([4, 5, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0.2, 3.9));
});
CheckEachTypedArray(function copyWithinNegativeZeroTarget(constructor) {
// test with -0
assertArrayEquals([4, 5, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(-0, 3));
});
CheckEachTypedArray(function copyWithinTargetOutsideStart(constructor) {
// test with arguments more than this.length
assertArrayEquals([1, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, 7));
// test with arguments less than -this.length
assertArrayEquals([1, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(-7, 0));
});
CheckEachTypedArray(function copyWithinEmptyArray(constructor) {
// test on empty array
assertArrayEquals([], new constructor([]).copyWithin(0, 3));
});
CheckEachTypedArray(function copyWithinTargetCutOff(constructor) {
// test with target range being shorter than end - start
assertArrayEquals([1, 2, 2, 3, 4], [1, 2, 3, 4, 5].copyWithin(2, 1, 4));
});
CheckEachTypedArray(function copyWithinOverlappingRanges(constructor) {
// test overlapping ranges
var arr = [1, 2, 3, 4, 5];
arr.copyWithin(2, 1, 4);
assertArrayEquals([1, 2, 2, 2, 3], arr.copyWithin(2, 1, 4));
});
CheckEachTypedArray(function copyWithinDefaultEnd(constructor) {
// undefined as third argument
assertArrayEquals([4, 5, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, 3, undefined));
});
CheckEachTypedArray(function copyWithinLargeArray(constructor) {
var large = 10000;
// test on a large array
var arr = new constructor(large);
assertArrayEquals(arr, arr.copyWithin(45, 9000));
var expected = new Array(large);
// test on numbers
for (var i = 0; i < large; i++) {
arr[i] = Math.random() * 100; // May be cast to an int
expected[i] = arr[i];
if (i >= 9000) {
expected[(i - 9000) + 45] = arr[i];
}
}
assertArrayEquals(expected, arr.copyWithin(45, 9000));
// test array length remains same
assertEquals(large, arr.length);
});
CheckEachTypedArray(function copyWithinNullEnd(constructor) {
// test null on third argument is converted to +0
assertArrayEquals([1, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, 3, null));
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment