Optimize snapshot operations to return special collection implementations when result is empty or has single element.

#KT-9990 Fixed
This commit is contained in:
Ilya Gorbunov
2016-02-10 15:48:05 +03:00
parent 0a5db2fea4
commit f35dc47b4e
10 changed files with 237 additions and 42 deletions
+2
View File
@@ -91,6 +91,8 @@ internal fun <T> arrayPlusCollection(array: dynamic, collection: Collection<T>):
return result
}
// no singleton map implementation in js, return map as is
internal inline fun <K, V> Map<K, V>.toSingletonMap(): Map<K, V> = this
internal inline fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<out Any?> =
if (isVarargs)
+90 -18
View File
@@ -6308,63 +6308,99 @@ public fun CharArray.toHashSet(): HashSet<Char> {
* Returns a [List] containing all elements.
*/
public fun <T> Array<out T>.toList(): List<T> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun ByteArray.toList(): List<Byte> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun ShortArray.toList(): List<Short> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun IntArray.toList(): List<Int> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun LongArray.toList(): List<Long> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun FloatArray.toList(): List<Float> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun DoubleArray.toList(): List<Double> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun BooleanArray.toList(): List<Boolean> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
* Returns a [List] containing all elements.
*/
public fun CharArray.toList(): List<Char> {
return this.toMutableList()
return when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
@@ -6450,63 +6486,99 @@ public fun CharArray.toMutableList(): MutableList<Char> {
* Returns a [Set] of all elements.
*/
public fun <T> Array<out T>.toSet(): Set<T> {
return toCollection(LinkedHashSet<T>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<T>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun ByteArray.toSet(): Set<Byte> {
return toCollection(LinkedHashSet<Byte>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Byte>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun ShortArray.toSet(): Set<Short> {
return toCollection(LinkedHashSet<Short>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Short>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun IntArray.toSet(): Set<Int> {
return toCollection(LinkedHashSet<Int>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Int>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun LongArray.toSet(): Set<Long> {
return toCollection(LinkedHashSet<Long>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Long>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun FloatArray.toSet(): Set<Float> {
return toCollection(LinkedHashSet<Float>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Float>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun DoubleArray.toSet(): Set<Double> {
return toCollection(LinkedHashSet<Double>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Double>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun BooleanArray.toSet(): Set<Boolean> {
return toCollection(LinkedHashSet<Boolean>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Boolean>(mapCapacity(size)))
}
}
/**
* Returns a [Set] of all elements.
*/
public fun CharArray.toSet(): Set<Char> {
return toCollection(LinkedHashSet<Char>(mapCapacity(size)))
return when (size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Char>(mapCapacity(size)))
}
}
/**
+16 -2
View File
@@ -1003,7 +1003,14 @@ public fun <T> Iterable<T>.toHashSet(): HashSet<T> {
* Returns a [List] containing all elements.
*/
public fun <T> Iterable<T>.toList(): List<T> {
return this.toMutableList()
if (this is Collection) {
return when (size) {
0 -> emptyList()
1 -> listOf(if (this is List) get(0) else iterator().next())
else -> this.toMutableList()
}
}
return this.toMutableList().optimizeReadOnlyList()
}
/**
@@ -1026,7 +1033,14 @@ public fun <T> Collection<T>.toMutableList(): MutableList<T> {
* Returns a [Set] of all elements.
*/
public fun <T> Iterable<T>.toSet(): Set<T> {
return toCollection(LinkedHashSet<T>(mapCapacity(collectionSizeOrDefault(12))))
if (this is Collection) {
return when (size) {
0 -> emptySet()
1 -> setOf(if (this is List) this[0] else iterator().next())
else -> toCollection(LinkedHashSet<T>(mapCapacity(size)))
}
}
return toCollection(LinkedHashSet<T>()).optimizeReadOnlySet()
}
/**
+12 -2
View File
@@ -17,9 +17,19 @@ import java.util.Collections // TODO: it's temporary while we have java.util.Col
* Returns a [List] containing all key-value pairs.
*/
public fun <K, V> Map<K, V>.toList(): List<Pair<K, V>> {
if (size == 0)
return emptyList()
val iterator = entries.iterator()
if (!iterator.hasNext())
return emptyList()
val first = iterator.next()
if (!iterator.hasNext())
return listOf(first.toPair())
val result = ArrayList<Pair<K, V>>(size)
for (item in this)
result.add(item.key to item.value)
result.add(first.toPair())
do {
result.add(iterator.next().toPair())
} while (iterator.hasNext())
return result
}
+2 -2
View File
@@ -522,7 +522,7 @@ public fun <T> Sequence<T>.toHashSet(): HashSet<T> {
* Returns a [List] containing all elements.
*/
public fun <T> Sequence<T>.toList(): List<T> {
return this.toMutableList()
return this.toMutableList().optimizeReadOnlyList()
}
/**
@@ -536,7 +536,7 @@ public fun <T> Sequence<T>.toMutableList(): MutableList<T> {
* Returns a [Set] of all elements.
*/
public fun <T> Sequence<T>.toSet(): Set<T> {
return toCollection(LinkedHashSet<T>())
return toCollection(LinkedHashSet<T>()).optimizeReadOnlySet()
}
/**
+10 -2
View File
@@ -590,7 +590,11 @@ public fun CharSequence.toHashSet(): HashSet<Char> {
* Returns a [List] containing all characters.
*/
public fun CharSequence.toList(): List<Char> {
return this.toMutableList()
return when (length) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
}
/**
@@ -604,7 +608,11 @@ public fun CharSequence.toMutableList(): MutableList<Char> {
* Returns a [Set] of all characters.
*/
public fun CharSequence.toSet(): Set<Char> {
return toCollection(LinkedHashSet<Char>(mapCapacity(length)))
return when (length) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<Char>(mapCapacity(length)))
}
}
/**
@@ -130,6 +130,11 @@ public inline fun <T> Enumeration<T>.toList(): List<T> = Collections.list(this)
@kotlin.internal.InlineOnly
public inline fun <@kotlin.internal.OnlyInputTypes T> Collection<T>.containsAll(elements: Collection<T>): Boolean = this.containsAll(elements)
internal fun <T> List<T>.optimizeReadOnlyList() = when (size) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this
}
// copies typed varargs array to array of objects
@JvmVersion
@@ -283,7 +283,7 @@ public fun <K, V> MutableMap<in K, in V>.putAll(pairs: Sequence<Pair<K,V>>): Uni
*/
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
public inline fun <K, V, R> Map<K, V>.mapValues(transform: (Map.Entry<K, V>) -> R): Map<K, R> {
return mapValuesTo(LinkedHashMap<K, R>(mapCapacity(size)), transform)
return mapValuesTo(LinkedHashMap<K, R>(mapCapacity(size)), transform) // .optimizeReadOnlyMap()
}
/**
@@ -294,7 +294,7 @@ public inline fun <K, V, R> Map<K, V>.mapValues(transform: (Map.Entry<K, V>) ->
*/
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
public inline fun <K, V, R> Map<K, V>.mapKeys(transform: (Map.Entry<K, V>) -> R): Map<R, V> {
return mapKeysTo(LinkedHashMap<R, V>(mapCapacity(size)), transform)
return mapKeysTo(LinkedHashMap<R, V>(mapCapacity(size)), transform) // .optimizeReadOnlyMap()
}
/**
@@ -369,7 +369,16 @@ public inline fun <K, V> Map<K, V>.filterNot(predicate: (Map.Entry<K, V>) -> Boo
/**
* Returns a new map containing all key-value pairs from the given collection of pairs.
*/
public fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V> = toMap(LinkedHashMap<K, V>(collectionSizeOrNull()?.let { mapCapacity(it) } ?: 16))
public fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V> {
if (this is Collection) {
return when (size) {
0 -> emptyMap()
1 -> mapOf(if (this is List) this[0] else iterator().next())
else -> toMap(LinkedHashMap<K, V>(mapCapacity(size)))
}
}
return toMap(LinkedHashMap<K, V>()).optimizeReadOnlyMap()
}
/**
* Populates and returns the [destination] mutable map with key-value pairs from the given collection of pairs.
@@ -380,7 +389,11 @@ public fun <K, V, M : MutableMap<in K, in V>> Iterable<Pair<K, V>>.toMap(destina
/**
* Returns a new map containing all key-value pairs from the given array of pairs.
*/
public fun <K, V> Array<out Pair<K, V>>.toMap(): Map<K, V> = toMap(LinkedHashMap<K, V>(mapCapacity(size)))
public fun <K, V> Array<out Pair<K, V>>.toMap(): Map<K, V> = when(size) {
0 -> emptyMap()
1 -> mapOf(this[0])
else -> toMap(LinkedHashMap<K, V>(mapCapacity(size)))
}
/**
* Populates and returns the [destination] mutable map with key-value pairs from the given array of pairs.
@@ -392,7 +405,7 @@ public fun <K, V, M : MutableMap<in K, in V>> Array<out Pair<K, V>>.toMap(destin
* Returns a new map containing all key-value pairs from the given sequence of pairs.
*/
public fun <K, V> Sequence<Pair<K, V>>.toMap(): Map<K, V> = toMap(LinkedHashMap<K, V>())
public fun <K, V> Sequence<Pair<K, V>>.toMap(): Map<K, V> = toMap(LinkedHashMap<K, V>()).optimizeReadOnlyMap()
/**
* Populates and returns the [destination] mutable map with key-value pairs from the given sequence of pairs.
@@ -405,25 +418,25 @@ public fun <K, V, M : MutableMap<in K, in V>> Sequence<Pair<K, V>>.toMap(destina
* Creates a new read-only map by replacing or adding an entry to this map from a given key-value [pair].
*/
public operator fun <K, V> Map<out K, V>.plus(pair: Pair<K, V>): Map<K, V>
= LinkedHashMap(this).apply { put(pair.first, pair.second) }
= if (this.isEmpty()) mapOf(pair) else LinkedHashMap(this).apply { put(pair.first, pair.second) }
/**
* Creates a new read-only map by replacing or adding entries to this map from a given collection of key-value [pairs].
*/
public operator fun <K, V> Map<out K, V>.plus(pairs: Iterable<Pair<K, V>>): Map<K, V>
= LinkedHashMap(this).apply { putAll(pairs) }
= if (this.isEmpty()) pairs.toMap() else LinkedHashMap(this).apply { putAll(pairs) }
/**
* Creates a new read-only map by replacing or adding entries to this map from a given array of key-value [pairs].
*/
public operator fun <K, V> Map<out K, V>.plus(pairs: Array<out Pair<K, V>>): Map<K, V>
= LinkedHashMap(this).apply { putAll(pairs) }
= if (this.isEmpty()) pairs.toMap() else LinkedHashMap(this).apply { putAll(pairs) }
/**
* Creates a new read-only map by replacing or adding entries to this map from a given sequence of key-value [pairs].
*/
public operator fun <K, V> Map<out K, V>.plus(pairs: Sequence<Pair<K, V>>): Map<K, V>
= LinkedHashMap(this).apply { putAll(pairs) }
= LinkedHashMap(this).apply { putAll(pairs) }.optimizeReadOnlyMap()
/**
* Creates a new read-only map by replacing or adding entries to this map from another [map].
@@ -471,3 +484,15 @@ public inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(pairs: Seque
public inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(map: Map<K, V>) {
putAll(map)
}
// do not expose for now @kotlin.internal.InlineExposed
internal fun <K, V> Map<K, V>.optimizeReadOnlyMap() = when (size) {
0 -> emptyMap()
1 -> toSingletonMap()
else -> this
}
@kotlin.jvm.JvmVersion
internal fun <K, V> Map<K, V>.toSingletonMap(): Map<K, V>
= with (entries.iterator().next()) { Collections.singletonMap(key, value) }
@@ -64,3 +64,10 @@ public fun <T> sortedSetOf(vararg elements: T): TreeSet<T> = elements.toCollecti
*/
@JvmVersion
public fun <T> sortedSetOf(comparator: Comparator<in T>, vararg elements: T): TreeSet<T> = elements.toCollection(TreeSet<T>(comparator))
internal fun <T> Set<T>.optimizeReadOnlySet() = when (size) {
0 -> emptySet()
1 -> setOf(iterator().next())
else -> this
}
@@ -23,10 +23,31 @@ fun snapshots(): List<GenericFunction> {
templates add f("toSet()") {
doc { f -> "Returns a [Set] of all ${f.element.pluralize()}." }
returns("Set<T>")
body { "return toCollection(LinkedHashSet<T>(mapCapacity(collectionSizeOrDefault(12))))" }
body(Sequences) { "return toCollection(LinkedHashSet<T>())" }
body(CharSequences) { "return toCollection(LinkedHashSet<T>(mapCapacity(length)))" }
body(ArraysOfObjects, ArraysOfPrimitives) { "return toCollection(LinkedHashSet<T>(mapCapacity(size)))" }
body(Iterables) {
"""
if (this is Collection) {
return when (size) {
0 -> emptySet()
1 -> setOf(if (this is List) this[0] else iterator().next())
else -> toCollection(LinkedHashSet<T>(mapCapacity(size)))
}
}
return toCollection(LinkedHashSet<T>()).optimizeReadOnlySet()
"""
}
body(Sequences) { "return toCollection(LinkedHashSet<T>()).optimizeReadOnlySet()" }
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives) { f ->
val size = if (f == CharSequences) "length" else "size"
"""
return when ($size) {
0 -> emptySet()
1 -> setOf(this[0])
else -> toCollection(LinkedHashSet<T>(mapCapacity($size)))
}
"""
}
}
templates add f("toHashSet()") {
@@ -90,9 +111,19 @@ fun snapshots(): List<GenericFunction> {
returns("List<Pair<K, V>>")
body {
"""
if (size == 0)
return emptyList()
val iterator = entries.iterator()
if (!iterator.hasNext())
return emptyList()
val first = iterator.next()
if (!iterator.hasNext())
return listOf(first.toPair())
val result = ArrayList<Pair<K, V>>(size)
for (item in this)
result.add(item.key to item.value)
result.add(first.toPair())
do {
result.add(iterator.next().toPair())
} while (iterator.hasNext())
return result
"""
}
@@ -102,7 +133,28 @@ fun snapshots(): List<GenericFunction> {
include(CharSequences)
doc { f -> "Returns a [List] containing all ${f.element.pluralize()}." }
returns("List<T>")
body { "return this.toMutableList()" }
body { "return this.toMutableList().optimizeReadOnlyList()" }
body(Iterables) {
"""
if (this is Collection) {
return when (size) {
0 -> emptyList()
1 -> listOf(if (this is List) get(0) else iterator().next())
else -> this.toMutableList()
}
}
return this.toMutableList().optimizeReadOnlyList()
"""
}
body(CharSequences, ArraysOfPrimitives, ArraysOfObjects) { f ->
"""
return when (${ if (f == CharSequences) "length" else "size" }) {
0 -> emptyList()
1 -> listOf(this[0])
else -> this.toMutableList()
}
"""
}
}
templates add f("associate(transform: (T) -> Pair<K, V>)") {