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