From b57428e9efe2b07656e5d78fbcfb2d4ba62bb86b Mon Sep 17 00:00:00 2001 From: dehrenberg Date: Tue, 12 May 2015 21:32:12 -0700 Subject: [PATCH] Implement %TypedArray%.{fill,find,findIndex} This patch adds three methods to TypedArrays which are already implemented for arrays. The implementations are made by calling out to the underlying code used by Arrays. R=adamk@chromium.org BUG=v8:3578 LOG=Y Review URL: https://codereview.chromium.org/1136663005 Cr-Commit-Position: refs/heads/master@{#28382} --- src/harmony-array.js | 73 +++++------ src/harmony-typedarray.js | 36 +++++- test/mjsunit/harmony/typedarray-fill.js | 39 ++++++ test/mjsunit/harmony/typedarray-find.js | 179 +++++++++++++++++++++++++++ test/mjsunit/harmony/typedarray-findindex.js | 179 +++++++++++++++++++++++++++ 5 files changed, 469 insertions(+), 37 deletions(-) create mode 100644 test/mjsunit/harmony/typedarray-fill.js create mode 100644 test/mjsunit/harmony/typedarray-find.js create mode 100644 test/mjsunit/harmony/typedarray-findindex.js diff --git a/src/harmony-array.js b/src/harmony-array.js index acf1b14..c0de2b9 100644 --- a/src/harmony-array.js +++ b/src/harmony-array.js @@ -3,6 +3,9 @@ // found in the LICENSE file. var $innerArrayCopyWithin; +var $innerArrayFill; +var $innerArrayFind; +var $innerArrayFindIndex; (function(global, exports) { @@ -73,22 +76,11 @@ function ArrayCopyWithin(target, start, end) { return InnerArrayCopyWithin(target, start, end, array, length); } -// ES6 draft 07-15-13, section 15.4.3.23 -function ArrayFind(predicate /* thisArg */) { // length == 1 - CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find"); - - var array = $toObject(this); - var length = $toInteger(array.length); - +function InnerArrayFind(predicate, thisArg, array, length) { if (!IS_SPEC_FUNCTION(predicate)) { throw MakeTypeError(kCalledNonCallable, predicate); } - var thisArg; - if (%_ArgumentsLength() > 1) { - thisArg = %_Arguments(1); - } - var needs_wrapper = false; if (IS_NULL(thisArg)) { if (%IsSloppyModeFunction(predicate)) thisArg = UNDEFINED; @@ -108,24 +100,23 @@ function ArrayFind(predicate /* thisArg */) { // length == 1 return; } +$innerArrayFind = InnerArrayFind; - -// ES6 draft 07-15-13, section 15.4.3.24 -function ArrayFindIndex(predicate /* thisArg */) { // length == 1 - CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex"); +// ES6 draft 07-15-13, section 15.4.3.23 +function ArrayFind(predicate, thisArg) { + CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find"); var array = $toObject(this); var length = $toInteger(array.length); + return InnerArrayFind(predicate, thisArg, array, length); +} + +function InnerArrayFindIndex(predicate, thisArg, array, length) { if (!IS_SPEC_FUNCTION(predicate)) { throw MakeTypeError(kCalledNonCallable, predicate); } - var thisArg; - if (%_ArgumentsLength() > 1) { - thisArg = %_Arguments(1); - } - var needs_wrapper = false; if (IS_NULL(thisArg)) { if (%IsSloppyModeFunction(predicate)) thisArg = UNDEFINED; @@ -145,26 +136,22 @@ function ArrayFindIndex(predicate /* thisArg */) { // length == 1 return -1; } +$innerArrayFindIndex = InnerArrayFindIndex; - -// ES6, draft 04-05-14, section 22.1.3.6 -function ArrayFill(value /* [, start [, end ] ] */) { // length == 1 - CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill"); +// ES6 draft 07-15-13, section 15.4.3.24 +function ArrayFindIndex(predicate, thisArg) { + CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex"); var array = $toObject(this); - var length = TO_UINT32(array.length); + var length = $toInteger(array.length); - var i = 0; - var end = length; + return InnerArrayFindIndex(predicate, thisArg, array, length); +} - if (%_ArgumentsLength() > 1) { - i = %_Arguments(1); - i = IS_UNDEFINED(i) ? 0 : TO_INTEGER(i); - if (%_ArgumentsLength() > 2) { - end = %_Arguments(2); - end = IS_UNDEFINED(end) ? length : TO_INTEGER(end); - } - } +// ES6, draft 04-05-14, section 22.1.3.6 +function InnerArrayFill(value, start, end, array, length) { + var i = IS_UNDEFINED(start) ? 0 : TO_INTEGER(start); + var end = IS_UNDEFINED(end) ? length : TO_INTEGER(end); if (i < 0) { i += length; @@ -188,6 +175,17 @@ function ArrayFill(value /* [, start [, end ] ] */) { // length == 1 array[i] = value; return array; } +$innerArrayFill = InnerArrayFill; + +// ES6, draft 04-05-14, section 22.1.3.6 +function ArrayFill(value, start, end) { + CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill"); + + var array = $toObject(this); + var length = TO_UINT32(array.length); + + return InnerArrayFill(value, start, end, array, length); +} // ES6, draft 10-14-14, section 22.1.2.1 function ArrayFrom(arrayLike, mapfn, receiver) { @@ -279,6 +277,9 @@ $installConstants(GlobalSymbol, [ %FunctionSetLength(ArrayCopyWithin, 2); %FunctionSetLength(ArrayFrom, 1); +%FunctionSetLength(ArrayFill, 1); +%FunctionSetLength(ArrayFind, 1); +%FunctionSetLength(ArrayFindIndex, 1); // Set up non-enumerable functions on the Array object. $installFunctions(GlobalArray, DONT_ENUM, [ diff --git a/src/harmony-typedarray.js b/src/harmony-typedarray.js index c33e08b..3c4c4a4 100644 --- a/src/harmony-typedarray.js +++ b/src/harmony-typedarray.js @@ -59,6 +59,37 @@ function TypedArrayForEach(f, receiver) { } %FunctionSetLength(TypedArrayForEach, 1); +// ES6 draft 04-05-14 section 22.2.3.8 +function TypedArrayFill(value, start , end) { + if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + + var length = %_TypedArrayGetLength(this); + + return $innerArrayFill(value, start, end, this, length); +} +%FunctionSetLength(TypedArrayFill, 1); + +// ES6 draft 07-15-13, section 22.2.3.10 +function TypedArrayFind(predicate, thisArg) { + if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + + var length = %_TypedArrayGetLength(this); + + return $innerArrayFind(predicate, thisArg, this, length); +} +%FunctionSetLength(TypedArrayFind, 1); + +// ES6 draft 07-15-13, section 22.2.3.11 +function TypedArrayFindIndex(predicate, thisArg) { + if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + + var length = %_TypedArrayGetLength(this); + + return $innerArrayFindIndex(predicate, thisArg, this, length); +} +%FunctionSetLength(TypedArrayFindIndex, 1); + + // ES6 draft 08-24-14, section 22.2.2.2 function TypedArrayOf() { var length = %_ArgumentsLength(); @@ -79,7 +110,10 @@ macro EXTEND_TYPED_ARRAY(NAME) $installFunctions(GlobalNAME.prototype, DONT_ENUM, [ "copyWithin", TypedArrayCopyWithin, "every", TypedArrayEvery, - "forEach", TypedArrayForEach + "forEach", TypedArrayForEach, + "find", TypedArrayFind, + "findIndex", TypedArrayFindIndex, + "fill", TypedArrayFill ]); endmacro diff --git a/test/mjsunit/harmony/typedarray-fill.js b/test/mjsunit/harmony/typedarray-fill.js new file mode 100644 index 0000000..40605bb --- /dev/null +++ b/test/mjsunit/harmony/typedarray-fill.js @@ -0,0 +1,39 @@ +// 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]; + +for (var constructor of typedArrayConstructors) { + assertEquals(1, constructor.prototype.fill.length); + + assertArrayEquals(new constructor([]).fill(8), []); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8), [8, 8, 8, 8, 8]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1), [0, 8, 8, 8, 8]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 10), [0, 0, 0, 0, 0]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -5), [8, 8, 8, 8, 8]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1, 4), [0, 8, 8, 8, 0]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1, -1), [0, 8, 8, 8, 0]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1, 42), [0, 8, 8, 8, 8]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -3, 42), [0, 0, 8, 8, 8]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -3, 4), [0, 0, 8, 8, 0]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -2, -1), [0, 0, 0, 8, 0]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -1, -3), [0, 0, 0, 0, 0]); + assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 0, 4), [8, 8, 8, 8, 0]); + + // Test exceptions + assertThrows('constructor.prototype.fill.call(null)', TypeError); + assertThrows('constructor.prototype.fill.call(undefined)', TypeError); + assertThrows('constructor.prototype.fill.call([])', TypeError); +} diff --git a/test/mjsunit/harmony/typedarray-find.js b/test/mjsunit/harmony/typedarray-find.js new file mode 100644 index 0000000..5e35125 --- /dev/null +++ b/test/mjsunit/harmony/typedarray-find.js @@ -0,0 +1,179 @@ +// 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]; + +for (var constructor of typedArrayConstructors) { + +assertEquals(1, constructor.prototype.find.length); + +var a = new constructor([21, 22, 23, 24]); +assertEquals(undefined, a.find(function() { return false; })); +assertEquals(21, a.find(function() { return true; })); +assertEquals(undefined, a.find(function(val) { return 121 === val; })); +assertEquals(24, a.find(function(val) { return 24 === val; })); +assertEquals(23, a.find(function(val) { return 23 === val; }), null); +assertEquals(22, a.find(function(val) { return 22 === val; }), undefined); + + +// +// Test predicate is not called when array is empty +// +(function() { + var a = new constructor([]); + var l = -1; + var o = -1; + var v = -1; + var k = -1; + + a.find(function(val, key, obj) { + o = obj; + l = obj.length; + v = val; + k = key; + + return false; + }); + + assertEquals(-1, l); + assertEquals(-1, o); + assertEquals(-1, v); + assertEquals(-1, k); +})(); + + +// +// Test predicate is called with correct arguments +// +(function() { + var a = new constructor([5]); + var l = -1; + var o = -1; + var v = -1; + var k = -1; + + var found = a.find(function(val, key, obj) { + o = obj; + l = obj.length; + v = val; + k = key; + + return false; + }); + + assertArrayEquals(a, o); + assertEquals(a.length, l); + assertEquals(5, v); + assertEquals(0, k); + assertEquals(undefined, found); +})(); + + +// +// Test predicate is called array.length times +// +(function() { + var a = new constructor([1, 2, 3, 4, 5]); + var l = 0; + var found = a.find(function() { + l++; + return false; + }); + + assertEquals(a.length, l); + assertEquals(undefined, found); +})(); + + +// +// Test array modifications +// +(function() { + a = new constructor([1, 2, 3]); + found = a.find(function(val, key) { a[key] = ++val; return false; }); + assertArrayEquals([2, 3, 4], a); + assertEquals(3, a.length); + assertEquals(undefined, found); +})(); + +// +// Test thisArg +// +(function() { + // Test String as a thisArg + var found = new constructor([1, 2, 3]).find(function(val, key) { + return this.charAt(Number(key)) === String(val); + }, "321"); + assertEquals(2, found); + + // Test object as a thisArg + var thisArg = { + elementAt: function(key) { + return this[key]; + } + }; + Array.prototype.push.apply(thisArg, [3, 2, 1]); + + found = new constructor([1, 2, 3]).find(function(val, key) { + return this.elementAt(key) === val; + }, thisArg); + assertEquals(2, found); + + // Create a new object in each function call when receiver is a + // primitive value. See ECMA-262, Annex C. + a = []; + new constructor([1, 2]).find(function() { a.push(this) }, ""); + assertTrue(a[0] !== a[1]); + + // Do not create a new object otherwise. + a = []; + new constructor([1, 2]).find(function() { a.push(this) }, {}); + assertEquals(a[0], a[1]); + + // In strict mode primitive values should not be coerced to an object. + a = []; + new constructor([1, 2]).find(function() { 'use strict'; a.push(this); }, ""); + assertEquals("", a[0]); + assertEquals(a[0], a[1]); + +})(); + +// Test exceptions +assertThrows('constructor.prototype.find.call(null, function() { })', + TypeError); +assertThrows('constructor.prototype.find.call(undefined, function() { })', + TypeError); +assertThrows('constructor.prototype.find.apply(null, function() { }, [])', + TypeError); +assertThrows('constructor.prototype.find.apply(undefined, function() { }, [])', + TypeError); +assertThrows('constructor.prototype.find.apply([], function() { }, [])', + TypeError); +assertThrows('constructor.prototype.find.apply({}, function() { }, [])', + TypeError); +assertThrows('constructor.prototype.find.apply("", function() { }, [])', + TypeError); + +assertThrows('new constructor([]).find(null)', TypeError); +assertThrows('new constructor([]).find(undefined)', TypeError); +assertThrows('new constructor([]).find(0)', TypeError); +assertThrows('new constructor([]).find(true)', TypeError); +assertThrows('new constructor([]).find(false)', TypeError); +assertThrows('new constructor([]).find("")', TypeError); +assertThrows('new constructor([]).find({})', TypeError); +assertThrows('new constructor([]).find([])', TypeError); +assertThrows('new constructor([]).find(/\d+/)', TypeError); + +} diff --git a/test/mjsunit/harmony/typedarray-findindex.js b/test/mjsunit/harmony/typedarray-findindex.js new file mode 100644 index 0000000..5a0afb4 --- /dev/null +++ b/test/mjsunit/harmony/typedarray-findindex.js @@ -0,0 +1,179 @@ +// Copyright 2014 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]; + +for (var constructor of typedArrayConstructors) { + +assertEquals(1, constructor.prototype.findIndex.length); + +var a = new constructor([21, 22, 23, 24]); +assertEquals(-1, a.findIndex(function() { return false; })); +assertEquals(-1, a.findIndex(function(val) { return 121 === val; })); +assertEquals(0, a.findIndex(function() { return true; })); +assertEquals(1, a.findIndex(function(val) { return 22 === val; }), undefined); +assertEquals(2, a.findIndex(function(val) { return 23 === val; }), null); +assertEquals(3, a.findIndex(function(val) { return 24 === val; })); + + +// +// Test predicate is not called when array is empty +// +(function() { + var a = new constructor([]); + var l = -1; + var o = -1; + var v = -1; + var k = -1; + + a.findIndex(function(val, key, obj) { + o = obj; + l = obj.length; + v = val; + k = key; + + return false; + }); + + assertEquals(-1, l); + assertEquals(-1, o); + assertEquals(-1, v); + assertEquals(-1, k); +})(); + + +// +// Test predicate is called with correct argumetns +// +(function() { + var a = new constructor([5]); + var l = -1; + var o = -1; + var v = -1; + var k = -1; + + var index = a.findIndex(function(val, key, obj) { + o = obj; + l = obj.length; + v = val; + k = key; + + return false; + }); + + assertArrayEquals(a, o); + assertEquals(a.length, l); + assertEquals(5, v); + assertEquals(0, k); + assertEquals(-1, index); +})(); + + +// +// Test predicate is called array.length times +// +(function() { + var a = new constructor([1, 2, 3, 4, 5]); + var l = 0; + + a.findIndex(function() { + l++; + return false; + }); + + assertEquals(a.length, l); +})(); + + +// +// Test array modifications +// +(function() { + a = new constructor([1, 2, 3]); + a.findIndex(function(val, key) { a[key] = ++val; return false; }); + assertArrayEquals([2, 3, 4], a); + assertEquals(3, a.length); +})(); + + +// +// Test thisArg +// +(function() { + // Test String as a thisArg + var index = new constructor([1, 2, 3]).findIndex(function(val, key) { + return this.charAt(Number(key)) === String(val); + }, "321"); + assertEquals(1, index); + + // Test object as a thisArg + var thisArg = { + elementAt: function(key) { + return this[key]; + } + }; + Array.prototype.push.apply(thisArg, [3, 2, 1]); + + index = new constructor([1, 2, 3]).findIndex(function(val, key) { + return this.elementAt(key) === val; + }, thisArg); + assertEquals(1, index); + + // Create a new object in each function call when receiver is a + // primitive value. See ECMA-262, Annex C. + a = []; + new constructor([1, 2]).findIndex(function() { a.push(this) }, ""); + assertTrue(a[0] !== a[1]); + + // Do not create a new object otherwise. + a = []; + new constructor([1, 2]).findIndex(function() { a.push(this) }, {}); + assertEquals(a[0], a[1]); + + // In strict mode primitive values should not be coerced to an object. + a = []; + new constructor([1, 2]).findIndex(function() { 'use strict'; a.push(this); }, ""); + assertEquals("", a[0]); + assertEquals(a[0], a[1]); + +})(); + +// Test exceptions +assertThrows('constructor.prototype.findIndex.call(null, function() { })', + TypeError); +assertThrows('constructor.prototype.findIndex.call(undefined, function() { })', + TypeError); +assertThrows('constructor.prototype.findIndex.apply(null, function() { }, [])', + TypeError); +assertThrows('constructor.prototype.findIndex.apply(undefined, function() { }, [])', + TypeError); +assertThrows('constructor.prototype.findIndex.apply([], function() { }, [])', + TypeError); +assertThrows('constructor.prototype.findIndex.apply({}, function() { }, [])', + TypeError); +assertThrows('constructor.prototype.findIndex.apply("", function() { }, [])', + TypeError); + +assertThrows('new constructor([]).findIndex(null)', TypeError); +assertThrows('new constructor([]).findIndex(undefined)', TypeError); +assertThrows('new constructor([]).findIndex(0)', TypeError); +assertThrows('new constructor([]).findIndex(true)', TypeError); +assertThrows('new constructor([]).findIndex(false)', TypeError); +assertThrows('new constructor([]).findIndex("")', TypeError); +assertThrows('new constructor([]).findIndex({})', TypeError); +assertThrows('new constructor([]).findIndex([])', TypeError); +assertThrows('new constructor([]).findIndex(/\d+/)', TypeError); + +} -- 2.7.4