Provide removeAll and retainAll with predicate for MutableIterables and MutableList.
#KT-8760 Fixed
This commit is contained in:
@@ -222,10 +222,64 @@ public fun <T> MutableCollection<in T>.addAll(elements: Array<out T>) {
|
|||||||
addAll(elements.asList())
|
addAll(elements.asList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements from this [MutableIterable] that match the given [predicate].
|
||||||
|
*/
|
||||||
|
public fun <T> MutableIterable<T>.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retains only elements of this [MutableIterable] that match the given [predicate].
|
||||||
|
*/
|
||||||
|
public fun <T> MutableIterable<T>.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false)
|
||||||
|
|
||||||
|
private fun <T> MutableIterable<T>.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean {
|
||||||
|
var result = false
|
||||||
|
with (iterator()) {
|
||||||
|
while (hasNext())
|
||||||
|
if (predicate(next()) == predicateResultToRemove) {
|
||||||
|
remove()
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements from this [MutableList] that match the given [predicate].
|
||||||
|
*/
|
||||||
|
public fun <T> MutableList<T>.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retains only elements of this [MutableList] that match the given [predicate].
|
||||||
|
*/
|
||||||
|
public fun <T> MutableList<T>.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false)
|
||||||
|
|
||||||
|
private fun <T> MutableList<T>.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean {
|
||||||
|
var writeIndex: Int = 0
|
||||||
|
for (readIndex in 0..lastIndex) {
|
||||||
|
val element = this[readIndex]
|
||||||
|
if (predicate(element) == predicateResultToRemove)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (writeIndex != readIndex)
|
||||||
|
this[writeIndex] = element
|
||||||
|
|
||||||
|
writeIndex++
|
||||||
|
}
|
||||||
|
if (writeIndex < size) {
|
||||||
|
for (removeIndex in lastIndex downTo writeIndex)
|
||||||
|
removeAt(removeIndex)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all elements from this [MutableCollection] that are also contained in the given [elements] collection.
|
* Removes all elements from this [MutableCollection] that are also contained in the given [elements] collection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public fun <T> MutableCollection<in T>.removeAll(elements: Iterable<T>): Boolean {
|
public fun <T> MutableCollection<in T>.removeAll(elements: Iterable<T>): Boolean {
|
||||||
return removeAll(elements.convertToSetForSetOperationWith(this))
|
return removeAll(elements.convertToSetForSetOperationWith(this))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,12 +28,7 @@ private fun Iterable<FlagEnum>.toInt(): Int =
|
|||||||
this.fold(0, { value, option -> value or option.value })
|
this.fold(0, { value, option -> value or option.value })
|
||||||
private inline fun <reified T> fromInt(value: Int): Set<T> where T : FlagEnum, T: Enum<T> =
|
private inline fun <reified T> fromInt(value: Int): Set<T> where T : FlagEnum, T: Enum<T> =
|
||||||
Collections.unmodifiableSet(EnumSet.allOf(T::class.java).apply {
|
Collections.unmodifiableSet(EnumSet.allOf(T::class.java).apply {
|
||||||
// TODO: use removeAll with predicate
|
retainAll { value and it.mask == it.value }
|
||||||
with (iterator()) {
|
|
||||||
while (hasNext())
|
|
||||||
if (next().let { value and it.mask != it.value })
|
|
||||||
remove()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ import org.junit.Test as test
|
|||||||
|
|
||||||
class MutableCollectionTest {
|
class MutableCollectionTest {
|
||||||
|
|
||||||
// TODO: Use apply scope function
|
|
||||||
|
|
||||||
@test fun addAll() {
|
@test fun addAll() {
|
||||||
val data = listOf("foo", "bar")
|
val data = listOf("foo", "bar")
|
||||||
|
|
||||||
fun assertAdd(f: MutableList<String>.() -> Unit) = assertEquals(data, arrayListOf<String>().let { it.f(); it })
|
fun assertAdd(f: MutableList<String>.() -> Unit) = assertEquals(data, arrayListOf<String>().apply(f))
|
||||||
|
|
||||||
assertAdd { addAll(data) }
|
assertAdd { addAll(data) }
|
||||||
assertAdd { addAll(data.toTypedArray()) }
|
assertAdd { addAll(data.toTypedArray()) }
|
||||||
@@ -26,12 +24,17 @@ class MutableCollectionTest {
|
|||||||
val data = listOf("bar")
|
val data = listOf("bar")
|
||||||
val expected = listOf("foo")
|
val expected = listOf("foo")
|
||||||
|
|
||||||
fun assertRemove(f: MutableList<String>.() -> Unit) = assertEquals(expected, arrayListOf(*content).let { it.f(); it })
|
fun assertRemove(f: MutableList<String>.() -> Unit) = assertEquals(expected, content.toArrayList().apply(f))
|
||||||
|
|
||||||
assertRemove { removeAll(data) }
|
assertRemove { removeAll(data) }
|
||||||
assertRemove { removeAll(data.toTypedArray()) }
|
assertRemove { removeAll(data.toTypedArray()) }
|
||||||
assertRemove { removeAll(data.toTypedArray().asIterable()) }
|
assertRemove { removeAll(data.toTypedArray().asIterable()) }
|
||||||
assertRemove { removeAll(data.asSequence()) }
|
assertRemove { removeAll(data.asSequence()) }
|
||||||
|
assertRemove { removeAll { it in data } }
|
||||||
|
assertRemove { (this as MutableIterable<String>).removeAll { it in data } }
|
||||||
|
|
||||||
|
val predicate = { cs: CharSequence -> cs.first() == 'b' }
|
||||||
|
assertRemove { removeAll(predicate) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -40,12 +43,17 @@ class MutableCollectionTest {
|
|||||||
val data = listOf("bar")
|
val data = listOf("bar")
|
||||||
val expected = listOf("bar", "bar")
|
val expected = listOf("bar", "bar")
|
||||||
|
|
||||||
fun assertRetain(f: MutableList<String>.() -> Unit) = assertEquals(expected, arrayListOf(*content).let { it.f(); it })
|
fun assertRetain(f: MutableList<String>.() -> Unit) = assertEquals(expected, content.toArrayList().apply(f))
|
||||||
|
|
||||||
assertRetain { retainAll(data) }
|
assertRetain { retainAll(data) }
|
||||||
assertRetain { retainAll(data.toTypedArray()) }
|
assertRetain { retainAll(data.toTypedArray()) }
|
||||||
assertRetain { retainAll(data.toTypedArray().asIterable()) }
|
assertRetain { retainAll(data.toTypedArray().asIterable()) }
|
||||||
assertRetain { retainAll(data.asSequence()) }
|
assertRetain { retainAll(data.asSequence()) }
|
||||||
|
assertRetain { retainAll { it in data } }
|
||||||
|
assertRetain { (this as MutableIterable<String>).retainAll { it in data } }
|
||||||
|
|
||||||
|
val predicate = { cs: CharSequence -> cs.first() == 'b' }
|
||||||
|
assertRetain { retainAll(predicate) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user