Browse Source

Use C# 12's collection expressions (#51378)

Günther Foidl 2 years ago
parent
commit
4ad01cdb03

+ 1 - 1
src/Http/Headers/src/MediaTypeHeaderValue.cs

@@ -25,7 +25,7 @@ public class MediaTypeHeaderValue
     private const char PeriodCharacter = '.';
     private const char PlusCharacter = '+';
 
-    private static readonly char[] PeriodCharacterArray = new char[] { PeriodCharacter };
+    private static readonly char[] PeriodCharacterArray = [PeriodCharacter];
 
     private static readonly HttpHeaderParser<MediaTypeHeaderValue> SingleValueParser
         = new GenericHeaderParser<MediaTypeHeaderValue>(false, GetMediaTypeLength);

+ 1 - 1
src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs

@@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 internal partial class Http1Connection : HttpProtocol, IRequestProcessor, IHttpOutputAborter
 {
-    internal static ReadOnlySpan<byte> Http2GoAwayHttp11RequiredBytes => new byte[17] { 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 };
+    internal static ReadOnlySpan<byte> Http2GoAwayHttp11RequiredBytes => [0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13];
 
     private const byte ByteCR = (byte)'\r';
     private const byte ByteLF = (byte)'\n';

+ 0 - 1
src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs

@@ -16,7 +16,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 internal class Http1OutputProducer : IHttpOutputProducer, IDisposable
 #pragma warning restore CA1852 // Seal internal types
 {
-    // Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
     private static ReadOnlySpan<byte> ContinueBytes => "HTTP/1.1 100 Continue\r\n\r\n"u8;
     private static ReadOnlySpan<byte> HttpVersion11Bytes => "HTTP/1.1 "u8;
     private static ReadOnlySpan<byte> EndHeadersBytes => "\r\n\r\n"u8;

File diff suppressed because it is too large
+ 0 - 2
src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs


+ 1 - 2
src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs

@@ -17,8 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
 internal sealed class Http2FrameWriter
 {
     // Literal Header Field without Indexing - Indexed Name (Index 8 - :status)
-    // This uses C# compiler's ability to refer to static data directly. For more information see https://vcsjones.dev/2019/02/01/csharp-readonly-span-bytes-static
-    private static ReadOnlySpan<byte> ContinueBytes => new byte[] { 0x08, 0x03, (byte)'1', (byte)'0', (byte)'0' };
+    private static ReadOnlySpan<byte> ContinueBytes => [0x08, 0x03, (byte)'1', (byte)'0', (byte)'0'];
 
     /// Increase this value to be more lenient (disconnect fewer clients).
     /// A non-positive value will disable the limit.

+ 1 - 1
src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameWriter.cs

@@ -23,7 +23,7 @@ internal sealed class Http3FrameWriter
     // is 63, and encode it to get ff 00 (see QPackEncoder.EncodeStaticIndexedHeaderField).
     // The two zero bytes are for the section prefix
     // (https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#header-prefix)
-    private static ReadOnlySpan<byte> ContinueBytes => new byte[] { 0x00, 0x00, 0xff, 0x00 };
+    private static ReadOnlySpan<byte> ContinueBytes => [0x00, 0x00, 0xff, 0x00];
 
     // Size based on HTTP/2 default frame size
     private const int MaxDataFrameSize = 16 * 1024;

+ 0 - 1
src/Servers/Kestrel/Core/src/Internal/HttpConnection.cs

@@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
 
 internal sealed class HttpConnection : ITimeoutHandler
 {
-    // Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
     private static ReadOnlySpan<byte> Http2Id => "h2"u8;
 
     private readonly BaseHttpConnectionContext _context;

+ 5 - 10
src/Servers/Kestrel/Core/src/Internal/Infrastructure/HttpUtilities.Generated.cs

@@ -22,20 +22,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
         private static readonly ulong _httpOptionsMethodLong = GetAsciiStringAsLong("OPTIONS ");
         private static readonly ulong _httpTraceMethodLong = GetAsciiStringAsLong("TRACE \0\0");
 
-        private static readonly ulong _mask8Chars = GetMaskAsLong(new byte[]
-            {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
+        private static readonly ulong _mask8Chars = GetMaskAsLong([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
 
-        private static readonly ulong _mask7Chars = GetMaskAsLong(new byte[]
-            {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00});
+        private static readonly ulong _mask7Chars = GetMaskAsLong([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00]);
 
-        private static readonly ulong _mask6Chars = GetMaskAsLong(new byte[]
-            {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00});
+        private static readonly ulong _mask6Chars = GetMaskAsLong([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00]);
 
-        private static readonly ulong _mask5Chars = GetMaskAsLong(new byte[]
-            {0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00});
+        private static readonly ulong _mask5Chars = GetMaskAsLong([0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00]);
 
-        private static readonly ulong _mask4Chars = GetMaskAsLong(new byte[]
-            {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00});
+        private static readonly ulong _mask4Chars = GetMaskAsLong([0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00]);
 
         private static readonly Tuple<ulong, ulong, HttpMethod, int>[] _knownMethods =
             new Tuple<ulong, ulong, HttpMethod, int>[17];

+ 23 - 25
src/Servers/Kestrel/Core/src/Internal/Infrastructure/HttpUtilities.cs

@@ -74,7 +74,7 @@ internal static partial class HttpUtilities
         return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
     }
 
-    private static ulong GetMaskAsLong(byte[] bytes)
+    private static ulong GetMaskAsLong(ReadOnlySpan<byte> bytes)
     {
         Debug.Assert(bytes.Length == 8, "Mask must be exactly 8 bytes long.");
 
@@ -258,7 +258,7 @@ internal static partial class HttpUtilities
             return HttpMethod.None;
         }
 
-        if (((uint)(value.Length - MinWordLength) <= (MaxWordLength - MinWordLength)))
+        if ((uint)(value.Length - MinWordLength) <= (MaxWordLength - MinWordLength))
         {
             var methodsLookup = Methods();
 
@@ -270,7 +270,7 @@ internal static partial class HttpUtilities
                 && WordListForPerfectHashOfMethods[index] == value
                 && index < (uint)methodsLookup.Length)
             {
-                return (HttpMethod)methodsLookup[(int)index];
+                return methodsLookup[(int)index];
             }
         }
 
@@ -279,9 +279,8 @@ internal static partial class HttpUtilities
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         static uint PerfectHash(ReadOnlySpan<char> str)
         {
-            // This uses C#'s optimization to refer to static data of assembly, and doesn't allocate.
-            ReadOnlySpan<byte> associatedValues = new byte[]
-            {
+            ReadOnlySpan<byte> associatedValues =
+            [
                 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
                 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
                 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -308,32 +307,31 @@ internal static partial class HttpUtilities
                 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
                 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
                 13, 13, 13, 13, 13, 13
-            };
+            ];
 
             var c = MemoryMarshal.GetReference(str);
 
-            Debug.Assert(char.IsAscii(c), "Must already be valiated");
+            Debug.Assert(char.IsAscii(c), "Must already be validated");
 
             return (uint)str.Length + associatedValues[c];
         }
 
-        // This uses C#'s optimization to refer to static data of assembly, and doesn't allocate.
-        static ReadOnlySpan<byte> Methods() => new byte[]
-        {
-            (byte)HttpMethod.None,
-            (byte)HttpMethod.None,
-            (byte)HttpMethod.None,
-            (byte)HttpMethod.Get,
-            (byte)HttpMethod.Head,
-            (byte)HttpMethod.Trace,
-            (byte)HttpMethod.Delete,
-            (byte)HttpMethod.Options,
-            (byte)HttpMethod.Put,
-            (byte)HttpMethod.Post,
-            (byte)HttpMethod.Patch,
-            (byte)HttpMethod.None,
-            (byte)HttpMethod.Connect
-        };
+        static ReadOnlySpan<HttpMethod> Methods() =>
+        [
+            HttpMethod.None,
+            HttpMethod.None,
+            HttpMethod.None,
+            HttpMethod.Get,
+            HttpMethod.Head,
+            HttpMethod.Trace,
+            HttpMethod.Delete,
+            HttpMethod.Options,
+            HttpMethod.Put,
+            HttpMethod.Post,
+            HttpMethod.Patch,
+            HttpMethod.None,
+            HttpMethod.Connect
+        ];
     }
 
     private static readonly string[] WordListForPerfectHashOfMethods =

+ 1 - 4
src/Servers/Kestrel/shared/KnownHeaders.cs

@@ -858,10 +858,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
     internal partial class {loop.ClassName} : IHeaderDictionary
     {{{(loop.Bytes != null ?
         $@"
-        private static ReadOnlySpan<byte> HeaderBytes => new byte[]
-        {{
-            {Each(loop.Bytes, b => $"{b},")}
-        }};"
+        private static ReadOnlySpan<byte> HeaderBytes => [{Each(loop.Bytes, b => $"{b},")}];"
         : "")}
         private HeaderReferences _headers;
 {Each(loop.Headers.Where(header => header.ExistenceCheck), header => $@"

+ 2 - 2
src/Servers/Kestrel/tools/CodeGenerator/HttpUtilities/HttpUtilities.cs

@@ -35,7 +35,7 @@ public class HttpUtilities
 
         var methodsInfo = httpMethods.Select(GetMethodStringAndUlongAndMaskLength).ToList();
 
-        var methodsInfoWithoutGet = methodsInfo.Where(m => m.HttpMethod != "Get".ToString()).ToList();
+        var methodsInfoWithoutGet = methodsInfo.Where(m => m.HttpMethod != "Get").ToList();
 
         var methodsAsciiStringAsLong = methodsInfo.Select(m => m.AsciiStringAsLong).ToArray();
 
@@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
             var hexMaskString = HttpUtilitiesGeneratorHelpers.GeHexString(maskArray, "0x", ", ");
             var maskFieldName = GetMaskFieldName(maskBytesLength);
 
-            result.AppendFormat(CultureInfo.InvariantCulture, "        private static readonly ulong {0} = GetMaskAsLong(new byte[]\r\n            {{{1}}});", maskFieldName, hexMaskString);
+            result.AppendFormat(CultureInfo.InvariantCulture, """        private static readonly ulong {0} = GetMaskAsLong([{1}]);""", maskFieldName, hexMaskString);
             result.AppendLine();
             if (index < distinctLengths.Count - 1)
             {

+ 2 - 1
src/Shared/HttpSys/NativeInterop/HttpSysRequestHeader.cs

@@ -3,7 +3,8 @@
 
 namespace Microsoft.AspNetCore.HttpSys.Internal;
 
-internal enum HttpSysRequestHeader
+// With the byte a ROS<HttpSysRequestHeader> can be created that referes to assembly's static data segment.
+internal enum HttpSysRequestHeader : byte
 {
     CacheControl = 0,    // general-header [section 4.5]
     Connection = 1,    // general-header [section 4.5]

File diff suppressed because it is too large
+ 76 - 494
src/Shared/HttpSys/RequestProcessing/RequestHeaders.Generated.cs


+ 4 - 4
src/Shared/HttpSys/RequestProcessing/RequestHeaders.Generated.tt

@@ -214,12 +214,12 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
 <# } #>
         }
 
-        private static ReadOnlySpan<byte> HeaderKeys => new byte[]
-        {
+        private static ReadOnlySpan<HttpSysRequestHeader> HeaderKeys =>
+        [
 <# foreach(var prop in props) { #>
-            (byte)<#=prop.ID#>,
+            <#=prop.ID#>,
 <# } #>
-        };
+        ];
 
         private string GetHeaderKeyName(HttpSysRequestHeader header) => header switch
         {

+ 2 - 2
src/Shared/HttpSys/RequestProcessing/RequestHeaders.cs

@@ -279,7 +279,7 @@ internal sealed partial class RequestHeaders : IHeaderDictionary
         int observedHeadersCount = 0;
         for (int i = 0; i < HeaderKeys.Length; i++)
         {
-            var header = (HttpSysRequestHeader)HeaderKeys[i];
+            var header = HeaderKeys[i];
             if (HasKnownHeader(header))
             {
                 observedHeaders[observedHeadersCount++] = GetHeaderKeyName(header);
@@ -293,7 +293,7 @@ internal sealed partial class RequestHeaders : IHeaderDictionary
         int observedHeadersCount = 0;
         for (int i = 0; i < HeaderKeys.Length; i++)
         {
-            var header = (HttpSysRequestHeader)HeaderKeys[i];
+            var header = HeaderKeys[i];
             if (HasKnownHeader(header))
             {
                 observedHeadersCount++;

+ 3 - 3
src/Shared/UrlDecoder/UrlDecoder.cs

@@ -603,8 +603,8 @@ internal sealed class UrlDecoder
         return (uint)c >= (uint)CharToHexLookup.Length ? -1 : CharToHexLookup[c];
     }
 
-    private static ReadOnlySpan<sbyte> CharToHexLookup => new sbyte[]
-    {
+    private static ReadOnlySpan<sbyte> CharToHexLookup =>
+    [
              -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, // 15
              -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, // 31
              -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, // 47
@@ -621,5 +621,5 @@ internal sealed class UrlDecoder
              -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, // 223
              -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, // 239
              -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  // 255
-    };
+    ];
 }

+ 0 - 1
src/SignalR/common/Http.Connections.Common/src/NegotiateProtocol.cs

@@ -37,7 +37,6 @@ public static class NegotiateProtocol
     private const string StatefulReconnectPropertyName = "useStatefulReconnect";
     private static readonly JsonEncodedText StatefulReconnectPropertyNameBytes = JsonEncodedText.Encode(StatefulReconnectPropertyName);
 
-    // Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
     // Used to detect ASP.NET SignalR Server connection attempt
     private static ReadOnlySpan<byte> ProtocolVersionPropertyNameBytes => "ProtocolVersion"u8;
 

Some files were not shown because too many files changed in this diff