Bug 1111869 - Implement %TypedArray%.prototype.includes. r=till

This commit is contained in:
ziyunfei 2014-12-24 07:34:00 -05:00
parent d23a9bd047
commit 8dc8822499
8 changed files with 150 additions and 41 deletions

View File

@ -582,7 +582,7 @@ function ArrayFill(value, start = 0, end = undefined) {
}
// Proposed for ES7:
// https://github.com/domenic/Array.prototype.includes/blob/master/spec.md
// https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
function ArrayIncludes(searchElement, fromIndex = 0) {
// Steps 1-2.
var O = ToObject(this);

View File

@ -235,3 +235,53 @@ function TypedArrayReverse() {
// Step 9.
return O;
}
// Proposed for ES7:
// https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
function TypedArrayIncludes(searchElement, fromIndex = 0) {
// This function is not generic.
if (!IsObject(this) || !IsTypedArray(this)) {
return callFunction(CallTypedArrayMethodIfWrapped, this, searchElement,
fromIndex, "TypedArrayIncludes");
}
// Steps 1-2.
var O = this;
// Steps 3-4.
var len = TypedArrayLength(O);
// Step 5.
if (len === 0)
return false;
// Steps 6-7.
var n = ToInteger(fromIndex);
var k;
// Step 8.
if (n >= 0) {
k = n;
}
// Step 9.
else {
// Step a.
k = len + n;
// Step b.
if (k < 0)
k = 0;
}
// Step 10.
while (k < len) {
// Steps a-c.
if (SameValueZero(searchElement, O[k]))
return true;
// Step d.
k++;
}
// Step 11.
return false;
}

View File

@ -53,14 +53,14 @@ for (var constructor of constructors) {
}
// Throws if `this` isn't a TypedArray.
var nonTypedArrays = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
/* new Proxy(new constructor(), {}) // This probably should throw */
];
nonTypedArrays.forEach(nonTypedArray => {
assertThrowsInstanceOf(function() {
constructor.prototype.fill.call(nonTypedArray, 1);
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./]
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.fill.call(invalidReceiver, 1);
}, TypeError);
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.fill.call(new Proxy(new constructor(), {}));
// Test that the length getter is never called.
Object.defineProperty(new constructor([1, 2, 3]), "length", {

View File

@ -0,0 +1,56 @@
const constructors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];
for (var constructor of constructors) {
if (!("includes" in constructor.prototype))
break;
assertEq(constructor.prototype.includes.length, 1);
assertEq(new constructor([1, 2, 3]).includes(1), true);
assertEq(new constructor([1, 2, 3]).includes(2), true);
assertEq(new constructor([1, 2, 3]).includes(3), true);
assertEq(new constructor([1, 2, 3]).includes(2, 1), true);
assertEq(new constructor([1, 2, 3]).includes(2, -2), true);
assertEq(new constructor([1, 2, 3]).includes(2, -100), true);
assertEq(new constructor([1, 2, 3]).includes("2"), false);
assertEq(new constructor([1, 2, 3]).includes(2, 2), false);
assertEq(new constructor([1, 2, 3]).includes(2, -1), false);
assertEq(new constructor([1, 2, 3]).includes(2, 100), false);
// Called from other globals.
if (typeof newGlobal === "function") {
var includes = newGlobal()[constructor.name].prototype.includes;
assertEq(includes.call(new constructor([1, 2, 3]), 2), true);
}
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.includes.call(invalidReceiver);
}, TypeError, "Assert that reverse fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.includes.call(new Proxy(new constructor(), {}));
// Test that the length getter is never called.
assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
get() {
throw new Error("length accessor called");
}
}).includes(2), true);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -10,12 +10,11 @@ const constructors = [
Float64Array
];
// Tests for TypedArray#indexOf
// Tests for TypedArray#indexOf.
for (var constructor of constructors) {
assertEq(constructor.prototype.indexOf.length, 1);
// works with one argument
// Works with one argument.
assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(0), -1);
assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(1), 0);
assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(5), 4);
@ -33,7 +32,7 @@ for (var constructor of constructors) {
assertEq(new constructor([NaN, 0, -0]).indexOf(-0), 0);
}
// works with two arguments
// Works with two arguments.
assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(1, 1), -1);
assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(1, -100), 0);
assertEq(new constructor([1, 2, 3, 4, 5]).indexOf(3, 100), -1);
@ -41,15 +40,15 @@ for (var constructor of constructors) {
assertEq(new constructor([1, 2, 1, 2, 1]).indexOf(1, 2), 2);
assertEq(new constructor([1, 2, 1, 2, 1]).indexOf(1, -2), 4);
// throws if `this` isn't a TypedArray
var nonTypedArrays = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
/* new Proxy(new constructor(), {}) // this probably should throw */
];
nonTypedArrays.forEach(nonTypedArray => {
assertThrowsInstanceOf(function() {
constructor.prototype.indexOf.call(nonTypedArray);
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.indexOf.call(invalidReceiver);
}, TypeError, "Assert that indexOf fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.indexOf.call(new Proxy(new constructor(), {}));
// test that this.length is never called
assertEq(Object.defineProperty(new constructor([0, 1, 2, 3, 5]), "length", {
@ -63,12 +62,12 @@ assertEq(new Float32Array([.1, .2, .3]).indexOf(.2), -1);
assertEq(new Float32Array([.1, .2, .3]).indexOf(Math.fround(.2)), 1);
assertEq(new Float64Array([.1, .2, .3]).indexOf(.2), 1);
// Tests for TypedArray#lastIndexOf
// Tests for TypedArray#lastIndexOf.
for (var constructor of constructors) {
assertEq(constructor.prototype.lastIndexOf.length, 1);
// works with one argument
// Works with one arguments.
assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(0), -1);
assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(1), 0);
assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(5), 4);
@ -80,13 +79,13 @@ for (var constructor of constructors) {
assertEq(new constructor([NaN, 0, -0]).lastIndexOf(0), 2);
assertEq(new constructor([NaN, 0, -0]).lastIndexOf(-0), 2);
} else {
// [NaN, 0, -0] will be coerced to [0, 0, 0]
// [NaN, 0, -0] will be coerced to [0, 0, 0].
assertEq(new constructor([NaN, 0, -0]).lastIndexOf(NaN), -1);
assertEq(new constructor([NaN, 0, -0]).lastIndexOf(0), 2);
assertEq(new constructor([NaN, 0, -0]).lastIndexOf(-0), 2);
}
// works with two arguments
// Works with two arguments.
assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(1, 1), 0);
assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(1, -100), -1);
assertEq(new constructor([1, 2, 3, 4, 5]).lastIndexOf(3, 100), 2);
@ -94,17 +93,17 @@ for (var constructor of constructors) {
assertEq(new constructor([1, 2, 1, 2, 1]).lastIndexOf(1, 2), 2);
assertEq(new constructor([1, 2, 1, 2, 1]).lastIndexOf(1, -2), 2);
// throws if `this` isn't a TypedArray
var nonTypedArrays = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
/* new Proxy(new constructor(), {}) // this probably should throw */
];
nonTypedArrays.forEach(nonTypedArray => {
assertThrowsInstanceOf(function() {
constructor.prototype.lastIndexOf.call(nonTypedArray);
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.lastIndexOf.call(invalidReceiver);
}, TypeError, "Assert that lastIndexOf fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.lastIndexOf.call(new Proxy(new constructor(), {}));
// test that this.length is never called
// Test that the length getter is never called.
assertEq(Object.defineProperty(new constructor([0, 1, 2, 3, 5]), "length", {
get() {
throw new Error("length accessor called");

View File

@ -11,7 +11,6 @@ const constructors = [
];
for (var constructor of constructors) {
assertDeepEq(constructor.prototype.reverse.length, 0);
assertDeepEq(new constructor().reverse(), new constructor());
@ -24,23 +23,23 @@ for (var constructor of constructors) {
assertDeepEq(new constructor([1, 2, 3, 4, 5]).reverse(), new constructor([5, 4, 3, 2, 1]));
assertDeepEq(new constructor([.1, .2, .3]).reverse(), new constructor([.3, .2, .1]));
// called from other globals
// Called from other globals.
if (typeof newGlobal === "function") {
var reverse = newGlobal()[constructor.name].prototype.reverse;
assertDeepEq(reverse.call(new constructor([3, 2, 1])), new constructor([1, 2, 3]));
}
// throws if `this` isn't a TypedArray
var nonTypedArrays = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
/* new Proxy(new constructor(), {}) // this probably should throw */
];
nonTypedArrays.forEach(nonTypedArray => {
assertThrowsInstanceOf(function() {
constructor.prototype.reverse.call(nonTypedArray);
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.reverse.call(invalidReceiver);
}, TypeError, "Assert that reverse fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.reverse.call(new Proxy(new constructor(), {}));
// test that this.length is never called
// Test that the length getter is never called.
Object.defineProperty(new constructor([1, 2, 3]), "length", {
get() {
throw new Error("length accessor called");

View File

@ -787,6 +787,9 @@ TypedArrayObject::protoFunctions[] = {
JS_SELF_HOSTED_FN("indexOf", "TypedArrayIndexOf", 2, 0),
JS_SELF_HOSTED_FN("lastIndexOf", "TypedArrayLastIndexOf", 2, 0),
JS_SELF_HOSTED_FN("reverse", "TypedArrayReverse", 0, 0),
#ifdef NIGHTLY_BUILD
JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
#endif
JS_FS_END
};

View File

@ -181,7 +181,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
gPrototypeProperties['TypedArray'] =
["length", "buffer", "byteLength", "byteOffset", kIteratorSymbol, "subarray",
"set", "copyWithin", "find", "findIndex", "indexOf", "lastIndexOf", "reverse"];
if (isNightlyBuild) {
gPrototypeProperties['TypedArray'].push('includes');
}
for (var c of errorObjectClasses) {
gPrototypeProperties[c] = ["constructor", "name",
// We don't actually resolve these empty data properties