5
5
using System . Buffers ;
6
6
using System . Collections . Generic ;
7
7
using System . Runtime . CompilerServices ;
8
+ using System . Runtime . InteropServices ;
8
9
using System . Runtime . Intrinsics ;
9
10
using System . Runtime . Intrinsics . X86 ;
10
11
using Microsoft . AspNetCore . Internal ;
@@ -111,16 +112,8 @@ public IQueryCollection Query
111
112
return null ;
112
113
}
113
114
114
- KvpAccumulator accumulator = new ( ) ;
115
- var queryStringLength = queryString . Length ;
116
-
117
- char [ ] ? arryToReturnToPool = null ;
118
- Span < char > query = ( queryStringLength <= 128
119
- ? stackalloc char [ 128 ]
120
- : arryToReturnToPool = ArrayPool < char > . Shared . Rent ( queryStringLength )
121
- ) . Slice ( 0 , queryStringLength ) ;
122
-
123
- queryString . AsSpan ( ) . CopyTo ( query ) ;
115
+ var accumulator = new KvpAccumulator ( ) ;
116
+ var query = queryString . AsSpan ( ) ;
124
117
125
118
if ( query [ 0 ] == '?' )
126
119
{
@@ -148,15 +141,12 @@ public IQueryCollection Query
148
141
}
149
142
}
150
143
151
- var name = querySegment [ i ..equalIndex ] ;
152
- var value = querySegment . Slice ( equalIndex + 1 ) ;
153
-
154
- SpanHelper . ReplacePlusWithSpaceInPlace ( name ) ;
155
- SpanHelper . ReplacePlusWithSpaceInPlace ( value ) ;
144
+ var name = SpanHelper . ReplacePlusWithSpace ( querySegment [ i ..equalIndex ] ) ;
145
+ var value = SpanHelper . ReplacePlusWithSpace ( querySegment . Slice ( equalIndex + 1 ) ) ;
156
146
157
147
accumulator . Append (
158
- Uri . UnescapeDataString ( name . ToString ( ) ) ,
159
- Uri . UnescapeDataString ( value . ToString ( ) ) ) ;
148
+ Uri . UnescapeDataString ( name ) ,
149
+ Uri . UnescapeDataString ( value ) ) ;
160
150
}
161
151
else
162
152
{
@@ -174,17 +164,9 @@ public IQueryCollection Query
174
164
query = query . Slice ( delimiterIndex + 1 ) ;
175
165
}
176
166
177
- if ( arryToReturnToPool is not null )
178
- {
179
- ArrayPool < char > . Shared . Return ( arryToReturnToPool ) ;
180
- }
181
-
182
- if ( ! accumulator . HasValues )
183
- {
184
- return null ;
185
- }
186
-
187
- return accumulator . GetResults ( ) ;
167
+ return accumulator . HasValues
168
+ ? accumulator . GetResults ( )
169
+ : null ;
188
170
}
189
171
190
172
internal struct KvpAccumulator
@@ -288,40 +270,51 @@ public AdaptiveCapacityDictionary<string, StringValues> GetResults()
288
270
289
271
private static class SpanHelper
290
272
{
291
- public static void ReplacePlusWithSpaceInPlace ( Span < char > span )
292
- => ReplaceInPlace ( span , '+' , ' ' ) ;
273
+ private static readonly SpanAction < char , IntPtr > s_replacePlusWithSpace = ReplacePlusWithSpaceCore ;
293
274
294
275
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
295
- public static unsafe void ReplaceInPlace ( Span < char > span , char oldChar , char newChar )
276
+ public static unsafe string ReplacePlusWithSpace ( ReadOnlySpan < char > span )
296
277
{
297
- var i = ( nint ) 0 ;
298
- var n = ( nint ) ( uint ) span . Length ;
278
+ fixed ( char * ptr = & MemoryMarshal . GetReference ( span ) )
279
+ {
280
+ return string . Create ( span . Length , ( IntPtr ) ptr , s_replacePlusWithSpace ) ;
281
+ }
282
+ }
299
283
300
- fixed ( char * ptr = span )
284
+ private static unsafe void ReplacePlusWithSpaceCore ( Span < char > buffer , IntPtr state )
285
+ {
286
+ fixed ( char * ptr = & MemoryMarshal . GetReference ( buffer ) )
301
287
{
302
- var pVec = ( ushort * ) ptr ;
288
+ var input = ( ushort * ) state . ToPointer ( ) ;
289
+ var output = ( ushort * ) ptr ;
290
+
291
+ var i = ( nint ) 0 ;
292
+ var n = ( nint ) ( uint ) buffer . Length ;
303
293
304
294
if ( Sse41 . IsSupported && n >= Vector128 < ushort > . Count )
305
295
{
306
- var vecOldChar = Vector128 . Create ( ( ushort ) oldChar ) ;
307
- var vecNewChar = Vector128 . Create ( ( ushort ) newChar ) ;
296
+ var vecPlus = Vector128 . Create ( ( ushort ) '+' ) ;
297
+ var vecSpace = Vector128 . Create ( ( ushort ) ' ' ) ;
308
298
309
299
do
310
300
{
311
- var vec = Sse2 . LoadVector128 ( pVec + i ) ;
312
- var mask = Sse2 . CompareEqual ( vec , vecOldChar ) ;
313
- var res = Sse41 . BlendVariable ( vec , vecNewChar , mask ) ;
314
- Sse2 . Store ( pVec + i , res ) ;
315
-
301
+ var vec = Sse2 . LoadVector128 ( input + i ) ;
302
+ var mask = Sse2 . CompareEqual ( vec , vecPlus ) ;
303
+ var res = Sse41 . BlendVariable ( vec , vecSpace , mask ) ;
304
+ Sse2 . Store ( output + i , res ) ;
316
305
i += Vector128 < ushort > . Count ;
317
306
} while ( i <= n - Vector128 < ushort > . Count ) ;
318
307
}
319
308
320
309
for ( ; i < n ; ++ i )
321
310
{
322
- if ( ptr [ i ] == oldChar )
311
+ if ( input [ i ] != '+' )
312
+ {
313
+ output [ i ] = input [ i ] ;
314
+ }
315
+ else
323
316
{
324
- ptr [ i ] = newChar ;
317
+ output [ i ] = ' ' ;
325
318
}
326
319
}
327
320
}
0 commit comments