3
3
4
4
using System ;
5
5
using System . Buffers ;
6
+ using System . Diagnostics ;
6
7
using System . IO ;
8
+ using System . Runtime . CompilerServices ;
7
9
using System . Text ;
8
10
using System . Threading . Tasks ;
9
11
@@ -150,33 +152,65 @@ public override void Write(string value)
150
152
}
151
153
}
152
154
153
- public override async Task WriteAsync ( char value )
155
+ public override Task WriteAsync ( char value )
154
156
{
155
157
if ( _disposed )
156
158
{
157
- throw new ObjectDisposedException ( nameof ( HttpResponseStreamWriter ) ) ;
159
+ return GetObjectDisposedTask ( ) ;
158
160
}
159
161
160
162
if ( _charBufferCount == _charBufferSize )
161
163
{
162
- await FlushInternalAsync ( flushEncoder : false ) ;
164
+ return WriteAsyncAwaited ( value ) ;
165
+ }
166
+ else
167
+ {
168
+ // Enough room in buffer, no need to go async
169
+ _charBuffer [ _charBufferCount ] = value ;
170
+ _charBufferCount ++ ;
171
+ return Task . CompletedTask ;
163
172
}
173
+ }
174
+
175
+ private async Task WriteAsyncAwaited ( char value )
176
+ {
177
+ Debug . Assert ( _charBufferCount == _charBufferSize ) ;
178
+
179
+ await FlushInternalAsync ( flushEncoder : false ) ;
164
180
165
181
_charBuffer [ _charBufferCount ] = value ;
166
182
_charBufferCount ++ ;
167
183
}
168
184
169
- public override async Task WriteAsync ( char [ ] values , int index , int count )
185
+ public override Task WriteAsync ( char [ ] values , int index , int count )
170
186
{
171
187
if ( _disposed )
172
188
{
173
- throw new ObjectDisposedException ( nameof ( HttpResponseStreamWriter ) ) ;
189
+ return GetObjectDisposedTask ( ) ;
174
190
}
175
191
176
- if ( values == null )
192
+ if ( values == null || count == 0 )
177
193
{
178
- return ;
194
+ return Task . CompletedTask ;
195
+ }
196
+
197
+ var remaining = _charBufferSize - _charBufferCount ;
198
+ if ( remaining >= count )
199
+ {
200
+ // Enough room in buffer, no need to go async
201
+ CopyToCharBuffer ( values , ref index , ref count ) ;
202
+ return Task . CompletedTask ;
179
203
}
204
+ else
205
+ {
206
+ return WriteAsyncAwaited ( values , index , count ) ;
207
+ }
208
+ }
209
+
210
+ private async Task WriteAsyncAwaited ( char [ ] values , int index , int count )
211
+ {
212
+ Debug . Assert ( count > 0 ) ;
213
+ Debug . Assert ( _charBufferSize - _charBufferCount > count ) ;
180
214
181
215
while ( count > 0 )
182
216
{
@@ -186,22 +220,43 @@ public override async Task WriteAsync(char[] values, int index, int count)
186
220
}
187
221
188
222
CopyToCharBuffer ( values , ref index , ref count ) ;
223
+ Debug . Assert ( count == 0 ) ;
189
224
}
190
225
}
191
226
192
- public override async Task WriteAsync ( string value )
227
+ public override Task WriteAsync ( string value )
193
228
{
194
229
if ( _disposed )
195
230
{
196
- throw new ObjectDisposedException ( nameof ( HttpResponseStreamWriter ) ) ;
231
+ return GetObjectDisposedTask ( ) ;
197
232
}
198
233
199
- if ( value == null )
234
+ var count = value ? . Length ?? 0 ;
235
+ if ( count == 0 )
200
236
{
201
- return ;
237
+ return Task . CompletedTask ;
202
238
}
203
239
240
+ var remaining = _charBufferSize - _charBufferCount ;
241
+ if ( remaining >= count )
242
+ {
243
+ // Enough room in buffer, no need to go async
244
+ CopyToCharBuffer ( value ) ;
245
+ return Task . CompletedTask ;
246
+ }
247
+ else
248
+ {
249
+ return WriteAsyncAwaited ( value ) ;
250
+ }
251
+ }
252
+
253
+ private async Task WriteAsyncAwaited ( string value )
254
+ {
204
255
var count = value . Length ;
256
+
257
+ Debug . Assert ( count > 0 ) ;
258
+ Debug . Assert ( _charBufferSize - _charBufferCount < count ) ;
259
+
205
260
var index = 0 ;
206
261
while ( count > 0 )
207
262
{
@@ -231,7 +286,7 @@ public override Task FlushAsync()
231
286
{
232
287
if ( _disposed )
233
288
{
234
- throw new ObjectDisposedException ( nameof ( HttpResponseStreamWriter ) ) ;
289
+ return GetObjectDisposedTask ( ) ;
235
290
}
236
291
237
292
return FlushInternalAsync ( flushEncoder : true ) ;
@@ -306,6 +361,19 @@ private async Task FlushInternalAsync(bool flushEncoder)
306
361
}
307
362
}
308
363
364
+ private void CopyToCharBuffer ( string value )
365
+ {
366
+ Debug . Assert ( _charBufferSize - _charBufferCount >= value . Length ) ;
367
+
368
+ value . CopyTo (
369
+ sourceIndex : 0 ,
370
+ destination : _charBuffer ,
371
+ destinationIndex : _charBufferCount ,
372
+ count : value . Length ) ;
373
+
374
+ _charBufferCount += value . Length ;
375
+ }
376
+
309
377
private void CopyToCharBuffer ( string value , ref int index , ref int count )
310
378
{
311
379
var remaining = Math . Min ( _charBufferSize - _charBufferCount , count ) ;
@@ -336,5 +404,11 @@ private void CopyToCharBuffer(char[] values, ref int index, ref int count)
336
404
index += remaining ;
337
405
count -= remaining ;
338
406
}
407
+
408
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
409
+ private static Task GetObjectDisposedTask ( )
410
+ {
411
+ return Task . FromException ( new ObjectDisposedException ( nameof ( HttpResponseStreamWriter ) ) ) ;
412
+ }
339
413
}
340
414
}
0 commit comments