Merge pull request #570 from JetBrains/rr/yole/generate-more-stdlib

Replace some manually duplicated stdlib method implementations with generated code
This commit is contained in:
Evgeny Gerashchenko
2015-02-11 17:26:30 +04:00
8 changed files with 448 additions and 197 deletions
+108
View File
@@ -9,6 +9,60 @@ import java.util.*
import java.util.Collections // TODO: it's temporary while we have java.util.Collections in js
/**
* Returns the range of valid indices for the array
*/
public val <T> Array<out T>.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val BooleanArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val ByteArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val CharArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val DoubleArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val FloatArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val IntArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val LongArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the range of valid indices for the array
*/
public val ShortArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns true if the array is empty
*/
@@ -135,3 +189,57 @@ public fun ShortArray.isNotEmpty(): Boolean {
return !isEmpty()
}
/**
* Returns the last valid index for the array
*/
public val <T> Array<out T>.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val BooleanArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val ByteArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val CharArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val DoubleArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val FloatArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val IntArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val LongArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array
*/
public val ShortArray.lastIndex: Int
get() = size - 1
+223
View File
@@ -0,0 +1,223 @@
package kotlin
//
// NOTE THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt
// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib
//
import java.util.*
import java.util.Collections // TODO: it's temporary while we have java.util.Collections in js
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun ByteProgression.reversed(): ByteProgression {
return ByteProgression(end, start, -increment)
}
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun CharProgression.reversed(): CharProgression {
return CharProgression(end, start, -increment)
}
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun DoubleProgression.reversed(): DoubleProgression {
return DoubleProgression(end, start, -increment)
}
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun FloatProgression.reversed(): FloatProgression {
return FloatProgression(end, start, -increment)
}
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun IntProgression.reversed(): IntProgression {
return IntProgression(end, start, -increment)
}
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun LongProgression.reversed(): LongProgression {
return LongProgression(end, start, -increment)
}
/**
* Returns a progression that goes over the same range in the opposite direction with the same step
*/
public fun ShortProgression.reversed(): ShortProgression {
return ShortProgression(end, start, -increment)
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun ByteRange.reversed(): ByteProgression {
return ByteProgression(end, start, -1)
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun CharRange.reversed(): CharProgression {
return CharProgression(end, start, -1)
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun DoubleRange.reversed(): DoubleProgression {
return DoubleProgression(end, start, -1.0)
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun FloatRange.reversed(): FloatProgression {
return FloatProgression(end, start, -1.0f)
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun IntRange.reversed(): IntProgression {
return IntProgression(end, start, -1)
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun LongRange.reversed(): LongProgression {
return LongProgression(end, start, -1.toLong())
}
/**
* Returns a progression that goes over this range in reverse direction
*/
public fun ShortRange.reversed(): ShortProgression {
return ShortProgression(end, start, -1)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun ByteProgression.step(step: Int): ByteProgression {
checkStepIsPositive(step > 0, step)
return ByteProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun CharProgression.step(step: Int): CharProgression {
checkStepIsPositive(step > 0, step)
return CharProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun DoubleProgression.step(step: Double): DoubleProgression {
checkStepIsPositive(step > 0, step)
return DoubleProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun FloatProgression.step(step: Float): FloatProgression {
checkStepIsPositive(step > 0, step)
return FloatProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun IntProgression.step(step: Int): IntProgression {
checkStepIsPositive(step > 0, step)
return IntProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun LongProgression.step(step: Long): LongProgression {
checkStepIsPositive(step > 0, step)
return LongProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over the same range with the given step
*/
public fun ShortProgression.step(step: Int): ShortProgression {
checkStepIsPositive(step > 0, step)
return ShortProgression(start, end, if (increment > 0) step else -step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun ByteRange.step(step: Int): ByteProgression {
checkStepIsPositive(step > 0, step)
return ByteProgression(start, end, step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun CharRange.step(step: Int): CharProgression {
checkStepIsPositive(step > 0, step)
return CharProgression(start, end, step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun DoubleRange.step(step: Double): DoubleProgression {
if (step.isNaN()) throw IllegalArgumentException("Step must not be NaN")
checkStepIsPositive(step > 0, step)
return DoubleProgression(start, end, step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun FloatRange.step(step: Float): FloatProgression {
if (step.isNaN()) throw IllegalArgumentException("Step must not be NaN")
checkStepIsPositive(step > 0, step)
return FloatProgression(start, end, step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun IntRange.step(step: Int): IntProgression {
checkStepIsPositive(step > 0, step)
return IntProgression(start, end, step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun LongRange.step(step: Long): LongProgression {
checkStepIsPositive(step > 0, step)
return LongProgression(start, end, step)
}
/**
* Returns a progression that goes over this range with given step
*/
public fun ShortRange.step(step: Int): ShortProgression {
checkStepIsPositive(step > 0, step)
return ShortProgression(start, end, step)
}
@@ -9,58 +9,3 @@ public inline fun <reified T> Array(size: Int, init: (Int) -> T): Array<T> {
return result as Array<T>
}
public val BooleanArray.lastIndex: Int
get() = size() - 1
public val ByteArray.lastIndex: Int
get() = size() - 1
public val ShortArray.lastIndex: Int
get() = size() - 1
public val IntArray.lastIndex: Int
get() = size() - 1
public val LongArray.lastIndex: Int
get() = size() - 1
public val FloatArray.lastIndex: Int
get() = size() - 1
public val DoubleArray.lastIndex: Int
get() = size() - 1
public val CharArray.lastIndex: Int
get() = size() - 1
public val Array<*>.lastIndex: Int
get() = size() - 1
public val BooleanArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val ByteArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val ShortArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val IntArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val LongArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val FloatArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val DoubleArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val CharArray.indices: IntRange
get() = IntRange(0, lastIndex)
public val Array<*>.indices: IntRange
get() = IntRange(0, lastIndex)
-133
View File
@@ -23,139 +23,6 @@ public fun <T: Comparable<T>> T.rangeTo(that: T): ComparableRange<T> {
}
public fun CharProgression.reversed(): CharProgression {
return CharProgression(end, start, -increment)
}
public fun ByteProgression.reversed(): ByteProgression {
return ByteProgression(end, start, -increment)
}
public fun ShortProgression.reversed(): ShortProgression {
return ShortProgression(end, start, -increment)
}
public fun IntProgression.reversed(): IntProgression {
return IntProgression(end, start, -increment)
}
public fun FloatProgression.reversed(): FloatProgression {
return FloatProgression(end, start, -increment)
}
public fun LongProgression.reversed(): LongProgression {
return LongProgression(end, start, -increment)
}
public fun DoubleProgression.reversed(): DoubleProgression {
return DoubleProgression(end, start, -increment)
}
public fun CharRange.reversed(): CharProgression {
return CharProgression(end, start, -1)
}
public fun ByteRange.reversed(): ByteProgression {
return ByteProgression(end, start, -1)
}
public fun ShortRange.reversed(): ShortProgression {
return ShortProgression(end, start, -1)
}
public fun IntRange.reversed(): IntProgression {
return IntProgression(end, start, -1)
}
public fun FloatRange.reversed(): FloatProgression {
return FloatProgression(end, start, -1.0.toFloat())
}
public fun LongRange.reversed(): LongProgression {
return LongProgression(end, start, -1.toLong())
}
public fun DoubleRange.reversed(): DoubleProgression {
return DoubleProgression(end, start, -1.0)
}
public fun IntProgression.step(step: Int): IntProgression {
checkStepIsPositive(step > 0, step)
return IntProgression(start, end, if (increment > 0) step else -step)
}
public fun CharProgression.step(step: Int): CharProgression {
checkStepIsPositive(step > 0, step)
return CharProgression(start, end, if (increment > 0) step else -step)
}
public fun ByteProgression.step(step: Int): ByteProgression {
checkStepIsPositive(step > 0, step)
return ByteProgression(start, end, if (increment > 0) step else -step)
}
public fun ShortProgression.step(step: Int): ShortProgression {
checkStepIsPositive(step > 0, step)
return ShortProgression(start, end, if (increment > 0) step else -step)
}
public fun LongProgression.step(step: Long): LongProgression {
checkStepIsPositive(step > 0, step)
return LongProgression(start, end, if (increment > 0) step else -step)
}
public fun FloatProgression.step(step: Float): FloatProgression {
checkStepIsPositive(step > 0, step)
return FloatProgression(start, end, if (increment > 0) step else -step)
}
public fun DoubleProgression.step(step: Double): DoubleProgression {
checkStepIsPositive(step > 0, step)
return DoubleProgression(start, end, if (increment > 0) step else -step)
}
public fun IntRange.step(step: Int): IntProgression {
checkStepIsPositive(step > 0, step)
return IntProgression(start, end, step)
}
public fun CharRange.step(step: Int): CharProgression {
checkStepIsPositive(step > 0, step)
return CharProgression(start, end, step)
}
public fun ByteRange.step(step: Int): ByteProgression {
checkStepIsPositive(step > 0, step)
return ByteProgression(start, end, step)
}
public fun ShortRange.step(step: Int): ShortProgression {
checkStepIsPositive(step > 0, step)
return ShortProgression(start, end, step)
}
public fun LongRange.step(step: Long): LongProgression {
checkStepIsPositive(step > 0, step)
return LongProgression(start, end, step)
}
public fun FloatRange.step(step: Float): FloatProgression {
if (step.isNaN()) throw IllegalArgumentException("Step must not be NaN")
checkStepIsPositive(step > 0, step)
return FloatProgression(start, end, step)
}
public fun DoubleRange.step(step: Double): DoubleProgression {
if (step.isNaN()) throw IllegalArgumentException("Step must not be NaN")
checkStepIsPositive(step > 0, step)
return DoubleProgression(start, end, step)
}
private fun checkStepIsPositive(isPositive: Boolean, step: Number) {
if (!isPositive) throw IllegalArgumentException("Step must be positive, was: $step")
}
@@ -19,16 +19,17 @@ fun generateCollectionsAPI(outDir: File) {
strings().writeTo(File(outDir, "_Strings.kt")) { build() }
streams().writeTo(File(outDir, "_Streams.kt")) { build() }
specialJVM().writeTo(File(outDir, "_SpecialJVM.kt")) { build() }
ranges().writeTo(File(outDir, "_Ranges.kt")) { build() }
numeric().writeTo(File(outDir, "_Numeric.kt")) {
val builder = StringBuilder()
// TODO: decide if sum for byte and short is needed and how to make it work
for (numeric in listOf(Int, Long, /*Byte, Short, */ Double, Float)) {
for (numeric in listOf(PrimitiveType.Int, PrimitiveType.Long, /*Byte, Short, */ PrimitiveType.Double, PrimitiveType.Float)) {
build(builder, Iterables, numeric)
build(builder, Streams, numeric)
}
for (numeric in listOf(Int, Long, Byte, Short, Double, Float)) {
for (numeric in listOf(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Byte, PrimitiveType.Short, PrimitiveType.Double, PrimitiveType.Float)) {
build(builder, ArraysOfObjects, numeric)
build(builder, ArraysOfPrimitives, numeric)
}
@@ -23,5 +23,23 @@ fun arrays(): List<GenericFunction> {
}
}
templates add pval("lastIndex") {
only(ArraysOfObjects, ArraysOfPrimitives)
doc { "Returns the last valid index for the array" }
returns("Int")
body {
"get() = size - 1"
}
}
templates add pval("indices") {
only(ArraysOfObjects, ArraysOfPrimitives)
doc { "Returns the range of valid indices for the array" }
returns("IntRange")
body {
"get() = IntRange(0, lastIndex)"
}
}
return templates
}
@@ -16,6 +16,8 @@ enum class Family {
ArraysOfObjects
ArraysOfPrimitives
Strings
RangesOfPrimitives
ProgressionsOfPrimitives
}
enum class PrimitiveType(val name: String) {
@@ -30,7 +32,7 @@ enum class PrimitiveType(val name: String) {
}
class GenericFunction(val signature: String) : Comparable<GenericFunction> {
class GenericFunction(val signature: String, val keyword: String = "fun") : Comparable<GenericFunction> {
val defaultFamilies = array(Iterables, Streams, ArraysOfObjects, ArraysOfPrimitives, Strings)
var toNullableT: Boolean = false
@@ -50,6 +52,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
var defaultBody: String = ""
val bodies = HashMap<Family, String>()
val customPrimitiveBodies = HashMap<Pair<Family, PrimitiveType>, String>()
var defaultReturnType = ""
val returnTypes = HashMap<Family, String>()
@@ -67,6 +70,13 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
}
}
fun bodyForTypes(family: Family, vararg primitiveTypes: PrimitiveType, b: () -> String) {
include(family)
for (f in primitiveTypes) {
customPrimitiveBodies.put(family to f, b())
}
}
fun doc(vararg families: Family, b: () -> String) {
if (families.isEmpty())
doc = b()
@@ -149,7 +159,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
}
fun build(builder: StringBuilder, f: Family) {
if (f == ArraysOfPrimitives) {
if (f == ArraysOfPrimitives || f == RangesOfPrimitives || f == ProgressionsOfPrimitives) {
for (primitive in buildPrimitives.sortBy { it.name() })
build(builder, f, primitive)
} else {
@@ -172,6 +182,8 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
ArraysOfObjects -> "Array<$isAsteriskOrT>"
Strings -> "String"
ArraysOfPrimitives -> primitive?.let { it.name() + "Array" } ?: throw IllegalArgumentException("Primitive array should specify primitive type")
RangesOfPrimitives -> primitive?.let { it.name() + "Range" } ?: throw IllegalArgumentException("Primitive range should specify primitive type")
ProgressionsOfPrimitives -> primitive?.let { it.name() + "Progression" } ?: throw IllegalArgumentException("Primitive progression should specify primitive type")
else -> throw IllegalStateException("Invalid family")
}
@@ -187,7 +199,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
"PRIMITIVE" -> primitive?.name() ?: token
"SUM" -> {
when (primitive) {
PrimitiveType.Byte, PrimitiveType.Short -> "Int"
PrimitiveType.Byte, PrimitiveType.Short, PrimitiveType.Char -> "Int"
else -> primitive
}
}
@@ -196,6 +208,18 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
PrimitiveType.Float -> "0.0f"
else -> "0"
}
"ONE" -> when (primitive) {
PrimitiveType.Double -> "1.0"
PrimitiveType.Float -> "1.0f"
PrimitiveType.Long -> "1.toLong()"
else -> "1"
}
"-ONE" -> when (primitive) {
PrimitiveType.Double -> "-1.0"
PrimitiveType.Float -> "-1.0f"
PrimitiveType.Long -> "-1.toLong()"
else -> "-1"
}
"TCollection" -> {
when (f) {
Strings -> "Appendable"
@@ -209,6 +233,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
else -> primitive?.name() ?: token
}
}
"TProgression" -> primitive!!.name + "Progression"
else -> token
})
}
@@ -253,7 +278,7 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
if (inlineFamilies[f] ?: defaultInline)
builder.append("inline ")
builder.append("fun ")
builder.append("$keyword ")
val types = effectiveTypeParams()
if (!types.isEmpty()) {
@@ -267,9 +292,10 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
builder.append(receiverType)
builder.append(".${signature.renderType()}: ${returnType.renderType()} {")
builder.append(".${signature.renderType()}: ${returnType.renderType()}")
if (keyword == "fun") builder.append(" {")
val body = (bodies[f] ?: defaultBody).trim("\n")
val body = (customPrimitiveBodies[f to primitive] ?: bodies[f] ?: defaultBody).trim("\n")
val indent: Int = body.takeWhile { it == ' ' }.length()
builder.append('\n')
@@ -281,7 +307,8 @@ class GenericFunction(val signature: String) : Comparable<GenericFunction> {
builder.append("\n")
}
}
builder.append("}\n\n")
if (keyword == "fun") builder.append("}\n")
builder.append("\n")
}
public override fun compareTo(other: GenericFunction): Int = this.signature.compareTo(other.signature)
@@ -298,3 +325,15 @@ fun f(signature: String, init: GenericFunction.() -> Unit): GenericFunction {
gf.init()
return gf
}
fun pval(signature: String, init: GenericFunction.() -> Unit): GenericFunction {
val gf = GenericFunction(signature, "val")
gf.init()
return gf
}
fun pvar(signature: String, init: GenericFunction.() -> Unit): GenericFunction {
val gf = GenericFunction(signature, "var")
gf.init()
return gf
}
@@ -0,0 +1,50 @@
package templates
import templates.Family.*
fun ranges(): List<GenericFunction> {
val templates = arrayListOf<GenericFunction>()
templates add f("reversed()") {
only(RangesOfPrimitives, ProgressionsOfPrimitives)
exclude(PrimitiveType.Boolean)
doc(ProgressionsOfPrimitives) { "Returns a progression that goes over the same range in the opposite direction with the same step" }
doc(RangesOfPrimitives) { "Returns a progression that goes over this range in reverse direction" }
returns("TProgression")
body(RangesOfPrimitives) {
"return TProgression(end, start, -ONE)"
}
body(ProgressionsOfPrimitives) {
"return TProgression(end, start, -increment)"
}
}
templates add f("step(step: SUM)") {
only(RangesOfPrimitives, ProgressionsOfPrimitives)
exclude(PrimitiveType.Boolean)
doc(ProgressionsOfPrimitives) { "Returns a progression that goes over the same range with the given step" }
doc(RangesOfPrimitives) { "Returns a progression that goes over this range with given step" }
returns("TProgression")
body(RangesOfPrimitives) {
"""
checkStepIsPositive(step > 0, step)
return TProgression(start, end, step)
"""
}
bodyForTypes(RangesOfPrimitives, PrimitiveType.Float, PrimitiveType.Double) {
"""
if (step.isNaN()) throw IllegalArgumentException("Step must not be NaN")
checkStepIsPositive(step > 0, step)
return TProgression(start, end, step)
"""
}
body(ProgressionsOfPrimitives) {
"""
checkStepIsPositive(step > 0, step)
return TProgression(start, end, if (increment > 0) step else -step)
"""
}
}
return templates
}