-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from itn3000/add-bufferwriter
Add bufferwriter
- Loading branch information
Showing
6 changed files
with
344 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Buffers; | ||
using Xunit; | ||
|
||
namespace PooledStream.Test | ||
{ | ||
public class TestPooledBufferWriter | ||
{ | ||
[Fact] | ||
public void Write() | ||
{ | ||
using var bw = new PooledMemoryBufferWriter<byte>(ArrayPool<byte>.Shared, 1024); | ||
var data = new byte[128]; | ||
for (int i = 0; i < 16; i++) | ||
{ | ||
data.AsSpan().Fill((byte)(i + 1)); | ||
var sp = bw.GetSpan(data.Length); | ||
data.AsSpan().CopyTo(sp); | ||
bw.Advance(data.Length); | ||
} | ||
var resultsp = bw.ToSpanUnsafe(); | ||
for (int i = 0; i < 16; i++) | ||
{ | ||
data.AsSpan().Fill((byte)(i + 1)); | ||
Assert.True(resultsp.Slice(i * 128, data.Length).SequenceEqual(data)); | ||
} | ||
} | ||
[Fact] | ||
public void Reset() | ||
{ | ||
using var bw = new PooledMemoryBufferWriter<byte>(); | ||
var sp = bw.GetSpan(128); | ||
sp.Fill(1); | ||
bw.Advance(128); | ||
var rsp = bw.ToSpanUnsafe(); | ||
Assert.Equal(128, rsp.Length); | ||
bw.Reset(); | ||
rsp = bw.ToSpanUnsafe(); | ||
Assert.Equal(0, rsp.Length); | ||
sp = bw.GetSpan(128); | ||
sp.Fill(2); | ||
bw.Advance(128); | ||
rsp = bw.ToSpanUnsafe(); | ||
Assert.Equal(128, rsp.Length); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace PooledStream | ||
{ | ||
public class PooledMemoryBufferWriter<T> : IDisposable, IBufferWriter<T> where T : struct | ||
{ | ||
ArrayPool<T> _Pool; | ||
T[] _currentBuffer; | ||
int _Position; | ||
int _Length; | ||
const int DefaultSize = 1024; | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
void Reallocate(int sizeHint) | ||
{ | ||
var nar = _Pool.Rent(sizeHint); | ||
if (_currentBuffer != null) | ||
{ | ||
Buffer.BlockCopy(_currentBuffer, 0, nar, 0, _currentBuffer.Length < nar.Length ? _currentBuffer.Length : nar.Length); | ||
_Pool.Return(_currentBuffer); | ||
} | ||
_currentBuffer = nar; | ||
} | ||
/// <summary> | ||
/// use shared instance and preallocatedSize = 1024 | ||
/// </summary> | ||
public PooledMemoryBufferWriter() : this(ArrayPool<T>.Shared) | ||
{ | ||
|
||
} | ||
/// <summary> | ||
/// use shared instance, use preallocateSize as reserved buffer length | ||
/// </summary> | ||
/// <param name="preallocateSize">initial reserved buffer size</param> | ||
public PooledMemoryBufferWriter(int preallocateSize) : this(ArrayPool<T>.Shared, preallocateSize) | ||
{ | ||
|
||
} | ||
/// <summary> | ||
/// use pool for memory pool | ||
/// </summary> | ||
/// <param name="pool">memory pool</param> | ||
public PooledMemoryBufferWriter(ArrayPool<T> pool) : this(pool, DefaultSize) | ||
{ | ||
} | ||
/// <summary> | ||
/// </summary> | ||
/// <param name="pool">memory pool</param> | ||
/// <param name="preallocateSize">initial reserved buffer size</param> | ||
public PooledMemoryBufferWriter(ArrayPool<T> pool, int preallocateSize) | ||
{ | ||
if(pool == null) | ||
{ | ||
throw new ArgumentNullException(nameof(pool)); | ||
} | ||
if(preallocateSize < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(preallocateSize), "size must be greater than 0"); | ||
} | ||
_Pool = pool; | ||
_currentBuffer = null; | ||
_Position = 0; | ||
_Length = 0; | ||
Reallocate(preallocateSize); | ||
} | ||
/// <inheritdoc/> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public void Advance(int count) | ||
{ | ||
if (_Position + count > _currentBuffer.Length) | ||
{ | ||
throw new ArgumentOutOfRangeException("advance too many(" + count.ToString() + ")"); | ||
} | ||
_Position += count; | ||
if (_Length < _Position) | ||
{ | ||
_Length = _Position; | ||
} | ||
} | ||
|
||
/// <summary>return buffer to pool and reset buffer status</summary> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public void Dispose() | ||
{ | ||
if (_currentBuffer != null) | ||
{ | ||
_Pool.Return(_currentBuffer); | ||
_currentBuffer = null; | ||
_Position = 0; | ||
_Length = 0; | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public Memory<T> GetMemory(int sizeHint = 0) | ||
{ | ||
if (sizeHint < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException("sizeHint", "size must be greater than 0"); | ||
} | ||
if (sizeHint == 0) | ||
{ | ||
sizeHint = DefaultSize; | ||
} | ||
if (_Position + sizeHint > _currentBuffer.Length) | ||
{ | ||
Reallocate(_Position + sizeHint); | ||
} | ||
return _currentBuffer.AsMemory(_Position, sizeHint); | ||
} | ||
/// <inheritdoc/> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public Span<T> GetSpan(int sizeHint = 0) | ||
{ | ||
if (sizeHint < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException("sizeHint", "size must be greater than 0"); | ||
} | ||
if (sizeHint == 0) | ||
{ | ||
sizeHint = DefaultSize; | ||
} | ||
if (_Position + sizeHint > _currentBuffer.Length) | ||
{ | ||
Reallocate(_Position + sizeHint); | ||
} | ||
return _currentBuffer.AsSpan(_Position, sizeHint); | ||
} | ||
/// <summary>expose current buffer as Span</summary> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlySpan<T> ToSpanUnsafe() | ||
{ | ||
return _currentBuffer.AsSpan(0, _Length); | ||
} | ||
/// <summary>expose current buffer as Memory</summary> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlyMemory<T> ToMemoryUnsafe() | ||
{ | ||
return _currentBuffer.AsMemory(0, _Length); | ||
} | ||
/// <summary>reset buffer status, buffer will be reallocated</summary> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public void Reset(int preallocateSize) | ||
{ | ||
if(preallocateSize < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException("preallocateSize", "size must be greater than 0"); | ||
} | ||
_Pool.Return(_currentBuffer); | ||
_currentBuffer = _Pool.Rent(preallocateSize); | ||
_Length = 0; | ||
_Position = 0; | ||
} | ||
/// <summary>reset buffer status, buffer will be reused</summary> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public void Reset() | ||
{ | ||
_Length = 0; | ||
_Position = 0; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.