Skip to content

Commit 45b2299

Browse files
authored
Merge pull request #6 from itn3000/add-bufferwriter
Add bufferwriter
2 parents a1ec57f + cbb5a25 commit 45b2299

6 files changed

Lines changed: 344 additions & 76 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Buffers;
3+
using Xunit;
4+
5+
namespace PooledStream.Test
6+
{
7+
public class TestPooledBufferWriter
8+
{
9+
[Fact]
10+
public void Write()
11+
{
12+
using var bw = new PooledMemoryBufferWriter<byte>(ArrayPool<byte>.Shared, 1024);
13+
var data = new byte[128];
14+
for (int i = 0; i < 16; i++)
15+
{
16+
data.AsSpan().Fill((byte)(i + 1));
17+
var sp = bw.GetSpan(data.Length);
18+
data.AsSpan().CopyTo(sp);
19+
bw.Advance(data.Length);
20+
}
21+
var resultsp = bw.ToSpanUnsafe();
22+
for (int i = 0; i < 16; i++)
23+
{
24+
data.AsSpan().Fill((byte)(i + 1));
25+
Assert.True(resultsp.Slice(i * 128, data.Length).SequenceEqual(data));
26+
}
27+
}
28+
[Fact]
29+
public void Reset()
30+
{
31+
using var bw = new PooledMemoryBufferWriter<byte>();
32+
var sp = bw.GetSpan(128);
33+
sp.Fill(1);
34+
bw.Advance(128);
35+
var rsp = bw.ToSpanUnsafe();
36+
Assert.Equal(128, rsp.Length);
37+
bw.Reset();
38+
rsp = bw.ToSpanUnsafe();
39+
Assert.Equal(0, rsp.Length);
40+
sp = bw.GetSpan(128);
41+
sp.Fill(2);
42+
bw.Advance(128);
43+
rsp = bw.ToSpanUnsafe();
44+
Assert.Equal(128, rsp.Length);
45+
}
46+
}
47+
}

PooledStream.sln

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
Microsoft Visual Studio Solution File, Format Version 12.0
2-
# Visual Studio Version 16
3-
VisualStudioVersion = 16.0
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio Version 17
3+
VisualStudioVersion = 17.0.32002.185
44
MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PooledStream.Benchmark", "PooledStream.Benchmark\PooledStream.Benchmark.csproj", "{41130469-5601-4C78-87DC-14574AD1EB0F}"
66
EndProject
77
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PooledStream.Test", "PooledStream.Test\PooledStream.Test.csproj", "{DA3F4EB2-D0F8-49C3-8A34-C86412EFC151}"
88
EndProject
99
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PooledStream", "PooledStream\PooledStream.csproj", "{3C446344-2FF5-45F9-9010-3227F715B8A9}"
1010
EndProject
11+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{180A5C83-F82B-40F0-BCAF-F240679667EC}"
12+
ProjectSection(SolutionItems) = preProject
13+
README.md = README.md
14+
EndProjectSection
15+
EndProject
1116
Global
1217
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1318
Debug|AnyCPU = Debug|AnyCPU
@@ -27,4 +32,10 @@ Global
2732
{3C446344-2FF5-45F9-9010-3227F715B8A9}.Release|AnyCPU.ActiveCfg = Debug|Any CPU
2833
{3C446344-2FF5-45F9-9010-3227F715B8A9}.Release|AnyCPU.Build.0 = Debug|Any CPU
2934
EndGlobalSection
35+
GlobalSection(SolutionProperties) = preSolution
36+
HideSolutionNode = FALSE
37+
EndGlobalSection
38+
GlobalSection(ExtensibilityGlobals) = postSolution
39+
SolutionGuid = {F11B0785-81AF-4F25-9079-8A1432151A79}
40+
EndGlobalSection
3041
EndGlobal

PooledStream/PooledBufferWriter.cs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Runtime.CompilerServices;
4+
5+
namespace PooledStream
6+
{
7+
public class PooledMemoryBufferWriter<T> : IDisposable, IBufferWriter<T> where T : struct
8+
{
9+
ArrayPool<T> _Pool;
10+
T[] _currentBuffer;
11+
int _Position;
12+
int _Length;
13+
const int DefaultSize = 1024;
14+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
15+
void Reallocate(int sizeHint)
16+
{
17+
var nar = _Pool.Rent(sizeHint);
18+
if (_currentBuffer != null)
19+
{
20+
Buffer.BlockCopy(_currentBuffer, 0, nar, 0, _currentBuffer.Length < nar.Length ? _currentBuffer.Length : nar.Length);
21+
_Pool.Return(_currentBuffer);
22+
}
23+
_currentBuffer = nar;
24+
}
25+
/// <summary>
26+
/// use shared instance and preallocatedSize = 1024
27+
/// </summary>
28+
public PooledMemoryBufferWriter() : this(ArrayPool<T>.Shared)
29+
{
30+
31+
}
32+
/// <summary>
33+
/// use shared instance, use preallocateSize as reserved buffer length
34+
/// </summary>
35+
/// <param name="preallocateSize">initial reserved buffer size</param>
36+
public PooledMemoryBufferWriter(int preallocateSize) : this(ArrayPool<T>.Shared, preallocateSize)
37+
{
38+
39+
}
40+
/// <summary>
41+
/// use pool for memory pool
42+
/// </summary>
43+
/// <param name="pool">memory pool</param>
44+
public PooledMemoryBufferWriter(ArrayPool<T> pool) : this(pool, DefaultSize)
45+
{
46+
}
47+
/// <summary>
48+
/// </summary>
49+
/// <param name="pool">memory pool</param>
50+
/// <param name="preallocateSize">initial reserved buffer size</param>
51+
public PooledMemoryBufferWriter(ArrayPool<T> pool, int preallocateSize)
52+
{
53+
if(pool == null)
54+
{
55+
throw new ArgumentNullException(nameof(pool));
56+
}
57+
if(preallocateSize < 0)
58+
{
59+
throw new ArgumentOutOfRangeException(nameof(preallocateSize), "size must be greater than 0");
60+
}
61+
_Pool = pool;
62+
_currentBuffer = null;
63+
_Position = 0;
64+
_Length = 0;
65+
Reallocate(preallocateSize);
66+
}
67+
/// <inheritdoc/>
68+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
69+
public void Advance(int count)
70+
{
71+
if (_Position + count > _currentBuffer.Length)
72+
{
73+
throw new ArgumentOutOfRangeException("advance too many(" + count.ToString() + ")");
74+
}
75+
_Position += count;
76+
if (_Length < _Position)
77+
{
78+
_Length = _Position;
79+
}
80+
}
81+
82+
/// <summary>return buffer to pool and reset buffer status</summary>
83+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
84+
public void Dispose()
85+
{
86+
if (_currentBuffer != null)
87+
{
88+
_Pool.Return(_currentBuffer);
89+
_currentBuffer = null;
90+
_Position = 0;
91+
_Length = 0;
92+
}
93+
}
94+
95+
/// <inheritdoc/>
96+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
97+
public Memory<T> GetMemory(int sizeHint = 0)
98+
{
99+
if (sizeHint < 0)
100+
{
101+
throw new ArgumentOutOfRangeException("sizeHint", "size must be greater than 0");
102+
}
103+
if (sizeHint == 0)
104+
{
105+
sizeHint = DefaultSize;
106+
}
107+
if (_Position + sizeHint > _currentBuffer.Length)
108+
{
109+
Reallocate(_Position + sizeHint);
110+
}
111+
return _currentBuffer.AsMemory(_Position, sizeHint);
112+
}
113+
/// <inheritdoc/>
114+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
115+
public Span<T> GetSpan(int sizeHint = 0)
116+
{
117+
if (sizeHint < 0)
118+
{
119+
throw new ArgumentOutOfRangeException("sizeHint", "size must be greater than 0");
120+
}
121+
if (sizeHint == 0)
122+
{
123+
sizeHint = DefaultSize;
124+
}
125+
if (_Position + sizeHint > _currentBuffer.Length)
126+
{
127+
Reallocate(_Position + sizeHint);
128+
}
129+
return _currentBuffer.AsSpan(_Position, sizeHint);
130+
}
131+
/// <summary>expose current buffer as Span</summary>
132+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
133+
public ReadOnlySpan<T> ToSpanUnsafe()
134+
{
135+
return _currentBuffer.AsSpan(0, _Length);
136+
}
137+
/// <summary>expose current buffer as Memory</summary>
138+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
139+
public ReadOnlyMemory<T> ToMemoryUnsafe()
140+
{
141+
return _currentBuffer.AsMemory(0, _Length);
142+
}
143+
/// <summary>reset buffer status, buffer will be reallocated</summary>
144+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
145+
public void Reset(int preallocateSize)
146+
{
147+
if(preallocateSize < 0)
148+
{
149+
throw new ArgumentOutOfRangeException("preallocateSize", "size must be greater than 0");
150+
}
151+
_Pool.Return(_currentBuffer);
152+
_currentBuffer = _Pool.Rent(preallocateSize);
153+
_Length = 0;
154+
_Position = 0;
155+
}
156+
/// <summary>reset buffer status, buffer will be reused</summary>
157+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
158+
public void Reset()
159+
{
160+
_Length = 0;
161+
_Position = 0;
162+
}
163+
}
164+
}

PooledStream/PooledStream.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
<TargetFrameworks>netstandard2.1;netstandard1.1</TargetFrameworks>
55
<!-- <TargetFramework>netstandard2.1</TargetFramework> -->
66
<PackageId>PooledStream</PackageId>
7-
<PackageVersion>0.2.1.2</PackageVersion>
7+
<PackageVersion>0.3.0</PackageVersion>
88
<Authors>itn3000</Authors>
99
<Description>Efficient MemoryStream powered by System.Buffers.ArrayPool</Description>
1010
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
11-
<PackageReleaseNotes>add netstandard2.1 to TargetFramework</PackageReleaseNotes>
11+
<PackageReleaseNotes>add PooledMemoryBufferWriter</PackageReleaseNotes>
1212
<Copyright>Copyright(c) 2017 itn3000. All rights reserved</Copyright>
13-
<PackageTags>MemoryStream</PackageTags>
13+
<PackageTags>MemoryStream;ArrayPool</PackageTags>
1414
<PackageProjectUrl>https://github.com/itn3000/PooledStream/</PackageProjectUrl>
1515
<RepositoryUrl>https://github.com/itn3000/PooledStream/</RepositoryUrl>
1616
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>

0 commit comments

Comments
 (0)