OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
CircularBuffer.cs
Go to the documentation of this file.
1 /*
2 Copyright (c) 2012, Alex Regueiro
3 All rights reserved.
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5 following conditions are met:
6 
7 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
9 in the documentation and/or other materials provided with the distribution.
10 
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
12 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
14 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
15 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
16 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17 POSSIBILITY OF SUCH DAMAGE.
18 */
19 using System;
20 using System.Collections;
21 using System.Collections.Generic;
22 using System.Threading;
23 
24 namespace OpenSim.Framework
25 {
26  public class CircularBuffer<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
27  {
28  private int capacity;
29  private int size;
30  private int head;
31  private int tail;
32  private T[] buffer;
33 
34  [NonSerialized()]
35  private object syncRoot;
36 
37  public CircularBuffer(int capacity)
38  : this(capacity, false)
39  {
40  }
41 
42  public CircularBuffer(int capacity, bool allowOverflow)
43  {
44  if (capacity < 0)
45  throw new ArgumentException("Needs to have at least 1","capacity");
46 
47  this.capacity = capacity;
48  size = 0;
49  head = 0;
50  tail = 0;
51  buffer = new T[capacity];
52  AllowOverflow = allowOverflow;
53  }
54 
55  public bool AllowOverflow
56  {
57  get;
58  set;
59  }
60 
61  public int Capacity
62  {
63  get { return capacity; }
64  set
65  {
66  if (value == capacity)
67  return;
68 
69  if (value < size)
70  throw new ArgumentOutOfRangeException("value","Capacity is too small.");
71 
72  var dst = new T[value];
73  if (size > 0)
74  CopyTo(dst);
75  buffer = dst;
76 
77  capacity = value;
78  }
79  }
80 
81  public int Size
82  {
83  get { return size; }
84  }
85 
86  public bool Contains(T item)
87  {
88  int bufferIndex = head;
89  var comparer = EqualityComparer<T>.Default;
90  for (int i = 0; i < size; i++, bufferIndex++)
91  {
92  if (bufferIndex == capacity)
93  bufferIndex = 0;
94 
95  if (item == null && buffer[bufferIndex] == null)
96  return true;
97  else if ((buffer[bufferIndex] != null) &&
98  comparer.Equals(buffer[bufferIndex], item))
99  return true;
100  }
101 
102  return false;
103  }
104 
105  public void Clear()
106  {
107  size = 0;
108  head = 0;
109  tail = 0;
110  }
111 
112  public int Put(T[] src)
113  {
114  return Put(src, 0, src.Length);
115  }
116 
117  public int Put(T[] src, int offset, int count)
118  {
119  if (!AllowOverflow && count > capacity - size)
120  throw new InvalidOperationException("Buffer Overflow");
121 
122  int srcIndex = offset;
123  for (int i = 0; i < count; i++, tail++, srcIndex++)
124  {
125  if (tail == capacity)
126  tail = 0;
127  buffer[tail] = src[srcIndex];
128  }
129  size = Math.Min(size + count, capacity);
130  return count;
131  }
132 
133  public void Put(T item)
134  {
135  if (!AllowOverflow && size == capacity)
136  throw new InvalidOperationException("Buffer Overflow");
137 
138  buffer[tail] = item;
139  if (++tail == capacity)
140  tail = 0;
141  size++;
142  }
143 
144  public void Skip(int count)
145  {
146  head += count;
147  if (head >= capacity)
148  head -= capacity;
149  }
150 
151  public T[] Get(int count)
152  {
153  var dst = new T[count];
154  Get(dst);
155  return dst;
156  }
157 
158  public int Get(T[] dst)
159  {
160  return Get(dst, 0, dst.Length);
161  }
162 
163  public int Get(T[] dst, int offset, int count)
164  {
165  int realCount = Math.Min(count, size);
166  int dstIndex = offset;
167  for (int i = 0; i < realCount; i++, head++, dstIndex++)
168  {
169  if (head == capacity)
170  head = 0;
171  dst[dstIndex] = buffer[head];
172  }
173  size -= realCount;
174  return realCount;
175  }
176 
177  public T Get()
178  {
179  if (size == 0)
180  throw new InvalidOperationException("Buffer Empty");
181 
182  var item = buffer[head];
183  if (++head == capacity)
184  head = 0;
185  size--;
186  return item;
187  }
188 
189  public void CopyTo(T[] array)
190  {
191  CopyTo(array, 0);
192  }
193 
194  public void CopyTo(T[] array, int arrayIndex)
195  {
196  CopyTo(0, array, arrayIndex, size);
197  }
198 
199  public void CopyTo(int index, T[] array, int arrayIndex, int count)
200  {
201  if (count > size)
202  throw new ArgumentOutOfRangeException("count", "Count Too Large");
203 
204  int bufferIndex = head;
205  for (int i = 0; i < count; i++, bufferIndex++, arrayIndex++)
206  {
207  if (bufferIndex == capacity)
208  bufferIndex = 0;
209  array[arrayIndex] = buffer[bufferIndex];
210  }
211  }
212 
213  public IEnumerator<T> GetEnumerator()
214  {
215  int bufferIndex = head;
216  for (int i = 0; i < size; i++, bufferIndex++)
217  {
218  if (bufferIndex == capacity)
219  bufferIndex = 0;
220 
221  yield return buffer[bufferIndex];
222  }
223  }
224 
225  public T[] GetBuffer()
226  {
227  return buffer;
228  }
229 
230  public T[] ToArray()
231  {
232  var dst = new T[size];
233  CopyTo(dst);
234  return dst;
235  }
236 
237  #region ICollection<T> Members
238 
239  int ICollection<T>.Count
240  {
241  get { return Size; }
242  }
243 
244  bool ICollection<T>.IsReadOnly
245  {
246  get { return false; }
247  }
248 
249  void ICollection<T>.Add(T item)
250  {
251  Put(item);
252  }
253 
254  bool ICollection<T>.Remove(T item)
255  {
256  if (size == 0)
257  return false;
258 
259  Get();
260  return true;
261  }
262 
263  #endregion
264 
265  #region IEnumerable<T> Members
266 
267  IEnumerator<T> IEnumerable<T>.GetEnumerator()
268  {
269  return GetEnumerator();
270  }
271 
272  #endregion
273 
274  #region ICollection Members
275 
276  int ICollection.Count
277  {
278  get { return Size; }
279  }
280 
281  bool ICollection.IsSynchronized
282  {
283  get { return false; }
284  }
285 
286  object ICollection.SyncRoot
287  {
288  get
289  {
290  if (syncRoot == null)
291  Interlocked.CompareExchange(ref syncRoot, new object(), null);
292  return syncRoot;
293  }
294  }
295 
296  void ICollection.CopyTo(Array array, int arrayIndex)
297  {
298  CopyTo((T[])array, arrayIndex);
299  }
300 
301  #endregion
302 
303  #region IEnumerable Members
304 
305  IEnumerator IEnumerable.GetEnumerator()
306  {
307  return (IEnumerator)GetEnumerator();
308  }
309 
310  #endregion
311  }
312 }
void CopyTo(int index, T[] array, int arrayIndex, int count)
int Put(T[] src, int offset, int count)
System.Collections.IEnumerable IEnumerable
void CopyTo(T[] array, int arrayIndex)
CircularBuffer(int capacity, bool allowOverflow)
int Get(T[] dst, int offset, int count)