Bug 1069063 - Implement Array.prototype.contains. r=till
☠☠ backed out by c902ebaa8520 ☠ ☠
authorziyunfei <446240525@qq.com>
Thu, 18 Sep 2014 17:22:05 +0800
changeset 206319 2c92e43e29d8d1c2a538d79d406e50fd78d6f82b
parent 206318 cb9c67b221bb869f3f710892efa7a20e72454f53
child 206320 7f06ae718751ffebf434c7a1f1f2c2e88bc7d962
push id49406
push usertschneidereit@gmail.com
push dateSun, 21 Sep 2014 02:21:28 +0000
treeherdermozilla-inbound@7f06ae718751 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1069063
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1069063 - Implement Array.prototype.contains. r=till
js/src/builtin/Array.js
js/src/builtin/Utilities.js
js/src/jsarray.cpp
js/src/tests/ecma_7/Array/browser.js
js/src/tests/ecma_7/Array/contains.js
js/src/tests/ecma_7/Array/shell.js
js/src/tests/ecma_7/browser.js
js/src/tests/ecma_7/shell.js
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -576,16 +576,66 @@ function ArrayFill(value, start = 0, end
     for (; k < final; k++) {
         O[k] = value;
     }
 
     // Step 13.
     return O;
 }
 
+// Proposed for ES7:
+// https://github.com/domenic/Array.prototype.contains/blob/master/spec.md
+function ArrayContains(searchElement, fromIndex = 0) {
+    // Steps 1-2.
+    var O = ToObject(this);
+
+    // Steps 3-4.
+    var len = ToLength(O.length);
+
+    // Step 5.
+    if (len === 0)
+        return false;
+
+    // Steps 6-7.
+    var n = ToInteger(fromIndex);
+
+    // Step 8.
+    if (n >= len)
+        return false;
+
+    // Step 9.
+    var k;
+    if (n >= 0)
+        k = n;
+    // Step 10.
+    else {
+        // Step a.
+        k = len + n;
+        // Step b.
+        if (k < 0)
+            k = 0;
+    }
+
+    // Step 11.
+    while (k < len) {
+        // Steps a-b.
+        var elementK = O[k];
+
+        // Step c.
+        if (SameValueZero(searchElement, elementK))
+            return true;
+
+        // Step d.
+        k++;
+    }
+
+    // Step 12.
+    return false;
+}
+
 #define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
 #define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
 #define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
 
 #define ITEM_KIND_VALUE 0
 #define ITEM_KIND_KEY_AND_VALUE 1
 #define ITEM_KIND_KEY 2
 
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -151,16 +151,21 @@ function ToLength(v) {
 
     if (v <= 0)
         return 0;
 
     // Math.pow(2, 53) - 1 = 0x1fffffffffffff
     return v < 0x1fffffffffffff ? v : 0x1fffffffffffff;
 }
 
+/* Spec: ECMAScript Draft, 6 edition Aug 24, 2014, 7.2.4 */
+function SameValueZero(x, y) {
+    return x !== x && y !== y || x === y
+}
+
 /********** Testing code **********/
 
 #ifdef ENABLE_PARALLEL_JS
 
 /**
  * Internal debugging tool: checks that the given `mode` permits
  * sequential execution
  */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3018,16 +3018,22 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
     JS_SELF_HOSTED_FN("copyWithin",  "ArrayCopyWithin",  3,0),
 
     JS_SELF_HOSTED_FN("fill",        "ArrayFill",        3,0),
 
     JS_SELF_HOSTED_FN("@@iterator",  "ArrayValues",      0,0),
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
+
+    /* ES7 additions */
+#ifdef NIGHTLY_BUILD
+    JS_SELF_HOSTED_FN("contains",    "ArrayContains",    2,0),
+#endif
+
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayStaticIndexOf", 2,0),
     JS_SELF_HOSTED_FN("forEach",     "ArrayStaticForEach", 2,0),
copy from js/src/tests/ecma_6/Array/browser.js
copy to js/src/tests/ecma_7/Array/browser.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/Array/contains.js
@@ -0,0 +1,61 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var BUGNUMBER = 1069063;
+var summary = "Implement Array.prototype.contains";
+
+print(BUGNUMBER + ": " + summary);
+
+if ('contains' in Array.prototype) {
+    assertEq(typeof [].contains, "function");
+    assertEq([].contains.length, 1);
+    
+    assertTrue([1, 2, 3].contains(2));
+    assertTrue([1,,2].contains(2));
+    assertTrue([1, 2, 3].contains(2, 1));
+    assertTrue([1, 2, 3].contains(2, -2));
+    assertTrue([1, 2, 3].contains(2, -100));
+    assertTrue([Object, Function, Array].contains(Function));
+    assertTrue([-0].contains(0));
+    assertTrue([NaN].contains(NaN));
+    assertTrue([,].contains());
+    assertTrue(staticContains("123", "2"));
+    assertTrue(staticContains({length: 3, 1: 2}, 2));
+    assertTrue(staticContains({length: 3, 1: 2, get 3(){throw ""}}, 2));
+    assertTrue(staticContains({length: 3, get 1() {return 2}}, 2));
+    assertTrue(staticContains({__proto__: {1: 2}, length: 3}, 2));
+    assertTrue(staticContains(new Proxy([1], {get(){return 2}}), 2));
+    
+    assertFalse([1, 2, 3].contains("2"));
+    assertFalse([1, 2, 3].contains(2, 2));
+    assertFalse([1, 2, 3].contains(2, -1));
+    assertFalse([undefined].contains(NaN));
+    assertFalse([{}].contains({}));
+    assertFalse(staticContains({length: 3, 1: 2}, 2, 2));
+    assertFalse(staticContains({length: 3, get 0(){delete this[1]}, 1: 2}, 2));
+    assertFalse(staticContains({length: -100, 0: 1}, 1));
+    
+    assertThrowsInstanceOf(() => staticContains(), TypeError);
+    assertThrowsInstanceOf(() => staticContains(null), TypeError);
+    assertThrowsInstanceOf(() => staticContains({get length(){throw TypeError()}}), TypeError);
+    assertThrowsInstanceOf(() => staticContains({length: 3, get 1() {throw TypeError()}}, 2), TypeError);
+    assertThrowsInstanceOf(() => staticContains({__proto__: {get 1() {throw TypeError()}}, length: 3}, 2), TypeError);
+    assertThrowsInstanceOf(() => staticContains(new Proxy([1], {get(){throw TypeError()}})), TypeError);
+}
+
+function assertTrue(v){
+    assertEq(v, true)
+}
+
+function assertFalse(v){
+    assertEq(v, false)
+}
+
+function staticContains(o, v, f){
+    return [].contains.call(o, v, f)
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
copy from js/src/tests/ecma_6/Array/browser.js
copy to js/src/tests/ecma_7/Array/shell.js
copy from js/src/tests/ecma_6/browser.js
copy to js/src/tests/ecma_7/browser.js
copy from js/src/tests/ecma_6/shell.js
copy to js/src/tests/ecma_7/shell.js