浏览代码

Revert back to favoring SearchValues<char> (#1990)

Marko Lahma 9 月之前
父节点
当前提交
04466d0a3b

+ 3 - 4
Jint/Extensions/Character.cs

@@ -5,14 +5,13 @@ namespace Jint.Extensions;
 
 internal static class Character
 {
-    [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool IsInRange(this char c, ushort min, ushort max) => (uint)(c - min) <= (uint)(max - min);
-
     /// <summary>
     /// https://tc39.es/ecma262/#ASCII-word-characters
     /// </summary>
+    public const string AsciiWordCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool IsAsciiWordCharacter(this char c) => c == '_' || c.IsDecimalDigit() || c.IsInRange('a', 'z') || c.IsInRange('A', 'Z');
+    public static bool IsInRange(this char c, ushort min, ushort max) => (uint)(c - min) <= (uint)(max - min);
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     public static bool IsOctalDigit(this char c) => c.IsInRange('0', '7');

+ 16 - 16
Jint/Native/Global/GlobalObject.cs

@@ -274,8 +274,8 @@ public sealed partial class GlobalObject : ObjectInstance
 
     private const string UriReservedString = ";/?:@&=+$,";
     private const string UriUnescapedString = "-.!~*'()";
-    private static readonly SearchValues<char> UriUnescaped = SearchValues.Create(UriUnescapedString);
-    private static readonly SearchValues<char> UnescapedUriSet = SearchValues.Create(UriReservedString + UriUnescapedString + '#');
+    private static readonly SearchValues<char> UriUnescaped = SearchValues.Create(Character.AsciiWordCharacters + UriUnescapedString);
+    private static readonly SearchValues<char> UnescapedUriSet = SearchValues.Create(Character.AsciiWordCharacters + UriReservedString + UriUnescapedString + '#');
     private static readonly SearchValues<char> ReservedUriSet = SearchValues.Create(UriReservedString + '#');
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -300,7 +300,7 @@ public sealed partial class GlobalObject : ObjectInstance
         return Encode(uriString, UriUnescaped);
     }
 
-    private JsValue Encode(string uriString, SearchValues<char> unescapedUriSet)
+    private JsValue Encode(string uriString, SearchValues<char> allowedCharacters)
     {
         var strLen = uriString.Length;
         var builder = new ValueStringBuilder(uriString.Length);
@@ -309,7 +309,7 @@ public sealed partial class GlobalObject : ObjectInstance
         for (var k = 0; k < strLen; k++)
         {
             var c = uriString[k];
-            if (c.IsAsciiWordCharacter() || unescapedUriSet.Contains(c))
+            if (allowedCharacters.Contains(c))
             {
                 builder.Append(c);
             }
@@ -416,7 +416,7 @@ public sealed partial class GlobalObject : ObjectInstance
         _stringBuilder.Clear();
 
 #if SUPPORTS_SPAN_PARSE
-            Span<byte> octets = stackalloc byte[4];
+        Span<byte> octets = stackalloc byte[4];
 #else
         var octets = new byte[4];
 #endif
@@ -576,6 +576,8 @@ public sealed partial class GlobalObject : ObjectInstance
         return tmp < radix;
     }
 
+    private static readonly SearchValues<char> EscapeAllowList = SearchValues.Create(Character.AsciiWordCharacters + "@*+-./");
+
     /// <summary>
     /// https://tc39.es/ecma262/#sec-escape-string
     /// </summary>
@@ -583,29 +585,27 @@ public sealed partial class GlobalObject : ObjectInstance
     {
         var uriString = TypeConverter.ToString(arguments.At(0));
 
-        var strLen = uriString.Length;
-
-        _stringBuilder.EnsureCapacity(strLen);
-        _stringBuilder.Clear();
+        var builder = new ValueStringBuilder(uriString.Length);
 
-        for (var k = 0; k < strLen; k++)
+        foreach (var c in uriString)
         {
-            var c = uriString[k];
-            if (c.IsAsciiWordCharacter() || c == '@' || c == '*' || c == '+' || c == '-' || c == '.' || c == '/')
+            if (EscapeAllowList.Contains(c))
             {
-                _stringBuilder.Append(c);
+                builder.Append(c);
             }
             else if (c < 256)
             {
-                _stringBuilder.Append('%').AppendFormat(CultureInfo.InvariantCulture, "{0:X2}", (int) c);
+                builder.Append('%');
+                builder.AppendHex((byte) c);
             }
             else
             {
-                _stringBuilder.Append("%u").AppendFormat(CultureInfo.InvariantCulture, "{0:X4}", (int) c);
+                builder.Append("%u");
+                builder.Append(((int) c).ToString("X4", CultureInfo.InvariantCulture));
             }
         }
 
-        return _stringBuilder.ToString();
+        return builder.ToString();
     }
 
     /// <summary>

+ 9 - 5
Jint/Native/TypedArray/TypedArrayConstructor.Uint8Array.cs

@@ -22,7 +22,12 @@ public sealed class Uint8ArrayConstructor : TypedArrayConstructor
     protected override void Initialize()
     {
         const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
-        var properties = new PropertyDictionary(1, checkExistingKeys: false) { ["BYTES_PER_ELEMENT"] = new(new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.AllForbidden)), ["fromBase64"] = new(new ClrFunction(Engine, "fromBase64", FromBase64, 1, PropertyFlag.Configurable), PropertyFlags), ["fromHex"] = new(new ClrFunction(Engine, "fromHex", FromHex, 1, PropertyFlag.Configurable), PropertyFlags), };
+        var properties = new PropertyDictionary(3, checkExistingKeys: false)
+        {
+            ["BYTES_PER_ELEMENT"] = new(new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.AllForbidden)),
+            ["fromBase64"] = new(new ClrFunction(Engine, "fromBase64", FromBase64, 1, PropertyFlag.Configurable), PropertyFlags),
+            ["fromHex"] = new(new ClrFunction(Engine, "fromHex", FromHex, 1, PropertyFlag.Configurable), PropertyFlags),
+        };
         SetProperties(properties);
     }
 
@@ -92,6 +97,8 @@ public sealed class Uint8ArrayConstructor : TypedArrayConstructor
 
     internal readonly record struct FromEncodingResult(byte[] Bytes, JavaScriptException? Error, int Read);
 
+    private static readonly SearchValues<char> Base64Alphabet = SearchValues.Create("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+
     internal static FromEncodingResult FromBase64(Engine engine, string input, string alphabet, string lastChunkHandling, uint maxLength = uint.MaxValue)
     {
         if (maxLength == 0)
@@ -200,10 +207,7 @@ public sealed class Uint8ArrayConstructor : TypedArrayConstructor
                 }
             }
 
-            if (!currentChar.IsDecimalDigit()
-                && !char.ToLowerInvariant(currentChar).IsInRange('a', 'z')
-                && currentChar != '+'
-                && currentChar != '/')
+            if (!Base64Alphabet.Contains(currentChar))
             {
                 return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 character."), read);
             }

+ 4 - 4
Jint/Pooling/ValueStringBuilder.cs

@@ -192,11 +192,11 @@ internal ref struct ValueStringBuilder
     public void AppendHex(byte b)
     {
         const string Map = "0123456789ABCDEF";
-        Span<char> data = stackalloc char[]
-        {
+        ReadOnlySpan<char> data =
+        [
             Map[b / 16],
-            Map[b % 16],
-        };
+            Map[b % 16]
+        ];
         Append(data);
     }