Last active
March 19, 2025 14:22
-
-
Save niusounds/e3cdb5aec24274093d781bd7d7ec6cf6 to your computer and use it in GitHub Desktop.
RingBuffer in Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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