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:
Ilya Matveev
2017-04-14 12:50:22 +07:00
committed by ilmat192
parent 69a49f987c
commit 321386d95e
7 changed files with 139 additions and 46 deletions
+5
View File
@@ -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<*>) &&