d0847f2519
Improve the performance of reversed list view iterators by delegating to underlying list iterators instead of using implementations provided by the AbstractList. Latter use AbstractList::get(index: Int) to implement next() and previous() methods and depending on the underlying list's implementation it may lead to worse performance. The change also improves reversed list views test coverage.
345 lines
11 KiB
Kotlin
345 lines
11 KiB
Kotlin
/*
|
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
*/
|
|
|
|
package test.collections
|
|
|
|
import test.collections.behaviors.listBehavior
|
|
import kotlin.test.*
|
|
|
|
class ReversedViewsTest {
|
|
|
|
@Test fun testNullToString() {
|
|
assertEquals("[null]", listOf<String?>(null).asReversed().toString())
|
|
}
|
|
|
|
@Test fun testBehavior() {
|
|
val original = listOf(2L, 3L, Long.MAX_VALUE)
|
|
val reversed = original.reversed()
|
|
compare(reversed, original.asReversed()) {
|
|
listBehavior()
|
|
}
|
|
}
|
|
|
|
@Test fun testMutableBehavior() {
|
|
val original = mutableListOf(2L, 3L, Long.MAX_VALUE)
|
|
val reversed = original.reversed()
|
|
compare(reversed, original.asReversed()) {
|
|
listBehavior()
|
|
}
|
|
}
|
|
|
|
@Test fun testSimple() {
|
|
assertEquals(listOf(3, 2, 1), listOf(1, 2, 3).asReversed())
|
|
assertEquals(listOf(3, 2, 1), listOf(1, 2, 3).asReversed().toList())
|
|
}
|
|
|
|
@Test fun testRandomAccess() {
|
|
val reversed = listOf(1, 2, 3).asReversed()
|
|
|
|
assertEquals(3, reversed[0])
|
|
assertEquals(2, reversed[1])
|
|
assertEquals(1, reversed[2])
|
|
}
|
|
|
|
@Test fun testDoubleReverse() {
|
|
assertEquals(listOf(1, 2, 3), listOf(1, 2, 3).asReversed().asReversed())
|
|
assertEquals(listOf(2, 3), listOf(1, 2, 3, 4).asReversed().subList(1, 3).asReversed())
|
|
}
|
|
|
|
@Test fun testEmpty() {
|
|
assertEquals(emptyList<Int>(), emptyList<Int>().asReversed())
|
|
}
|
|
|
|
@Test fun testReversedSubList() {
|
|
val reversed = (1..10).toList().asReversed()
|
|
assertEquals(listOf(9, 8, 7), reversed.subList(1, 4))
|
|
}
|
|
|
|
@Test fun testMutableSubList() {
|
|
val original = arrayListOf(1, 2, 3, 4)
|
|
val reversedSubList = original.asReversed().subList(1, 3)
|
|
|
|
assertEquals(listOf(3, 2), reversedSubList)
|
|
reversedSubList.clear()
|
|
assertEquals(emptyList<Int>(), reversedSubList)
|
|
assertEquals(listOf(1, 4), original)
|
|
|
|
reversedSubList.add(100)
|
|
assertEquals(listOf(100), reversedSubList)
|
|
assertEquals(listOf(1, 100, 4), original)
|
|
}
|
|
|
|
@Test fun testMutableSimple() {
|
|
assertEquals(listOf(3, 2, 1), mutableListOf(1, 2, 3).asReversed())
|
|
assertEquals(listOf(3, 2, 1), mutableListOf(1, 2, 3).asReversed().toList())
|
|
}
|
|
|
|
@Test fun testMutableDoubleReverse() {
|
|
assertEquals(listOf(1, 2, 3), mutableListOf(1, 2, 3).asReversed().asReversed())
|
|
assertEquals(listOf(2, 3), mutableListOf(1, 2, 3, 4).asReversed().subList(1, 3).asReversed())
|
|
}
|
|
|
|
@Test fun testMutableEmpty() {
|
|
assertEquals(emptyList<Int>(), mutableListOf<Int>().asReversed())
|
|
}
|
|
|
|
@Test fun testMutableReversedSubList() {
|
|
val reversed = (1..10).toMutableList().asReversed()
|
|
assertEquals(listOf(9, 8, 7), reversed.subList(1, 4))
|
|
}
|
|
|
|
@Test fun testMutableAdd() {
|
|
val original = mutableListOf(1, 2, 3)
|
|
val reversed = original.asReversed()
|
|
|
|
reversed.add(0) // add zero at end of reversed
|
|
assertEquals(listOf(3, 2, 1, 0), reversed)
|
|
assertEquals(listOf(0, 1, 2, 3), original)
|
|
|
|
reversed.add(0, 4) // add four at position 0
|
|
assertEquals(listOf(4, 3, 2, 1, 0), reversed)
|
|
assertEquals(listOf(0, 1, 2, 3, 4), original)
|
|
}
|
|
|
|
@Test fun testMutableSet() {
|
|
val original = mutableListOf(1, 2, 3)
|
|
val reversed = original.asReversed()
|
|
|
|
reversed.set(0, 300)
|
|
reversed.set(1, 200)
|
|
reversed.set(2, 100)
|
|
|
|
assertEquals(listOf(100, 200, 300), original)
|
|
assertEquals(listOf(300, 200, 100), reversed)
|
|
}
|
|
|
|
@Test fun testMutableRemove() {
|
|
val original = mutableListOf("a", "b", "c")
|
|
val reversed = original.asReversed()
|
|
|
|
reversed.removeAt(0) // remove c
|
|
assertEquals(listOf("a", "b"), original)
|
|
assertEquals(listOf("b", "a"), reversed)
|
|
|
|
reversed.removeAt(1) // remove a
|
|
assertEquals(listOf("b"), original)
|
|
|
|
reversed.removeAt(0) // remove remaining b
|
|
assertEquals(emptyList<String>(), original)
|
|
}
|
|
|
|
@Test fun testMutableRemoveByObj() {
|
|
val original = mutableListOf("a", "b", "c")
|
|
val reversed = original.asReversed()
|
|
|
|
reversed.remove("c")
|
|
assertEquals(listOf("a", "b"), original)
|
|
assertEquals(listOf("b", "a"), reversed)
|
|
}
|
|
|
|
@Test fun testMutableClear() {
|
|
val original = mutableListOf(1, 2, 3)
|
|
val reversed = original.asReversed()
|
|
|
|
reversed.clear()
|
|
|
|
assertEquals(emptyList<Int>(), reversed)
|
|
assertEquals(emptyList<Int>(), original)
|
|
}
|
|
|
|
@Test fun testContains() {
|
|
assertTrue { 1 in listOf(1, 2, 3).asReversed() }
|
|
assertTrue { 1 in mutableListOf(1, 2, 3).asReversed() }
|
|
}
|
|
|
|
@Test fun testBidirectionalModifications() {
|
|
val original = mutableListOf(1, 2, 3, 4)
|
|
val reversed = original.asReversed()
|
|
|
|
original.removeAt(3)
|
|
assertEquals(listOf(1, 2, 3), original)
|
|
assertEquals(listOf(3, 2, 1), reversed)
|
|
|
|
reversed.removeAt(2)
|
|
assertEquals(listOf(2, 3), original)
|
|
assertEquals(listOf(3, 2), reversed)
|
|
}
|
|
|
|
@Test fun testIndexOf() {
|
|
assertEquals(2, listOf(1, 2, 3).asReversed().indexOf(1))
|
|
assertEquals(2, mutableListOf(1, 2, 3).asReversed().indexOf(1))
|
|
|
|
assertEquals(-1, listOf(1, 2, 3).asReversed().indexOf(0))
|
|
assertEquals(-1, mutableListOf(1, 2, 3).asReversed().indexOf(0))
|
|
}
|
|
|
|
@Test fun testLastIndexOf() {
|
|
assertEquals(2, listOf(1, 2, 3).asReversed().indexOf(1))
|
|
assertEquals(2, mutableListOf(1, 2, 3).asReversed().indexOf(1))
|
|
|
|
assertEquals(-1, listOf(1, 2, 3).asReversed().lastIndexOf(0))
|
|
assertEquals(-1, mutableListOf(1, 2, 3).asReversed().lastIndexOf(0))
|
|
}
|
|
|
|
@Test fun testIteratorAdd() {
|
|
val original = mutableListOf(1, 2, 4)
|
|
val reversedView = original.asReversed()
|
|
val iter = reversedView.listIterator()
|
|
|
|
val reversedCopy = original.reversed().toMutableList()
|
|
val copyIter = reversedCopy.listIterator()
|
|
|
|
compare(copyIter, iter) {
|
|
propertyEquals { add(5) }
|
|
propertyEquals { previousIndex() }
|
|
propertyEquals { nextIndex() }
|
|
propertyEquals { next() }
|
|
}
|
|
assertEquals(reversedCopy, reversedView)
|
|
assertEquals(listOf(1, 2, 4, 5), original)
|
|
|
|
compare(copyIter, iter) {
|
|
propertyEquals { add(3) }
|
|
propertyEquals { previousIndex() }
|
|
propertyEquals { nextIndex() }
|
|
propertyEquals { previous() }
|
|
}
|
|
|
|
iter.seekEnd()
|
|
iter.add(0)
|
|
assertEquals(listOf(5, 4, 3, 2, 1, 0), reversedView)
|
|
assertEquals(listOf(0, 1, 2, 3, 4, 5), original)
|
|
}
|
|
|
|
@Test fun testIteratorRemove() {
|
|
val original = mutableListOf(0, 1, 2, 3, 4)
|
|
val reversedView = original.asReversed()
|
|
val iter = reversedView.listIterator()
|
|
|
|
val reversedCopy = original.reversed().toMutableList()
|
|
val copyIter = reversedCopy.listIterator()
|
|
|
|
compare(copyIter, iter) {
|
|
propertyFailsWith<IllegalStateException> { remove() }
|
|
propertyEquals {
|
|
next()
|
|
remove()
|
|
}
|
|
propertyEquals { previousIndex() }
|
|
propertyEquals { nextIndex() }
|
|
propertyFailsWith<IllegalStateException> { remove() }
|
|
propertyEquals { next() }
|
|
}
|
|
assertEquals(reversedCopy, reversedView)
|
|
assertEquals(listOf(0, 1, 2, 3), original)
|
|
|
|
compare(copyIter, iter) {
|
|
propertyEquals {
|
|
next()
|
|
remove()
|
|
}
|
|
propertyEquals { previousIndex() }
|
|
propertyEquals { nextIndex() }
|
|
propertyEquals { previous() }
|
|
}
|
|
assertEquals(reversedCopy, reversedView)
|
|
assertEquals(listOf(0, 1, 3), original)
|
|
|
|
iter.seekEnd()
|
|
iter.remove()
|
|
assertEquals(listOf(3, 1), reversedView)
|
|
assertEquals(listOf(1, 3), original)
|
|
}
|
|
|
|
@Test fun testIteratorSet() {
|
|
val original = mutableListOf(2, 3, 4)
|
|
val iter = original.asReversed().listIterator()
|
|
|
|
while (iter.hasNext()) {
|
|
val v = iter.next()
|
|
iter.set(v * v)
|
|
}
|
|
|
|
assertEquals(listOf(4, 9, 16), original)
|
|
}
|
|
|
|
@Test fun testGetIOOB() {
|
|
assertFailsWith<IndexOutOfBoundsException> {
|
|
listOf(1, 2, 3).asReversed().get(3)
|
|
}.let { exception ->
|
|
// we actually don't care about the exact wording,
|
|
// we just need the index to be not confusing
|
|
assertContains(exception.message!!, "index 3")
|
|
}
|
|
|
|
assertFailsWith<IndexOutOfBoundsException> {
|
|
mutableListOf(1, 2, 3).asReversed().get(3)
|
|
}.let { exception ->
|
|
// we actually don't care about the exact wording,
|
|
// we just need the index to be not confusing
|
|
assertContains(exception.message!!, "index 3")
|
|
}
|
|
}
|
|
|
|
@Test fun testSetIOOB() {
|
|
assertFailsWith<IndexOutOfBoundsException> {
|
|
mutableListOf(1, 2, 3, 4).asReversed().set(4, 0)
|
|
}.let { exception ->
|
|
// we actually don't care about the exact wording,
|
|
// we just need the index to be not confusing
|
|
assertContains(exception.message!!, "index 4")
|
|
}
|
|
}
|
|
|
|
@Test fun testAddIOOB() {
|
|
assertFailsWith<IndexOutOfBoundsException> {
|
|
mutableListOf(1, 2, 3).asReversed().add(4, 0)
|
|
}.let { exception ->
|
|
// we actually don't care about the exact wording,
|
|
// we just need the index to be not confusing
|
|
assertContains(exception.message!!, "index 4")
|
|
}
|
|
}
|
|
|
|
@Test fun testRemoveIOOB() {
|
|
assertFailsWith<IndexOutOfBoundsException> {
|
|
mutableListOf(1, 2, 3).asReversed().removeAt(3)
|
|
}.let { exception ->
|
|
// we actually don't care about the exact wording,
|
|
// we just need the index to be not confusing
|
|
assertContains(exception.message!!, "index 3")
|
|
}
|
|
}
|
|
|
|
@Test fun testIteratorNSEOnNext() {
|
|
assertFailsWith<NoSuchElementException> {
|
|
val it = listOf(1, 2, 3).asReversed().iterator()
|
|
it.seekEnd()
|
|
it.next()
|
|
}
|
|
|
|
assertFailsWith<NoSuchElementException> {
|
|
val it = mutableListOf(1, 2, 3).asReversed().iterator()
|
|
it.seekEnd()
|
|
it.next()
|
|
}
|
|
}
|
|
|
|
@Test fun testIteratorNSEOnPrevious() {
|
|
assertFailsWith<NoSuchElementException> {
|
|
listOf(1, 2, 3).asReversed().listIterator().previous()
|
|
}
|
|
assertFailsWith<NoSuchElementException> {
|
|
mutableListOf(1, 2, 3).asReversed().listIterator().previous()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun Iterator<*>.seekEnd() {
|
|
while (hasNext()) {
|
|
next()
|
|
}
|
|
}
|