Skip to content

Instantly share code, notes, and snippets.

@ToxicBakery
Last active February 27, 2024 00:46
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ToxicBakery/05d3d98256aaae50bfbde04ae0c62dbd to your computer and use it in GitHub Desktop.
Save ToxicBakery/05d3d98256aaae50bfbde04ae0c62dbd to your computer and use it in GitHub Desktop.
Simple circular/ring buffer style implementation backed by an array for kotlin with test coverage
import java.util.concurrent.atomic.AtomicInteger
class CircularArray<T> : Iterable<T>, Cloneable {
/**
* Creates a new instance of the array with the given size.
*/
constructor(bufferSize: Int) {
this.arr = arrayOfNulls(bufferSize)
this.tail = -1
}
/**
* Creates a new instance of the array as a copy.
*/
constructor(circularArray: CircularArray<T>) {
this.arr = circularArray.arr.copyOf()
this._size = circularArray._size
this.tail = circularArray.tail
}
private val arr: Array<Any?>
private var _size: Int = 0
private var tail: Int
private val head: Int
get() = if (_size == arr.size) (tail + 1) % _size else 0
/**
* Number of elements currently stored in the array.
*/
val size: Int
get() = _size
/**
* Add an element to the array.
*/
fun add(item: T) {
tail = (tail + 1) % arr.size
arr[tail] = item
if (_size < arr.size) _size++
}
/**
* Get an element from the array.
*/
@Suppress("UNCHECKED_CAST")
operator fun get(index: Int): T =
when {
_size == 0 || index > _size || index < 0 -> throw IndexOutOfBoundsException("$index")
_size == arr.size -> arr[(head + index) % arr.size]
else -> arr[index]
} as T
/**
* This array as a list.
*/
@Suppress("UNCHECKED_CAST")
fun toList(): List<T> = iterator().asSequence().toList()
public override fun clone(): CircularArray<T> = CircularArray(this)
override fun iterator(): Iterator<T> = object : Iterator<T> {
private val index: AtomicInteger = AtomicInteger(0)
override fun hasNext(): Boolean = index.get() < size
override fun next(): T = get(index.getAndIncrement())
}
}
import org.junit.Assert.assertEquals
import org.junit.Test
class CircularArrayTest {
@Test
fun getSize() {
val circularArray = CircularArray<Int>(10)
assertEquals(0, circularArray.size)
circularArray.add(1)
assertEquals(1, circularArray.size)
(0..100).forEach(circularArray::add)
assertEquals(10, circularArray.size)
}
@Test
fun get() {
CircularArray<Int>(1).also { circularArray ->
circularArray.add(1)
assertEquals(1, circularArray[0])
circularArray.add(2)
assertEquals(2, circularArray[0])
}
CircularArray<Int>(2).also { circularArray ->
circularArray.add(1)
assertEquals(1, circularArray[0])
circularArray.add(2)
assertEquals(1, circularArray[0])
assertEquals(2, circularArray[1])
circularArray.add(3)
assertEquals(2, circularArray[0])
assertEquals(3, circularArray[1])
circularArray.add(4)
assertEquals(3, circularArray[0])
assertEquals(4, circularArray[1])
}
}
@Test(expected = IndexOutOfBoundsException::class)
fun getZeroSizeException() {
CircularArray<Int>(1).get(0)
}
@Test(expected = IndexOutOfBoundsException::class)
fun getIndexOutOfBounds() {
CircularArray<Int>(1).also { circularArray ->
circularArray.add(1)
circularArray[10]
}
}
@Test(expected = IndexOutOfBoundsException::class)
fun getIndexNegative() {
CircularArray<Int>(1).also { circularArray ->
circularArray.add(1)
circularArray[-1]
}
}
@Test
fun toList() {
CircularArray<Int>(1).also { circularArray ->
circularArray.add(0)
assertEquals(listOf(0), circularArray.toList())
circularArray.add(1)
assertEquals(listOf(1), circularArray.toList())
}
CircularArray<Int>(2).also { circularArray ->
circularArray.add(0)
assertEquals(listOf(0), circularArray.toList())
circularArray.add(1)
assertEquals(listOf(0, 1), circularArray.toList())
circularArray.add(2)
assertEquals(listOf(1, 2), circularArray.toList())
println("${circularArray[0]}")
circularArray.add(3)
assertEquals(listOf(2, 3), circularArray.toList())
circularArray.add(4)
assertEquals(listOf(3, 4), circularArray.toList())
}
}
@Test
fun testClone() {
CircularArray<Int>(1)
.also { circularArray -> circularArray.add(1) }
.clone()
.also { clonedCircularArray -> assertEquals(1, clonedCircularArray[0]) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment