From 5f4e8bf4fb979e51a6615ae01009edd8964bb617 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Fri, 2 Nov 2018 00:06:37 +0300 Subject: [PATCH] Correct abstract mutable collections declarations in kotlin-stdlib-common Add SinceKotlin(1.3) to the new and substantially changed common declarations #KT-28091 --- .../collections/AbstractMutableCollection.kt | 32 ++++ .../kotlin/collections/AbstractMutableList.kt | 7 +- .../kotlin/collections/AbstractMutableMap.kt | 25 ++- .../kotlin/collections/AbstractMutableSet.kt | 21 ++- .../collections/AbstractMutableCollection.kt | 14 +- .../kotlin/collections/AbstractMutableMap.kt | 12 +- .../collections/AbstractMutableCollection.kt | 4 +- .../collections/AbstractCollectionsTest.kt | 167 ++++++++++++++++++ 8 files changed, 263 insertions(+), 19 deletions(-) create mode 100644 libraries/stdlib/common/src/kotlin/collections/AbstractMutableCollection.kt create mode 100644 libraries/stdlib/test/collections/AbstractCollectionsTest.kt diff --git a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableCollection.kt b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableCollection.kt new file mode 100644 index 00000000000..c41ec582146 --- /dev/null +++ b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableCollection.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.collections + +/** + * Provides a skeletal implementation of the [MutableCollection] interface. + * + * @param E the type of elements contained in the collection. The collection is invariant on its element type. + */ +@SinceKotlin("1.3") +public expect abstract class AbstractMutableCollection : MutableCollection { + protected constructor() + + abstract override val size: Int + abstract override fun iterator(): MutableIterator + abstract override fun add(element: E): Boolean + + override fun isEmpty(): Boolean + override fun contains(element: @UnsafeVariance E): Boolean + override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean + + + override fun addAll(elements: Collection): Boolean + override fun remove(element: E): Boolean + override fun removeAll(elements: Collection): Boolean + override fun retainAll(elements: Collection): Boolean + override fun clear(): Unit +} + diff --git a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableList.kt b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableList.kt index 3864de20db9..a2411b2d33f 100644 --- a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableList.kt +++ b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableList.kt @@ -5,7 +5,12 @@ package kotlin.collections -expect abstract class AbstractMutableList : MutableList { +/** + * Provides a skeletal implementation of the [MutableList] interface. + * + * @param E the type of elements contained in the list. The list is invariant on its element type. + */ +public expect abstract class AbstractMutableList : MutableList { protected constructor() // From List diff --git a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableMap.kt b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableMap.kt index 2368c1afa6c..4ab33a2fdc8 100644 --- a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableMap.kt +++ b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableMap.kt @@ -5,8 +5,16 @@ package kotlin.collections -expect abstract class AbstractMutableMap : MutableMap { - +/** + * Provides a skeletal implementation of the [MutableMap] interface. + * + * The implementor is required to implement [entries] property, which should return mutable set of map entries, and [put] function. + * + * @param K the type of map keys. The map is invariant on its key type. + * @param V the type of map values. The map is invariant on its value type. + */ +@SinceKotlin("1.3") +public expect abstract class AbstractMutableMap : MutableMap { protected constructor() /** @@ -18,4 +26,17 @@ expect abstract class AbstractMutableMap : MutableMap { * @return the previous value associated with the key, or `null` if the key was not present in the map. */ abstract override fun put(key: K, value: V): V? + + abstract override val entries: MutableSet> + + override val keys: MutableSet + override val size: Int + override val values: MutableCollection + override fun clear() + override fun containsKey(key: K): Boolean + override fun containsValue(value: V): Boolean + override fun get(key: K): V? + override fun isEmpty(): Boolean + override fun putAll(from: Map) + override fun remove(key: K): V? } \ No newline at end of file diff --git a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableSet.kt b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableSet.kt index cbca8cfc5da..352ff499f66 100644 --- a/libraries/stdlib/common/src/kotlin/collections/AbstractMutableSet.kt +++ b/libraries/stdlib/common/src/kotlin/collections/AbstractMutableSet.kt @@ -5,8 +5,27 @@ package kotlin.collections -expect abstract class AbstractMutableSet : MutableSet { +/** + * Provides a skeletal implementation of the [MutableSet] interface. + * + * @param E the type of elements contained in the set. The set is invariant on its element type. + */ +@SinceKotlin("1.3") +public expect abstract class AbstractMutableSet : MutableSet { protected constructor() + abstract override val size: Int + abstract override fun iterator(): MutableIterator abstract override fun add(element: E): Boolean + + override fun isEmpty(): Boolean + override fun contains(element: @UnsafeVariance E): Boolean + override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean + + + override fun addAll(elements: Collection): Boolean + override fun remove(element: E): Boolean + override fun removeAll(elements: Collection): Boolean + override fun retainAll(elements: Collection): Boolean + override fun clear(): Unit } \ No newline at end of file diff --git a/libraries/stdlib/js/src/kotlin/collections/AbstractMutableCollection.kt b/libraries/stdlib/js/src/kotlin/collections/AbstractMutableCollection.kt index c02e4e44886..2b737f29cac 100644 --- a/libraries/stdlib/js/src/kotlin/collections/AbstractMutableCollection.kt +++ b/libraries/stdlib/js/src/kotlin/collections/AbstractMutableCollection.kt @@ -10,11 +10,11 @@ package kotlin.collections * * @param E the type of elements contained in the collection. The collection is invariant on its element type. */ -public abstract class AbstractMutableCollection protected constructor() : AbstractCollection(), MutableCollection { +public actual abstract class AbstractMutableCollection protected actual constructor() : AbstractCollection(), MutableCollection { - abstract override fun add(element: E): Boolean + actual abstract override fun add(element: E): Boolean - override fun remove(element: E): Boolean { + actual override fun remove(element: E): Boolean { val iterator = iterator() while (iterator.hasNext()) { if (iterator.next() == element) { @@ -25,7 +25,7 @@ public abstract class AbstractMutableCollection protected constructor() : Abs return false } - override fun addAll(elements: Collection): Boolean { + actual override fun addAll(elements: Collection): Boolean { var modified = false for (element in elements) { if (add(element)) modified = true @@ -33,10 +33,10 @@ public abstract class AbstractMutableCollection protected constructor() : Abs return modified } - override fun removeAll(elements: Collection): Boolean = (this as MutableIterable).removeAll { it in elements } - override fun retainAll(elements: Collection): Boolean = (this as MutableIterable).removeAll { it !in elements } + actual override fun removeAll(elements: Collection): Boolean = (this as MutableIterable).removeAll { it in elements } + actual override fun retainAll(elements: Collection): Boolean = (this as MutableIterable).removeAll { it !in elements } - override fun clear(): Unit { + actual override fun clear(): Unit { val iterator = this.iterator() while (iterator.hasNext()) { iterator.next() diff --git a/libraries/stdlib/js/src/kotlin/collections/AbstractMutableMap.kt b/libraries/stdlib/js/src/kotlin/collections/AbstractMutableMap.kt index 85573747fd3..da5eb0cc6aa 100644 --- a/libraries/stdlib/js/src/kotlin/collections/AbstractMutableMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/AbstractMutableMap.kt @@ -41,12 +41,12 @@ public actual abstract class AbstractMutableMap protected actual construct } - override fun clear() { + actual override fun clear() { entries.clear() } private var _keys: MutableSet? = null - override val keys: MutableSet + actual override val keys: MutableSet get() { if (_keys == null) { _keys = object : AbstractMutableSet() { @@ -82,14 +82,14 @@ public actual abstract class AbstractMutableMap protected actual construct actual abstract override fun put(key: K, value: V): V? - override fun putAll(from: Map) { + actual override fun putAll(from: Map) { for ((key, value) in from) { put(key, value) } } private var _values: MutableCollection? = null - override val values: MutableCollection + actual override val values: MutableCollection get() { if (_values == null) { _values = object : AbstractMutableCollection() { @@ -122,10 +122,10 @@ public actual abstract class AbstractMutableMap protected actual construct return _values!! } - override fun remove(key: K): V? { + actual override fun remove(key: K): V? { val iter = entries.iterator() while (iter.hasNext()) { - var entry = iter.next() + val entry = iter.next() val k = entry.key if (key == k) { val value = entry.value diff --git a/libraries/stdlib/jvm/src/kotlin/collections/AbstractMutableCollection.kt b/libraries/stdlib/jvm/src/kotlin/collections/AbstractMutableCollection.kt index a10453a5208..34042382dae 100644 --- a/libraries/stdlib/jvm/src/kotlin/collections/AbstractMutableCollection.kt +++ b/libraries/stdlib/jvm/src/kotlin/collections/AbstractMutableCollection.kt @@ -13,7 +13,7 @@ import java.util.AbstractCollection * @param E the type of elements contained in the collection. The collection is invariant on its element type. */ @SinceKotlin("1.1") -public abstract class AbstractMutableCollection protected constructor() : MutableCollection, AbstractCollection() { +public actual abstract class AbstractMutableCollection protected actual constructor() : MutableCollection, AbstractCollection() { /** * Adds the specified element to the collection. * @@ -23,5 +23,5 @@ public abstract class AbstractMutableCollection protected constructor() : Mut * @return `true` if the element has been added, `false` if the collection does not support duplicates * and the element is already contained in the collection. */ - abstract override fun add(element: E): Boolean + actual abstract override fun add(element: E): Boolean } \ No newline at end of file diff --git a/libraries/stdlib/test/collections/AbstractCollectionsTest.kt b/libraries/stdlib/test/collections/AbstractCollectionsTest.kt new file mode 100644 index 00000000000..73a9cd10610 --- /dev/null +++ b/libraries/stdlib/test/collections/AbstractCollectionsTest.kt @@ -0,0 +1,167 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.* +import kotlin.test.* + +class AbstractCollectionsTest { + + class ReadOnlyCollection : AbstractCollection() { + private val data = arrayOf("ok") + override val size: Int get() = 1 + override fun iterator(): Iterator = data.iterator() + } + + class ReadOnlySet : AbstractSet() { + private val data = arrayOf("ok") + override val size: Int get() = 1 + override fun iterator(): Iterator = data.iterator() + } + + class ReadOnlyList(override val size: Int = 1) : AbstractList() { + override fun get(index: Int): String = index.takeIf { it in indices }?.let { "ok" } ?: throw IndexOutOfBoundsException() + } + + class ReadOnlyMap : AbstractMap() { + override val entries: Set> = mapOf("ok" to 42).entries + } + + + @Test + fun abstractCollection() { + val coll = ReadOnlyCollection() + assertEquals(listOf("ok"), coll.toList()) + + compare(coll.toList(), coll) { + collectionBehavior() + } + } + + @Test + fun abstractSet() { + val set = ReadOnlySet() + assertEquals(1, set.size) + assertTrue("ok" in set) + + compare(set.toSet(), set) { + setBehavior() + } + } + + @Test + fun abstractList() { + val list = ReadOnlyList(4) + assertEquals(listOf("ok", "ok", "ok", "ok"), list) + + compare(list.toList(), list) { + listBehavior() + } + } + + @Test + fun abstractMap() { + val map = ReadOnlyMap() + assertEquals(1, map.size) + assertTrue(map.contains("ok")) + assertTrue(map.containsValue(42)) + assertEquals(setOf("ok"), map.keys) + assertEquals(listOf(42), map.values.toList()) + + compare(map.toMap(), map) { + mapBehavior() + } + } + + class MutColl(val storage: MutableCollection = mutableListOf()) : AbstractMutableCollection() { + override val size: Int get() = storage.size + override fun iterator(): MutableIterator = storage.iterator() + override fun add(element: String): Boolean = storage.add(element) + } + + class MutList(val storage: MutableList = mutableListOf()) : AbstractMutableList() { + override val size: Int get() = storage.size + override fun get(index: Int): String = storage.get(index) + override fun add(index: Int, element: String) = storage.add(index, element) + override fun removeAt(index: Int): String = storage.removeAt(index) + override fun set(index: Int, element: String): String = storage.set(index, element) + } + + class MutSet(val storage: MutableSet = mutableSetOf()) : AbstractMutableSet() { + override val size: Int get() = storage.size + override fun iterator(): MutableIterator = storage.iterator() + override fun add(element: String): Boolean = storage.add(element) + } + + class MutMap(val storage: MutableMap = mutableMapOf()) : AbstractMutableMap() { + override fun put(key: String, value: Int): Int? = storage.put(key, value) + override val entries: MutableSet> get() = storage.entries + } + + @Test + fun abstractMutableCollection() { + val coll = MutColl() + coll += "ok" + coll += "test" + coll.removeAll { it.length > 2 } + assertEquals(1, coll.size) + assertEquals(listOf("ok"), coll.toList()) + + compare(coll.storage, coll) { + collectionBehavior() + } + } + + @Test + fun abstractMutableList() { + val list = MutList() + list += "test" + list += "ok" + list += "element" + + val subList = list.subList(0, 2) + subList.retainAll { it.length <= 2 } + + assertEquals(listOf("ok", "element"), list) + + compare(list.storage, list) { + listBehavior() + } + } + + @Test + fun abstractMutableSet() { + val set = MutSet() + set.addAll(listOf("ok", "test", "element", "test")) + set.removeAll { it.length < 4 } + + assertEquals(2, set.size) + assertEquals(setOf("element", "test"), set) + + compare(set.storage, set) { + setBehavior() + } + } + + @Test + fun abstractMutableMap() { + val map = MutMap() + for (e in 'a'..'z') map[e.toString()] = e.toInt() + assertEquals(26, map.size) + + map.remove("a") + map.keys.remove("b") + map.keys.removeAll { it == "c" } + + map.values.remove('d'.toInt()) + assertTrue(map.containsKey("e")) + assertTrue(map.containsValue('f'.toInt())) + + compare(map.storage, map) { + mapBehavior() + } + } +} \ No newline at end of file