Skip to content

Commit

Permalink
Merge pull request #6 from itn3000/add-bufferwriter
Browse files Browse the repository at this point in the history
Add bufferwriter
  • Loading branch information
itn3000 authored Feb 10, 2022
2 parents a1ec57f + cbb5a25 commit 45b2299
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 76 deletions.
47 changes: 47 additions & 0 deletions PooledStream.Test/TestPooledBufferWriter.cs
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);
}
}
}
17 changes: 14 additions & 3 deletions PooledStream.sln
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
Microsoft Visual Studio Solution File, Format Version 12.0
# Visual Studio Version 16
VisualStudioVersion = 16.0
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32002.185
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PooledStream.Benchmark", "PooledStream.Benchmark\PooledStream.Benchmark.csproj", "{41130469-5601-4C78-87DC-14574AD1EB0F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PooledStream.Test", "PooledStream.Test\PooledStream.Test.csproj", "{DA3F4EB2-D0F8-49C3-8A34-C86412EFC151}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PooledStream", "PooledStream\PooledStream.csproj", "{3C446344-2FF5-45F9-9010-3227F715B8A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{180A5C83-F82B-40F0-BCAF-F240679667EC}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AnyCPU = Debug|AnyCPU
Expand All @@ -27,4 +32,10 @@ Global
{3C446344-2FF5-45F9-9010-3227F715B8A9}.Release|AnyCPU.ActiveCfg = Debug|Any CPU
{3C446344-2FF5-45F9-9010-3227F715B8A9}.Release|AnyCPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F11B0785-81AF-4F25-9079-8A1432151A79}
EndGlobalSection
EndGlobal
164 changes: 164 additions & 0 deletions PooledStream/PooledBufferWriter.cs
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;
}
}
}
6 changes: 3 additions & 3 deletions PooledStream/PooledStream.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
<TargetFrameworks>netstandard2.1;netstandard1.1</TargetFrameworks>
<!-- <TargetFramework>netstandard2.1</TargetFramework> -->
<PackageId>PooledStream</PackageId>
<PackageVersion>0.2.1.2</PackageVersion>
<PackageVersion>0.3.0</PackageVersion>
<Authors>itn3000</Authors>
<Description>Efficient MemoryStream powered by System.Buffers.ArrayPool</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReleaseNotes>add netstandard2.1 to TargetFramework</PackageReleaseNotes>
<PackageReleaseNotes>add PooledMemoryBufferWriter</PackageReleaseNotes>
<Copyright>Copyright(c) 2017 itn3000. All rights reserved</Copyright>
<PackageTags>MemoryStream</PackageTags>
<PackageTags>MemoryStream;ArrayPool</PackageTags>
<PackageProjectUrl>https://github.com/itn3000/PooledStream/</PackageProjectUrl>
<RepositoryUrl>https://github.com/itn3000/PooledStream/</RepositoryUrl>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
Expand Down
Loading

0 comments on commit 45b2299

Please sign in to comment.