Browse Source

Refactor: optimize LuaTableEnumerator and extract MoveNext logic to LuaValueDictionary

Akeit0 7 months ago
parent
commit
3cd21a8d5f
2 changed files with 58 additions and 25 deletions
  1. 34 24
      src/Lua/Internal/LuaValueDictionary.cs
  2. 24 1
      src/Lua/LuaTable.cs

+ 34 - 24
src/Lua/Internal/LuaValueDictionary.cs

@@ -409,6 +409,39 @@ namespace Lua.Internal
             public LuaValue value; // Value of entry
             public LuaValue value; // Value of entry
         }
         }
 
 
+        internal int Version => _version;
+
+        internal static bool MoveNext(LuaValueDictionary dictionary, int version, ref int index, out KeyValuePair<LuaValue, LuaValue> current)
+        {
+            if (version != dictionary._version)
+            {
+                ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
+            }
+
+        SearchNext:
+            // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
+            // dictionary.count+1 could be negative if dictionary.count is int.MaxValue
+            while ((uint)index < (uint)dictionary._count)
+            {
+                ref Entry entry = ref dictionary._entries![index++];
+
+                if (entry.next >= -1)
+                {
+                    if (entry.value.Type is LuaValueType.Nil)
+                    {
+                        goto SearchNext;
+                    }
+
+                    current = new KeyValuePair<LuaValue, LuaValue>(entry.key, entry.value);
+                    return true;
+                }
+            }
+
+            index = dictionary._count + 1;
+            current = default;
+            return false;
+        }
+
         public struct Enumerator
         public struct Enumerator
         {
         {
             private readonly LuaValueDictionary dictionary;
             private readonly LuaValueDictionary dictionary;
@@ -424,30 +457,7 @@ namespace Lua.Internal
                 _current = default;
                 _current = default;
             }
             }
 
 
-            public bool MoveNext()
-            {
-                if (_version != dictionary._version)
-                {
-                    ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
-                }
-
-                // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
-                // dictionary.count+1 could be negative if dictionary.count is int.MaxValue
-                while ((uint)_index < (uint)dictionary._count)
-                {
-                    ref Entry entry = ref dictionary._entries![_index++];
-
-                    if (entry.next >= -1)
-                    {
-                        _current = new KeyValuePair<LuaValue, LuaValue>(entry.key, entry.value);
-                        return true;
-                    }
-                }
-
-                _index = dictionary._count + 1;
-                _current = default;
-                return false;
-            }
+            public bool MoveNext() => LuaValueDictionary.MoveNext(dictionary, _version, ref _index, out _current);
 
 
             public KeyValuePair<LuaValue, LuaValue> Current => _current;
             public KeyValuePair<LuaValue, LuaValue> Current => _current;
         }
         }

+ 24 - 1
src/Lua/LuaTable.cs

@@ -334,11 +334,34 @@ public sealed class LuaTable : IEnumerable<KeyValuePair<LuaValue, LuaValue>>
     public struct LuaTableEnumerator(LuaTable table) : IEnumerator<KeyValuePair<LuaValue, LuaValue>>
     public struct LuaTableEnumerator(LuaTable table) : IEnumerator<KeyValuePair<LuaValue, LuaValue>>
     {
     {
         public KeyValuePair<LuaValue, LuaValue> Current => current;
         public KeyValuePair<LuaValue, LuaValue> Current => current;
+        int index = -1;
+        readonly int version = table.dictionary.Version;
         KeyValuePair<LuaValue, LuaValue> current = default;
         KeyValuePair<LuaValue, LuaValue> current = default;
 
 
         public bool MoveNext()
         public bool MoveNext()
         {
         {
-            return table.TryGetNext(Current.Key, out current);
+            if (index < 0)
+            {
+                var arrayIndex = -index - 1;
+                var span = table.array.AsSpan(arrayIndex);
+                for (int i = 0; i < span.Length; i++)
+                {
+                    if (span[i].Type is not LuaValueType.Nil)
+                    {
+                        current = new(arrayIndex + i + 1, span[i]);
+                        index = -arrayIndex - i - 2;
+                        return true;
+                    }
+                }
+
+                index = 0;
+            }
+
+            while (LuaValueDictionary.MoveNext(table.Dictionary, version, ref index, out current) && current.Value.Type is LuaValueType.Nil)
+            {
+            }
+
+            return current.Value.Type is not LuaValueType.Nil;
         }
         }
 
 
         public void Reset()
         public void Reset()