Skip to content

Instantly share code, notes, and snippets.

@niusounds
Last active April 20, 2022 22:53
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niusounds/e3cdb5aec24274093d781bd7d7ec6cf6 to your computer and use it in GitHub Desktop.
Save niusounds/e3cdb5aec24274093d781bd7d7ec6cf6 to your computer and use it in GitHub Desktop.
RingBuffer in Kotlin
class RingBuffer(val capacity: Int) {
private val storage = ByteArray(capacity)
/**
* Convenient version of [read].
* This method allocates new array every time. Do not use this in heavy loop.
*
* @param startPosition Start position. Can be over than capacity.
* @param size Result data size.
*/
fun read(startPosition: Int, size: Int): ByteArray {
val outData = ByteArray(size)
read(startPosition, outData)
return outData
}
/**
* Read data. If [size] is larger than [capacity], circularly read values.
*
* @param startPosition Start position. Can be over than capacity.
* @param data Written data.
* @param offset Data offset in array. Default is 0.
* @param size Data size. Default is data.size - offset.
*/
fun read(startPosition: Int, data: ByteArray, offset: Int = 0, size: Int = data.size - offset) {
val normalizedStartPosition = startPosition % capacity
val remaining = capacity - normalizedStartPosition
// Use System.arrayCopy if available.
if (size <= remaining) {
System.arraycopy(storage, normalizedStartPosition, data, offset, size)
} else {
// Fill until last
if (remaining > 0) {
System.arraycopy(storage, normalizedStartPosition, data, offset, remaining)
}
// Fill from first
val rest = size - remaining
val nextStartPosition = normalizedStartPosition + remaining
val nextOffset = offset + remaining
read(nextStartPosition, data, nextOffset, rest)
}
}
/**
* Write data. If [size] is larger than [capacity], circularly write values.
*
* @param startPosition Start position. Can be over than capacity.
* @param data Written data.
* @param offset Data offset in array. Default is 0.
* @param size Data size. Cannot be larger than [capacity]. Default is data.size - offset.
*/
fun write(startPosition: Int, data: ByteArray, offset: Int = 0, size: Int = data.size - offset) {
val normalizedStartPosition = startPosition % capacity
val remaining = capacity - normalizedStartPosition
// Use System.arrayCopy if available.
if (size <= remaining) {
System.arraycopy(data, offset, storage, normalizedStartPosition, size)
} else {
// Fill until last
if (remaining > 0) {
System.arraycopy(data, offset, storage, normalizedStartPosition, remaining)
}
// Fill from first
val rest = size - remaining
val nextStartPosition = normalizedStartPosition + remaining
val nextOffset = offset + remaining
write(nextStartPosition, data, nextOffset, rest)
}
}
/**
* Iterator for [RingBuffer]. This reads data from buffer circularly. [hasNext] always returns true.
*
* @param dataSize Data size for array which is used to read data from buffer in each [next] calls.
*/
inner class Iterator(private val dataSize: Int) : kotlin.collections.Iterator<ByteArray> {
private val data = ByteArray(dataSize)
private var startPosition: Int = 0
/**
* Always returns true.
*/
override fun hasNext(): Boolean = true
/**
* Read values from buffer.
*/
override fun next(): ByteArray {
read(startPosition, data)
startPosition += dataSize
return data
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment