Collection performance improvements

Lists

- For arrays, use Arrays.asList, then toArrayList making the list creation an array copy
- For the same reason, use the ArrayList(Collection) constructor
- Replace duplicate code in toList, instead calling toArrayList

Maps/Sets

- Where the size of the source is known, precalculate the capacity, using the formula used by Guava's Maps class
- For toMap where we're unable to get at the private function, use HashSet's formula where the size is known
- Add a toMap that takes a selector and a transform, avoiding a separate step for transforming values
This commit is contained in:
Danny Thomas
2015-04-24 16:04:38 -07:00
committed by Ilya Gorbunov
parent 0e6babc96b
commit 7ce0487b7e
4 changed files with 363 additions and 118 deletions
@@ -1,6 +1,7 @@
package templates
import templates.Family.*
import java.util.ArrayList
fun snapshots(): List<GenericFunction> {
val templates = arrayListOf<GenericFunction>()
@@ -22,13 +23,19 @@ fun snapshots(): List<GenericFunction> {
templates add f("toSet()") {
doc { "Returns a Set of all elements" }
returns("Set<T>")
body { "return toCollection(LinkedHashSet<T>())" }
body { "return toCollection(LinkedHashSet<T>(mapCapacity(collectionSizeOrDefault(12))))" }
body(Sequences) { "return toCollection(LinkedHashSet<T>())" }
body(Strings) { "return toCollection(LinkedHashSet<T>(mapCapacity(length())))" }
body(ArraysOfObjects, ArraysOfPrimitives) { "return toCollection(LinkedHashSet<T>(mapCapacity(size())))" }
}
templates add f("toHashSet()") {
doc { "Returns a HashSet of all elements" }
returns("HashSet<T>")
body { "return toCollection(HashSet<T>())" }
body { "return toCollection(HashSet<T>(mapCapacity(collectionSizeOrDefault(12))))" }
body(Sequences) { "return toCollection(HashSet<T>())" }
body(Strings) { "return toCollection(HashSet<T>(mapCapacity(length())))" }
body(ArraysOfObjects, ArraysOfPrimitives) { "return toCollection(HashSet<T>(mapCapacity(size())))" }
}
templates add f("toSortedSet()") {
@@ -40,16 +47,10 @@ fun snapshots(): List<GenericFunction> {
templates add f("toArrayList()") {
doc { "Returns an ArrayList of all elements" }
returns("ArrayList<T>")
body { "return toCollection(ArrayList<T>(collectionSizeOrDefault(10)))" }
body(Sequences) { "return toCollection(ArrayList<T>())" }
body { "return toCollection(ArrayList<T>())" }
body(Collections) { "return ArrayList(this)" }
body(Strings) { "return toCollection(ArrayList<T>(length()))" }
body(ArraysOfObjects, ArraysOfPrimitives) {
"""
val list = ArrayList<T>(size())
for (item in this) list.add(item)
return list
"""
}
body(ArraysOfObjects, ArraysOfPrimitives) { "return this.asList().toArrayList()" }
}
templates add f("toList()") {
@@ -69,16 +70,7 @@ fun snapshots(): List<GenericFunction> {
templates add f("toList()") {
doc { "Returns a List containing all elements" }
returns("List<T>")
body { "return toCollection(ArrayList<T>(collectionSizeOrDefault(10)))" }
body(Sequences) { "return toCollection(ArrayList<T>())" }
body(Strings) { "return toCollection(ArrayList<T>(length()))" }
body(ArraysOfObjects, ArraysOfPrimitives) {
"""
val list = ArrayList<T>(size())
for (item in this) list.add(item)
return list
"""
}
body { "return this.toArrayList()" }
}
templates add f("toLinkedList()") {
@@ -96,7 +88,23 @@ fun snapshots(): List<GenericFunction> {
"""
}
returns("Map<K, T>")
/**
* Collection size helper methods are private, so we fall back to the calculation from HashSet's Collection
* constructor.
*/
body {
"""
val capacity = (collectionSizeOrDefault(10)/.75f) + 1
val result = LinkedHashMap<K, T>(Math.max(capacity.toInt(), 16))
for (element in this) {
result.put(selector(element), element)
}
return result
"""
}
body(Sequences) {
"""
val result = LinkedHashMap<K, T>()
for (element in this) {
@@ -105,6 +113,83 @@ fun snapshots(): List<GenericFunction> {
return result
"""
}
body(Strings) {
"""
val capacity = (length()/.75f) + 1
val result = LinkedHashMap<K, T>(Math.max(capacity.toInt(), 16))
for (element in this) {
result.put(selector(element), element)
}
return result
"""
}
body(ArraysOfObjects, ArraysOfPrimitives) {
"""
val capacity = (size()/.75f) + 1
val result = LinkedHashMap<K, T>(Math.max(capacity.toInt(), 16))
for (element in this) {
result.put(selector(element), element)
}
return result
"""
}
}
templates add f("toMap(selector: (T) -> K, transform: (T) -> V)") {
inline(true)
typeParam("K")
typeParam("V")
doc {
"""
Returns Map containing all the values provided by *transform* and indexed by *selector* from the given collection
"""
}
returns("Map<K, V>")
/**
* Collection size helper methods are private, so we fall back to the calculation from HashSet's Collection
* constructor.
*/
body {
"""
val capacity = (collectionSizeOrDefault(10)/.75f) + 1
val result = LinkedHashMap<K, V>(Math.max(capacity.toInt(), 16))
for (element in this) {
result.put(selector(element), transform(element))
}
return result
"""
}
body(Sequences) {
"""
val result = LinkedHashMap<K, V>()
for (element in this) {
result.put(selector(element), transform(element))
}
return result
"""
}
body(Strings) {
"""
val capacity = (length()/.75f) + 1
val result = LinkedHashMap<K, V>(Math.max(capacity.toInt(), 16))
for (element in this) {
result.put(selector(element), transform(element))
}
return result
"""
}
body(ArraysOfObjects, ArraysOfPrimitives) {
"""
val capacity = (size()/.75f) + 1
val result = LinkedHashMap<K, V>(Math.max(capacity.toInt(), 16))
for (element in this) {
result.put(selector(element), transform(element))
}
return result
"""
}
}
return templates