@@ -17,10 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
17
17
{
18
18
internal static class StringUtilities
19
19
{
20
- private static readonly SpanAction < char , IntPtr > s_getAsciiOrUtf8StringNonNullCharacters = GetAsciiStringNonNullCharacters ;
21
-
22
- private static string GetAsciiOrUTF8StringNonNullCharacters ( this Span < byte > span , Encoding defaultEncoding )
23
- => GetAsciiOrUTF8StringNonNullCharacters ( ( ReadOnlySpan < byte > ) span , defaultEncoding ) ;
20
+ private static readonly SpanAction < char , IntPtr > s_getAsciiOrUTF8StringNonNullCharacters = GetAsciiStringNonNullCharactersWithMarker ;
24
21
25
22
public static unsafe string GetAsciiOrUTF8StringNonNullCharacters ( this ReadOnlySpan < byte > span , Encoding defaultEncoding )
26
23
{
@@ -31,7 +28,7 @@ public static unsafe string GetAsciiOrUTF8StringNonNullCharacters(this ReadOnlyS
31
28
32
29
fixed ( byte * source = & MemoryMarshal . GetReference ( span ) )
33
30
{
34
- var resultString = string . Create ( span . Length , new IntPtr ( source ) , s_getAsciiOrUtf8StringNonNullCharacters ) ;
31
+ var resultString = string . Create ( span . Length , ( IntPtr ) source , s_getAsciiOrUTF8StringNonNullCharacters ) ;
35
32
36
33
// If resultString is marked, perform UTF-8 encoding
37
34
if ( resultString [ 0 ] == '\0 ' )
@@ -56,11 +53,11 @@ public static unsafe string GetAsciiOrUTF8StringNonNullCharacters(this ReadOnlyS
56
53
}
57
54
}
58
55
59
- private static unsafe void GetAsciiStringNonNullCharacters ( Span < char > buffer , IntPtr state )
56
+ private static unsafe void GetAsciiStringNonNullCharactersWithMarker ( Span < char > buffer , IntPtr state )
60
57
{
61
58
fixed ( char * output = & MemoryMarshal . GetReference ( buffer ) )
62
59
{
63
- // This version if AsciiUtilities returns false if there are any null ('\0') or non-Ascii
60
+ // This version of AsciiUtilities returns false if there are any null ('\0') or non-Ascii
64
61
// character (> 127) in the string.
65
62
if ( ! TryGetAsciiString ( ( byte * ) state . ToPointer ( ) , output , buffer . Length ) )
66
63
{
@@ -70,27 +67,59 @@ private static unsafe void GetAsciiStringNonNullCharacters(Span<char> buffer, In
70
67
}
71
68
}
72
69
70
+ private static readonly SpanAction < char , IntPtr > s_getAsciiStringNonNullCharacters = GetAsciiStringNonNullCharacters ;
71
+
72
+ public static unsafe string GetAsciiStringNonNullCharacters ( this ReadOnlySpan < byte > span )
73
+ {
74
+ if ( span . IsEmpty )
75
+ {
76
+ return string . Empty ;
77
+ }
78
+
79
+ fixed ( byte * source = & MemoryMarshal . GetReference ( span ) )
80
+ {
81
+ return string . Create ( span . Length , ( IntPtr ) source , s_getAsciiStringNonNullCharacters ) ;
82
+ }
83
+ }
84
+
85
+ private static unsafe void GetAsciiStringNonNullCharacters ( Span < char > buffer , IntPtr state )
86
+ {
87
+ fixed ( char * output = & MemoryMarshal . GetReference ( buffer ) )
88
+ {
89
+ // This version of AsciiUtilities returns false if there are any null ('\0') or non-Ascii
90
+ // character (> 127) in the string.
91
+ if ( ! TryGetAsciiString ( ( byte * ) state . ToPointer ( ) , output , buffer . Length ) )
92
+ {
93
+ throw new InvalidOperationException ( ) ;
94
+ }
95
+ }
96
+ }
97
+
98
+ private static readonly SpanAction < char , IntPtr > s_getLatin1StringNonNullCharacters = GetLatin1StringNonNullCharacters ;
99
+
73
100
public static unsafe string GetLatin1StringNonNullCharacters ( this ReadOnlySpan < byte > span )
74
101
{
75
102
if ( span . IsEmpty )
76
103
{
77
104
return string . Empty ;
78
105
}
79
106
80
- var resultString = new string ( '\0 ' , span . Length ) ;
107
+ fixed ( byte * source = & MemoryMarshal . GetReference ( span ) )
108
+ {
109
+ return string . Create ( span . Length , ( IntPtr ) source , s_getLatin1StringNonNullCharacters ) ;
110
+ }
111
+ }
81
112
82
- fixed ( char * output = resultString )
83
- fixed ( byte * buffer = span )
113
+ private static unsafe void GetLatin1StringNonNullCharacters ( Span < char > buffer , IntPtr state )
114
+ {
115
+ fixed ( char * output = & MemoryMarshal . GetReference ( buffer ) )
84
116
{
85
- // This returns false if there are any null (0 byte) characters in the string.
86
- if ( ! TryGetLatin1String ( buffer , output , span . Length ) )
117
+ if ( ! TryGetLatin1String ( ( byte * ) state . ToPointer ( ) , output , buffer . Length ) )
87
118
{
88
119
// null characters are considered invalid
89
120
throw new InvalidOperationException ( ) ;
90
121
}
91
122
}
92
-
93
- return resultString ;
94
123
}
95
124
96
125
[ MethodImpl ( MethodImplOptions . AggressiveOptimization ) ]
@@ -299,7 +328,7 @@ public static unsafe bool TryGetLatin1String(byte* input, char* output, int coun
299
328
// If Vector not-accelerated or remaining less than vector size
300
329
if ( ! Vector . IsHardwareAccelerated || input > end - Vector < sbyte > . Count )
301
330
{
302
- if ( IntPtr . Size == 8 ) // Use Intrinsic switch for branch elimination
331
+ if ( Environment . Is64BitProcess ) // Use Intrinsic switch for branch elimination
303
332
{
304
333
// 64-bit: Loop longs by default
305
334
while ( input <= end - sizeof ( long ) )
@@ -403,10 +432,6 @@ public static bool BytesOrdinalEqualsStringAndAscii(string previousValue, ReadOn
403
432
goto NotEqual ;
404
433
}
405
434
406
- // Use IntPtr values rather than int, to avoid unnecessary 32 -> 64 movs on 64-bit.
407
- // Unfortunately this means we also need to cast to byte* for comparisons as IntPtr doesn't
408
- // support operator comparisons (e.g. <=, >, etc).
409
- //
410
435
// Note: Pointer comparison is unsigned, so we use the compare pattern (offset + length <= count)
411
436
// rather than (offset <= count - length) which we'd do with signed comparison to avoid overflow.
412
437
// This isn't problematic as we know the maximum length is max string length (from test above)
@@ -666,6 +691,7 @@ private static bool IsValidHeaderString(string value)
666
691
return false ;
667
692
}
668
693
}
694
+
669
695
private static readonly SpanAction < char , ( string ? str , char separator , uint number ) > s_populateSpanWithHexSuffix = PopulateSpanWithHexSuffix ;
670
696
671
697
/// <summary>
0 commit comments