Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 75d5652

Browse files
authored
Use TryGetBuffer instead of GetBuffer and catching exceptions (#530)
* Use TryGetBuffer instead of GetBuffer and catching exceptions Should be way faster * Address comments
1 parent ab1c9dc commit 75d5652

File tree

1 file changed

+93
-44
lines changed

1 file changed

+93
-44
lines changed

src/ServiceStack.Text/StreamExtensions.cs

Lines changed: 93 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public static byte[] ReadFully(this Stream input, byte[] buffer)
119119
/// <summary>
120120
/// Reads the given stream up to the end, returning the MemoryStream Buffer as ReadOnlyMemory&lt;byte&gt;.
121121
/// </summary>
122-
public static ReadOnlyMemory<byte> ReadFullyAsMemory(this Stream input) =>
122+
public static ReadOnlyMemory<byte> ReadFullyAsMemory(this Stream input) =>
123123
ReadFullyAsMemory(input, DefaultBufferSize);
124124

125125
/// <summary>
@@ -176,8 +176,8 @@ public static long CopyTo(this Stream input, Stream output, int bufferSize)
176176
}
177177

178178
/// <summary>
179-
/// Copies all the data from one stream into another, using the given
180-
/// buffer for transferring data. Note that the current contents of
179+
/// Copies all the data from one stream into another, using the given
180+
/// buffer for transferring data. Note that the current contents of
181181
/// the buffer is ignored, so the buffer needn't be cleared beforehand.
182182
/// </summary>
183183
public static long CopyTo(this Stream input, Stream output, byte[] buffer)
@@ -313,18 +313,18 @@ public static byte[] Combine(this byte[] bytes, params byte[][] withBytes)
313313
public static int AsyncBufferSize = 81920; // CopyToAsync() default value
314314

315315
[MethodImpl(MethodImplOptions.AggressiveInlining)]
316-
public static Task WriteAsync(this Stream stream, ReadOnlyMemory<byte> value, CancellationToken token = default) =>
316+
public static Task WriteAsync(this Stream stream, ReadOnlyMemory<byte> value, CancellationToken token = default) =>
317317
MemoryProvider.Instance.WriteAsync(stream, value, token);
318318

319319
[MethodImpl(MethodImplOptions.AggressiveInlining)]
320-
public static Task WriteAsync(this Stream stream, byte[] bytes, CancellationToken token = default) =>
320+
public static Task WriteAsync(this Stream stream, byte[] bytes, CancellationToken token = default) =>
321321
MemoryProvider.Instance.WriteAsync(stream, bytes, token);
322322

323323
[MethodImpl(MethodImplOptions.AggressiveInlining)]
324324
public static Task CopyToAsync(this Stream input, Stream output, CancellationToken token = default) => input.CopyToAsync(output, AsyncBufferSize, token);
325325

326326
[MethodImpl(MethodImplOptions.AggressiveInlining)]
327-
public static Task WriteAsync(this Stream stream, string text, CancellationToken token = default) =>
327+
public static Task WriteAsync(this Stream stream, string text, CancellationToken token = default) =>
328328
MemoryProvider.Instance.WriteAsync(stream, text.AsSpan(), token);
329329

330330
public static string ToMd5Hash(this Stream stream)
@@ -361,78 +361,118 @@ public static MemoryStream InMemoryStream(this byte[] bytes)
361361
public static string ReadToEnd(this MemoryStream ms, Encoding encoding)
362362
{
363363
ms.Position = 0;
364+
365+
#if NETSTANDARD || NETCORE2_1
366+
if (ms.TryGetBuffer(out var buffer))
367+
{
368+
return encoding.GetString(buffer.Array, buffer.Offset, buffer.Count);
369+
}
370+
#else
364371
try
365372
{
366-
var ret = encoding.GetString(ms.GetBuffer(), 0, (int) ms.Length);
367-
return ret;
373+
return encoding.GetString(ms.GetBuffer(), 0, (int) ms.Length);
368374
}
369375
catch (UnauthorizedAccessException)
370376
{
371-
Tracer.Instance.WriteWarning("MemoryStream wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
372-
373-
using (var reader = new StreamReader(ms, encoding, true, DefaultBufferSize, leaveOpen:true))
374-
{
375-
return reader.ReadToEnd();
376-
}
377+
}
378+
#endif
379+
380+
Tracer.Instance.WriteWarning("MemoryStream wasn't created with a publiclyVisible:true byte[] buffer, falling back to slow impl");
381+
382+
using (var reader = new StreamReader(ms, encoding, true, DefaultBufferSize, leaveOpen: true))
383+
{
384+
return reader.ReadToEnd();
377385
}
378386
}
379387

380388
public static ReadOnlyMemory<byte> GetBufferAsMemory(this MemoryStream ms)
381389
{
390+
#if NETSTANDARD || NETCORE2_1
391+
if (ms.TryGetBuffer(out var buffer))
392+
{
393+
return new ReadOnlyMemory<byte>(buffer.Array, buffer.Offset, buffer.Count);
394+
}
395+
#else
382396
try
383397
{
384-
return new ReadOnlyMemory<byte>(ms.GetBuffer(), 0, (int)ms.Length);
398+
return new ReadOnlyMemory<byte>(ms.GetBuffer(), 0, (int) ms.Length);
385399
}
386400
catch (UnauthorizedAccessException)
387401
{
388-
Tracer.Instance.WriteWarning("MemoryStream in GetBufferAsSpan() wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
389-
return new ReadOnlyMemory<byte>(ms.ToArray());
390402
}
403+
#endif
404+
405+
Tracer.Instance.WriteWarning("MemoryStream in GetBufferAsSpan() wasn't created with a publiclyVisible:true byte[] buffer, falling back to slow impl");
406+
return new ReadOnlyMemory<byte>(ms.ToArray());
391407
}
392408

393409
public static ReadOnlySpan<byte> GetBufferAsSpan(this MemoryStream ms)
394410
{
411+
#if NETSTANDARD || NETCORE2_1
412+
if (ms.TryGetBuffer(out var buffer))
413+
{
414+
return new ReadOnlySpan<byte>(buffer.Array, buffer.Offset, buffer.Count);
415+
}
416+
#else
395417
try
396418
{
397-
return new ReadOnlySpan<byte>(ms.GetBuffer(), 0, (int)ms.Length);
419+
return new ReadOnlySpan<byte>(ms.GetBuffer(), 0, (int) ms.Length);
398420
}
399421
catch (UnauthorizedAccessException)
400422
{
401-
Tracer.Instance.WriteWarning("MemoryStream in GetBufferAsSpan() wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
402-
return new ReadOnlySpan<byte>(ms.ToArray());
403423
}
424+
#endif
425+
426+
Tracer.Instance.WriteWarning("MemoryStream in GetBufferAsSpan() wasn't created with a publiclyVisible:true byte[] buffer, falling back to slow impl");
427+
return new ReadOnlySpan<byte>(ms.ToArray());
404428
}
405429

406430
public static byte[] GetBufferAsBytes(this MemoryStream ms)
407431
{
432+
#if NETSTANDARD || NETCORE2_1
433+
if (ms.TryGetBuffer(out var buffer))
434+
{
435+
return buffer.Array;
436+
}
437+
#else
408438
try
409439
{
410440
return ms.GetBuffer();
411441
}
412442
catch (UnauthorizedAccessException)
413443
{
414-
Tracer.Instance.WriteWarning("MemoryStream in GetBufferAsBytes() wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
415-
return ms.ToArray();
416444
}
445+
#endif
446+
447+
Tracer.Instance.WriteWarning("MemoryStream in GetBufferAsBytes() wasn't created with a publiclyVisible:true byte[] buffer, falling back to slow impl");
448+
return ms.ToArray();
417449
}
418450

419451
public static Task<string> ReadToEndAsync(this MemoryStream ms) => ReadToEndAsync(ms, JsConfig.UTF8Encoding);
420452
public static Task<string> ReadToEndAsync(this MemoryStream ms, Encoding encoding)
421453
{
422454
ms.Position = 0;
455+
456+
#if NETSTANDARD || NETCORE2_1
457+
if (ms.TryGetBuffer(out var buffer))
458+
{
459+
return encoding.GetString(buffer.Array, buffer.Offset, buffer.Count).InTask();
460+
}
461+
#else
423462
try
424463
{
425-
var ret = encoding.GetString(ms.GetBuffer(), 0, (int) ms.Length);
426-
return ret.InTask();
464+
return encoding.GetString(ms.GetBuffer(), 0, (int) ms.Length).InTask();
427465
}
428466
catch (UnauthorizedAccessException)
429467
{
430-
Tracer.Instance.WriteWarning("MemoryStream in ReadToEndAsync() wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
431-
432-
using (var reader = new StreamReader(ms, encoding, true, DefaultBufferSize, leaveOpen:true))
433-
{
434-
return reader.ReadToEndAsync();
435-
}
468+
}
469+
#endif
470+
471+
Tracer.Instance.WriteWarning("MemoryStream in ReadToEndAsync() wasn't created with a publiclyVisible:true byte[] buffer, falling back to slow impl");
472+
473+
using (var reader = new StreamReader(ms, encoding, true, DefaultBufferSize, leaveOpen: true))
474+
{
475+
return reader.ReadToEndAsync();
436476
}
437477
}
438478

@@ -446,7 +486,7 @@ public static string ReadToEnd(this Stream stream, Encoding encoding)
446486
{
447487
stream.Position = 0;
448488
}
449-
489+
450490
using (var reader = new StreamReader(stream, encoding, true, DefaultBufferSize, leaveOpen:true))
451491
{
452492
return reader.ReadToEnd();
@@ -463,40 +503,49 @@ public static Task<string> ReadToEndAsync(this Stream stream, Encoding encoding)
463503
{
464504
stream.Position = 0;
465505
}
466-
506+
467507
using (var reader = new StreamReader(stream, encoding, true, DefaultBufferSize, leaveOpen:true))
468508
{
469509
return reader.ReadToEndAsync();
470510
}
471511
}
472512

473-
public static Task WriteToAsync(this MemoryStream stream, Stream output, CancellationToken token=default(CancellationToken)) =>
513+
public static Task WriteToAsync(this MemoryStream stream, Stream output, CancellationToken token=default(CancellationToken)) =>
474514
WriteToAsync(stream, output, JsConfig.UTF8Encoding, token);
475-
515+
476516
public static async Task WriteToAsync(this MemoryStream stream, Stream output, Encoding encoding, CancellationToken token)
477517
{
518+
#if NETSTANDARD || NETCORE2_1
519+
if (stream.TryGetBuffer(out var buffer))
520+
{
521+
await output.WriteAsync(buffer.Array, buffer.Offset, buffer.Count, token).ConfigAwait();
522+
return;
523+
}
524+
#else
478525
try
479526
{
480527
await output.WriteAsync(stream.GetBuffer(), 0, (int) stream.Length, token).ConfigAwait();
528+
return;
481529
}
482530
catch (UnauthorizedAccessException)
483531
{
484-
Tracer.Instance.WriteWarning("MemoryStream in WriteToAsync() wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
485-
486-
var bytes = stream.ToArray();
487-
await output.WriteAsync(bytes, 0, bytes.Length, token).ConfigAwait();
488532
}
533+
#endif
534+
Tracer.Instance.WriteWarning("MemoryStream in WriteToAsync() wasn't created with a publiclyVisible:true byte[] bufffer, falling back to slow impl");
535+
536+
var bytes = stream.ToArray();
537+
await output.WriteAsync(bytes, 0, bytes.Length, token).ConfigAwait();
489538
}
490-
491-
public static Task WriteToAsync(this Stream stream, Stream output, CancellationToken token=default(CancellationToken)) =>
539+
540+
public static Task WriteToAsync(this Stream stream, Stream output, CancellationToken token=default(CancellationToken)) =>
492541
WriteToAsync(stream, output, JsConfig.UTF8Encoding, token);
493-
494-
542+
543+
495544
public static Task WriteToAsync(this Stream stream, Stream output, Encoding encoding, CancellationToken token)
496545
{
497546
if (stream is MemoryStream ms)
498547
return ms.WriteToAsync(output, encoding, token);
499-
548+
500549
return stream.CopyToAsync(output, token);
501550
}
502551

@@ -516,4 +565,4 @@ public static async Task<MemoryStream> CopyToNewMemoryStreamAsync(this Stream st
516565
return ms;
517566
}
518567
}
519-
}
568+
}

0 commit comments

Comments
 (0)