diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt index 5846edffed5..20721dc34b6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt @@ -61,7 +61,7 @@ public class PseudocodeVariableDataCollector( // Variables declared in an inner (deeper) scope can't be accessed from an outer scope. // Thus they can be filtered out upon leaving the inner scope. - return data.filterKeys { variable -> + return data.filterKeys_tmp { variable -> val lexicalScope = lexicalScopeVariableInfo.declaredIn[variable] // '-1' for variables declared outside this pseudocode val depth = lexicalScope?.depth ?: -1 diff --git a/compiler/util/src/org/jetbrains/jet/utils/addToStdlib.kt b/compiler/util/src/org/jetbrains/jet/utils/addToStdlib.kt index 1fd917fda61..129706280c6 100644 --- a/compiler/util/src/org/jetbrains/jet/utils/addToStdlib.kt +++ b/compiler/util/src/org/jetbrains/jet/utils/addToStdlib.kt @@ -19,7 +19,8 @@ package org.jetbrains.jet.utils.addToStdlib import java.util.HashMap import java.util.Collections -fun Map.filterKeys(predicate: (K)->Boolean): Map { +deprecated("Replace with filterKeys when bootstrapped") +fun Map.filterKeys_tmp(predicate: (K)->Boolean): Map { val result = HashMap() for ((k, v) in this) { if (predicate(k)) { diff --git a/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java b/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java index 8f9283fe3b7..b1042979a58 100644 --- a/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java @@ -43,7 +43,7 @@ public class NavigateToStdlibSourceRegressionTest extends NavigateToLibraryRegre } public void testJavaClass() throws IOException { - doNavigationInSourcesTest("libraries/stdlib/src/kotlin/collections/Maps.kt", "Collections", "java.util.Collections"); + doNavigationInSourcesTest("libraries/stdlib/src/kotlin/collections/Iterators.kt", "Enumeration", "java.util.Enumeration"); } public void testKotlinClass() throws IOException { @@ -68,7 +68,7 @@ public class NavigateToStdlibSourceRegressionTest extends NavigateToLibraryRegre PsiFile psiFile = getPsiFileForFileFromSources(file); String text = psiFile.getText(); int index = text.indexOf(element); - assertNotSame(-1, "Cannot find text '" + element + "' in file " + path); + assertNotSame("Cannot find text '" + element + "' in file " + path, -1, index); while (Character.isLetter(text.charAt(index - 1))) { index = text.indexOf(element, index + 1); } diff --git a/js/js.libraries/src/core/core.kt b/js/js.libraries/src/core/core.kt index c4ab30bda4d..8592866f4c8 100644 --- a/js/js.libraries/src/core/core.kt +++ b/js/js.libraries/src/core/core.kt @@ -8,8 +8,9 @@ import java.lang.*; native public val noImpl : Nothing = throw Exception() +// Drop this after KT-2093 will be fixed and restore MutableMap.set in Maps.kt from MapsJVM.kt /** Provides [] access to maps */ -native public fun MutableMap.set(key: K, value: V): Unit = noImpl +native public fun MutableMap.set(key: K, value: V): V? = noImpl library("println") public fun println() {} @@ -22,4 +23,4 @@ native public fun parseInt(s: String, radix: Int = 10): Int = js.noImpl library public fun safeParseInt(s : String) : Int? = js.noImpl library -public fun safeParseDouble(s : String) : Double? = js.noImpl \ No newline at end of file +public fun safeParseDouble(s : String) : Double? = js.noImpl diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ArraysTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibArraysTest.java similarity index 93% rename from js/js.tests/test/org/jetbrains/k2js/test/semantics/ArraysTest.java rename to js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibArraysTest.java index f9463d4db69..a7a912d6a96 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ArraysTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibArraysTest.java @@ -19,7 +19,7 @@ package org.jetbrains.k2js.test.semantics; import junit.framework.Test; @SuppressWarnings("JUnitTestCaseWithNoTests") -public final class ArraysTest extends JsUnitTestBase { +public final class StdLibArraysTest extends JsUnitTestBase { public static Test suite() throws Exception { return createTestSuiteForFile("libraries/stdlib/test/collections/ArraysTest.kt"); } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/BitwiseOperationsTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibBitwiseOperationsTest.java similarity index 92% rename from js/js.tests/test/org/jetbrains/k2js/test/semantics/BitwiseOperationsTest.java rename to js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibBitwiseOperationsTest.java index a936f2d7d6d..d6da13bb521 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/BitwiseOperationsTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibBitwiseOperationsTest.java @@ -20,7 +20,7 @@ import junit.framework.Test; //NOTE: well, it has tests @SuppressWarnings("JUnitTestCaseWithNoTests") -public final class BitwiseOperationsTest extends JsUnitTestBase { +public final class StdLibBitwiseOperationsTest extends JsUnitTestBase { public static Test suite() throws Exception { return createTestSuiteForFile("libraries/stdlib/test/language/BitwiseOperationsTest.kt"); } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibMapTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibMapTest.java new file mode 100644 index 00000000000..6bafdf740d1 --- /dev/null +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibMapTest.java @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.test.semantics; + +import junit.framework.Test; + +@SuppressWarnings("JUnitTestCaseWithNoTests") +public final class StdLibMapTest extends JsUnitTestBase { + public static Test suite() throws Exception { + return createTestSuiteForFile("libraries/stdlib/test/collections/MapTest.kt"); + } +} + diff --git a/js/js.translator/testData/maps.js b/js/js.translator/testData/maps.js index 61e02737d8c..36e78202ff7 100644 --- a/js/js.translator/testData/maps.js +++ b/js/js.translator/testData/maps.js @@ -68,6 +68,8 @@ }; function hashObject(obj) { + if (obj == null) return ""; + var hashCode; if (typeof obj == "string") { return obj; @@ -97,23 +99,11 @@ } function equals_fixedValueNoEquals(fixedValue, variableValue) { - return (typeof variableValue.equals_za3rmp$ == FUNCTION) ? + return (variableValue != null && typeof variableValue.equals_za3rmp$ == FUNCTION) ? + // TODO: test this case variableValue.equals_za3rmp$(fixedValue) : (fixedValue === variableValue); } - function createKeyValCheck(kvStr) { - return function (kv) { - if (kv === null) { - throw new Error("null is not a valid " + kvStr); - } - else if (typeof kv == "undefined") { - throw new Error(kvStr + " must not be undefined"); - } - }; - } - - var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value"); - /** * @constructor * @param {string} hash @@ -167,7 +157,7 @@ Bucket.prototype = { getEqualityFunction: function (searchValue) { - return (typeof searchValue.equals_za3rmp$ == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals; + return (searchValue != null && typeof searchValue.equals_za3rmp$ == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals; }, getEntryForKey: createBucketSearcher(ENTRY), @@ -178,7 +168,7 @@ var result = this.getEntryAndIndexForKey(key); if (result) { arrayRemoveAt(this.entries, result[0]); - return result[1]; + return result; } return null; }, @@ -253,8 +243,6 @@ var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null; this.put_wn2jw4$ = function (key, value) { - checkKey(key); - checkValue(value); var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null; // Check if a bucket exists for the bucket key @@ -282,8 +270,6 @@ }; this.get_za3rmp$ = function (key) { - checkKey(key); - var hash = hashingFunction(key); // Check if a bucket exists for the bucket key @@ -300,7 +286,6 @@ }; this.containsKey_za3rmp$ = function (key) { - checkKey(key); var bucketKey = hashingFunction(key); // Check if a bucket exists for the bucket key @@ -310,7 +295,6 @@ }; this.containsValue_za3rmp$ = function (value) { - checkValue(value); var i = buckets.length; while (i--) { if (buckets[i].containsValue_za3rmp$(value)) { @@ -354,17 +338,17 @@ }; this.remove_za3rmp$ = function (key) { - checkKey(key); - - var hash = hashingFunction(key), bucketIndex, oldValue = null; + var hash = hashingFunction(key), bucketIndex, oldValue = null, result = null; // Check if a bucket exists for the bucket key var bucket = getBucketForHash(bucketsByHash, hash); if (bucket) { // Remove entry from this bucket for this key - oldValue = bucket.removeEntryForKey(key); - if (oldValue !== null) { + result = bucket.removeEntryForKey(key); + if (result !== null) { + oldValue = result[1]; + // Entry was removed, so check if bucket is empty if (!bucket.entries.length) { // Bucket is empty, so remove it from the bucket collections diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index f6e08fa2531..c90b3373d98 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -431,13 +431,6 @@ public inline fun Iterable.filter(predicate: (T) -> Boolean): List { return filterTo(ArrayList(), predicate) } -/** - * Returns a list containing all elements matching the given *predicate* - */ -public inline fun Map.filter(predicate: (Map.Entry) -> Boolean): List> { - return filterTo(ArrayList>(), predicate) -} - /** * Returns a stream containing all elements matching the given *predicate* */ @@ -522,13 +515,6 @@ public inline fun Iterable.filterNot(predicate: (T) -> Boolean): List return filterNotTo(ArrayList(), predicate) } -/** - * Returns a list containing all elements not matching the given *predicate* - */ -public inline fun Map.filterNot(predicate: (Map.Entry) -> Boolean): List> { - return filterNotTo(ArrayList>(), predicate) -} - /** * Returns a stream containing all elements not matching the given *predicate* */ @@ -668,14 +654,6 @@ public inline fun > Iterable.filterNotTo(desti return destination } -/** - * Appends all elements not matching the given *predicate* to the given *destination* - */ -public inline fun >> Map.filterNotTo(destination: C, predicate: (Map.Entry) -> Boolean): C { - for (element in this) if (!predicate(element)) destination.add(element) - return destination -} - /** * Appends all elements not matching the given *predicate* to the given *destination* */ @@ -772,14 +750,6 @@ public inline fun > Iterable.filterTo(destinat return destination } -/** - * Appends all elements matching the given *predicate* into the given *destination* - */ -public inline fun >> Map.filterTo(destination: C, predicate: (Map.Entry) -> Boolean): C { - for (element in this) if (predicate(element)) destination.add(element) - return destination -} - /** * Appends all elements matching the given *predicate* into the given *destination* */ diff --git a/libraries/stdlib/src/generated/_Mapping.kt b/libraries/stdlib/src/generated/_Mapping.kt index 36f29d62c67..b628312aee9 100644 --- a/libraries/stdlib/src/generated/_Mapping.kt +++ b/libraries/stdlib/src/generated/_Mapping.kt @@ -245,91 +245,84 @@ public inline fun > Stream.flatMapTo(destin * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun Array.groupBy(toKey: (T) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun BooleanArray.groupBy(toKey: (Boolean) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun ByteArray.groupBy(toKey: (Byte) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun CharArray.groupBy(toKey: (Char) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun DoubleArray.groupBy(toKey: (Double) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun FloatArray.groupBy(toKey: (Float) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun IntArray.groupBy(toKey: (Int) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun LongArray.groupBy(toKey: (Long) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun ShortArray.groupBy(toKey: (Short) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun Iterable.groupBy(toKey: (T) -> K): Map> { - return groupByTo(HashMap>(), toKey) -} - -/** - * Returns a map of the elements in original collection grouped by the result of given *toKey* function - */ -public inline fun Map.groupBy(toKey: (Map.Entry) -> K): Map>> { - return groupByTo(HashMap>>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun Stream.groupBy(toKey: (T) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ public inline fun String.groupBy(toKey: (Char) -> K): Map> { - return groupByTo(HashMap>(), toKey) + return groupByTo(LinkedHashMap>(), toKey) } /** @@ -452,18 +445,6 @@ public inline fun Iterable.groupByTo(map: MutableMap return map } -/** - * Appends elements from original collection grouped by the result of given *toKey* function to the given *map* - */ -public inline fun Map.groupByTo(map: MutableMap>>, toKey: (Map.Entry) -> K): Map>> { - for (element in this) { - val key = toKey(element) - val list = map.getOrPut(key) { ArrayList>() } - list.add(element) - } - return map -} - /** * Appends elements from original collection grouped by the result of given *toKey* function to the given *map* */ diff --git a/libraries/stdlib/src/generated/_Snapshots.kt b/libraries/stdlib/src/generated/_Snapshots.kt index 75336daf906..5fcf852e08d 100644 --- a/libraries/stdlib/src/generated/_Snapshots.kt +++ b/libraries/stdlib/src/generated/_Snapshots.kt @@ -400,10 +400,10 @@ public fun String.toLinkedList(): LinkedList { /** * Returns a List containing all key-value pairs */ -public fun Map.toList(): List> { - val result = ArrayList>(size) +public fun Map.toList(): List> { + val result = ArrayList>(size) for (item in this) - result.add(item) + result.add(item.key to item.value) return result } @@ -507,6 +507,138 @@ public fun String.toList(): List { return toCollection(ArrayList()) } +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun Array.toMap(selector: (T) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun BooleanArray.toMap(selector: (Boolean) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun ByteArray.toMap(selector: (Byte) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun CharArray.toMap(selector: (Char) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun DoubleArray.toMap(selector: (Double) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun FloatArray.toMap(selector: (Float) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun IntArray.toMap(selector: (Int) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun LongArray.toMap(selector: (Long) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun ShortArray.toMap(selector: (Short) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun Iterable.toMap(selector: (T) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun Stream.toMap(selector: (T) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + +/** + * Returns Map containing all the values from the given collection indexed by *selector* + */ +public inline fun String.toMap(selector: (Char) -> K): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + /** * Returns a Set of all elements */ diff --git a/libraries/stdlib/src/kotlin/collections/Iterators.kt b/libraries/stdlib/src/kotlin/collections/Iterators.kt index b3cdf0bff5b..c64a7b20b9e 100644 --- a/libraries/stdlib/src/kotlin/collections/Iterators.kt +++ b/libraries/stdlib/src/kotlin/collections/Iterators.kt @@ -1,11 +1,11 @@ package kotlin -import java.util.* +import java.util.Enumeration /** Helper to make java.util.Enumeration usable in for */ -public fun java.util.Enumeration.iterator(): Iterator = object: Iterator { +public fun Enumeration.iterator(): Iterator = object: Iterator { override fun hasNext(): Boolean = hasMoreElements() public override fun next(): T = nextElement() diff --git a/libraries/stdlib/src/kotlin/collections/JUtil.kt b/libraries/stdlib/src/kotlin/collections/JUtil.kt index b5025cd45c5..05bb42dc830 100644 --- a/libraries/stdlib/src/kotlin/collections/JUtil.kt +++ b/libraries/stdlib/src/kotlin/collections/JUtil.kt @@ -17,7 +17,7 @@ public fun listOf(vararg values: T): List = if (values.size == 0) stdlib_e public fun listOf(): List = stdlib_emptyList() /** Returns a new read-only map of given pairs, where the first value is the key, and the second is value */ -public fun mapOf(vararg values: Pair): Map = if (values.size == 0) stdlib_emptyMap() else hashMapOf(*values) +public fun mapOf(vararg values: Pair): Map = if (values.size == 0) stdlib_emptyMap() else linkedMapOf(*values) /** Returns an empty read-only map */ public fun mapOf(): Map = stdlib_emptyMap() @@ -40,6 +40,19 @@ public fun hashMapOf(vararg values: Pair): HashMap { return answer } +/** + * Returns a new [[LinkedHashMap]] populated with the given pairs where the first value in each pair + * is the key and the second value is the value. This map preserves insertion order so iterating through + * the map's entries will be in the same order + * + * @includeFunctionBody ../../test/collections/MapTest.kt createLinkedMap + */ +public fun linkedMapOf(vararg values: Pair): LinkedHashMap { + val answer = LinkedHashMap(values.size) + answer.putAll(*values) + return answer +} + /** Returns the size of the collection */ public val Collection<*>.size: Int get() = size() diff --git a/libraries/stdlib/src/kotlin/collections/JUtilJVM.kt b/libraries/stdlib/src/kotlin/collections/JUtilJVM.kt index 27fb8175976..a83d1ede0c6 100644 --- a/libraries/stdlib/src/kotlin/collections/JUtilJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/JUtilJVM.kt @@ -36,25 +36,6 @@ public fun sortedMapOf(vararg values: Pair): SortedMap { return answer } -/** - * Returns a new [[LinkedHashMap]] populated with the given pairs where the first value in each pair - * is the key and the second value is the value. This map preserves insertion order so iterating through - * the map's entries will be in the same order - * - * @includeFunctionBody ../../test/collections/MapTest.kt createLinkedMap - */ -public fun linkedMapOf(vararg values: Pair): LinkedHashMap { - val answer = LinkedHashMap(values.size) - /** - TODO replace by this simpler call when we can pass vararg values into other methods - answer.putAll(values) - */ - for (v in values) { - answer.put(v.first, v.second) - } - return answer -} - /** Returns the Set if its not null otherwise returns the empty set */ public fun Set?.orEmpty(): Set = if (this != null) this else Collections.EMPTY_SET as Set diff --git a/libraries/stdlib/src/kotlin/collections/Maps.kt b/libraries/stdlib/src/kotlin/collections/Maps.kt index 75d99d79b77..48540340d2c 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -1,51 +1,52 @@ package kotlin -import java.util.Collections -import java.util.HashMap +import java.util.* // Map APIs /** Returns the size of the map */ -public val Map<*,*>.size : Int -get() = size() +public val Map<*, *>.size: Int + get() = size() /** Returns true if this map is empty */ -public val Map<*,*>.empty : Boolean -get() = isEmpty() - -/** Provides [] access to maps */ -public fun MutableMap.set(key : K, value : V) : V? = this.put(key, value) +public val Map<*, *>.empty: Boolean + get() = isEmpty() /** Returns the [[Map]] if its not null otherwise it returns the empty [[Map]] */ public fun Map?.orEmpty() : Map -= if (this != null) this else stdlib_emptyMap() + = if (this != null) this else stdlib_emptyMap() public fun Map.contains(key : K) : Boolean = containsKey(key) /** Returns the key of the entry */ -public val Map.Entry.key : K +public val Map.Entry.key: K get() = getKey() /** Returns the value of the entry */ -public val Map.Entry.value : V +public val Map.Entry.value: V get() = getValue() /** Returns the key of the entry */ -fun Map.Entry.component1() : K { +fun Map.Entry.component1(): K { return getKey() } /** Returns the value of the entry */ -fun Map.Entry.component2() : V { +fun Map.Entry.component2(): V { return getValue() } +/** Converts entry to Pair with key being first component and value being second */ +fun Map.Entry.toPair(): Pair { + return Pair(getKey(), getValue()) +} + /** * Returns the value for the given key or returns the result of the defaultValue function if there was no entry for the given key * * @includeFunctionBody ../../test/collections/MapTest.kt getOrElse */ -public inline fun Map.getOrElse(key: K, defaultValue: ()-> V) : V { +public inline fun Map.getOrElse(key: K, defaultValue: () -> V): V { if (this.containsKey(key)) { return this.get(key) as V } else { @@ -58,7 +59,7 @@ public inline fun Map.getOrElse(key: K, defaultValue: ()-> V) : V { * * @includeFunctionBody ../../test/collections/MapTest.kt getOrPut */ -public inline fun MutableMap.getOrPut(key: K, defaultValue: ()-> V) : V { +public inline fun MutableMap.getOrPut(key: K, defaultValue: () -> V): V { if (this.containsKey(key)) { return this.get(key) as V } else { @@ -68,63 +69,54 @@ public inline fun MutableMap.getOrPut(key: K, defaultValue: ()-> V) : } } - /** * Returns an [[Iterator]] over the entries in the [[Map]] * * @includeFunctionBody ../../test/collections/MapTest.kt iterateWithProperties */ -public fun Map.iterator(): Iterator> { +public fun Map.iterator(): Iterator> { val entrySet = this.entrySet() return entrySet.iterator() } /** - * Populates the given *result* [[Map]] with the value returned by applying the *transform* function on each [[Map.Entry]] in this [[Map]] + * Populates the given *destination* [[Map]] with the value returned by applying the *transform* function on each [[Map.Entry]] in this [[Map]] */ -public inline fun > Map.mapValuesTo(result: C, transform : (Map.Entry) -> R) : C { - for (e in this) { - val newValue = transform(e) - result.put(e.key, newValue) - } - return result +public inline fun > Map.mapValuesTo(destination: C, transform: (Map.Entry) -> R): C { + for (e in this) { + val newValue = transform(e) + destination.put(e.key, newValue) + } + return destination +} + +/** + * Populates the given *destination* [[Map]] with the value returned by applying the *transform* function on each [[Map.Entry]] in this [[Map]] + */ +public inline fun > Map.mapKeysTo(destination: C, transform: (Map.Entry) -> R): C { + for (e in this) { + val newKey = transform(e) + destination.put(newKey, e.value) + } + return destination } /** * Puts all the entries into this [[MutableMap]] with the first value in the pair being the key and the second the value */ -public fun MutableMap.putAll(vararg values: Pair): Unit { +public fun MutableMap.putAll(vararg values: Pair): Unit { for ((key, value) in values) { put(key, value) } } /** - * Copies the entries in this [[Map]] to the given mutable *map* + * Puts all the entries into this [[MutableMap]] with the first value in the pair being the key and the second the value */ -public fun > Map.toMap(map: C): C { - map.putAll(this) - return map -} - -/** - * Copies the entries from given iterable of pairs to the given mutable *map* - */ -public fun > Iterable>.toMap(map: C): C { - for((key,value) in this) { - if (map.containsKey(key)) { - throw DuplicateKeyException() - } - map.put(key,value) +public fun MutableMap.putAll(values: Iterable>): Unit { + for ((key, value) in values) { + put(key, value) } - return map -} - -/** - * Creates map from given iterable of pairs - */ -public fun Iterable>.toMap() : Map { - return toMap(HashMap()) } /** @@ -132,6 +124,98 @@ public fun Iterable>.toMap() : Map { * * @includeFunctionBody ../../test/collections/MapTest.kt mapValues */ -public inline fun Map.mapValues(transform : (Map.Entry) -> R): Map { - return mapValuesTo(java.util.HashMap(this.size), transform) +public inline fun Map.mapValues(transform: (Map.Entry) -> R): Map { + return mapValuesTo(LinkedHashMap(this.size), transform) +} + +/** + * Returns a new Map containing the results of applying the given *transform* function to each [[Map.Entry]] in this [[Map]] + * + * @includeFunctionBody ../../test/collections/MapTest.kt mapKeys + */ +public inline fun Map.mapKeys(transform: (Map.Entry) -> R): Map { + return mapKeysTo(LinkedHashMap(this.size), transform) +} + +/** + * Returns a map containing all key-value pairs matching keys with the given *predicate* + */ +public inline fun Map.filterKeys(predicate: (K) -> Boolean): Map { + val result = LinkedHashMap() + for (entry in this) { + if (predicate(entry.key)) { + result.put(entry.key, entry.value) + } + } + return result +} + +/** + * Returns a map containing all key-value pairs matching values with the given *predicate* + */ +public inline fun Map.filterValues(predicate: (V) -> Boolean): Map { + val result = LinkedHashMap() + for (entry in this) { + if (predicate(entry.value)) { + result.put(entry.key, entry.value) + } + } + return result +} + + +/** + * Appends all elements matching the given *predicate* into the given *destination* + */ +public inline fun > Map.filterTo(destination: C, predicate: (Map.Entry) -> Boolean): C { + for (element in this) { + if (predicate(element)) { + destination.put(element.key, element.value) + } + } + return destination +} + +/** + * Returns a map containing all key-value pairs matching the given *predicate* + */ +public inline fun Map.filter(predicate: (Map.Entry) -> Boolean): Map { + return filterTo(LinkedHashMap(), predicate) +} + +/** + * Appends all elements matching the given *predicate* into the given *destination* + */ +public inline fun > Map.filterNotTo(destination: C, predicate: (Map.Entry) -> Boolean): C { + for (element in this) { + if (!predicate(element)) { + destination.put(element.key, element.value) + } + } + return destination +} + +/** + * Returns a map containing all key-value pairs matching the given *predicate* + */ +public inline fun Map.filterNot(predicate: (Map.Entry) -> Boolean): Map { + return filterNotTo(LinkedHashMap(), predicate) +} + +/** + * Appends given [pair] to the mutable map. + */ +public fun MutableMap.plusAssign(pair: Pair) { + put(pair.first, pair.second) +} + +/** + * Returns a map containing all key-value pairs from the given collection + */ +public fun Iterable>.toMap(): Map { + val result = LinkedHashMap() + for (element in this) { + result.put(element.first, element.second) + } + return result } diff --git a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt index 00aa9607741..f4ae05cd51f 100644 --- a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt @@ -8,17 +8,21 @@ import java.util.Properties // Map APIs +// Move back to Maps.kt after KT-2093 will be fixed +/** Provides [] access to maps */ +public fun MutableMap.set(key: K, value: V): V? = this.put(key, value) + /** * Converts this [[Map]] to a [[LinkedHashMap]] so future insertion orders are maintained */ -public fun Map.toLinkedMap(): LinkedHashMap = toMap(LinkedHashMap(size)) +public fun Map.toLinkedMap(): LinkedHashMap = LinkedHashMap(this) /** * Converts this [[Map]] to a [[SortedMap]] so iteration order will be in key order * * @includeFunctionBody ../../test/collections/MapTest.kt toSortedMap */ -public fun Map.toSortedMap(): SortedMap = toMap(TreeMap()) +public fun Map.toSortedMap(): SortedMap = TreeMap(this) /** * Converts this [[Map]] to a [[SortedMap]] using the given *comparator* so that iteration order will be in the order @@ -26,8 +30,11 @@ public fun Map.toSortedMap(): SortedMap = toMap(TreeMap()) * * @includeFunctionBody ../../test/collections/MapTest.kt toSortedMapWithComparator */ -public fun Map.toSortedMap(comparator: Comparator): SortedMap = toMap(TreeMap(comparator)) - +public fun Map.toSortedMap(comparator: Comparator): SortedMap { + val result = TreeMap(comparator) + result.putAll(this) + return result +} /** * Converts this [[Map]] to a [[Properties]] object diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 72ea5224722..611ff36962f 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -165,10 +165,17 @@ class CollectionTest { } test fun groupBy() { - val words = arrayListOf("a", "ab", "abc", "def", "abcd") + val words = arrayListOf("a", "abc", "ab", "def", "abcd") val byLength = words.groupBy { it.length } assertEquals(4, byLength.size()) + // verify that order of keys is preserved + val listOfPairs = byLength.toList() + assertEquals(1, listOfPairs[0].first) + assertEquals(3, listOfPairs[1].first) + assertEquals(2, listOfPairs[2].first) + assertEquals(4, listOfPairs[3].first) + val l3 = byLength.getOrElse(3, { ArrayList() }) assertEquals(2, l3.size) } diff --git a/libraries/stdlib/test/collections/ListSpecificTest.kt b/libraries/stdlib/test/collections/ListSpecificTest.kt index 4049fd8f956..f28527e862f 100644 --- a/libraries/stdlib/test/collections/ListSpecificTest.kt +++ b/libraries/stdlib/test/collections/ListSpecificTest.kt @@ -40,4 +40,16 @@ class ListSpecificTest { assertEquals("bar", data.last) assertEquals(1, data.lastIndex) } + + Test fun mutableList() { + val items = listOf("beverage", "location", "name") + + var list = arrayListOf() + for (item in items) { + list += item + } + + assertEquals(3, list.size()) + assertEquals("beverage,location,name", list.join(",")) + } } diff --git a/libraries/stdlib/test/collections/MapJVMTest.kt b/libraries/stdlib/test/collections/MapJVMTest.kt new file mode 100644 index 00000000000..6680456a3f1 --- /dev/null +++ b/libraries/stdlib/test/collections/MapJVMTest.kt @@ -0,0 +1,44 @@ +package test.collections + +import kotlin.test.* +import org.junit.Test as test + +class MapJVMTest { + test fun createSortedMap() { + val map = sortedMapOf(Pair("c", 3), Pair("b", 2), Pair("a", 1)) + assertEquals(1, map["a"]) + assertEquals(2, map["b"]) + assertEquals(3, map["c"]) + assertEquals(arrayListOf("a", "b", "c"), map.keySet().toList()) + } + + test fun toSortedMap() { + val map = mapOf(Pair("c", 3), Pair("b", 2), Pair("a", 1)) + val sorted = map.toSortedMap() + assertEquals(1, sorted["a"]) + assertEquals(2, sorted["b"]) + assertEquals(3, sorted["c"]) + assertEquals(arrayListOf("a", "b", "c"), sorted.keySet().toList()) + } + + test fun toSortedMapWithComparator() { + val map = mapOf(Pair("c", 3), Pair("bc", 2), Pair("bd", 4), Pair("abc", 1)) + val c = comparator{ a, b -> + val answer = a.length() - b.length() + if (answer == 0) a.compareTo(b) else answer + } + val sorted = map.toSortedMap(c) + assertEquals(arrayListOf("c", "bc", "bd", "abc"), sorted.keySet().toList()) + assertEquals(1, sorted["abc"]) + assertEquals(2, sorted["bc"]) + assertEquals(3, sorted["c"]) + } + + test fun toProperties() { + val map = mapOf("a" to "A", "b" to "B") + val prop = map.toProperties() + assertEquals(2, prop.size) + assertEquals("A", prop.getProperty("a", "fail")) + assertEquals("B", prop.getProperty("b", "fail")) + } +} diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 4638138a035..12b7f99656d 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -1,68 +1,61 @@ package test.collections import kotlin.test.* - -import java.util.* import org.junit.Test as test class MapTest { test fun getOrElse() { - val data = hashMapOf() - val a = data.getOrElse("foo"){2} + val data = mapOf() + val a = data.getOrElse("foo") { 2 } assertEquals(2, a) - val b = data.getOrElse("foo"){3} + val b = data.getOrElse("foo") { 3 } assertEquals(3, b) assertEquals(0, data.size()) - val empty = hashMapOf() - val c = empty.getOrElse("") {null} + val empty = mapOf() + val c = empty.getOrElse("") { null } assertEquals(null, c) } test fun getOrPut() { val data = hashMapOf() - val a = data.getOrPut("foo"){2} + val a = data.getOrPut("foo") { 2 } assertEquals(2, a) - val b = data.getOrPut("foo"){3} + val b = data.getOrPut("foo") { 3 } assertEquals(2, b) assertEquals(1, data.size()) val empty = hashMapOf() - val c = empty.getOrPut("") {null} + val c = empty.getOrPut("") { null } assertEquals(null, c) } test fun sizeAndEmpty() { val data = hashMapOf() - assertTrue{ data.empty } + assertTrue { data.empty } assertEquals(data.size, 0) } test fun setViaIndexOperators() { val map = hashMapOf() - assertTrue{ map.empty } + assertTrue { map.empty } assertEquals(map.size, 0) map["name"] = "James" - assertTrue{ !map.empty } + assertTrue { !map.empty } assertEquals(map.size(), 1) assertEquals("James", map["name"]) } - + test fun iterate() { - val map = TreeMap() - map["beverage"] = "beer" - map["location"] = "Mells" - map["name"] = "James" - + val map = mapOf("beverage" to "beer", "location" to "Mells", "name" to "James") val list = arrayListOf() for (e in map) { - println("key = ${e.getKey()}, value = ${e.getValue()}") list.add(e.getKey()) list.add(e.getValue()) } @@ -72,14 +65,9 @@ class MapTest { } test fun iterateWithProperties() { - val map = TreeMap() - map["beverage"] = "beer" - map["location"] = "Mells" - map["name"] = "James" - + val map = mapOf("beverage" to "beer", "location" to "Mells", "name" to "James") val list = arrayListOf() for (e in map) { - println("key = ${e.key}, value = ${e.value}") list.add(e.key) list.add(e.value) } @@ -89,14 +77,9 @@ class MapTest { } test fun iterateWithExtraction() { - val map = TreeMap() - map["beverage"] = "beer" - map["location"] = "Mells" - map["name"] = "James" - + val map = mapOf("beverage" to "beer", "location" to "Mells", "name" to "James") val list = arrayListOf() for ((key, value) in map) { - println("key = ${key}, value = ${value}") list.add(key) list.add(value) } @@ -106,38 +89,39 @@ class MapTest { } test fun contains() { - val map = hashMapOf("a" to 1, "b" to 2) - assert("a" in map) - assert("c" !in map) + val map = mapOf("a" to 1, "b" to 2) + assertTrue("a" in map) + assertTrue("c" !in map) } test fun map() { - val m1 = TreeMap() - m1["beverage"] = "beer" - m1["location"] = "Mells" + val m1 = mapOf("beverage" to "beer", "location" to "Mells") + val list = m1.map { it.value + " rocks" } - val list = m1.map{ it.value + " rocks" } - - println("Got new list $list") assertEquals(arrayListOf("beer rocks", "Mells rocks"), list) } test fun mapValues() { - val m1 = TreeMap() - m1["beverage"] = "beer" - m1["location"] = "Mells" - - val m2 = m1.mapValues{ it.value + "2" } + val m1 = mapOf("beverage" to "beer", "location" to "Mells") + val m2 = m1.mapValues { it.value + "2" } assertEquals("beer2", m2["beverage"]) assertEquals("Mells2", m2["location"]) } + test fun mapKeys() { + val m1 = mapOf("beverage" to "beer", "location" to "Mells") + val m2 = m1.mapKeys { it.key + "2" } + + assertEquals("beer", m2["beverage2"]) + assertEquals("Mells", m2["location2"]) + } + test fun createUsingPairs() { - val map = hashMapOf(Pair("a", 1), Pair("b", 2)) + val map = mapOf(Pair("a", 1), Pair("b", 2)) assertEquals(2, map.size) - assertEquals(1, map.get("a")) - assertEquals(2, map.get("b")) + assertEquals(1, map["a"]) + assertEquals(2, map["b"]) } test fun createFromIterable() { @@ -147,80 +131,77 @@ class MapTest { assertEquals(2, map.get("b")) } - test fun createUsingTo() { - val map = hashMapOf("a" to 1, "b" to 2) + test fun createWithSelector() { + val map = listOf("a", "bb", "ccc").toMap { it.length } + assertEquals(3, map.size) + assertEquals("a", map.get(1)) + assertEquals("bb", map.get(2)) + assertEquals("ccc", map.get(3)) + } + + test fun createWithSelectorAndOverwrite() { + val map = listOf("aa", "bb", "ccc").toMap { it.length } assertEquals(2, map.size) - assertEquals(1, map.get("a")) - assertEquals(2, map.get("b")) + assertEquals("bb", map.get(2)) + assertEquals("ccc", map.get(3)) + } + + test fun createUsingTo() { + val map = mapOf("a" to 1, "b" to 2) + assertEquals(2, map.size) + assertEquals(1, map["a"]) + assertEquals(2, map["b"]) } test fun createLinkedMap() { val map = linkedMapOf(Pair("c", 3), Pair("b", 2), Pair("a", 1)) - assertEquals(1, map.get("a")) - assertEquals(2, map.get("b")) - assertEquals(3, map.get("c")) + assertEquals(1, map["a"]) + assertEquals(2, map["b"]) + assertEquals(3, map["c"]) assertEquals(arrayListOf("c", "b", "a"), map.keySet().toList()) } - test fun createSortedMap() { - val map = sortedMapOf(Pair("c", 3), Pair("b", 2), Pair("a", 1)) - assertEquals(1, map.get("a")) - assertEquals(2, map.get("b")) - assertEquals(3, map.get("c")) - assertEquals(arrayListOf("a", "b", "c"), map.keySet().toList()) + test fun filter() { + val map = mapOf(Pair("b", 3), Pair("c", 2), Pair("a", 2)) + val filteredByKey = map.filter { it.key == "b" } + assertEquals(1, filteredByKey.size) + assertEquals(3, filteredByKey["b"]) + + val filteredByKey2 = map.filterKeys { it == "b" } + assertEquals(1, filteredByKey2.size) + assertEquals(3, filteredByKey2["b"]) + + val filteredByValue = map.filter { it.value == 2 } + assertEquals(2, filteredByValue.size) + assertEquals(null, filteredByValue["b"]) + assertEquals(2, filteredByValue["c"]) + assertEquals(2, filteredByValue["a"]) + + val filteredByValue2 = map.filterValues { it == 2 } + assertEquals(2, filteredByValue2.size) + assertEquals(null, filteredByValue2["b"]) + assertEquals(2, filteredByValue2["c"]) + assertEquals(2, filteredByValue2["a"]) } - test fun toSortedMap() { - val map = hashMapOf(Pair("c", 3), Pair("b", 2), Pair("a", 1)) - val sorted = map.toSortedMap() - assertEquals(1, sorted.get("a")) - assertEquals(2, sorted.get("b")) - assertEquals(3, sorted.get("c")) - assertEquals(arrayListOf("a", "b", "c"), sorted.keySet().toList()) + test fun filterNot() { + val map = mapOf(Pair("b", 3), Pair("c", 2), Pair("a", 2)) + val filteredByKey = map.filterNot { it.key == "b" } + assertEquals(2, filteredByKey.size) + assertEquals(null, filteredByKey["b"]) + assertEquals(2, filteredByKey["c"]) + assertEquals(2, filteredByKey["a"]) + + val filteredByValue = map.filterNot { it.value == 2 } + assertEquals(1, filteredByValue.size) + assertEquals(3, filteredByValue["b"]) } - test fun toSortedMapWithComparator() { - val map = hashMapOf(Pair("c", 3), Pair("bc", 2), Pair("bd", 4), Pair("abc", 1)) - val c = comparator{ a, b -> - val answer = a.length() - b.length() - if (answer == 0) a.compareTo(b) else answer - } - val sorted = map.toSortedMap(c) - assertEquals(arrayListOf("c", "bc", "bd", "abc"), sorted.keySet().toList()) - assertEquals(1, sorted.get("abc")) - assertEquals(2, sorted.get("bc")) - assertEquals(3, sorted.get("c")) + test fun plusAssign() { + val extended = hashMapOf(Pair("b", 3)) + extended += ("c" to 2) + assertEquals(2, extended.size) + assertEquals(2, extended["c"]) + assertEquals(3, extended["b"]) } - - /** - TODO - test case for http://youtrack.jetbrains.com/issue/KT-1773 - - test fun compilerBug() { - val map = TreeMap() - map["beverage"] = "beer" - map["location"] = "Mells" - map["name"] = "James" - - var list = arrayListOf() - for (e in map) { - println("key = ${e.getKey()}, value = ${e.getValue()}") - list += e.getKey() - list += e.getValue() - } - - assertEquals(6, list.size()) - assertEquals("beverage,beer,location,Mells,name,James", list.join(",")) - println("==== worked! $list") - } - */ - - test fun toProperties() { - val map = hashMapOf("a" to "A", "b" to "B") - val prop = map.toProperties() - assertEquals(2, prop.size) - assertEquals("A", prop.getProperty("a", "fail")) - assertEquals("B", prop.getProperty("b", "fail")) - } - } diff --git a/libraries/stdlib/test/js/MapJsTest.kt b/libraries/stdlib/test/js/MapJsTest.kt index 9e976453f7a..96d86e1e70d 100644 --- a/libraries/stdlib/test/js/MapJsTest.kt +++ b/libraries/stdlib/test/js/MapJsTest.kt @@ -23,6 +23,7 @@ class ComplexMapJsTest : MapJsTest() { override fun > Collection.toNormalizedList(): List = this.toSortedList() // hashMapOf returns ComlpexHashMap because it is Generic override fun emptyMutableMap(): MutableMap = hashMapOf() + override fun emptyMutableMapWithNullableKeyValue(): MutableMap = hashMapOf() } class PrimitiveMapJsTest : MapJsTest() { @@ -39,6 +40,7 @@ class PrimitiveMapJsTest : MapJsTest() { override fun > Collection.toNormalizedList(): List = this.toSortedList() override fun emptyMutableMap(): MutableMap = HashMap() + override fun emptyMutableMapWithNullableKeyValue(): MutableMap = HashMap() } class LinkedHashMapTest : MapJsTest() { @@ -55,6 +57,7 @@ class LinkedHashMapTest : MapJsTest() { override fun > Collection.toNormalizedList(): List = this.toList() override fun emptyMutableMap(): MutableMap = LinkedHashMap() + override fun emptyMutableMapWithNullableKeyValue(): MutableMap = LinkedHashMap() } abstract class MapJsTest { @@ -224,6 +227,31 @@ abstract class MapJsTest { assertTrue(map.isEmpty()) } + test fun nullAsKey() { + val map = emptyMutableMapWithNullableKeyValue() + + assertTrue(map.isEmpty()) + map.put(null, 23) + assertFalse(map.isEmpty()) + assertTrue(map.containsKey(null)) + assertEquals(23, map[null]) + assertEquals(23, map.remove(null)) + assertTrue(map.isEmpty()) + assertEquals(null, map[null]) + } + + test fun nullAsValue() { + val map = emptyMutableMapWithNullableKeyValue() + val KEY = "Key" + + assertTrue(map.isEmpty()) + map.put(KEY, null) + assertFalse(map.isEmpty()) + assertEquals(null, map[KEY]) + assertTrue(map.containsValue(null)) + assertEquals(null, map.remove(KEY)) + assertTrue(map.isEmpty()) + } /* TODO fix bug with .set() on Map... @@ -444,6 +472,8 @@ abstract class MapJsTest { abstract fun emptyMutableMap(): MutableMap + abstract fun emptyMutableMapWithNullableKeyValue(): MutableMap + fun createTestMap(): Map = createTestMutableMap() fun createTestMutableMap(): MutableMap { diff --git a/libraries/stdlib/test/js/SetJsTest.kt b/libraries/stdlib/test/js/SetJsTest.kt index 6cf3a28a4a3..f09e026e8d2 100644 --- a/libraries/stdlib/test/js/SetJsTest.kt +++ b/libraries/stdlib/test/js/SetJsTest.kt @@ -22,10 +22,13 @@ class ComplexSetJsTest : SetJsTest() { } // hashSetOf returns ComlpexHashSet because it is Generic - override fun createEmptyMutableSet(): MutableSet = hashSetOf() + override fun createEmptyMutableSet(): MutableSet = hashSetOf() + override fun createEmptyMutableSetWithNullableValues(): MutableSet = hashSetOf() } class PrimitiveSetJsTest : SetJsTest() { + override fun createEmptyMutableSet(): MutableSet = HashSet() + override fun createEmptyMutableSetWithNullableValues(): MutableSet = HashSet() test override fun constructors() { HashSet() HashSet(3) @@ -35,11 +38,11 @@ class PrimitiveSetJsTest : SetJsTest() { assertEquals(data, set) } - - override fun createEmptyMutableSet(): MutableSet = HashSet() } class LinkedHashSetTest : SetJsTest() { + override fun createEmptyMutableSet(): MutableSet = LinkedHashSet() + override fun createEmptyMutableSetWithNullableValues(): MutableSet = LinkedHashSet() test override fun constructors() { LinkedHashSet() LinkedHashSet(3) @@ -49,8 +52,6 @@ class LinkedHashSetTest : SetJsTest() { assertEquals(data, set) } - - override fun createEmptyMutableSet(): MutableSet = LinkedHashSet() } abstract class SetJsTest { @@ -187,8 +188,20 @@ abstract class SetJsTest { test abstract fun constructors() + Test fun nullAsValue() { + val set = createEmptyMutableSetWithNullableValues() + + assertTrue(set.isEmpty(), "Set should be empty") + set.add(null) + assertFalse(set.isEmpty(), "Set should not be empty") + assertTrue(set.contains(null), "Set should contains null") + assertTrue(set.remove(null), "Expected true when remove null") + assertTrue(set.isEmpty(), "Set should be empty") + } + //Helpers abstract fun createEmptyMutableSet(): MutableSet + abstract fun createEmptyMutableSetWithNullableValues(): MutableSet fun createTestMutableSet(): MutableSet { val set = createEmptyMutableSet() diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index 5a17166734d..4e041edd93c 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -205,7 +205,6 @@ fun filtering(): List { return FilteringStream(this, true, predicate) """ } - include(Maps) } templates add f("filterTo(destination: C, predicate: (T) -> Boolean)") { @@ -232,8 +231,6 @@ fun filtering(): List { return destination """ } - - include(Maps) } templates add f("filterNot(predicate: (T) -> Boolean)") { @@ -262,7 +259,6 @@ fun filtering(): List { return FilteringStream(this, false, predicate) """ } - include(Maps) } templates add f("filterNotTo(destination: C, predicate: (T) -> Boolean)") { @@ -286,7 +282,6 @@ fun filtering(): List { return destination """ } - include(Maps) } templates add f("filterNotNull()") { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt index b1416a96181..b9d2095f3b5 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt @@ -184,8 +184,7 @@ fun mapping(): List { doc { "Returns a map of the elements in original collection grouped by the result of given *toKey* function" } typeParam("K") returns("Map>") - body { "return groupByTo(HashMap>(), toKey)" } - include(Maps) + body { "return groupByTo(LinkedHashMap>(), toKey)" } } templates add f("groupByTo(map: MutableMap>, toKey: (T) -> K)") { @@ -204,7 +203,6 @@ fun mapping(): List { return map """ } - include(Maps) } return templates } \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt index 46531b16dee..4692853aa65 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt @@ -62,12 +62,12 @@ fun snapshots(): List { templates add f("toList()") { only(Maps) doc { "Returns a List containing all key-value pairs" } - returns("List>") + returns("List>") body { """ - val result = ArrayList>(size) + val result = ArrayList>(size) for (item in this) - result.add(item) + result.add(item.key to item.value) return result """ } @@ -106,5 +106,25 @@ fun snapshots(): List { body { "return toCollection(LinkedList())" } } + templates add f("toMap(selector: (T) -> K)") { + inline(true) + typeParam("K") + doc { + """ + Returns Map containing all the values from the given collection indexed by *selector* + """ + } + returns("Map") + body { + """ + val result = LinkedHashMap() + for (element in this) { + result.put(selector(element), element) + } + return result + """ + } + } + return templates } \ No newline at end of file