stdlib: Improve ArrayList.removeAll implementation.
This patch replaces ArrayList.removeAll implementation with a faster one. It also adds the AbstractMutableCollection class containing default implementations for addAll, removeAll and retainAll methods and fixes tests to check if removeAll removes all occurrences found or not.
This commit is contained in:
@@ -790,6 +790,11 @@ task lateinit_notInitialized(type: RunKonanTest) {
|
||||
source = "codegen/lateinit/notInitialized.kt"
|
||||
}
|
||||
|
||||
task AbstractMutableCollectionRemoveAll(type: RunKonanTest) {
|
||||
expectedExitStatus = 0
|
||||
source = "runtime/collections/AbstractMutableCollectionRemoveAll.kt"
|
||||
}
|
||||
|
||||
task array0(type: RunKonanTest) {
|
||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||
source = "runtime/collections/array0.kt"
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
class TestCollection(): AbstractMutableCollection<Int>() {
|
||||
companion object {
|
||||
const val SIZE = 7
|
||||
}
|
||||
|
||||
private val array = IntArray(SIZE)
|
||||
private var len = 0
|
||||
|
||||
override val size: Int
|
||||
get() = len
|
||||
|
||||
override fun add(element: Int): Boolean {
|
||||
if (len >= SIZE) return false
|
||||
array[len++] = element
|
||||
return true
|
||||
}
|
||||
|
||||
override fun remove(element: Int): Boolean {
|
||||
val it = iterator()
|
||||
while(it.hasNext()) {
|
||||
if (it.next() == element) {
|
||||
it.remove()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun iterator(): MutableIterator<Int> = object: MutableIterator<Int> {
|
||||
var nextIndex = 0
|
||||
|
||||
override fun hasNext() = nextIndex < len
|
||||
override fun next() = array[nextIndex++]
|
||||
|
||||
override fun remove() {
|
||||
if (nextIndex == 0) throw IllegalStateException()
|
||||
for (i in nextIndex..len - 1) {
|
||||
array[i - 1] = array[i]
|
||||
}
|
||||
len--
|
||||
nextIndex--
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
len = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun assertEquals(a: TestCollection, b: List<Int>) {
|
||||
if (a.size != b.size) {
|
||||
throw AssertionError()
|
||||
}
|
||||
val aIt = a.iterator()
|
||||
val bIt = b.iterator()
|
||||
while (aIt.hasNext()) {
|
||||
if (aIt.next() != bIt.next()) throw AssertionError("TestCollection contains wrong elements. Expected: $b, actual: $a.")
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val c = TestCollection()
|
||||
if (!c.addAll(listOf(1, 2, 3, 2, 4, 5, 4))) throw AssertionError("addAll is false when it must be true.")
|
||||
if (c.addAll(listOf(1, 2)) != false) throw AssertionError("addAll is true when it must be false.")
|
||||
c.removeAll(listOf(1, 2))
|
||||
assertEquals(c, listOf(3, 4, 5, 4))
|
||||
c.retainAll(listOf(4, 5))
|
||||
assertEquals(c, listOf(4, 5, 4))
|
||||
}
|
||||
@@ -85,9 +85,9 @@ fun testRemove() {
|
||||
}
|
||||
|
||||
fun testRemoveAll() {
|
||||
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
|
||||
val a = ArrayList(listOf("1", "2", "3", "4", "5", "1"))
|
||||
assertFalse(a.removeAll(listOf("6", "7", "8")))
|
||||
assertEquals(listOf("1", "2", "3", "4", "5"), a)
|
||||
assertEquals(listOf("1", "2", "3", "4", "5", "1"), a)
|
||||
assertTrue(a.removeAll(listOf("5", "3", "1")))
|
||||
assertEquals(listOf("2", "4"), a)
|
||||
}
|
||||
@@ -277,9 +277,9 @@ fun testSubListSubListRemoveAt() {
|
||||
}
|
||||
|
||||
fun testSubListRemoveAll() {
|
||||
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
|
||||
val s = a.subList(1, 4)
|
||||
assertEquals(listOf("2", "3", "4"), s)
|
||||
val a = ArrayList(listOf("1", "2", "3", "3", "4", "5"))
|
||||
val s = a.subList(1, 5)
|
||||
assertEquals(listOf("2", "3", "3", "4"), s)
|
||||
|
||||
assertTrue(s.removeAll(listOf("3", "5")))
|
||||
assertEquals(listOf("2", "4"), s)
|
||||
|
||||
@@ -103,9 +103,9 @@ fun testContainsAll() {
|
||||
}
|
||||
|
||||
fun testRemoveAll() {
|
||||
val s = HashSet(listOf("1", "2", "3", "4", "5"))
|
||||
val s = HashSet(listOf("1", "2", "3", "4", "5", "1"))
|
||||
assertFalse(s.removeAll(listOf("6", "7", "8")))
|
||||
assertEquals(setOf("1", "2", "3", "4", "5"), s)
|
||||
assertEquals(setOf("1", "2", "3", "4", "5", "1"), s)
|
||||
assertTrue(s.removeAll(listOf("5", "3", "1")))
|
||||
assertEquals(setOf("2", "4"), s)
|
||||
}
|
||||
|
||||
@@ -49,3 +49,52 @@ public abstract class AbstractCollection<out E> protected constructor() : Collec
|
||||
*/
|
||||
protected open fun <T> toArray(array: Array<T>): Array<T> = collectionToArray(this, array)
|
||||
}
|
||||
|
||||
public abstract class AbstractMutableCollection<E> protected constructor(): MutableCollection<E>, AbstractCollection<E>() {
|
||||
|
||||
// Bulk Modification Operations
|
||||
/**
|
||||
* Adds all of the elements in the specified collection to this collection.
|
||||
*
|
||||
* @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified.
|
||||
*/
|
||||
override public fun addAll(elements: Collection<E>): Boolean {
|
||||
var changed = false
|
||||
for (v in elements) {
|
||||
if(add(v)) changed = true
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of this collection's elements that are also contained in the specified collection.
|
||||
*
|
||||
* @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified.
|
||||
*/
|
||||
override public fun removeAll(elements: Collection<E>): Boolean = removeAll(elements, true)
|
||||
|
||||
/**
|
||||
* Retains only the elements in this collection that are contained in the specified collection.
|
||||
*
|
||||
* @return `true` if any element was removed from the collection, `false` if the collection was not modified.
|
||||
*/
|
||||
override public fun retainAll(elements: Collection<E>): Boolean = removeAll(elements, false)
|
||||
|
||||
/**
|
||||
* Removes the elements in this collection that are contained (if [contained] == true) or
|
||||
* not contained (if [contained] == false) in [elements].
|
||||
*
|
||||
* @return `true` if the collection has been modified and `false` otherwise.
|
||||
*/
|
||||
protected fun removeAll(elements: Collection<E>, contained: Boolean): Boolean {
|
||||
val it = iterator()
|
||||
var changed = false
|
||||
while (it.hasNext()) {
|
||||
if (elements.contains(it.next()) == contained) {
|
||||
it.remove()
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class ArrayList<E> private constructor(
|
||||
private var offset: Int,
|
||||
private var length: Int,
|
||||
private val backing: ArrayList<E>?
|
||||
) : MutableList<E>, RandomAccess {
|
||||
) : MutableList<E>, RandomAccess, AbstractMutableCollection<E>() {
|
||||
|
||||
constructor() : this(10)
|
||||
|
||||
@@ -131,19 +131,11 @@ class ArrayList<E> private constructor(
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<E>): Boolean {
|
||||
var changed = false
|
||||
val it = iterator()
|
||||
while (it.hasNext()) {
|
||||
if (elements.contains(it.next())) {
|
||||
it.remove()
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
return changed
|
||||
return retainOrRemoveAllInternal(offset, length, elements, false) > 0
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<E>): Boolean {
|
||||
return retainAllInRangeInternal(offset, length, elements) > 0
|
||||
return retainOrRemoveAllInternal(offset, length, elements, true) > 0
|
||||
}
|
||||
|
||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
||||
@@ -274,16 +266,17 @@ class ArrayList<E> private constructor(
|
||||
length -= rangeLength
|
||||
}
|
||||
|
||||
private fun retainAllInRangeInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>): Int {
|
||||
/** Retains elements if [retain] == true and removes them it [retain] == false. */
|
||||
private fun retainOrRemoveAllInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>, retain: Boolean): Int {
|
||||
if (backing != null) {
|
||||
val removed = backing.retainAllInRangeInternal(rangeOffset, rangeLength, elements)
|
||||
val removed = backing.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
||||
length -= removed
|
||||
return removed
|
||||
} else {
|
||||
var i = 0
|
||||
var j = 0
|
||||
while (i < rangeLength) {
|
||||
if (elements.contains(array[rangeOffset + i])) {
|
||||
if (elements.contains(array[rangeOffset + i]) == retain) {
|
||||
array[rangeOffset + j++] = array[rangeOffset + i++]
|
||||
} else {
|
||||
i++
|
||||
|
||||
@@ -18,7 +18,7 @@ package kotlin.collections
|
||||
|
||||
class HashSet<K> internal constructor(
|
||||
val backing: HashMap<K, *>
|
||||
) : MutableSet<K> {
|
||||
) : MutableSet<K>, AbstractMutableCollection<K>() {
|
||||
|
||||
constructor() : this(HashMap<K, Nothing>())
|
||||
|
||||
@@ -55,30 +55,6 @@ class HashSet<K> internal constructor(
|
||||
return updated
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<K>): Boolean {
|
||||
val it = iterator()
|
||||
var updated = false
|
||||
while (it.hasNext()) {
|
||||
if (elements.contains(it.next())) {
|
||||
it.remove()
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<K>): Boolean {
|
||||
val it = iterator()
|
||||
var updated = false
|
||||
while (it.hasNext()) {
|
||||
if (!elements.contains(it.next())) {
|
||||
it.remove()
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other === this ||
|
||||
(other is Set<*>) &&
|
||||
|
||||
Reference in New Issue
Block a user