@@ -9,8 +9,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
9
9
{
10
10
public static class MemoryPoolIterator2Extensions
11
11
{
12
- private const int _maxStackAllocBytes = 16384 ;
13
-
14
12
private static Encoding _utf8 = Encoding . UTF8 ;
15
13
16
14
public const string HttpConnectMethod = "CONNECT" ;
@@ -70,102 +68,110 @@ private unsafe static long GetAsciiStringAsLong(string str)
70
68
}
71
69
}
72
70
73
- private static unsafe string GetAsciiStringStack ( byte [ ] input , int inputOffset , int length )
71
+ public unsafe static string GetAsciiString ( this MemoryPoolIterator2 start , MemoryPoolIterator2 end )
74
72
{
75
- // avoid declaring other local vars, or doing work with stackalloc
76
- // to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
77
- char * output = stackalloc char [ length ] ;
78
-
79
- return GetAsciiStringImplementation ( output , input , inputOffset , length ) ;
80
- }
81
-
82
- private static unsafe string GetAsciiStringImplementation ( char * output , byte [ ] input , int inputOffset , int length )
83
- {
84
- for ( var i = 0 ; i < length ; i ++ )
73
+ if ( start . IsDefault || end . IsDefault )
85
74
{
86
- output [ i ] = ( char ) input [ inputOffset + i ] ;
75
+ return null ;
87
76
}
88
77
89
- return new string ( output , 0 , length ) ;
90
- }
91
-
92
- private static unsafe string GetAsciiStringStack ( MemoryPoolBlock2 start , MemoryPoolIterator2 end , int inputOffset , int length )
93
- {
94
- // avoid declaring other local vars, or doing work with stackalloc
95
- // to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
96
- char * output = stackalloc char [ length ] ;
97
-
98
- return GetAsciiStringImplementation ( output , start , end , inputOffset , length ) ;
99
- }
100
-
101
- private unsafe static string GetAsciiStringHeap ( MemoryPoolBlock2 start , MemoryPoolIterator2 end , int inputOffset , int length )
102
- {
103
- var buffer = new char [ length ] ;
78
+ var length = start . GetLength ( end ) ;
104
79
105
- fixed ( char * output = buffer )
80
+ if ( length == 0 )
106
81
{
107
- return GetAsciiStringImplementation ( output , start , end , inputOffset , length ) ;
82
+ return null ;
108
83
}
109
- }
110
84
111
- private static unsafe string GetAsciiStringImplementation ( char * output , MemoryPoolBlock2 start , MemoryPoolIterator2 end , int inputOffset , int length )
112
- {
113
- var outputOffset = 0 ;
114
- var block = start ;
115
- var remaining = length ;
85
+ // Bytes out of the range of ascii are treated as "opaque data"
86
+ // and kept in string as a char value that casts to same input byte value
87
+ // https://tools.ietf.org/html/rfc7230#section-3.2.4
116
88
117
- var endBlock = end . Block ;
118
- var endIndex = end . Index ;
89
+ var inputOffset = start . Index ;
90
+ var block = start . Block ;
119
91
120
- while ( true )
92
+ var asciiString = new string ( '\0 ' , length ) ;
93
+
94
+ fixed ( char * outputStart = asciiString )
121
95
{
122
- int following = ( block != endBlock ? block . End : endIndex ) - inputOffset ;
96
+ var output = outputStart ;
97
+ var remaining = length ;
123
98
124
- if ( following > 0 )
99
+ var endBlock = end . Block ;
100
+ var endIndex = end . Index ;
101
+
102
+ while ( true )
125
103
{
126
- var input = block . Array ;
127
- for ( var i = 0 ; i < following ; i ++ )
104
+ int following = ( block != endBlock ? block . End : endIndex ) - inputOffset ;
105
+
106
+ if ( following > 0 )
128
107
{
129
- output [ i + outputOffset ] = ( char ) input [ i + inputOffset ] ;
108
+ fixed ( byte * blockStart = block . Array )
109
+ {
110
+ var input = blockStart + inputOffset ;
111
+ var i = 0 ;
112
+ while ( i < following - 11 )
113
+ {
114
+ i += 12 ;
115
+ * ( output ) = ( char ) * ( input ) ;
116
+ * ( output + 1 ) = ( char ) * ( input + 1 ) ;
117
+ * ( output + 2 ) = ( char ) * ( input + 2 ) ;
118
+ * ( output + 3 ) = ( char ) * ( input + 3 ) ;
119
+ * ( output + 4 ) = ( char ) * ( input + 4 ) ;
120
+ * ( output + 5 ) = ( char ) * ( input + 5 ) ;
121
+ * ( output + 6 ) = ( char ) * ( input + 6 ) ;
122
+ * ( output + 7 ) = ( char ) * ( input + 7 ) ;
123
+ * ( output + 8 ) = ( char ) * ( input + 8 ) ;
124
+ * ( output + 9 ) = ( char ) * ( input + 9 ) ;
125
+ * ( output + 10 ) = ( char ) * ( input + 10 ) ;
126
+ * ( output + 11 ) = ( char ) * ( input + 11 ) ;
127
+ output += 12 ;
128
+ input += 12 ;
129
+ }
130
+ if ( i < following - 5 )
131
+ {
132
+ i += 6 ;
133
+ * ( output ) = ( char ) * ( input ) ;
134
+ * ( output + 1 ) = ( char ) * ( input + 1 ) ;
135
+ * ( output + 2 ) = ( char ) * ( input + 2 ) ;
136
+ * ( output + 3 ) = ( char ) * ( input + 3 ) ;
137
+ * ( output + 4 ) = ( char ) * ( input + 4 ) ;
138
+ * ( output + 5 ) = ( char ) * ( input + 5 ) ;
139
+ output += 6 ;
140
+ input += 6 ;
141
+ }
142
+ if ( i < following - 3 )
143
+ {
144
+ i += 4 ;
145
+ * ( output ) = ( char ) * ( input ) ;
146
+ * ( output + 1 ) = ( char ) * ( input + 1 ) ;
147
+ * ( output + 2 ) = ( char ) * ( input + 2 ) ;
148
+ * ( output + 3 ) = ( char ) * ( input + 3 ) ;
149
+ output += 4 ;
150
+ input += 4 ;
151
+ }
152
+ while ( i < following )
153
+ {
154
+ i++ ;
155
+ * output = ( char ) * input ;
156
+ output++ ;
157
+ input++ ;
158
+ }
159
+
160
+ remaining -= following;
161
+ }
130
162
}
131
163
132
- remaining -= following ;
133
- outputOffset += following ;
134
- }
164
+ if ( remaining == 0 )
165
+ {
166
+ break ;
167
+ }
135
168
136
- if ( remaining == 0 )
137
- {
138
- return new string ( output , 0 , length ) ;
169
+ block = block. Next ;
170
+ inputOffset = block . Start ;
139
171
}
140
-
141
- block = block . Next ;
142
- inputOffset = block . Start ;
143
- }
144
- }
145
-
146
- public static string GetAsciiString ( this MemoryPoolIterator2 start , MemoryPoolIterator2 end )
147
- {
148
- if ( start . IsDefault || end . IsDefault )
149
- {
150
- return default ( string ) ;
151
- }
152
-
153
- var length = start . GetLength ( end ) ;
154
-
155
- // Bytes out of the range of ascii are treated as "opaque data"
156
- // and kept in string as a char value that casts to same input byte value
157
- // https://tools.ietf.org/html/rfc7230#section-3.2.4
158
- if ( end . Block == start . Block )
159
- {
160
- return GetAsciiStringStack ( start . Block . Array , start . Index , length ) ;
161
- }
162
-
163
- if ( length > _maxStackAllocBytes )
164
- {
165
- return GetAsciiStringHeap ( start . Block , end , start . Index , length ) ;
166
172
}
167
173
168
- return GetAsciiStringStack ( start . Block , end , start . Index , length ) ;
174
+ return asciiString ;
169
175
}
170
176
171
177
public static string GetUtf8String ( this MemoryPoolIterator2 start , MemoryPoolIterator2 end )
0 commit comments