diff --git a/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt b/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt index ef7000dc7f9..e7e968b6ae0 100644 --- a/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt +++ b/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt @@ -60,9 +60,7 @@ internal fun windowedIterator(iterator: Iterator, size: Int, step: Int, d buffer.removeFirst(step) } } - if (dropTrailing) { - if (buffer.size == size) yield(buffer) - } else { + if (!dropTrailing) { while (buffer.size > step) { yield(if (reuseBuffer) buffer else ArrayList(buffer)) buffer.removeFirst(step) @@ -96,8 +94,7 @@ internal class MovingSubList(private val list: List) : AbstractList /** * Provides ring buffer implementation. * - * Buffer overflow is not allowed so [add] doesn't overwrite tail but raises an exception while [offer] returns `false` - * If it is going to be public API perhaps this behaviour could be customizable + * Buffer overflow is not allowed so [add] doesn't overwrite tail but raises an exception. */ private class RingBuffer(val capacity: Int): AbstractList(), RandomAccess { init { @@ -105,76 +102,76 @@ private class RingBuffer(val capacity: Int): AbstractList(), RandomAccess } private val buffer = arrayOfNulls(capacity) - private var writePosition = 0 + private var startIndex: Int = 0 override var size: Int = 0 private set override fun get(index: Int): T { checkElementIndex(index, size) - return getAtUnsafe(writePosition.backward(size - index)) + @Suppress("UNCHECKED_CAST") + return buffer[startIndex.forward(index)] as T } fun isFull() = size == capacity override fun iterator(): Iterator = object : AbstractIterator() { private var count = size - private var index = writePosition.backward(size) + private var index = startIndex override fun computeNext() { if (count == 0) { done() } else { - setNext(getAtUnsafe(index)) + @Suppress("UNCHECKED_CAST") + setNext(buffer[index] as T) index = index.forward(1) count-- } } } - override fun toArray(): Array { + @Suppress("UNCHECKED_CAST") + override fun toArray(array: Array): Array { + val result: Array = + if (array.size < this.size) array.copyOf(this.size) else array as Array + val size = this.size - val result = arrayOfNulls(size) + var widx = 0 - var idx = writePosition.backward(size) + var idx = startIndex while (widx < size && idx < capacity) { - result[widx] = buffer[idx] + result[widx] = buffer[idx] as T widx++ idx++ } idx = 0 while (widx < size) { - result[widx] = buffer[idx] + result[widx] = buffer[idx] as T widx++ idx++ } + if (result.size > this.size) result[this.size] = null - return result + return result as Array + } + + override fun toArray(): Array { + return toArray(arrayOfNulls(size)) } /** * Add [element] to the buffer or fail with [IllegalStateException] if no free space available in the buffer */ 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()) { - return false + throw IllegalStateException("ring buffer is full") } - buffer[writePosition] = element - writePosition = writePosition.forward(1) + buffer[startIndex.forward(size)] = element size++ - return true } /** @@ -185,30 +182,25 @@ private class RingBuffer(val capacity: Int): AbstractList(), RandomAccess require(n <= size) { "n shouldn't be greater than the buffer size: n = $n, size = $size" } if (n > 0) { - val start = writePosition.backward(size) - val end = start.forward(n - 1) + val start = startIndex + val end = start.forward(n) if (start > end) { buffer.fill(null, start, capacity) - buffer.fill(null, 0, end + 1) + buffer.fill(null, 0, end) } else { - buffer.fill(null, start, end + 1) + buffer.fill(null, start, end) } + startIndex = end size -= n } } - @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") - private inline fun getAtUnsafe(idx: Int): T = buffer[idx] as T - @Suppress("NOTHING_TO_INLINE") 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 private fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit { for (idx in fromIndex .. toIndex-1) {