Implement optimized removeRange for ArrayDeque #KT-64956
Test ArrayDeque with size 15. With the existing sizes the removeRange implementation couldn't reach the maximum number of iterations - 3. Benchmark results for ArrayDeque.subList().clear() that uses removeRange() can be found here: https://github.com/qurbonzoda/KotlinArrayDequeBenchmarks/tree/master/results
This commit is contained in:
committed by
Space Team
parent
240a423bed
commit
b67ebf36a2
@@ -517,12 +517,9 @@ public class ArrayDeque<E> : AbstractMutableList<E> {
|
||||
}
|
||||
|
||||
public override fun clear() {
|
||||
val tail = internalIndex(size)
|
||||
if (head < tail) {
|
||||
elementData.fill(null, head, tail)
|
||||
} else if (isNotEmpty()) {
|
||||
elementData.fill(null, head, elementData.size)
|
||||
elementData.fill(null, 0, tail)
|
||||
if (isNotEmpty()) {
|
||||
val tail = internalIndex(size)
|
||||
nullifyNonEmpty(head, tail)
|
||||
}
|
||||
head = 0
|
||||
size = 0
|
||||
@@ -550,9 +547,85 @@ public class ArrayDeque<E> : AbstractMutableList<E> {
|
||||
return toArray(arrayOfNulls<Any?>(size))
|
||||
}
|
||||
|
||||
override fun removeRange(fromIndex: Int, toIndex: Int) {
|
||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||
// TODO: registerModification()
|
||||
|
||||
val length = toIndex - fromIndex
|
||||
when (length) {
|
||||
0 -> return
|
||||
size -> {
|
||||
clear()
|
||||
return
|
||||
}
|
||||
1 -> {
|
||||
removeAt(fromIndex)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (fromIndex < size - toIndex) {
|
||||
// closer to the first element -> shift preceding elements
|
||||
removeRangeShiftPreceding(fromIndex, toIndex)
|
||||
|
||||
val newHead = positiveMod(head + length)
|
||||
nullifyNonEmpty(head, newHead)
|
||||
head = newHead
|
||||
} else {
|
||||
// closer to the last element -> shift succeeding elements
|
||||
removeRangeShiftSucceeding(fromIndex, toIndex)
|
||||
|
||||
val tail = internalIndex(size)
|
||||
nullifyNonEmpty(negativeMod(tail - length), tail)
|
||||
}
|
||||
|
||||
size -= length
|
||||
}
|
||||
|
||||
private fun removeRangeShiftPreceding(fromIndex: Int, toIndex: Int) {
|
||||
var copyFromIndex = internalIndex(fromIndex - 1) // upper bound of range, inclusive
|
||||
var copyToIndex = internalIndex(toIndex - 1) // upper bound of range, inclusive
|
||||
var copyCount = fromIndex
|
||||
|
||||
while (copyCount > 0) { // maximum 3 iterations
|
||||
val segmentLength = minOf(copyCount, copyFromIndex + 1, copyToIndex + 1)
|
||||
elementData.copyInto(elementData, copyToIndex - segmentLength + 1, copyFromIndex - segmentLength + 1, copyFromIndex + 1)
|
||||
|
||||
copyFromIndex = negativeMod(copyFromIndex - segmentLength)
|
||||
copyToIndex = negativeMod(copyToIndex - segmentLength)
|
||||
copyCount -= segmentLength
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeRangeShiftSucceeding(fromIndex: Int, toIndex: Int) {
|
||||
var copyFromIndex = internalIndex(toIndex) // lower bound of range, inclusive
|
||||
var copyToIndex = internalIndex(fromIndex) // lower bound of range, inclusive
|
||||
var copyCount = size - toIndex
|
||||
|
||||
while (copyCount > 0) { // maximum 3 iterations
|
||||
val segmentLength = minOf(copyCount, elementData.size - copyFromIndex, elementData.size - copyToIndex)
|
||||
elementData.copyInto(elementData, copyToIndex, copyFromIndex, copyFromIndex + segmentLength)
|
||||
|
||||
copyFromIndex = positiveMod(copyFromIndex + segmentLength)
|
||||
copyToIndex = positiveMod(copyToIndex + segmentLength)
|
||||
copyCount -= segmentLength
|
||||
}
|
||||
}
|
||||
|
||||
/** If `internalFromIndex == internalToIndex`, the buffer is considered full and all elements are nullified. */
|
||||
private fun nullifyNonEmpty(internalFromIndex: Int, internalToIndex: Int) {
|
||||
if (internalFromIndex < internalToIndex) {
|
||||
elementData.fill(null, internalFromIndex, internalToIndex)
|
||||
} else {
|
||||
elementData.fill(null, internalFromIndex, elementData.size)
|
||||
elementData.fill(null, 0, internalToIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// for testing
|
||||
internal fun <T> testToArray(array: Array<T>): Array<T> = toArray(array)
|
||||
internal fun testToArray(): Array<Any?> = toArray()
|
||||
internal fun testRemoveRange(fromIndex: Int, toIndex: Int) = removeRange(fromIndex, toIndex)
|
||||
|
||||
internal companion object {
|
||||
private val emptyElementData = emptyArray<Any?>()
|
||||
|
||||
Reference in New Issue
Block a user