Răsfoiți Sursa

Implement array find from last (#1070)

Marko Lahma 3 ani în urmă
părinte
comite
13e45e1f46

+ 34 - 10
Jint/Native/Array/ArrayInstance.cs

@@ -818,7 +818,8 @@ namespace Jint.Native.Array
             JsValue[] arguments,
             out uint index,
             out JsValue value,
-            bool visitUnassigned)
+            bool visitUnassigned,
+            bool fromEnd = false)
         {
             var thisArg = arguments.At(1);
             var callbackfn = arguments.At(0);
@@ -834,18 +835,41 @@ namespace Jint.Native.Array
 
             var args = _engine._jsValueArrayPool.RentArray(3);
             args[2] = this;
-            for (uint k = 0; k < len; k++)
+
+            if (!fromEnd)
             {
-                if (TryGetValue(k, out var kvalue) || visitUnassigned)
+                for (uint k = 0; k < len; k++)
                 {
-                    args[0] = kvalue;
-                    args[1] = k;
-                    var testResult = callable.Call(thisArg, args);
-                    if (TypeConverter.ToBoolean(testResult))
+                    if (TryGetValue(k, out var kvalue) || visitUnassigned)
                     {
-                        index = k;
-                        value = kvalue;
-                        return true;
+                        args[0] = kvalue;
+                        args[1] = k;
+                        var testResult = callable.Call(thisArg, args);
+                        if (TypeConverter.ToBoolean(testResult))
+                        {
+                            index = k;
+                            value = kvalue;
+                            return true;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (long k = len - 1; k >= 0; k--)
+                {
+                    var idx = (uint) k;
+                    if (TryGetValue(idx, out var kvalue) || visitUnassigned)
+                    {
+                        args[0] = kvalue;
+                        args[1] = idx;
+                        var testResult = callable.Call(thisArg, args);
+                        if (TypeConverter.ToBoolean(testResult))
+                        {
+                            index = idx;
+                            value = kvalue;
+                            return true;
+                        }
                     }
                 }
             }

+ 24 - 3
Jint/Native/Array/ArrayPrototype.cs

@@ -47,6 +47,8 @@ namespace Jint.Native.Array
             unscopables.SetDataProperty("fill", JsBoolean.True);
             unscopables.SetDataProperty("find", JsBoolean.True);
             unscopables.SetDataProperty("findIndex", JsBoolean.True);
+            unscopables.SetDataProperty("findLast", JsBoolean.True);
+            unscopables.SetDataProperty("findLastIndex", JsBoolean.True);
             unscopables.SetDataProperty("flat", JsBoolean.True);
             unscopables.SetDataProperty("flatMap", JsBoolean.True);
             unscopables.SetDataProperty("includes", JsBoolean.True);
@@ -54,7 +56,7 @@ namespace Jint.Native.Array
             unscopables.SetDataProperty("values", JsBoolean.True);
 
             const PropertyFlag propertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
-            var properties = new PropertyDictionary(32, checkExistingKeys: false)
+            var properties = new PropertyDictionary(34, checkExistingKeys: false)
             {
                 ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
                 ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0, PropertyFlag.Configurable), propertyFlags),
@@ -84,6 +86,8 @@ namespace Jint.Native.Array
                 ["reduceRight"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "reduceRight", ReduceRight, 1, PropertyFlag.Configurable), propertyFlags),
                 ["find"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "find", Find, 1, PropertyFlag.Configurable), propertyFlags),
                 ["findIndex"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "findIndex", FindIndex, 1, PropertyFlag.Configurable), propertyFlags),
+                ["findLast"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "findLast", FindLast, 1, PropertyFlag.Configurable), propertyFlags),
+                ["findLastIndex"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "findLastIndex", FindLastIndex, 1, PropertyFlag.Configurable), propertyFlags),
                 ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 0, PropertyFlag.Configurable), propertyFlags),
                 ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
                 ["flat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flat", Flat, 0, PropertyFlag.Configurable), propertyFlags),
@@ -771,14 +775,31 @@ namespace Jint.Native.Array
         private JsValue Find(JsValue thisObj, JsValue[] arguments)
         {
             var target = TypeConverter.ToObject(_realm, thisObj);
-            target.FindWithCallback(arguments, out _, out var value, true);
+            target.FindWithCallback(arguments, out _, out var value, visitUnassigned: true);
             return value;
         }
 
         private JsValue FindIndex(JsValue thisObj, JsValue[] arguments)
         {
             var target = TypeConverter.ToObject(_realm, thisObj);
-            if (target.FindWithCallback(arguments, out var index, out _, true))
+            if (target.FindWithCallback(arguments, out var index, out _, visitUnassigned: true))
+            {
+                return index;
+            }
+            return -1;
+        }
+
+        private JsValue FindLast(JsValue thisObj, JsValue[] arguments)
+        {
+            var target = TypeConverter.ToObject(_realm, thisObj);
+            target.FindWithCallback(arguments, out _, out var value, visitUnassigned: true, fromEnd: true);
+            return value;
+        }
+
+        private JsValue FindLastIndex(JsValue thisObj, JsValue[] arguments)
+        {
+            var target = TypeConverter.ToObject(_realm, thisObj);
+            if (target.FindWithCallback(arguments, out var index, out _, visitUnassigned: true, fromEnd: true))
             {
                 return index;
             }

+ 2 - 1
Jint/Native/Object/ObjectInstance.cs

@@ -1017,7 +1017,8 @@ namespace Jint.Native.Object
             JsValue[] arguments,
             out uint index,
             out JsValue value,
-            bool visitUnassigned)
+            bool visitUnassigned,
+            bool fromEnd = false)
         {
             long GetLength()
             {

+ 38 - 9
Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs

@@ -53,6 +53,8 @@ namespace Jint.Native.TypedArray
                 ["filter"] = new(new ClrFunctionInstance(Engine, "filter", Filter, 1, PropertyFlag.Configurable), propertyFlags),
                 ["find"] = new(new ClrFunctionInstance(Engine, "find", Find, 1, PropertyFlag.Configurable), propertyFlags),
                 ["findIndex"] = new(new ClrFunctionInstance(Engine, "findIndex", FindIndex, 1, PropertyFlag.Configurable), propertyFlags),
+                ["findLast"] = new(new ClrFunctionInstance(Engine, "findLast", FindLast, 1, PropertyFlag.Configurable), propertyFlags),
+                ["findLastIndex"] = new(new ClrFunctionInstance(Engine, "findLastIndex", FindLastIndex, 1, PropertyFlag.Configurable), propertyFlags),
                 ["forEach"] = new(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), propertyFlags),
                 ["includes"] = new(new ClrFunctionInstance(Engine, "includes", Includes, 1, PropertyFlag.Configurable), propertyFlags),
                 ["indexOf"] = new(new ClrFunctionInstance(Engine, "indexOf", IndexOf, 1, PropertyFlag.Configurable), propertyFlags),
@@ -421,25 +423,52 @@ namespace Jint.Native.TypedArray
             return DoFind(thisObj, arguments).Key;
         }
 
-        private KeyValuePair<JsValue, JsValue> DoFind(JsValue thisObj, JsValue[] arguments)
+        private JsValue FindLast(JsValue thisObj, JsValue[] arguments)
+        {
+            return DoFind(thisObj, arguments, fromEnd: true).Value;
+        }
+
+        private JsValue FindLastIndex(JsValue thisObj, JsValue[] arguments)
+        {
+            return DoFind(thisObj, arguments, fromEnd: true).Key;
+        }
+
+        private KeyValuePair<JsValue, JsValue> DoFind(JsValue thisObj, JsValue[] arguments, bool fromEnd = false)
         {
             var o = thisObj.ValidateTypedArray(_realm);
-            var len = o.Length;
+            var len = (int) o.Length;
 
             var predicate = GetCallable(arguments.At(0));
             var thisArg = arguments.At(1);
 
             var args = _engine._jsValueArrayPool.RentArray(3);
             args[2] = o;
-            for (var k = 0; k < len; k++)
+            if (!fromEnd)
             {
-                var kNumber = JsNumber.Create(k);
-                var kValue = o[k];
-                args[0] = kValue;
-                args[1] = kNumber;
-                if (TypeConverter.ToBoolean(predicate.Call(thisArg, args)))
+                for (var k = 0; k < len; k++)
+                {
+                    var kNumber = JsNumber.Create(k);
+                    var kValue = o[k];
+                    args[0] = kValue;
+                    args[1] = kNumber;
+                    if (TypeConverter.ToBoolean(predicate.Call(thisArg, args)))
+                    {
+                        return new KeyValuePair<JsValue, JsValue>(kNumber, kValue);
+                    }
+                }
+            }
+            else
+            {
+                for (var k = len - 1; k >= 0; k--)
                 {
-                    return new KeyValuePair<JsValue, JsValue>(kNumber, kValue);
+                    var kNumber = JsNumber.Create(k);
+                    var kValue = o[k];
+                    args[0] = kValue;
+                    args[1] = kNumber;
+                    if (TypeConverter.ToBoolean(predicate.Call(thisArg, args)))
+                    {
+                        return new KeyValuePair<JsValue, JsValue>(kNumber, kValue);
+                    }
                 }
             }