diff --git a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt index 5de72445502..a335d7d6189 100644 --- a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt +++ b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt @@ -222,10 +222,64 @@ public fun MutableCollection.addAll(elements: Array) { addAll(elements.asList()) } +/** + * Removes all elements from this [MutableIterable] that match the given [predicate]. + */ +public fun MutableIterable.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true) + +/** + * Retains only elements of this [MutableIterable] that match the given [predicate]. + */ +public fun MutableIterable.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false) + +private fun MutableIterable.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 MutableList.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true) + +/** + * Retains only elements of this [MutableList] that match the given [predicate]. + */ +public fun MutableList.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false) + +private fun MutableList.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. */ - public fun MutableCollection.removeAll(elements: Iterable): Boolean { return removeAll(elements.convertToSetForSetOperationWith(this)) } diff --git a/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt b/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt index 1cdbc594168..2fcfbfcd3fd 100644 --- a/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt +++ b/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt @@ -28,12 +28,7 @@ private fun Iterable.toInt(): Int = this.fold(0, { value, option -> value or option.value }) private inline fun fromInt(value: Int): Set where T : FlagEnum, T: Enum = Collections.unmodifiableSet(EnumSet.allOf(T::class.java).apply { - // TODO: use removeAll with predicate - with (iterator()) { - while (hasNext()) - if (next().let { value and it.mask != it.value }) - remove() - } + retainAll { value and it.mask == it.value } }) /** diff --git a/libraries/stdlib/test/collections/MutableCollectionsTest.kt b/libraries/stdlib/test/collections/MutableCollectionsTest.kt index 0a2e3732df5..33212e10fa1 100644 --- a/libraries/stdlib/test/collections/MutableCollectionsTest.kt +++ b/libraries/stdlib/test/collections/MutableCollectionsTest.kt @@ -8,12 +8,10 @@ import org.junit.Test as test class MutableCollectionTest { - // TODO: Use apply scope function - @test fun addAll() { val data = listOf("foo", "bar") - fun assertAdd(f: MutableList.() -> Unit) = assertEquals(data, arrayListOf().let { it.f(); it }) + fun assertAdd(f: MutableList.() -> Unit) = assertEquals(data, arrayListOf().apply(f)) assertAdd { addAll(data) } assertAdd { addAll(data.toTypedArray()) } @@ -26,12 +24,17 @@ class MutableCollectionTest { val data = listOf("bar") val expected = listOf("foo") - fun assertRemove(f: MutableList.() -> Unit) = assertEquals(expected, arrayListOf(*content).let { it.f(); it }) + fun assertRemove(f: MutableList.() -> Unit) = assertEquals(expected, content.toArrayList().apply(f)) assertRemove { removeAll(data) } assertRemove { removeAll(data.toTypedArray()) } assertRemove { removeAll(data.toTypedArray().asIterable()) } assertRemove { removeAll(data.asSequence()) } + assertRemove { removeAll { it in data } } + assertRemove { (this as MutableIterable).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 expected = listOf("bar", "bar") - fun assertRetain(f: MutableList.() -> Unit) = assertEquals(expected, arrayListOf(*content).let { it.f(); it }) + fun assertRetain(f: MutableList.() -> Unit) = assertEquals(expected, content.toArrayList().apply(f)) assertRetain { retainAll(data) } assertRetain { retainAll(data.toTypedArray()) } assertRetain { retainAll(data.toTypedArray().asIterable()) } assertRetain { retainAll(data.asSequence()) } + assertRetain { retainAll { it in data } } + assertRetain { (this as MutableIterable).retainAll { it in data } } + + val predicate = { cs: CharSequence -> cs.first() == 'b' } + assertRetain { retainAll(predicate) } } }