Skip to content

Commit 927e173

Browse files
author
Ben Watson
committed
Add TryGetBuffer, remove buggy bounds check
Remove superfluous bounds checking. Add implementation of TryGetBuffer.
1 parent 0184606 commit 927e173

3 files changed

Lines changed: 42 additions & 28 deletions

File tree

UnitTests/Tests.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ public void GettingBlockAdjustsFreeAndInUseSize()
337337
}
338338
#endregion
339339

340-
#region GetBuffer Tests
340+
#region GetBuffer/TryGetBuffer Tests
341341
[Test]
342342
public void GetBufferReturnsSingleBlockForBlockSize()
343343
{
@@ -347,6 +347,7 @@ public void GetBufferReturnsSingleBlockForBlockSize()
347347
stream.Write(buffer, 0, buffer.Length);
348348
var returnedBuffer = stream.GetBuffer();
349349
Assert.That(returnedBuffer.Length, Is.EqualTo(stream.MemoryManager.BlockSize));
350+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
350351
}
351352

352353
[Test]
@@ -358,6 +359,7 @@ public void GetBufferReturnsSingleBlockForLessThanBlockSize()
358359
stream.Write(buffer, 0, buffer.Length);
359360
var returnedBuffer = stream.GetBuffer();
360361
Assert.That(returnedBuffer.Length, Is.EqualTo(stream.MemoryManager.BlockSize));
362+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
361363
}
362364

363365
[Test]
@@ -369,6 +371,7 @@ public void GetBufferReturnsLargeBufferForMoreThanBlockSize()
369371
stream.Write(buffer, 0, buffer.Length);
370372
var returnedBuffer = stream.GetBuffer();
371373
Assert.That(returnedBuffer.Length, Is.EqualTo(stream.MemoryManager.LargeBufferMultiple));
374+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
372375
}
373376

374377
[Test]
@@ -380,6 +383,7 @@ public void GetBufferReturnsSameLarge()
380383
var returnedBuffer = stream.GetBuffer();
381384
var returnedBuffer2 = stream.GetBuffer();
382385
Assert.That(returnedBuffer, Is.SameAs(returnedBuffer2));
386+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
383387
}
384388

385389
[Test]
@@ -392,6 +396,7 @@ public void GetBufferAdjustsLargePoolFreeSize()
392396
stream.Write(buffer, 0, buffer.Length);
393397

394398
var newBuffer = stream.GetBuffer();
399+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
395400

396401
stream.Dispose();
397402

@@ -403,6 +408,7 @@ public void GetBufferAdjustsLargePoolFreeSize()
403408
var newBuffer2 = newStream.GetBuffer();
404409
Assert.That(newBuffer2.Length, Is.EqualTo(newBuffer.Length));
405410
Assert.That(memMgr.LargePoolFreeSize, Is.EqualTo(0));
411+
RMSAssert.TryGetBufferEqualToGetBuffer(newStream);
406412
}
407413

408414
[Test]
@@ -422,6 +428,7 @@ public void CallingWriteAfterLargeGetBufferDoesNotLoseData()
422428
Assert.That(buffer[stream.MemoryManager.BlockSize], Is.EqualTo(13));
423429
RMSAssert.BuffersAreEqual(buffer, stream.MemoryManager.BlockSize + 1, bytesToWrite, 0, bytesToWrite.Length);
424430
Assert.That(stream.Position, Is.EqualTo(stream.MemoryManager.BlockSize + 1 + bytesToWrite.Length));
431+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
425432
}
426433

427434
[Test]
@@ -440,6 +447,7 @@ public void CallingWriteByteAfterLargeGetBufferDoesNotLoseData()
440447
Assert.That(buffer[stream.MemoryManager.BlockSize], Is.EqualTo(13));
441448
Assert.That(buffer[stream.MemoryManager.BlockSize + 1], Is.EqualTo(14));
442449
Assert.That(stream.Position, Is.EqualTo(stream.MemoryManager.BlockSize + 2));
450+
RMSAssert.TryGetBufferEqualToGetBuffer(stream);
443451
}
444452

445453
[Test]
@@ -2312,15 +2320,6 @@ protected virtual bool useExponentialLargeBuffer
23122320
get { return false; }
23132321
}
23142322

2315-
/*
2316-
* TODO: clocke to release logging libraries to enable some tests.
2317-
[TestFixtureSetUp]
2318-
public void Setup()
2319-
{
2320-
LogManager.Start();
2321-
}
2322-
*/
2323-
23242323
protected static class RMSAssert
23252324
{
23262325
/// <summary>
@@ -2371,6 +2370,16 @@ internal static void BuffersAreEqual(byte[] buffer1, int offset1, byte[] buffer2
23712370
Assert.That(rate, Is.AtMost(tolerance), "Too many errors. Buffers can differ to a tolerance of {0:F4}",
23722371
tolerance);
23732372
}
2373+
2374+
internal static void TryGetBufferEqualToGetBuffer(RecyclableMemoryStream stream)
2375+
{
2376+
var buffer = stream.GetBuffer();
2377+
ArraySegment<byte> segment;
2378+
Assert.That(stream.TryGetBuffer(out segment), Is.True);
2379+
Assert.That(segment.Offset, Is.Zero);
2380+
Assert.That(segment.Count, Is.EqualTo(stream.Length));
2381+
Assert.That(segment.Array, Is.SameAs(buffer));
2382+
}
23742383
}
23752384
}
23762385

src/Microsoft.IO.RecyclableMemoryStream.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFrameworks>netstandard1.4;netstandard2.1;net40;net45;netcoreapp2.1</TargetFrameworks>
3+
<TargetFrameworks>netstandard1.4;netstandard2.1;net40;net45;net46;netcoreapp2.1</TargetFrameworks>
44
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
55
</PropertyGroup>
66
<!-- for assembly signing we use a magic variable coupled with a special build definition which skips UTs -->

src/RecyclableMemoryStream.cs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,25 @@ public override byte[] GetBuffer()
452452
return this.largeBuffer;
453453
}
454454

455+
/// <summary>
456+
/// Returns an ArraySegment that wraps a single buffer containing the contents of the stream.
457+
/// </summary>
458+
/// <param name="buffer">An ArraySegment containing a reference to the underlying bytes.</param>
459+
/// <returns>Always returns true.</returns>
460+
/// <remarks>GetBuffer has no failure modes (it always returns something, even if it's an empty buffer), therefore this method
461+
/// always returns a valid ArraySegment to the same buffer returned by GetBuffer.</remarks>
462+
#if NET40 || NET45
463+
public bool TryGetBuffer(out ArraySegment<byte> buffer)
464+
#else
465+
public override bool TryGetBuffer(out ArraySegment<byte> buffer)
466+
#endif
467+
{
468+
this.CheckDisposed();
469+
buffer = new ArraySegment<byte>(this.GetBuffer(), 0, (int)this.Length);
470+
// GetBuffer has no failure modes, so this should always succeed
471+
return true;
472+
}
473+
455474
/// <summary>
456475
/// Returns a new array with a copy of the buffer's contents. You should almost certainly be using GetBuffer combined with the Length to
457476
/// access the bytes in this stream. Calling ToArray will destroy the benefits of pooled buffers, but it is included
@@ -601,13 +620,6 @@ public override void Write(byte[] buffer, int offset, int count)
601620
throw new IOException("Maximum capacity exceeded");
602621
}
603622

604-
long requiredBuffers = (end + blockSize - 1) / blockSize;
605-
606-
if (requiredBuffers * blockSize > MaxStreamLength)
607-
{
608-
throw new IOException("Maximum capacity exceeded");
609-
}
610-
611623
this.EnsureCapacity((int)end);
612624

613625
if (this.largeBuffer == null)
@@ -659,13 +671,6 @@ public override void Write(ReadOnlySpan<byte> source)
659671
throw new IOException("Maximum capacity exceeded");
660672
}
661673

662-
long requiredBuffers = (end + blockSize - 1) / blockSize;
663-
664-
if (requiredBuffers * blockSize > MaxStreamLength)
665-
{
666-
throw new IOException("Maximum capacity exceeded");
667-
}
668-
669674
this.EnsureCapacity((int)end);
670675

671676
if (this.largeBuffer == null)
@@ -850,9 +855,9 @@ public override void WriteTo(Stream stream)
850855
stream.Write(this.largeBuffer, 0, this.length);
851856
}
852857
}
853-
#endregion
858+
#endregion
854859

855-
#region Helper Methods
860+
#region Helper Methods
856861
private bool Disposed => Interlocked.Read(ref this.disposedState) != 0;
857862

858863
private void CheckDisposed()
@@ -1005,6 +1010,6 @@ private void ReleaseLargeBuffer()
10051010

10061011
this.largeBuffer = null;
10071012
}
1008-
#endregion
1013+
#endregion
10091014
}
10101015
}

0 commit comments

Comments
 (0)