Skip to content

Commit 7562d6a

Browse files
authored
Merge pull request aalhour#103 from NdubuisiJr/master
Added CircularBuffer DataStructure.
2 parents d9ed715 + d6a98e3 commit 7562d6a

File tree

2 files changed

+500
-0
lines changed

2 files changed

+500
-0
lines changed
+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace DataStructures.Lists
7+
{
8+
public class CircularBuffer<T> : IEnumerable<T>, ICollection<T> where T : IComparable<T>
9+
{
10+
private T[] _circularBuffer;
11+
private int _end;
12+
private int _start;
13+
private static readonly int _defaultBufferLength = 10;
14+
15+
/// <summary>
16+
/// Returns the length of the buffer
17+
/// </summary>
18+
public int Length
19+
{
20+
get
21+
{
22+
return _circularBuffer.Length - 1;
23+
}
24+
}
25+
26+
/// <summary>
27+
/// Checks if no element is inserted into the buffer
28+
/// </summary>
29+
public bool IsEmpty
30+
{
31+
get
32+
{
33+
return _count == 0;
34+
}
35+
}
36+
37+
/// <summary>
38+
/// Checks if the buffer is filled up
39+
/// </summary>
40+
public bool IsFilledUp
41+
{
42+
get
43+
{
44+
return ((_end + 1) % _circularBuffer.Length == _start) && !_circularBuffer[_start].Equals(_circularBuffer[_end]);
45+
}
46+
}
47+
48+
/// <summary>
49+
/// Controls whether data should be overridden when it is continously inserted without reading
50+
/// </summary>
51+
public bool CanOverride
52+
{
53+
get;
54+
}
55+
56+
/// <summary>
57+
/// Initializes a circular buffer with initial length of 10
58+
/// </summary>
59+
public CircularBuffer(bool canOverride = true) : this(_defaultBufferLength, canOverride)
60+
{
61+
}
62+
63+
/// <summary>
64+
/// Initializes a circular buffer with given length
65+
/// </summary>
66+
/// <param name="length">The length of the buffer</param>
67+
public CircularBuffer(int length, bool canOverride = true)
68+
{
69+
if (length < 1)
70+
{
71+
throw new ArgumentOutOfRangeException("length can not be zero or negative");
72+
}
73+
_circularBuffer = new T[length + 1];
74+
_end = 0;
75+
_start = 0;
76+
CanOverride = canOverride;
77+
}
78+
79+
/// <summary>
80+
/// Writes value to the back of the buffer
81+
/// </summary>
82+
/// <param name="value">value to be added to the buffer</param>
83+
public void Add(T value)
84+
{
85+
if (CanOverride==false && IsFilledUp==true)
86+
{
87+
throw new CircularBufferFullException($"Circular Buffer is filled up. {value} can not be inserted");
88+
}
89+
innerInsert(value);
90+
}
91+
92+
// Inserts data into the buffer without checking if it is full
93+
private void innerInsert(T value)
94+
{
95+
_circularBuffer[_end] = value;
96+
_end = (_end + 1) % _circularBuffer.Length;
97+
if (_end == _start)
98+
{
99+
_start = (_start + 1) % _circularBuffer.Length;
100+
}
101+
102+
// Count should not be greater than the length of the buffer when overriding
103+
_count = _count < Length ? ++_count : _count;
104+
}
105+
106+
/// <summary>
107+
/// Reads and removes the value in front of the buffer, and places the next value in front.
108+
/// </summary>
109+
public T Pop()
110+
{
111+
var result = _circularBuffer[_start];
112+
_circularBuffer[_start] = _circularBuffer[_end];
113+
_start = (_start + 1) % _circularBuffer.Length;
114+
//Count should not go below Zero when poping an empty buffer.
115+
_count = _count > 0 ? --_count : _count;
116+
return result;
117+
}
118+
119+
#region IEnumerable Implementation
120+
public IEnumerator<T> GetEnumerator()
121+
{
122+
for (int i = _start; i < Count; i++)
123+
{
124+
yield return _circularBuffer[i];
125+
}
126+
}
127+
128+
IEnumerator IEnumerable.GetEnumerator()
129+
{
130+
return GetEnumerator();
131+
}
132+
#endregion
133+
134+
#region ICollection Implementation
135+
private int _count;
136+
/// <summary>
137+
/// Returns the number of elements.
138+
/// </summary>
139+
public int Count
140+
{
141+
get
142+
{
143+
return _count;
144+
}
145+
}
146+
/// <summary>
147+
/// Checks whether this collection is readonly
148+
/// </summary>
149+
public bool IsReadOnly
150+
{
151+
get
152+
{
153+
return false;
154+
}
155+
}
156+
/// <summary>
157+
/// Clears this instance
158+
/// </summary>
159+
public void Clear()
160+
{
161+
_count = 0;
162+
_start = 0;
163+
_end = 0;
164+
_circularBuffer = new T[Length + 1];
165+
}
166+
/// <summary>
167+
/// Checks whether the buffer contains an item
168+
/// </summary>
169+
public bool Contains(T item)
170+
{
171+
return _circularBuffer.Contains(item);
172+
}
173+
/// <summary>
174+
/// Copies this buffer to an array
175+
/// </summary>
176+
public void CopyTo(T[] array, int arrayIndex)
177+
{
178+
if (array == null)
179+
{
180+
throw new ArgumentNullException("array can not be null");
181+
}
182+
183+
if (array.Length == 0 || arrayIndex >= array.Length || arrayIndex < 0)
184+
{
185+
throw new IndexOutOfRangeException();
186+
}
187+
188+
// Get enumerator
189+
var enumarator = GetEnumerator();
190+
191+
// Copy elements if there is any in the buffer and if the index is within the valid range
192+
while (arrayIndex < array.Length)
193+
{
194+
if (enumarator.MoveNext())
195+
{
196+
array[arrayIndex] = enumarator.Current;
197+
arrayIndex++;
198+
}
199+
else
200+
{
201+
break;
202+
}
203+
}
204+
}
205+
/// <summary>
206+
/// Removes an item from the buffer
207+
/// </summary>
208+
public bool Remove(T item)
209+
{
210+
if (!IsEmpty && Contains(item))
211+
{
212+
var sourceArray = _circularBuffer.Except(new T[] { item }).ToArray();
213+
_circularBuffer = new T[Length + 1];
214+
Array.Copy(sourceArray, _circularBuffer, sourceArray.Length);
215+
216+
if (!Equals(item,default(T)))
217+
{
218+
_end = sourceArray.Length - 1;
219+
_count = sourceArray.Length-1;
220+
}
221+
else
222+
{
223+
_end = sourceArray.Length;
224+
_count = sourceArray.Length;
225+
}
226+
227+
return true;
228+
}
229+
230+
return false;
231+
}
232+
#endregion
233+
}
234+
235+
public class CircularBufferFullException : Exception
236+
{
237+
public CircularBufferFullException(string message) : base(message)
238+
{
239+
}
240+
}
241+
}

0 commit comments

Comments
 (0)