From 7273f223f41b1191256384618e8aa78160d44f9b Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 23:18:41 +0400 Subject: [PATCH 01/17] Remove Map.groupBy --- libraries/stdlib/src/generated/_Mapping.kt | 19 ------------------- .../src/templates/Mapping.kt | 2 -- 2 files changed, 21 deletions(-) diff --git a/libraries/stdlib/src/generated/_Mapping.kt b/libraries/stdlib/src/generated/_Mapping.kt index 36f29d62c67..ab4de4fc0a6 100644 --- a/libraries/stdlib/src/generated/_Mapping.kt +++ b/libraries/stdlib/src/generated/_Mapping.kt @@ -311,13 +311,6 @@ 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) -} - /** * Returns a map of the elements in original collection grouped by the result of given *toKey* function */ @@ -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/tools/kotlin-stdlib-gen/src/templates/Mapping.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt index b1416a96181..18f2438deb5 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt @@ -185,7 +185,6 @@ fun mapping(): List { typeParam("K") returns("Map>") body { "return groupByTo(HashMap>(), toKey)" } - include(Maps) } 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 From 6849fb8358879a7f38b3947d652f6605ab5a12a4 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 23:22:38 +0400 Subject: [PATCH 02/17] Map.toList() returns List of Pairs instead of List of Entries. --- libraries/stdlib/src/generated/_Snapshots.kt | 6 +++--- .../tools/kotlin-stdlib-gen/src/templates/Snapshots.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/stdlib/src/generated/_Snapshots.kt b/libraries/stdlib/src/generated/_Snapshots.kt index 75336daf906..8b88e8c5833 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 } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt index 46531b16dee..40028f43a50 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 """ } From 4167359c084b5af684c36b4112f74841db4dfdcf Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 23:24:45 +0400 Subject: [PATCH 03/17] Map.filter() returns Map instead of List of Entries --- libraries/stdlib/src/generated/_Filtering.kt | 12 +++++++++--- .../kotlin-stdlib-gen/src/templates/Filtering.kt | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index f6e08fa2531..fdc46e28a27 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -432,10 +432,16 @@ public inline fun Iterable.filter(predicate: (T) -> Boolean): List { } /** - * Returns a list containing all elements matching the given *predicate* + * Returns a map containing all key-value pairs matching the given *predicate* */ -public inline fun Map.filter(predicate: (Map.Entry) -> Boolean): List> { - return filterTo(ArrayList>(), predicate) +public inline fun Map.filter(predicate: (Map.Entry) -> Boolean): Map { + val result = HashMap() + for (entry in this) { + if (predicate(entry)) { + result.put(entry.key, entry.value) + } + } + return result } /** diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index 5a17166734d..9547e89cb00 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -205,7 +205,21 @@ fun filtering(): List { return FilteringStream(this, true, predicate) """ } + include(Maps) + doc(Maps) { "Returns a map containing all key-value pairs matching the given *predicate*" } + returns(Maps) { "Map" } + body(Maps) { + """ + val result = HashMap() + for (entry in this) { + if (predicate(entry)) { + result.put(entry.key, entry.value) + } + } + return result + """ + } } templates add f("filterTo(destination: C, predicate: (T) -> Boolean)") { From ce5f7e9d615e38c1fa21f5be6e208864e9e57d7c Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 23:27:42 +0400 Subject: [PATCH 04/17] Breaking change. Map operations revisited. --- .../cfg/PseudocodeVariableDataCollector.kt | 2 +- .../org/jetbrains/jet/utils/addToStdlib.kt | 3 +- libraries/stdlib/src/generated/_Filtering.kt | 36 ---- .../stdlib/src/kotlin/collections/Maps.kt | 177 +++++++++++++----- .../stdlib/src/kotlin/collections/MapsJVM.kt | 11 +- .../src/templates/Filtering.kt | 19 -- 6 files changed, 140 insertions(+), 108 deletions(-) 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/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index fdc46e28a27..c90b3373d98 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -431,19 +431,6 @@ public inline fun Iterable.filter(predicate: (T) -> Boolean): List { return filterTo(ArrayList(), predicate) } -/** - * Returns a map containing all key-value pairs matching the given *predicate* - */ -public inline fun Map.filter(predicate: (Map.Entry) -> Boolean): Map { - val result = HashMap() - for (entry in this) { - if (predicate(entry)) { - result.put(entry.key, entry.value) - } - } - return result -} - /** * Returns a stream containing all elements matching the given *predicate* */ @@ -528,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* */ @@ -674,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* */ @@ -778,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/kotlin/collections/Maps.kt b/libraries/stdlib/src/kotlin/collections/Maps.kt index 75d99d79b77..0f21a570f35 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -6,37 +6,37 @@ import java.util.HashMap // 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() +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 fun MutableMap.set(key: K, value: V): V? = this.put(key, value) /** 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() } @@ -45,7 +45,7 @@ fun Map.Entry.component2() : V { * * @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 +58,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 +68,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 +123,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(HashMap(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(HashMap(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 = HashMap() + 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 = HashMap() + 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(HashMap(), 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(HashMap(), 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 = HashMap() + 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..1fa2f781125 100644 --- a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt @@ -11,14 +11,14 @@ import java.util.Properties /** * 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 +26,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/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index 9547e89cb00..4e041edd93c 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -205,21 +205,6 @@ fun filtering(): List { return FilteringStream(this, true, predicate) """ } - - include(Maps) - doc(Maps) { "Returns a map containing all key-value pairs matching the given *predicate*" } - returns(Maps) { "Map" } - body(Maps) { - """ - val result = HashMap() - for (entry in this) { - if (predicate(entry)) { - result.put(entry.key, entry.value) - } - } - return result - """ - } } templates add f("filterTo(destination: C, predicate: (T) -> Boolean)") { @@ -246,8 +231,6 @@ fun filtering(): List { return destination """ } - - include(Maps) } templates add f("filterNot(predicate: (T) -> Boolean)") { @@ -276,7 +259,6 @@ fun filtering(): List { return FilteringStream(this, false, predicate) """ } - include(Maps) } templates add f("filterNotTo(destination: C, predicate: (T) -> Boolean)") { @@ -300,7 +282,6 @@ fun filtering(): List { return destination """ } - include(Maps) } templates add f("filterNotNull()") { From 3491c88793dff948213de5e581db4236a87461d2 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 23:55:53 +0400 Subject: [PATCH 05/17] Recover test for mutable List variable and move it to ListSpecificTests --- .../test/collections/ListSpecificTest.kt | 13 ++ libraries/stdlib/test/collections/MapTest.kt | 123 ++++++------------ 2 files changed, 56 insertions(+), 80 deletions(-) diff --git a/libraries/stdlib/test/collections/ListSpecificTest.kt b/libraries/stdlib/test/collections/ListSpecificTest.kt index 4049fd8f956..778e795779c 100644 --- a/libraries/stdlib/test/collections/ListSpecificTest.kt +++ b/libraries/stdlib/test/collections/ListSpecificTest.kt @@ -40,4 +40,17 @@ class ListSpecificTest { assertEquals("bar", data.last) assertEquals(1, data.lastIndex) } + + Test fun mutableList() { + val map = mapOf("beverage" to "beer", "location" to "Mells", "name" to "James") + + var list = arrayListOf() + for (e in map) { + list += e.getKey() + list += e.getValue() + } + + assertEquals(6, list.size()) + assertEquals("beverage,beer,location,Mells,name,James", list.makeString(",")) + } } diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 4638138a035..6ba80d81c45 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -9,60 +9,55 @@ class MapTest { test fun getOrElse() { val data = hashMapOf() - val a = data.getOrElse("foo"){2} + 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 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 +67,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 +79,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) } @@ -112,32 +97,34 @@ class MapTest { } test fun map() { - val m1 = TreeMap() - m1["beverage"] = "beer" - m1["location"] = "Mells" - - val list = m1.map{ it.value + " rocks" } + val m1 = mapOf("beverage" to "beer", "location" to "Mells") + 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)) 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() { @@ -150,32 +137,32 @@ class MapTest { test fun createUsingTo() { val map = hashMapOf("a" to 1, "b" to 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 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(1, map["a"]) + assertEquals(2, map["b"]) + assertEquals(3, map["c"]) assertEquals(arrayListOf("a", "b", "c"), map.keySet().toList()) } 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")) + val map = hashMapOf(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()) } @@ -187,34 +174,11 @@ class MapTest { } 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")) + assertEquals(1, sorted["abc"]) + assertEquals(2, sorted["bc"]) + assertEquals(3, sorted["c"]) } - /** - 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() @@ -222,5 +186,4 @@ class MapTest { assertEquals("A", prop.getProperty("a", "fail")) assertEquals("B", prop.getProperty("b", "fail")) } - } From 0e656ce3ce93d3c1bd32f3dc044c51880019724f Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 10 Jun 2014 00:15:57 +0400 Subject: [PATCH 06/17] collection.toMap(selector) --- libraries/stdlib/src/generated/_Snapshots.kt | 132 ++++++++++++++++++ .../src/templates/Snapshots.kt | 20 +++ 2 files changed, 152 insertions(+) diff --git a/libraries/stdlib/src/generated/_Snapshots.kt b/libraries/stdlib/src/generated/_Snapshots.kt index 8b88e8c5833..8692019f98d 100644 --- a/libraries/stdlib/src/generated/_Snapshots.kt +++ b/libraries/stdlib/src/generated/_Snapshots.kt @@ -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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + 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 = HashMap() + for (element in this) { + result.put(selector(element), element) + } + return result +} + /** * Returns a Set of all elements */ diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt index 40028f43a50..0432bdbd2b7 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt @@ -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 = HashMap() + for (element in this) { + result.put(selector(element), element) + } + return result + """ + } + } + return templates } \ No newline at end of file From 2855741572d309ed5f694590f00de27eec4a2d35 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 10 Jun 2014 00:20:54 +0400 Subject: [PATCH 07/17] Map.Entry.toPair --- libraries/stdlib/src/kotlin/collections/Maps.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/stdlib/src/kotlin/collections/Maps.kt b/libraries/stdlib/src/kotlin/collections/Maps.kt index 0f21a570f35..57dcfc176dd 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -40,6 +40,11 @@ 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 * From cb17f0c635b6ce136e25c943b2d4d5074328349c Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 10 Jun 2014 22:42:52 +0400 Subject: [PATCH 08/17] Remove map iteration from ListSpecificTest - JS fails, but it is irrelevant to test. --- libraries/stdlib/test/collections/ListSpecificTest.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/stdlib/test/collections/ListSpecificTest.kt b/libraries/stdlib/test/collections/ListSpecificTest.kt index 778e795779c..f28527e862f 100644 --- a/libraries/stdlib/test/collections/ListSpecificTest.kt +++ b/libraries/stdlib/test/collections/ListSpecificTest.kt @@ -42,15 +42,14 @@ class ListSpecificTest { } Test fun mutableList() { - val map = mapOf("beverage" to "beer", "location" to "Mells", "name" to "James") + val items = listOf("beverage", "location", "name") var list = arrayListOf() - for (e in map) { - list += e.getKey() - list += e.getValue() + for (item in items) { + list += item } - assertEquals(6, list.size()) - assertEquals("beverage,beer,location,Mells,name,James", list.makeString(",")) + assertEquals(3, list.size()) + assertEquals("beverage,location,name", list.join(",")) } } From a9da7cfeea4ec8a1410a69b6a8258e0f8b411051 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Wed, 11 Jun 2014 18:10:46 +0400 Subject: [PATCH 09/17] Use LinkedHashMap everywhere to preserve order. --- libraries/stdlib/src/generated/_Mapping.kt | 24 +++++++++---------- libraries/stdlib/src/generated/_Snapshots.kt | 24 +++++++++---------- .../stdlib/src/kotlin/collections/JUtil.kt | 15 +++++++++++- .../stdlib/src/kotlin/collections/JUtilJVM.kt | 19 --------------- .../stdlib/src/kotlin/collections/Maps.kt | 17 +++++++------ libraries/stdlib/test/collections/MapTest.kt | 20 +++++++--------- .../src/templates/Mapping.kt | 2 +- .../src/templates/Snapshots.kt | 2 +- 8 files changed, 57 insertions(+), 66 deletions(-) diff --git a/libraries/stdlib/src/generated/_Mapping.kt b/libraries/stdlib/src/generated/_Mapping.kt index ab4de4fc0a6..b628312aee9 100644 --- a/libraries/stdlib/src/generated/_Mapping.kt +++ b/libraries/stdlib/src/generated/_Mapping.kt @@ -245,84 +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) + 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) } /** diff --git a/libraries/stdlib/src/generated/_Snapshots.kt b/libraries/stdlib/src/generated/_Snapshots.kt index 8692019f98d..5fcf852e08d 100644 --- a/libraries/stdlib/src/generated/_Snapshots.kt +++ b/libraries/stdlib/src/generated/_Snapshots.kt @@ -511,7 +511,7 @@ public fun String.toList(): List { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun Array.toMap(selector: (T) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -522,7 +522,7 @@ public inline fun Array.toMap(selector: (T) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun BooleanArray.toMap(selector: (Boolean) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -533,7 +533,7 @@ public inline fun BooleanArray.toMap(selector: (Boolean) -> K): Map ByteArray.toMap(selector: (Byte) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -544,7 +544,7 @@ public inline fun ByteArray.toMap(selector: (Byte) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun CharArray.toMap(selector: (Char) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -555,7 +555,7 @@ public inline fun CharArray.toMap(selector: (Char) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun DoubleArray.toMap(selector: (Double) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -566,7 +566,7 @@ public inline fun DoubleArray.toMap(selector: (Double) -> K): Map * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun FloatArray.toMap(selector: (Float) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -577,7 +577,7 @@ public inline fun FloatArray.toMap(selector: (Float) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun IntArray.toMap(selector: (Int) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -588,7 +588,7 @@ public inline fun IntArray.toMap(selector: (Int) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun LongArray.toMap(selector: (Long) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -599,7 +599,7 @@ public inline fun LongArray.toMap(selector: (Long) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun ShortArray.toMap(selector: (Short) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -610,7 +610,7 @@ public inline fun ShortArray.toMap(selector: (Short) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun Iterable.toMap(selector: (T) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -621,7 +621,7 @@ public inline fun Iterable.toMap(selector: (T) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun Stream.toMap(selector: (T) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } @@ -632,7 +632,7 @@ public inline fun Stream.toMap(selector: (T) -> K): Map { * Returns Map containing all the values from the given collection indexed by *selector* */ public inline fun String.toMap(selector: (Char) -> K): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } 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 57dcfc176dd..20494f02727 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -1,7 +1,6 @@ package kotlin -import java.util.Collections -import java.util.HashMap +import java.util.* // Map APIs @@ -129,7 +128,7 @@ public fun MutableMap.putAll(values: Iterable>): Unit { * @includeFunctionBody ../../test/collections/MapTest.kt mapValues */ public inline fun Map.mapValues(transform: (Map.Entry) -> R): Map { - return mapValuesTo(HashMap(this.size), transform) + return mapValuesTo(LinkedHashMap(this.size), transform) } /** @@ -138,14 +137,14 @@ public inline fun Map.mapValues(transform: (Map.Entry) -> * @includeFunctionBody ../../test/collections/MapTest.kt mapKeys */ public inline fun Map.mapKeys(transform: (Map.Entry) -> R): Map { - return mapKeysTo(HashMap(this.size), transform) + 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 = HashMap() + val result = LinkedHashMap() for (entry in this) { if (predicate(entry.key)) { result.put(entry.key, entry.value) @@ -158,7 +157,7 @@ public inline fun Map.filterKeys(predicate: (K) -> Boolean): Map Map.filterValues(predicate: (V) -> Boolean): Map { - val result = HashMap() + val result = LinkedHashMap() for (entry in this) { if (predicate(entry.value)) { result.put(entry.key, entry.value) @@ -184,7 +183,7 @@ public inline fun > Map.filterTo(destination: C * Returns a map containing all key-value pairs matching the given *predicate* */ public inline fun Map.filter(predicate: (Map.Entry) -> Boolean): Map { - return filterTo(HashMap(), predicate) + return filterTo(LinkedHashMap(), predicate) } /** @@ -203,7 +202,7 @@ public inline fun > Map.filterNotTo(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(HashMap(), predicate) + return filterNotTo(LinkedHashMap(), predicate) } /** @@ -217,7 +216,7 @@ public fun MutableMap.plusAssign(pair: Pair) { * Returns a map containing all key-value pairs from the given collection */ public fun Iterable>.toMap(): Map { - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(element.first, element.second) } diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 6ba80d81c45..c1da9679689 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -1,14 +1,12 @@ package test.collections import kotlin.test.* - -import java.util.* import org.junit.Test as test class MapTest { test fun getOrElse() { - val data = hashMapOf() + val data = mapOf() val a = data.getOrElse("foo") { 2 } assertEquals(2, a) @@ -16,7 +14,7 @@ class MapTest { assertEquals(3, b) assertEquals(0, data.size()) - val empty = hashMapOf() + val empty = mapOf() val c = empty.getOrElse("") { null } assertEquals(null, c) } @@ -91,7 +89,7 @@ class MapTest { } test fun contains() { - val map = hashMapOf("a" to 1, "b" to 2) + val map = mapOf("a" to 1, "b" to 2) assert("a" in map) assert("c" !in map) } @@ -121,7 +119,7 @@ class MapTest { } 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["a"]) assertEquals(2, map["b"]) @@ -135,7 +133,7 @@ class MapTest { } test fun createUsingTo() { - val map = hashMapOf("a" to 1, "b" to 2) + val map = mapOf("a" to 1, "b" to 2) assertEquals(2, map.size) assertEquals(1, map["a"]) assertEquals(2, map["b"]) @@ -158,8 +156,8 @@ class MapTest { } test fun toSortedMap() { - val map = hashMapOf(Pair("c", 3), Pair("b", 2), Pair("a", 1)) - val sorted = map.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"]) @@ -167,7 +165,7 @@ class MapTest { } test fun toSortedMapWithComparator() { - val map = hashMapOf(Pair("c", 3), Pair("bc", 2), Pair("bd", 4), Pair("abc", 1)) + 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 @@ -180,7 +178,7 @@ class MapTest { } test fun toProperties() { - val map = hashMapOf("a" to "A", "b" to "B") + val map = mapOf("a" to "A", "b" to "B") val prop = map.toProperties() assertEquals(2, prop.size) assertEquals("A", prop.getProperty("a", "fail")) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt index 18f2438deb5..b9d2095f3b5 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt @@ -184,7 +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)" } + body { "return groupByTo(LinkedHashMap>(), toKey)" } } templates add f("groupByTo(map: MutableMap>, toKey: (T) -> K)") { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt index 0432bdbd2b7..4692853aa65 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Snapshots.kt @@ -117,7 +117,7 @@ fun snapshots(): List { returns("Map") body { """ - val result = HashMap() + val result = LinkedHashMap() for (element in this) { result.put(selector(element), element) } From 8cfbaf4749086bab0ee8b115513e36d2373e4221 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Fri, 20 Jun 2014 22:21:58 +0400 Subject: [PATCH 10/17] Add StdLibMapTest, fix naming to convention StdLib* tests. --- ...{ArraysTest.java => StdLibArraysTest.java} | 2 +- ....java => StdLibBitwiseOperationsTest.java} | 2 +- .../k2js/test/semantics/StdLibMapTest.java | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) rename js/js.tests/test/org/jetbrains/k2js/test/semantics/{ArraysTest.java => StdLibArraysTest.java} (93%) rename js/js.tests/test/org/jetbrains/k2js/test/semantics/{BitwiseOperationsTest.java => StdLibBitwiseOperationsTest.java} (92%) create mode 100644 js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibMapTest.java 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"); + } +} + From 4ea62071b539b696cbaa44775d4239407ac8ac2c Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Fri, 20 Jun 2014 23:00:31 +0400 Subject: [PATCH 11/17] Split tests into platform-independent and JVM. --- .../stdlib/test/collections/MapJVMTest.kt | 44 +++++++++++++++++++ libraries/stdlib/test/collections/MapTest.kt | 37 ---------------- 2 files changed, 44 insertions(+), 37 deletions(-) create mode 100644 libraries/stdlib/test/collections/MapJVMTest.kt 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 c1da9679689..aea8dccd9da 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -98,7 +98,6 @@ class MapTest { val m1 = mapOf("beverage" to "beer", "location" to "Mells") val list = m1.map { it.value + " rocks" } - println("Got new list $list") assertEquals(arrayListOf("beer rocks", "Mells rocks"), list) } @@ -147,41 +146,5 @@ class MapTest { 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["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")) - } } From 9b081fd254aa3f1888db8f2f353618aaa3778a28 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 23 Jun 2014 21:58:30 +0400 Subject: [PATCH 12/17] Minor: assert -> assertTrue --- libraries/stdlib/test/collections/MapTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index aea8dccd9da..9f8f422a30b 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -90,8 +90,8 @@ class MapTest { test fun contains() { val map = mapOf("a" to 1, "b" to 2) - assert("a" in map) - assert("c" !in map) + assertTrue("a" in map) + assertTrue("c" !in map) } test fun map() { From 223a14a855b0e3b018b837b1e75bc3e47a0f273d Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 23 Jun 2014 22:04:34 +0400 Subject: [PATCH 13/17] Moved MutableMap.set from Maps.kt to MapsJVM.kt to avoid ambiguity when compile MapTest.kt by JS backend. --- js/js.libraries/src/core/core.kt | 5 +++-- libraries/stdlib/src/kotlin/collections/Maps.kt | 3 --- libraries/stdlib/src/kotlin/collections/MapsJVM.kt | 4 ++++ 3 files changed, 7 insertions(+), 5 deletions(-) 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/libraries/stdlib/src/kotlin/collections/Maps.kt b/libraries/stdlib/src/kotlin/collections/Maps.kt index 20494f02727..48540340d2c 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -12,9 +12,6 @@ public val Map<*, *>.size: Int public val Map<*, *>.empty: Boolean get() = isEmpty() -/** Provides [] access to maps */ -public fun MutableMap.set(key: K, value: V): V? = this.put(key, value) - /** 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() diff --git a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt index 1fa2f781125..f4ae05cd51f 100644 --- a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt @@ -8,6 +8,10 @@ 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 */ From 14ab3c4de1e9758a3691ec0ba9b3484cb8b5fa15 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 23 Jun 2014 21:39:33 +0400 Subject: [PATCH 14/17] JS stdlib: allowed use null as key and value in Map implementations. Added tests for using null in Set and Map implementations. --- js/js.translator/testData/maps.js | 38 ++++++++------------------- libraries/stdlib/test/js/MapJsTest.kt | 30 +++++++++++++++++++++ libraries/stdlib/test/js/SetJsTest.kt | 23 ++++++++++++---- 3 files changed, 59 insertions(+), 32 deletions(-) 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/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() From af8d0f7b9efc8adaed59c62e6a2ac9a67f58c277 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 24 Jun 2014 17:38:39 +0400 Subject: [PATCH 15/17] Fix assertion arguments. --- .../plugin/libraries/NavigateToStdlibSourceRegressionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java b/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java index 8f9283fe3b7..6859fa6f390 100644 --- a/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java @@ -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); } From 37874556ae2da64880275a0080aececd04b9d9c6 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 24 Jun 2014 18:10:16 +0400 Subject: [PATCH 16/17] Use different file for navigation test because of test framework limitation. --- .../libraries/NavigateToStdlibSourceRegressionTest.java | 2 +- libraries/stdlib/src/kotlin/collections/Iterators.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java b/idea/tests/org/jetbrains/jet/plugin/libraries/NavigateToStdlibSourceRegressionTest.java index 6859fa6f390..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 { 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() From 3980664049c9d6248d516a35ca41b37ae9c24934 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 15 Jul 2014 21:48:14 +0400 Subject: [PATCH 17/17] Tests for map functions. --- .../stdlib/test/collections/CollectionTest.kt | 9 ++- libraries/stdlib/test/collections/MapTest.kt | 57 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) 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/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 9f8f422a30b..12b7f99656d 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -131,6 +131,21 @@ class MapTest { assertEquals(2, map.get("b")) } + 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("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) @@ -146,5 +161,47 @@ class MapTest { assertEquals(arrayListOf("c", "b", "a"), 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 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 plusAssign() { + val extended = hashMapOf(Pair("b", 3)) + extended += ("c" to 2) + assertEquals(2, extended.size) + assertEquals(2, extended["c"]) + assertEquals(3, extended["b"]) + } }