Browse Source

Fix: table does not move elements of the hash part to the newly allocated array

AnnulusGames 1 year ago
parent
commit
bf616bbb18
2 changed files with 42 additions and 5 deletions
  1. 28 5
      src/Lua/LuaTable.cs
  2. 14 0
      tests/Lua.Tests/TableTests.cs

+ 28 - 5
src/Lua/LuaTable.cs

@@ -1,4 +1,5 @@
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
+using Lua.Internal;
 using Lua.Runtime;
 using Lua.Runtime;
 
 
 namespace Lua;
 namespace Lua;
@@ -147,15 +148,37 @@ public sealed class LuaTable
     {
     {
         if (array.Length >= newCapacity) return;
         if (array.Length >= newCapacity) return;
 
 
-        var newSize = array.Length;
-        if (newSize == 0) newSize = 8;
+        var prevLength = array.Length;
+        var newLength = array.Length;
+        if (newLength == 0) newLength = 8;
 
 
-        while (newSize < newCapacity)
+        while (newLength < newCapacity)
         {
         {
-            newSize *= 2;
+            newLength *= 2;
         }
         }
 
 
-        Array.Resize(ref array, newSize);
+        Array.Resize(ref array, newLength);
+
+        using var indexList = new PooledList<(int, LuaValue)>(dictionary.Count);
+
+        // Move some of the elements of the hash part to a newly allocated array
+        foreach (var kv in dictionary)
+        {
+            if (kv.Key.TryRead<double>(out var d) && MathEx.IsInteger(d))
+            {
+                var index = (int)d;
+                if (index > prevLength && index <= newLength)
+                {
+                    indexList.Add((index, kv.Value));
+                }
+            }
+        }
+
+        foreach ((var index, var value) in indexList.AsSpan())
+        {
+            dictionary.Remove(index);
+            array[index - 1] = value;
+        }
     }
     }
 
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 14 - 0
tests/Lua.Tests/TableTests.cs

@@ -14,4 +14,18 @@ public class TableTests
         Assert.That(table["bar"], Is.EqualTo(new LuaValue(2)));
         Assert.That(table["bar"], Is.EqualTo(new LuaValue(2)));
         Assert.That(table[true], Is.EqualTo(new LuaValue("baz")));
         Assert.That(table[true], Is.EqualTo(new LuaValue("baz")));
     }
     }
+
+    [Test]
+    public void Test_EnsureCapacity()
+    {
+        var table = new LuaTable(2, 2);
+        table[32] = 10; // hash part
+
+        for (int i = 1; i <= 31; i++)
+        {
+            table[i] = 10;
+        }
+
+        Assert.That(table[32], Is.EqualTo(new LuaValue(10)));
+    }
 }
 }