From cde36adbdc3051d0728611aa487dfb7d43144322 Mon Sep 17 00:00:00 2001 From: nik Date: Sun, 24 Nov 2013 17:33:05 +0400 Subject: [PATCH] standard library: 'sum' function added (KT-3714, KT-3843, KT-3126) --- libraries/stdlib/src/generated/_Arrays.kt | 42 +++++++++++++++++ libraries/stdlib/src/generated/_ByteArrays.kt | 7 +++ .../stdlib/src/generated/_DoubleArrays.kt | 7 +++ .../stdlib/src/generated/_FloatArrays.kt | 7 +++ libraries/stdlib/src/generated/_IntArrays.kt | 7 +++ libraries/stdlib/src/generated/_Iterables.kt | 28 +++++++++++ libraries/stdlib/src/generated/_LongArrays.kt | 7 +++ .../stdlib/src/generated/_ShortArrays.kt | 7 +++ libraries/stdlib/test/ArraysJVMTest.kt | 10 ++++ libraries/stdlib/test/ArraysTest.kt | 10 ++++ libraries/stdlib/test/CollectionTest.kt | 8 ++++ .../src/generators/GenerateStandardLib.kt | 20 ++++---- .../kotlin-stdlib-gen/src/templates/Engine.kt | 19 +++++--- .../src/templates/Primitives.kt | 47 +++++++++++++++++++ 14 files changed, 209 insertions(+), 17 deletions(-) create mode 100644 libraries/tools/kotlin-stdlib-gen/src/templates/Primitives.kt diff --git a/libraries/stdlib/src/generated/_Arrays.kt b/libraries/stdlib/src/generated/_Arrays.kt index 7cc7224e1cc..3cd3de83239 100644 --- a/libraries/stdlib/src/generated/_Arrays.kt +++ b/libraries/stdlib/src/generated/_Arrays.kt @@ -408,3 +408,45 @@ public inline fun Array.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun Array.sum() : Int { + return fold(0, {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Array.sum() : Int { + return fold(0, {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Array.sum() : Int { + return fold(0, {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Array.sum() : Long { + return fold(0.toLong(), {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Array.sum() : Float { + return fold(0.toFloat(), {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Array.sum() : Double { + return fold(0.0, {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_ByteArrays.kt b/libraries/stdlib/src/generated/_ByteArrays.kt index aa84ab06593..3fd3ea83b1a 100644 --- a/libraries/stdlib/src/generated/_ByteArrays.kt +++ b/libraries/stdlib/src/generated/_ByteArrays.kt @@ -381,3 +381,10 @@ public inline fun ByteArray.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun ByteArray.sum() : Int { + return fold(0, {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_DoubleArrays.kt b/libraries/stdlib/src/generated/_DoubleArrays.kt index 3d21a244c13..763c5951a46 100644 --- a/libraries/stdlib/src/generated/_DoubleArrays.kt +++ b/libraries/stdlib/src/generated/_DoubleArrays.kt @@ -381,3 +381,10 @@ public inline fun DoubleArray.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun DoubleArray.sum() : Double { + return fold(0.0, {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_FloatArrays.kt b/libraries/stdlib/src/generated/_FloatArrays.kt index b57bcd7646b..7599332272f 100644 --- a/libraries/stdlib/src/generated/_FloatArrays.kt +++ b/libraries/stdlib/src/generated/_FloatArrays.kt @@ -381,3 +381,10 @@ public inline fun FloatArray.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun FloatArray.sum() : Float { + return fold(0.toFloat(), {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_IntArrays.kt b/libraries/stdlib/src/generated/_IntArrays.kt index 902f5e7bfb6..905a729e37c 100644 --- a/libraries/stdlib/src/generated/_IntArrays.kt +++ b/libraries/stdlib/src/generated/_IntArrays.kt @@ -381,3 +381,10 @@ public inline fun IntArray.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun IntArray.sum() : Int { + return fold(0, {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_Iterables.kt b/libraries/stdlib/src/generated/_Iterables.kt index 738e99376a5..f7eaad52822 100644 --- a/libraries/stdlib/src/generated/_Iterables.kt +++ b/libraries/stdlib/src/generated/_Iterables.kt @@ -376,3 +376,31 @@ public inline fun Iterable.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun Iterable.sum() : Int { + return fold(0, {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Iterable.sum() : Long { + return fold(0.toLong(), {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Iterable.sum() : Float { + return fold(0.toFloat(), {a,b -> a+b}) +} + +/** + * Sums up the elements + */ +public fun Iterable.sum() : Double { + return fold(0.0, {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_LongArrays.kt b/libraries/stdlib/src/generated/_LongArrays.kt index d8d5a00fddc..fd15d7dfa8e 100644 --- a/libraries/stdlib/src/generated/_LongArrays.kt +++ b/libraries/stdlib/src/generated/_LongArrays.kt @@ -381,3 +381,10 @@ public inline fun LongArray.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun LongArray.sum() : Long { + return fold(0.toLong(), {a,b -> a+b}) +} + diff --git a/libraries/stdlib/src/generated/_ShortArrays.kt b/libraries/stdlib/src/generated/_ShortArrays.kt index a972d5e6735..3264f52d3fd 100644 --- a/libraries/stdlib/src/generated/_ShortArrays.kt +++ b/libraries/stdlib/src/generated/_ShortArrays.kt @@ -381,3 +381,10 @@ public inline fun ShortArray.withIndices() : Iterator> { return IndexIterator(iterator()) } +/** + * Sums up the elements + */ +public fun ShortArray.sum() : Int { + return fold(0, {a,b -> a+b}) +} + diff --git a/libraries/stdlib/test/ArraysJVMTest.kt b/libraries/stdlib/test/ArraysJVMTest.kt index 8049a44bb2f..d18dd149d7f 100644 --- a/libraries/stdlib/test/ArraysJVMTest.kt +++ b/libraries/stdlib/test/ArraysJVMTest.kt @@ -58,4 +58,14 @@ class ArraysJVMTest { intArray().reduceRight { a, b -> a + b} } } + + test fun sum() { + expect(0) { intArray().sum() } + expect(14) { intArray(2, 3, 9).sum() } + expect(3.0) { doubleArray(1.0, 2.0).sum() } + expect(200) { byteArray(100, 100).sum() } + expect(50000) { shortArray(20000, 30000).sum() } + expect(3000000000000) { longArray(1000000000000, 2000000000000).sum() } + expect(3.0) { floatArray(1.0, 2.0).sum() } + } } diff --git a/libraries/stdlib/test/ArraysTest.kt b/libraries/stdlib/test/ArraysTest.kt index 440f935fa19..7e90d0a1adf 100644 --- a/libraries/stdlib/test/ArraysTest.kt +++ b/libraries/stdlib/test/ArraysTest.kt @@ -101,6 +101,16 @@ class ArraysTest { assertEquals(false, arr[1]) } + test fun sum() { + expect(0) { array().sum() } + expect(14) { array(2, 3, 9).sum() } + expect(3.0) { array(1.0, 2.0).sum() } + expect(200) { array(100, 100).sum() } + expect(50000) { array(20000, 30000).sum() } + //TODO: uncomment when toLong() will be supported + //expect(3000000000000) { array(1000000000000, 2000000000000).sum() } + expect(3.0) { array(1.0, 2.0).sum() } + } /* TODO FIXME ASAP: These currently fail on JS due to missing upto() method on numbers diff --git a/libraries/stdlib/test/CollectionTest.kt b/libraries/stdlib/test/CollectionTest.kt index f20eeb16393..0d37ba4c0eb 100644 --- a/libraries/stdlib/test/CollectionTest.kt +++ b/libraries/stdlib/test/CollectionTest.kt @@ -414,6 +414,14 @@ class CollectionTest { expect(arrayList(2, 3, 1)) { list } } + test fun sum() { + expect(0) { ArrayList().sum() } + expect(14) { arrayListOf(2, 3, 9).sum() } + expect(3.0) { arrayListOf(1.0, 2.0).sum() } + expect(3000000000000) { arrayListOf(1000000000000, 2000000000000).sum() } + expect(3.0) { arrayListOf(1.0, 2.0).sum() } + } + class IterableWrapper(collection : Iterable) : Iterable { private val collection = collection diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt index ca85344be1f..4e46bda6b29 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt @@ -29,27 +29,27 @@ fun main(args: Array) { generateDomEventsAPI(File(jsCoreDir, "domEvents.kt")) iterators().writeTo(File(outDir, "_Iterators.kt")) { - buildFor(Iterators, "") + buildFor(Iterators, null) } val iterables = iterables() - iterables.writeTo(File(outDir, "_Arrays.kt")) { - buildFor(Arrays, "") + val sumFunctions = PrimitiveType.values().map(::sumFunction).filterNotNull() + (iterables + sumFunctions).writeTo(File(outDir, "_Arrays.kt")) { + buildFor(Arrays, null) } - val otherArrayNames = arrayListOf("Boolean", "Byte", "Char", "Short", "Int", "Long", "Float", "Double") - for (a in otherArrayNames) { - iterables.writeTo(File(outDir, "_${a}Arrays.kt")) { - buildFor(PrimitiveArrays, a) + for (primitive in PrimitiveType.values()) { + (iterables + sumFunction(primitive)).filterNotNull().writeTo(File(outDir, "_${primitive.name}Arrays.kt")) { + buildFor(PrimitiveArrays, primitive) } } - iterables.writeTo(File(outDir, "_Iterables.kt")) { - buildFor(Iterables, "") + (iterables + sumFunctions).writeTo(File(outDir, "_Iterables.kt")) { + buildFor(Iterables, null) } collections().writeTo(File(outDir, "_Collections.kt")) { - buildFor(Collections, "") + buildFor(Collections, null) } generateDownTos(File(outDir, "_DownTo.kt"), "package kotlin") diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt index 4ecf19027d7..23c388ead4b 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt @@ -18,7 +18,8 @@ enum class Family { class GenericFunction(val signature : String): Comparable { var doc : String = "" var toNullableT : Boolean = false - val isInline : Boolean = true; + var isInline : Boolean = true; + private val customReceivers = HashMap() val blockedFor = HashSet() val bodies = HashMap() val returnTypes = HashMap() @@ -44,6 +45,10 @@ class GenericFunction(val signature : String): Comparable { returnTypes[this] = r } + fun Family.customReceiver(r: String) { + customReceivers[this] = r + } + fun typeParam(t:String) { typeParams.add(t) } @@ -54,7 +59,7 @@ class GenericFunction(val signature : String): Comparable { private fun effectiveTypeParams(f : Family) : List { val types = ArrayList(typeParams) - if (typeParams.find { it.startsWith("T") } == null) { + if (typeParams.find { it.startsWith("T") } == null && !customReceivers.containsKey(f)) { types.add(0, "T") } @@ -67,7 +72,7 @@ class GenericFunction(val signature : String): Comparable { - fun buildFor(f: Family, arrName : String = "") : String { + fun buildFor(f: Family, primitiveType: PrimitiveType?) : String { if (blockedFor.contains(f)) return "" if (returnTypes[f] == null) throw RuntimeException("No return type specified for $signature") @@ -78,7 +83,7 @@ class GenericFunction(val signature : String): Comparable { Collections -> "Collection" Iterators -> "Iterator" Arrays -> "Array" - PrimitiveArrays -> "${arrName}Array" + PrimitiveArrays -> "${primitiveType!!.name}Array" } fun String.renderType() : String { @@ -89,7 +94,7 @@ class GenericFunction(val signature : String): Comparable { val token = t.nextToken() answer.append(when (token) { "SELF" -> selftype - "T" -> if (f == Family.PrimitiveArrays) arrName else token + "T" -> if (f == Family.PrimitiveArrays) primitiveType!!.name else token else -> token }) } @@ -120,7 +125,7 @@ class GenericFunction(val signature : String): Comparable { builder.append(types.makeString(separator = ", ", prefix = "<", postfix = "> ").renderType()) } - builder.append(( + builder.append((customReceivers[f] ?: if (toNullableT) { selftype.replace("T>", "T?>") } @@ -160,6 +165,6 @@ fun f(signature : String, init : GenericFunction.() -> Unit): GenericFunction { fun main(args : Array) { val templates = collections() for (t in templates) { - print(t.buildFor(PrimitiveArrays, "Byte")) + print(t.buildFor(PrimitiveArrays, PrimitiveType.Byte)) } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Primitives.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Primitives.kt new file mode 100644 index 00000000000..81ceab28862 --- /dev/null +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Primitives.kt @@ -0,0 +1,47 @@ +package templates + +import templates.Family.* + +enum class PrimitiveType(val name: String) { + Boolean: PrimitiveType("Boolean") + Byte: PrimitiveType("Byte") + Char: PrimitiveType("Char") + Short: PrimitiveType("Short") + Int: PrimitiveType("Int") + Long: PrimitiveType("Long") + Float: PrimitiveType("Float") + Double: PrimitiveType("Double") +} + +private fun PrimitiveType.zero() = when (this) { + PrimitiveType.Int -> "0" + PrimitiveType.Byte -> "0" + PrimitiveType.Short -> "0" + PrimitiveType.Long -> "0.toLong()" + PrimitiveType.Double -> "0.0" + PrimitiveType.Float -> "0.toFloat()" + else -> null +} + +private fun returnTypeForSum(primitive: PrimitiveType) = when (primitive) { + PrimitiveType.Byte -> PrimitiveType.Int + PrimitiveType.Short -> PrimitiveType.Int + else -> primitive +} + +fun sumFunction(primitive: PrimitiveType) = primitive.zero()?.let { zero -> + f("sum()") { + doc = "Sums up the elements" + isInline = false + if (returnTypeForSum(primitive) != primitive) { + //this is required to avoid clash of erasured method signatures (Iterables.sum(): Int) + absentFor(Iterables) + } + Iterables.customReceiver("Iterable<${primitive.name}>") + Arrays.customReceiver("Array<${primitive.name}>") + returns(returnTypeForSum(primitive).name) + body { + "return fold($zero, {a,b -> a+b})" + } + } +} \ No newline at end of file