Skip to content

Commit fdeba66

Browse files
authored
Merge pull request #6 from ByronMayne/ringbuffer-getters
Added options to fetch values from the ring buffer
2 parents 619bea6 + 975944a commit fdeba66

File tree

2 files changed

+84
-18
lines changed

2 files changed

+84
-18
lines changed

src/Extended.Collections.Tests/Generic/RingBufferTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@ public void Capacity_MatchesConstructorValue()
2727
=> Compose<string>(
2828
capacity: 10,
2929
assertCapacity: () => 10);
30+
31+
[Fact]
32+
public void Index_With_Empty_Collection_ThrowsIndexOutOfRangeException()
33+
{
34+
RingBuffer<int> buffer = new RingBuffer<int>(10);
35+
Assert.Throws<IndexOutOfRangeException>(() => buffer[0]);
36+
}
37+
38+
[Theory]
39+
[InlineData(15, 2, 2)]
40+
[InlineData(15, 3, 3)]
41+
[InlineData(15, -5, 5)]
42+
[InlineData(15, -1, 9)]
43+
[InlineData(10, 0, 0)]
44+
[InlineData(2, -1, 9)]
45+
public void Index_Returns_Expected(int size, int index, int expected)
46+
{
47+
RingBuffer<int> buffer = new RingBuffer<int>(size);
48+
buffer.AddRange(Enumerable.Range(0, 10));
49+
Assert.Equal(expected, buffer[index]);
50+
}
51+
3052
[Fact]
3153
public void AddItem_IncreaseCount()
3254
=> Compose(

src/Extended.Collections/Generic/RingBuffer{T}.cs

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using System.Collections;
1+
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Linq;
5+
using System.Runtime.CompilerServices;
46

57
namespace Extended.Collections.Generic
68
{
@@ -25,7 +27,44 @@ public class RingBuffer<T> : ICollection<T>, IReadOnlyCollection<T>
2527
public int Count { get; private set; }
2628

2729
/// <inheritdoc cref="ICollection"/>
28-
public bool IsReadOnly { get; }
30+
public bool IsReadOnly => false;
31+
32+
/// <summary>
33+
/// Gets the element at the given index, if the index is negetive it will wrap around
34+
/// </summary>
35+
/// <param name="index">The index to get</param>
36+
/// <returns>The current value</returns>
37+
public T this[int index]
38+
{
39+
get
40+
{
41+
if (Count == 0)
42+
{
43+
throw new IndexOutOfRangeException($"The collection currently contains no elements, you can't select");
44+
}
45+
46+
// Reduce the count
47+
if(index > 0)
48+
{
49+
if (-index > Count)
50+
throw new IndexOutOfRangeException("Index out of range.");
51+
index = (m_tail + index) % Capacity;
52+
}
53+
else
54+
{
55+
if (index >= Count)
56+
throw new IndexOutOfRangeException("Index out of range.");
57+
index = (m_head + index + Capacity) % Capacity;
58+
}
59+
60+
if(index < 0)
61+
{
62+
index = Capacity + index;
63+
}
64+
65+
return m_items[index]!;
66+
}
67+
}
2968

3069
/// <summary>
3170
/// Creates a new ring buffer with a fix capacity
@@ -38,7 +77,6 @@ public RingBuffer(int capacity, IEqualityComparer<T>? equalityComparer = null)
3877
Count = 0;
3978
m_tail = 0;
4079
m_items = new T[capacity];
41-
IsReadOnly = false;
4280
m_equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
4381
}
4482

@@ -56,6 +94,7 @@ public RingBuffer(IEnumerable<T> collection, IEqualityComparer<T>? equalityCompa
5694
m_equalityComparer = equalityComparer ?? EqualityComparer<T>.Default;
5795
}
5896

97+
5998
/// <summary>
6099
/// Adds a new item to the buffer
61100
/// </summary>
@@ -105,16 +144,15 @@ public void Clear()
105144
}
106145

107146
/// <summary>
108-
/// Returns back if a the biffer contains the item
147+
/// Returns back if a the buffer contains the item
109148
/// </summary>
110149
/// <param name="item">The item to check if it contains</param>
111150
/// <returns>True if it is within otherwise false</returns>
112151
public bool Contains(T item)
113152
{
114-
for (int i = 0; i < Count; i++)
153+
foreach(T value in this)
115154
{
116-
T? current = m_items[i];
117-
if (current != null && m_equalityComparer.Equals(current, item))
155+
if(m_equalityComparer.Equals(value, item))
118156
{
119157
return true;
120158
}
@@ -125,18 +163,23 @@ public bool Contains(T item)
125163
/// <summary>
126164
/// Copies this buffer into another array
127165
/// </summary>
128-
/// <param name="array">The array to copy into</param>
129-
/// <param name="arrayIndex">The index to start the copying</param>
130-
public void CopyTo(T[] array, int arrayIndex)
131-
{
132-
IEnumerator<T> enumerator = GetEnumerator();
166+
/// <param name="destination">The array to copy into</param>
167+
/// <param name="destinationIndex">The index to start the copying</param>
168+
public void CopyTo(T[] destination, int destinationIndex)
169+
=> CopyTo(destination, destinationIndex, 0, Count);
133170

134-
using (enumerator)
171+
/// <summary>
172+
/// Copies this buffer into another array
173+
/// </summary>
174+
/// <param name="destination">The array to copy into</param>
175+
/// <param name="destinationIndex">The index to start the copying</param>
176+
/// <param name="count">The max number of items to copy</param>
177+
public void CopyTo(T[] destination, int destinationIndex, int sourceIndex, int count)
178+
{
179+
for (int i = 0; i < Count; i++)
135180
{
136-
while (enumerator.MoveNext())
137-
{
138-
array[arrayIndex++] = enumerator.Current;
139-
}
181+
int index = (i + m_tail + sourceIndex) % Capacity;
182+
destination[destinationIndex + i] = m_items[index]!;
140183
}
141184
}
142185

@@ -153,7 +196,8 @@ public bool Remove(T item)
153196

154197
for (int i = 0; i < Count; i++)
155198
{
156-
T? current = m_items[i];
199+
int idx = (m_tail + i) % Capacity;
200+
T? current = m_items[idx];
157201

158202
if(current == null)
159203
{

0 commit comments

Comments
 (0)