Minor refactoring in RingBuffer
This commit is contained in:
@@ -60,9 +60,7 @@ internal fun <T> windowedIterator(iterator: Iterator<T>, size: Int, step: Int, d
|
|||||||
buffer.removeFirst(step)
|
buffer.removeFirst(step)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dropTrailing) {
|
if (!dropTrailing) {
|
||||||
if (buffer.size == size) yield(buffer)
|
|
||||||
} else {
|
|
||||||
while (buffer.size > step) {
|
while (buffer.size > step) {
|
||||||
yield(if (reuseBuffer) buffer else ArrayList(buffer))
|
yield(if (reuseBuffer) buffer else ArrayList(buffer))
|
||||||
buffer.removeFirst(step)
|
buffer.removeFirst(step)
|
||||||
@@ -96,8 +94,7 @@ internal class MovingSubList<out E>(private val list: List<E>) : AbstractList<E>
|
|||||||
/**
|
/**
|
||||||
* Provides ring buffer implementation.
|
* Provides ring buffer implementation.
|
||||||
*
|
*
|
||||||
* Buffer overflow is not allowed so [add] doesn't overwrite tail but raises an exception while [offer] returns `false`
|
* Buffer overflow is not allowed so [add] doesn't overwrite tail but raises an exception.
|
||||||
* If it is going to be public API perhaps this behaviour could be customizable
|
|
||||||
*/
|
*/
|
||||||
private class RingBuffer<T>(val capacity: Int): AbstractList<T>(), RandomAccess {
|
private class RingBuffer<T>(val capacity: Int): AbstractList<T>(), RandomAccess {
|
||||||
init {
|
init {
|
||||||
@@ -105,76 +102,76 @@ private class RingBuffer<T>(val capacity: Int): AbstractList<T>(), RandomAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val buffer = arrayOfNulls<Any?>(capacity)
|
private val buffer = arrayOfNulls<Any?>(capacity)
|
||||||
private var writePosition = 0
|
private var startIndex: Int = 0
|
||||||
|
|
||||||
override var size: Int = 0
|
override var size: Int = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override fun get(index: Int): T {
|
override fun get(index: Int): T {
|
||||||
checkElementIndex(index, size)
|
checkElementIndex(index, size)
|
||||||
return getAtUnsafe(writePosition.backward(size - index))
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return buffer[startIndex.forward(index)] as T
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFull() = size == capacity
|
fun isFull() = size == capacity
|
||||||
|
|
||||||
override fun iterator(): Iterator<T> = object : AbstractIterator<T>() {
|
override fun iterator(): Iterator<T> = object : AbstractIterator<T>() {
|
||||||
private var count = size
|
private var count = size
|
||||||
private var index = writePosition.backward(size)
|
private var index = startIndex
|
||||||
|
|
||||||
override fun computeNext() {
|
override fun computeNext() {
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
done()
|
done()
|
||||||
} else {
|
} else {
|
||||||
setNext(getAtUnsafe(index))
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
setNext(buffer[index] as T)
|
||||||
index = index.forward(1)
|
index = index.forward(1)
|
||||||
count--
|
count--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toArray(): Array<Any?> {
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T> toArray(array: Array<T>): Array<T> {
|
||||||
|
val result: Array<T?> =
|
||||||
|
if (array.size < this.size) array.copyOf(this.size) else array as Array<T?>
|
||||||
|
|
||||||
val size = this.size
|
val size = this.size
|
||||||
val result = arrayOfNulls<Any?>(size)
|
|
||||||
var widx = 0
|
var widx = 0
|
||||||
var idx = writePosition.backward(size)
|
var idx = startIndex
|
||||||
|
|
||||||
while (widx < size && idx < capacity) {
|
while (widx < size && idx < capacity) {
|
||||||
result[widx] = buffer[idx]
|
result[widx] = buffer[idx] as T
|
||||||
widx++
|
widx++
|
||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
while (widx < size) {
|
while (widx < size) {
|
||||||
result[widx] = buffer[idx]
|
result[widx] = buffer[idx] as T
|
||||||
widx++
|
widx++
|
||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
if (result.size > this.size) result[this.size] = null
|
||||||
|
|
||||||
return result
|
return result as Array<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toArray(): Array<Any?> {
|
||||||
|
return toArray(arrayOfNulls(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add [element] to the buffer or fail with [IllegalStateException] if no free space available in the buffer
|
* Add [element] to the buffer or fail with [IllegalStateException] if no free space available in the buffer
|
||||||
*/
|
*/
|
||||||
fun add(element: T) {
|
fun add(element: T) {
|
||||||
if (!offer(element)) {
|
|
||||||
throw IllegalStateException("Ring buffer is full.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Offers [element] to the buffer and return `true` if it was added or `false` when there is no free space available in the buffer
|
|
||||||
*/
|
|
||||||
fun offer(element: T): Boolean {
|
|
||||||
if (isFull()) {
|
if (isFull()) {
|
||||||
return false
|
throw IllegalStateException("ring buffer is full")
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[writePosition] = element
|
buffer[startIndex.forward(size)] = element
|
||||||
writePosition = writePosition.forward(1)
|
|
||||||
size++
|
size++
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,30 +182,25 @@ private class RingBuffer<T>(val capacity: Int): AbstractList<T>(), RandomAccess
|
|||||||
require(n <= size) { "n shouldn't be greater than the buffer size: n = $n, size = $size" }
|
require(n <= size) { "n shouldn't be greater than the buffer size: n = $n, size = $size" }
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
val start = writePosition.backward(size)
|
val start = startIndex
|
||||||
val end = start.forward(n - 1)
|
val end = start.forward(n)
|
||||||
|
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
buffer.fill(null, start, capacity)
|
buffer.fill(null, start, capacity)
|
||||||
buffer.fill(null, 0, end + 1)
|
buffer.fill(null, 0, end)
|
||||||
} else {
|
} else {
|
||||||
buffer.fill(null, start, end + 1)
|
buffer.fill(null, start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startIndex = end
|
||||||
size -= n
|
size -= n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
|
|
||||||
private inline fun getAtUnsafe(idx: Int): T = buffer[idx] as T
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline fun Int.forward(n: Int): Int = (this + n) % capacity
|
private inline fun Int.forward(n: Int): Int = (this + n) % capacity
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
private inline fun Int.backward(n: Int): Int = ((this - n) % capacity + capacity) % capacity
|
|
||||||
|
|
||||||
// TODO: replace with Array.fill from stdlib when available in common
|
// TODO: replace with Array.fill from stdlib when available in common
|
||||||
private fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
private fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||||
for (idx in fromIndex .. toIndex-1) {
|
for (idx in fromIndex .. toIndex-1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user