Skip to content

Commit 435674f

Browse files
committed
add RingBuffer
1 parent eb071e9 commit 435674f

File tree

3 files changed

+349
-0
lines changed

3 files changed

+349
-0
lines changed

src/CatLib.Core.NetStandard/CatLib.Core.NetStandard.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<Compile Include="..\CatLib.Core\Support\QuickList\InternalList.cs" Link="Support\QuickList\InternalList.cs" />
101101
<Compile Include="..\CatLib.Core\Support\QuickList\IQuickList.cs" Link="Support\QuickList\IQuickList.cs" />
102102
<Compile Include="..\CatLib.Core\Support\QuickList\QuickList.cs" Link="Support\QuickList\QuickList.cs" />
103+
<Compile Include="..\CatLib.Core\Support\RingBuffer\RingBuffer.cs" Link="Support\RingBuffer\RingBuffer.cs" />
103104
<Compile Include="..\CatLib.Core\Support\SortSet\ISortSet.cs" Link="Support\SortSet\ISortSet.cs" />
104105
<Compile Include="..\CatLib.Core\Support\SortSet\SortSet.cs" Link="Support\SortSet\SortSet.cs" />
105106
<Compile Include="..\CatLib.Core\Support\Template\IManaged.cs" Link="Support\Template\IManaged.cs" />
@@ -133,6 +134,7 @@
133134
<Folder Include="Support\QuickList\" />
134135
<Folder Include="Support\SortSet\" />
135136
<Folder Include="Support\Template\" />
137+
<Folder Include="Support\RingBuffer\" />
136138
</ItemGroup>
137139

138140
</Project>

src/CatLib.Core/CatLib.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<Compile Include="Support\QuickList\InternalList.cs" />
8484
<Compile Include="Support\QuickList\IQuickList.cs" />
8585
<Compile Include="Support\QuickList\QuickList.cs" />
86+
<Compile Include="Support\RingBuffer\RingBuffer.cs" />
8687
<Compile Include="Support\Util\Dict.cs" />
8788
<Compile Include="Support\SortSet\ISortSet.cs" />
8889
<Compile Include="Support\SortSet\SortSet.cs" />
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading;
6+
7+
namespace CatLib
8+
{
9+
/// <summary>
10+
/// 环型缓冲区
11+
/// </summary>
12+
public sealed class RingBufferStream : IDisposable
13+
{
14+
/// <summary>
15+
/// 容量
16+
/// </summary>
17+
private readonly long capacity;
18+
19+
/// <summary>
20+
/// 缓冲区容量
21+
/// </summary>
22+
public int Capacity
23+
{
24+
get { return (int)capacity; }
25+
}
26+
27+
/// <summary>
28+
/// 缓冲区大小
29+
/// </summary>
30+
private readonly byte[] buffer;
31+
32+
/// <summary>
33+
/// 原始数组是否可以返回给开发者
34+
/// </summary>
35+
private readonly bool exposable;
36+
37+
/// <summary>
38+
/// 写入的游标
39+
/// </summary>
40+
private long write;
41+
42+
/// <summary>
43+
/// 读取的游标
44+
/// </summary>
45+
private long read;
46+
47+
/// <summary>
48+
/// 遮罩层
49+
/// <para>为了快速计算出,环回中的写入点</para>
50+
/// </summary>
51+
private readonly long mask;
52+
53+
/// <summary>
54+
/// 同步锁
55+
/// </summary>
56+
private object syncRoot;
57+
58+
/// <summary>
59+
/// 同步锁
60+
/// </summary>
61+
public object SyncRoot
62+
{
63+
get
64+
{
65+
if (syncRoot == null)
66+
{
67+
Interlocked.CompareExchange(ref syncRoot, new object(), null);
68+
}
69+
return syncRoot;
70+
}
71+
}
72+
73+
/// <summary>
74+
/// 可以进行读取
75+
/// </summary>
76+
public bool CanRead
77+
{
78+
get { return GetCanReadSize() > 0; }
79+
}
80+
81+
/// <summary>
82+
/// 是否可以进行写入
83+
/// </summary>
84+
public bool CanWrite()
85+
{
86+
return CanWrite(1);
87+
}
88+
89+
/// <summary>
90+
/// 是否可以进行写入
91+
/// </summary>
92+
/// <param name="count">指定的长度</param>
93+
public bool CanWrite(int count)
94+
{
95+
return GetCanWriteSize() >= count;
96+
}
97+
98+
/// <summary>
99+
/// 构建一个新的环型缓冲区实例
100+
/// </summary>
101+
/// <param name="capacity">容量</param>
102+
/// <param name="exposable">是否可以访问内部数组</param>
103+
public RingBufferStream(int capacity, bool exposable = true)
104+
{
105+
buffer = new byte[this.capacity = GetPrime(capacity)];
106+
mask = this.capacity - 1;
107+
write = 0;
108+
read = 0;
109+
this.exposable = exposable;
110+
}
111+
112+
/// <summary>
113+
/// 获取环型缓冲区的原始数组
114+
/// </summary>
115+
/// <returns>原始数组</returns>
116+
public byte[] GetBuffer()
117+
{
118+
if (!exposable)
119+
{
120+
throw new UnauthorizedAccessException("Unable to access original array");
121+
}
122+
return buffer;
123+
}
124+
125+
/// <summary>
126+
/// 将可以读取的数据全部返回
127+
/// </summary>
128+
/// <returns>可以读取的数据</returns>
129+
public byte[] Read()
130+
{
131+
var readSize = GetCanReadSize();
132+
if (readSize <= 0)
133+
{
134+
return null;
135+
}
136+
137+
var result = new byte[readSize];
138+
Read(result);
139+
return result;
140+
}
141+
142+
/// <summary>
143+
/// 将数据读取到<paramref name="buffer"/>中
144+
/// </summary>
145+
/// <param name="buffer">输出的数据</param>
146+
/// <returns>实际输出的长度</returns>
147+
public int Read(byte[] buffer)
148+
{
149+
Guard.Requires<ArgumentNullException>(buffer != null);
150+
return Read(buffer, 0, buffer.Length);
151+
}
152+
153+
/// <summary>
154+
/// 将数据读取到<paramref name="buffer"/>中
155+
/// </summary>
156+
/// <param name="buffer">输出的数据</param>
157+
/// <param name="offset">输出数组偏移多少作为起始</param>
158+
/// <returns>实际输出的长度</returns>
159+
public int Read(byte[] buffer, int offset)
160+
{
161+
Guard.Requires<ArgumentNullException>(buffer != null);
162+
return Read(buffer, offset, buffer.Length - offset);
163+
}
164+
165+
/// <summary>
166+
/// 将数据读取到<paramref name="buffer"/>中
167+
/// </summary>
168+
/// <param name="buffer">输出的数据</param>
169+
/// <param name="offset">输出数组偏移多少作为起始</param>
170+
/// <param name="count">输出的长度</param>
171+
/// <returns>实际输出的长度</returns>
172+
public int Read(byte[] buffer, int offset, int count)
173+
{
174+
Guard.Requires<ArgumentNullException>(buffer != null);
175+
Guard.Requires<ArgumentOutOfRangeException>(offset >= 0);
176+
Guard.Requires<ArgumentOutOfRangeException>(count >= 0);
177+
Guard.Requires<ArgumentOutOfRangeException>((buffer.Length - offset) >= count);
178+
179+
var readSize = GetCanReadSize();
180+
if (readSize > count)
181+
{
182+
readSize = count;
183+
}
184+
185+
if (readSize <= 0)
186+
{
187+
return 0;
188+
}
189+
190+
var nextReadPos = read + readSize;
191+
192+
var realReadPos = read & mask;
193+
var realNextReadPos = nextReadPos & mask;
194+
195+
if (realNextReadPos >= realReadPos)
196+
{
197+
Buffer.BlockCopy(this.buffer, (int)realReadPos, buffer, offset, (int)readSize);
198+
}
199+
else
200+
{
201+
var tail = (int)(capacity - realReadPos);
202+
Buffer.BlockCopy(this.buffer, (int)realReadPos, buffer, offset, tail);
203+
204+
if (readSize - tail > 0)
205+
{
206+
Buffer.BlockCopy(this.buffer, 0, buffer, offset + tail, (int)readSize - tail);
207+
}
208+
}
209+
210+
read = nextReadPos;
211+
return (int)readSize;
212+
}
213+
214+
/// <summary>
215+
/// 将数据写入到环型缓冲区
216+
/// </summary>
217+
/// <param name="buffer">写入的数据</param>
218+
/// <returns>实际被写入的长度</returns>
219+
public int Write(byte[] buffer)
220+
{
221+
Guard.Requires<ArgumentNullException>(buffer != null);
222+
return Write(buffer, 0, buffer.Length);
223+
}
224+
225+
/// <summary>
226+
/// 将数据写入到环型缓冲区
227+
/// </summary>
228+
/// <param name="buffer">写入的数据</param>
229+
/// <param name="offset">偏移多少数据开始写入</param>
230+
/// <returns>实际被写入的长度</returns>
231+
public int Write(byte[] buffer, int offset)
232+
{
233+
Guard.Requires<ArgumentNullException>(buffer != null);
234+
return Write(buffer, offset, buffer.Length - offset);
235+
}
236+
237+
/// <summary>
238+
/// 将数据写入到环型缓冲区
239+
/// </summary>
240+
/// <param name="buffer">写入的数据</param>
241+
/// <param name="offset">偏移多少数据开始写入</param>
242+
/// <param name="count">写入的长度</param>
243+
/// <returns>实际被写入的长度</returns>
244+
public int Write(byte[] buffer, int offset, int count)
245+
{
246+
Guard.Requires<ArgumentNullException>(buffer != null);
247+
Guard.Requires<ArgumentOutOfRangeException>(offset >= 0);
248+
Guard.Requires<ArgumentOutOfRangeException>(count >= 0);
249+
Guard.Requires<ArgumentOutOfRangeException>((buffer.Length - offset) >= count);
250+
251+
// 得到可以被写入的字节流大小
252+
var writeSize = GetCanWriteSize();
253+
if (writeSize > count)
254+
{
255+
writeSize = count;
256+
}
257+
258+
if (writeSize <= 0)
259+
{
260+
return 0;
261+
}
262+
263+
// 当前输入结束后下一次开始的写入点
264+
var nextWritePos = write + writeSize;
265+
266+
// 通过&运算遮罩快速获得环回中的写入点
267+
var realWritePos = write & mask;
268+
var realNextWritePos = nextWritePos & mask;
269+
270+
if (realNextWritePos >= realWritePos)
271+
{
272+
// 不会产生环回,只需要单纯写入
273+
Buffer.BlockCopy(buffer, offset, this.buffer, (int)realWritePos, (int)writeSize);
274+
}
275+
else
276+
{
277+
// 从写入位置到buffer流尾部的长度
278+
var tail = (int)(capacity - realWritePos);
279+
Buffer.BlockCopy(buffer, offset, this.buffer, (int)realWritePos, tail);
280+
281+
if ((writeSize - tail) > 0)
282+
{
283+
Buffer.BlockCopy(buffer, offset + tail, this.buffer, 0, (int)writeSize - tail);
284+
}
285+
}
286+
287+
write = nextWritePos;
288+
return (int)writeSize;
289+
}
290+
291+
/// <summary>
292+
/// 清空缓冲区中的所有数据
293+
/// </summary>
294+
public void Flush()
295+
{
296+
write = 0;
297+
read = 0;
298+
Array.Clear(buffer, 0, buffer.Length);
299+
}
300+
301+
/// <summary>
302+
/// 释放
303+
/// </summary>
304+
public void Dispose()
305+
{
306+
Flush();
307+
}
308+
309+
/// <summary>
310+
/// 获取可以被读取的字节流大小
311+
/// </summary>
312+
/// <returns></returns>
313+
private long GetCanReadSize()
314+
{
315+
return write - read;
316+
}
317+
318+
/// <summary>
319+
/// 得到可以被写入的字节流大小
320+
/// </summary>
321+
private long GetCanWriteSize()
322+
{
323+
return Math.Max(0, capacity - GetCanReadSize());
324+
}
325+
326+
/// <summary>
327+
/// 计算规定值最近的二的次幂的容量
328+
/// </summary>
329+
/// <param name="min">规定值值</param>
330+
/// <returns>容量</returns>
331+
private static int GetPrime(int min)
332+
{
333+
min = Math.Max(0, min);
334+
335+
for (var i = 2; i < int.MaxValue; i = i << 1)
336+
{
337+
if (i >= min)
338+
{
339+
return i;
340+
}
341+
}
342+
343+
throw new RuntimeException("Can not get prime");
344+
}
345+
}
346+
}

0 commit comments

Comments
 (0)