Browse Source

Merge pull request #122 from wmltogether/fix-nextvar-test

Pass NextVar tests
Akeit0 8 months ago
parent
commit
321d25e5ce
3 changed files with 63 additions and 7 deletions
  1. 22 1
      src/Lua/Internal/MathEx.cs
  2. 20 6
      src/Lua/LuaTable.cs
  3. 21 0
      tests/Lua.Tests/TableTests.cs

+ 22 - 1
src/Lua/Internal/MathEx.cs

@@ -1,5 +1,7 @@
 using System.Runtime.CompilerServices;
-
+#if NET6_0_OR_GREATER
+using System.Numerics;
+#endif
 namespace Lua;
 
 internal static class MathEx
@@ -86,4 +88,23 @@ internal static class MathEx
     {
         return ((int)Math.Truncate(d), d % 1.0);
     }
+    
+    /// <summary>Returns the smallest power of two greater than or equal to the input.</summary>
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static int NextPowerOfTwo(int x)
+    {
+#if NET6_0_OR_GREATER
+        if (x <= 0) return 0;
+        return (int)BitOperations.RoundUpToPowerOf2((uint)x);
+#else
+        if (x <= 0) return 0;
+        x -= 1;
+        x |= x >> 1;
+        x |= x >> 2;
+        x |= x >> 4;
+        x |= x >> 8;
+        x |= x >> 16;
+        return x + 1;
+#endif
+    }
 }

+ 20 - 6
src/Lua/LuaTable.cs

@@ -19,6 +19,10 @@ public sealed class LuaTable
     readonly LuaValueDictionary dictionary;
     LuaTable? metatable;
 
+    internal LuaValueDictionary Dictionary => dictionary;
+    private const int MaxArraySize = 1 << 24;
+    private const int MaxDistance = 1 << 12;
+
     public LuaValue this[LuaValue key]
     {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -51,7 +55,15 @@ public sealed class LuaTable
                 if (MathEx.IsInteger(d))
                 {
                     var index = (int)d;
-                    if (0 < index && index <= Math.Max(array.Length * 2, 8))
+                    
+                    var distance = index - array.Length;
+                    if (distance > MaxDistance)
+                    {
+                        dictionary[key] = value;
+                        return;
+                    }
+                    
+                    if (0 < index && index < MaxArraySize && index <= Math.Max(array.Length * 2, 8))
                     {
                         if (array.Length < index)
                             EnsureArrayCapacity(index);
@@ -168,6 +180,12 @@ public sealed class LuaTable
         }
 
         var arrayIndex = index - 1;
+        var distance = index - array.Length;
+        if (distance > MaxDistance)
+        {
+            dictionary[index] = value;
+            return;
+        }
 
         if (index > array.Length || array[^1].Type != LuaValueType.Nil)
         {
@@ -249,11 +267,7 @@ public sealed class LuaTable
         var prevLength = array.Length;
         var newLength = array.Length;
         if (newLength == 0) newLength = 8;
-
-        while (newLength < newCapacity)
-        {
-            newLength *= 2;
-        }
+        newLength = newCapacity <= 8 ? 8 : MathEx.NextPowerOfTwo(newCapacity);
 
         Array.Resize(ref array, newLength);
 

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

@@ -41,4 +41,25 @@ public class TableTests
         Assert.That(value, Is.EqualTo(new LuaValue(2)));
         Assert.That(table[2], Is.EqualTo(new LuaValue(3)));
     }
+
+    [Test]
+    public void Test_TableResize()
+    {
+        var table = new LuaTable();
+        int i = 1;
+        int count = 10000;
+        while (count > 0)
+        {
+            var key = i;
+            table[key] = key;
+            table[key * 2 - key / 2] = key;
+            i += key;
+            count--;
+        }
+
+        table[1] = 0;
+        table[int.MaxValue - 1] = 0;
+        Assert.That(table[1], Is.EqualTo(new LuaValue(0)));
+        Assert.That(table[int.MaxValue - 1], Is.EqualTo(new LuaValue(0)));
+    }
 }