From a0e2ca669b646d4ee84e807d01a566896cefd101 Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Tue, 5 Mar 2019 20:36:17 +0300 Subject: [PATCH] Write docs for primitive types conversions --- core/builtins/native/kotlin/Primitives.kt | 238 ++++++++++++++++++++++ generators/builtins/common.kt | 14 +- generators/builtins/primitives.kt | 148 +++++++++++++- 3 files changed, 389 insertions(+), 11 deletions(-) diff --git a/core/builtins/native/kotlin/Primitives.kt b/core/builtins/native/kotlin/Primitives.kt index 906c615da8f..37ae364daec 100644 --- a/core/builtins/native/kotlin/Primitives.kt +++ b/core/builtins/native/kotlin/Primitives.kt @@ -186,12 +186,52 @@ public class Byte private constructor() : Number(), Comparable { /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Long): LongRange + /** Returns this value. */ public override fun toByte(): Byte + /** + * Converts this [Byte] value to [Char]. + * + * Returns the `Char` with the numeric value equal to this value sign-extended to 16 bits. + */ public override fun toChar(): Char + /** + * Converts this [Byte] value to [Short]. + * + * The resulting `Short` value represents the same numerical value as this `Byte`. + * + * The least significant 8 bits of the resulting `Short` value are the same as the binary representation of this `Byte` value, + * whereas the most significant 8 bits are filled with the bit sign of this value. + */ public override fun toShort(): Short + /** + * Converts this [Byte] value to [Int]. + * + * The resulting `Int` value represents the same numerical value as this `Byte`. + * + * The least significant 8 bits of the resulting `Int` value are the same as the binary representation of this `Byte` value, + * whereas the most significant 24 bits are filled with the bit sign of this value. + */ public override fun toInt(): Int + /** + * Converts this [Byte] value to [Long]. + * + * The resulting `Long` value represents the same numerical value as this `Byte`. + * + * The least significant 8 bits of the resulting `Long` value are the same as the binary representation of this `Byte` value, + * whereas the most significant 56 bits are filled with the bit sign of this value. + */ public override fun toLong(): Long + /** + * Converts this [Byte] value to [Float]. + * + * The resulting `Float` value represents the same numerical value as this `Byte`. + */ public override fun toFloat(): Float + /** + * Converts this [Byte] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Byte`. + */ public override fun toDouble(): Double } @@ -374,12 +414,52 @@ public class Short private constructor() : Number(), Comparable { /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Long): LongRange + /** + * Converts this [Short] value to [Byte]. + * + * If this value is in [Byte.MIN_VALUE]..[Byte.MAX_VALUE], the resulting `Byte` value represents + * the same numerical value as this `Short`. + * + * The resulting `Byte` value is represented by the least significant 8 bits of this `Short` value. + */ public override fun toByte(): Byte + /** + * Converts this [Short] value to [Char]. + * + * Returns the `Char` with the numeric value equal to this value. + */ public override fun toChar(): Char + /** Returns this value. */ public override fun toShort(): Short + /** + * Converts this [Short] value to [Int]. + * + * The resulting `Int` value represents the same numerical value as this `Short`. + * + * The least significant 16 bits of the resulting `Int` value are the same as the binary representation of this `Short` value, + * whereas the most significant 16 bits are filled with the bit sign of this value. + */ public override fun toInt(): Int + /** + * Converts this [Short] value to [Long]. + * + * The resulting `Long` value represents the same numerical value as this `Short`. + * + * The least significant 16 bits of the resulting `Long` value are the same as the binary representation of this `Short` value, + * whereas the most significant 48 bits are filled with the bit sign of this value. + */ public override fun toLong(): Long + /** + * Converts this [Short] value to [Float]. + * + * The resulting `Float` value represents the same numerical value as this `Short`. + */ public override fun toFloat(): Float + /** + * Converts this [Short] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Short`. + */ public override fun toDouble(): Double } @@ -577,12 +657,54 @@ public class Int private constructor() : Number(), Comparable { /** Inverts the bits in this value. */ public fun inv(): Int + /** + * Converts this [Int] value to [Byte]. + * + * If this value is in [Byte.MIN_VALUE]..[Byte.MAX_VALUE], the resulting `Byte` value represents + * the same numerical value as this `Int`. + * + * The resulting `Byte` value is represented by the least significant 8 bits of this `Int` value. + */ public override fun toByte(): Byte + /** + * Converts this [Int] value to [Char]. + * + * Returns the `Char` with the numeric value equal to this value truncated to 16 bits. + */ public override fun toChar(): Char + /** + * Converts this [Int] value to [Short]. + * + * If this value is in [Short.MIN_VALUE]..[Short.MAX_VALUE], the resulting `Short` value represents + * the same numerical value as this `Int`. + * + * The resulting `Short` value is represented by the least significant 16 bits of this `Int` value. + */ public override fun toShort(): Short + /** Returns this value. */ public override fun toInt(): Int + /** + * Converts this [Int] value to [Long]. + * + * The resulting `Long` value represents the same numerical value as this `Int`. + * + * The least significant 32 bits of the resulting `Long` value are the same as the binary representation of this `Int` value, + * whereas the most significant 32 bits are filled with the bit sign of this value. + */ public override fun toLong(): Long + /** + * Converts this [Int] value to [Float]. + * + * The resulting value is the closest `Float` to this `Int` value. + * In case when this `Int` value is exactly between two `Float`s, + * the one with zero at least significant bit of mantissa is selected. + */ public override fun toFloat(): Float + /** + * Converts this [Int] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Int`. + */ public override fun toDouble(): Double } @@ -780,12 +902,56 @@ public class Long private constructor() : Number(), Comparable { /** Inverts the bits in this value. */ public fun inv(): Long + /** + * Converts this [Long] value to [Byte]. + * + * If this value is in [Byte.MIN_VALUE]..[Byte.MAX_VALUE], the resulting `Byte` value represents + * the same numerical value as this `Long`. + * + * The resulting `Byte` value is represented by the least significant 8 bits of this `Long` value. + */ public override fun toByte(): Byte + /** + * Converts this [Long] value to [Char]. + * + * Returns the `Char` with the numeric value equal to this value truncated to 16 bits. + */ public override fun toChar(): Char + /** + * Converts this [Long] value to [Short]. + * + * If this value is in [Short.MIN_VALUE]..[Short.MAX_VALUE], the resulting `Short` value represents + * the same numerical value as this `Long`. + * + * The resulting `Short` value is represented by the least significant 16 bits of this `Long` value. + */ public override fun toShort(): Short + /** + * Converts this [Long] value to [Int]. + * + * If this value is in [Int.MIN_VALUE]..[Int.MAX_VALUE], the resulting `Int` value represents + * the same numerical value as this `Long`. + * + * The resulting `Int` value is represented by the least significant 32 bits of this `Long` value. + */ public override fun toInt(): Int + /** Returns this value. */ public override fun toLong(): Long + /** + * Converts this [Long] value to [Float]. + * + * The resulting value is the closest `Float` to this `Long` value. + * In case when this `Long` value is exactly between two `Float`s, + * the one with zero at least significant bit of mantissa is selected. + */ public override fun toFloat(): Float + /** + * Converts this [Long] value to [Double]. + * + * The resulting value is the closest `Double` to this `Long` value. + * In case when this `Long` value is exactly between two `Double`s, + * the one with zero at least significant bit of mantissa is selected. + */ public override fun toDouble(): Double } @@ -963,12 +1129,47 @@ public class Float private constructor() : Number(), Comparable { public operator fun unaryMinus(): Float + /** + * Converts this [Float] value to [Byte]. + * + * The resulting `Byte` value is equal to `this.toInt().toByte()`. + */ public override fun toByte(): Byte + /** + * Converts this [Float] value to [Char]. + * + * The resulting `Char` value is equal to `this.toInt().toChar()`. + */ public override fun toChar(): Char + /** + * Converts this [Float] value to [Short]. + * + * The resulting `Short` value is equal to `this.toInt().toShort()`. + */ public override fun toShort(): Short + /** + * Converts this [Float] value to [Int]. + * + * The fractional part, if any, is rounded down. + * Returns zero if this `Float` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`, + * [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`. + */ public override fun toInt(): Int + /** + * Converts this [Float] value to [Long]. + * + * The fractional part, if any, is rounded down. + * Returns zero if this `Float` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`, + * [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`. + */ public override fun toLong(): Long + /** Returns this value. */ public override fun toFloat(): Float + /** + * Converts this [Float] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Float`. + */ public override fun toDouble(): Double } @@ -1146,12 +1347,49 @@ public class Double private constructor() : Number(), Comparable { public operator fun unaryMinus(): Double + /** + * Converts this [Double] value to [Byte]. + * + * The resulting `Byte` value is equal to `this.toInt().toByte()`. + */ public override fun toByte(): Byte + /** + * Converts this [Double] value to [Char]. + * + * The resulting `Char` value is equal to `this.toInt().toChar()`. + */ public override fun toChar(): Char + /** + * Converts this [Double] value to [Short]. + * + * The resulting `Short` value is equal to `this.toInt().toShort()`. + */ public override fun toShort(): Short + /** + * Converts this [Double] value to [Int]. + * + * The fractional part, if any, is rounded down. + * Returns zero if this `Double` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`, + * [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`. + */ public override fun toInt(): Int + /** + * Converts this [Double] value to [Long]. + * + * The fractional part, if any, is rounded down. + * Returns zero if this `Double` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`, + * [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`. + */ public override fun toLong(): Long + /** + * Converts this [Double] value to [Float]. + * + * The resulting value is the closest `Float` to this `Double` value. + * In case when this `Double` value is exactly between two `Float`s, + * the one with zero at least significant bit of mantissa is selected. + */ public override fun toFloat(): Float + /** Returns this value. */ public override fun toDouble(): Double } diff --git a/generators/builtins/common.kt b/generators/builtins/common.kt index 211673daead..034652ab90b 100644 --- a/generators/builtins/common.kt +++ b/generators/builtins/common.kt @@ -17,24 +17,28 @@ package org.jetbrains.kotlin.generators.builtins import org.jetbrains.kotlin.generators.builtins.ProgressionKind.* -import kotlin.properties.Delegates -enum class PrimitiveType(val byteSize: Int?) { +enum class PrimitiveType(val byteSize: Int) { BYTE(1), CHAR(2), SHORT(2), INT(4), LONG(8), - FLOAT(null), - DOUBLE(null), - BOOLEAN(null); + FLOAT(4), + DOUBLE(8), + BOOLEAN(1); val capitalized: String get() = name.toLowerCase().capitalize() + val bitSize = byteSize * 8 + + val isFloatingPoint: Boolean get() = this in floatingPoint + val isIntegral: Boolean get() = this in integral companion object { val exceptBoolean = PrimitiveType.values().filterNot { it == BOOLEAN } val onlyNumeric = PrimitiveType.values().filterNot { it == BOOLEAN || it == CHAR } val floatingPoint = listOf(FLOAT, DOUBLE) + val integral = exceptBoolean - floatingPoint } } diff --git a/generators/builtins/primitives.kt b/generators/builtins/primitives.kt index 0dac7819999..b645fd5f2e8 100644 --- a/generators/builtins/primitives.kt +++ b/generators/builtins/primitives.kt @@ -101,7 +101,7 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) { */ public const val MAX_VALUE: $className = $maxValue""") } - if (kind.byteSize != null) { + if (kind.isIntegral) { out.println(""" /** * The number of bytes used to represent an instance of $className in a binary form. @@ -113,7 +113,7 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) { * The number of bits used to represent an instance of $className in a binary form. */ @SinceKotlin("1.3") - public const val SIZE_BITS: Int = ${kind.byteSize * 8}""") + public const val SIZE_BITS: Int = ${kind.bitSize}""") } out.println(""" }""") @@ -130,7 +130,7 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) { generateBitwiseOperators(className, since = if (kind == PrimitiveType.BYTE || kind == PrimitiveType.SHORT) "1.1" else null) } - generateConversions() + generateConversions(kind) out.println("}\n") } @@ -223,10 +223,146 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) { out.println() } - private fun generateConversions() { + + private fun compareByDomainCapacity(type1: PrimitiveType, type2: PrimitiveType): Int = + if (type1.isIntegral && type2.isIntegral) type1.byteSize - type2.byteSize else type1.ordinal - type2.ordinal + + private fun docForConversionFromFloatingToIntegral(fromFloating: PrimitiveType, toIntegral: PrimitiveType): String { + require(fromFloating.isFloatingPoint) + require(toIntegral.isIntegral) + + val thisName = fromFloating.capitalized + val otherName = toIntegral.capitalized + + return if (compareByDomainCapacity(toIntegral, PrimitiveType.INT) < 0) { + """ + * The resulting `$otherName` value is equal to `this.toInt().to$otherName()`. + */ + """ + } else { + """ + * The fractional part, if any, is rounded down. + * Returns zero if this `$thisName` value is `NaN`, [$otherName.MIN_VALUE] if it's less than `$otherName.MIN_VALUE`, + * [$otherName.MAX_VALUE] if it's bigger than `$otherName.MAX_VALUE`. + */ + """ + } + } + + private fun docForConversionFromFloatingToFloating(fromFloating: PrimitiveType, toFloating: PrimitiveType): String { + require(fromFloating.isFloatingPoint) + require(toFloating.isFloatingPoint) + + val thisName = fromFloating.capitalized + val otherName = toFloating.capitalized + + return if (compareByDomainCapacity(toFloating, fromFloating) < 0) { + """ + * The resulting value is the closest `$otherName` to this `$thisName` value. + * In case when this `$thisName` value is exactly between two `$otherName`s, + * the one with zero at least significant bit of mantissa is selected. + */ + """ + } else { + """ + * The resulting `$otherName` value represents the same numerical value as this `$thisName`. + */ + """ + } + } + + private fun docForConversionFromIntegralToIntegral(fromIntegral: PrimitiveType, toIntegral: PrimitiveType): String { + require(fromIntegral.isIntegral) + require(toIntegral.isIntegral) + + val thisName = fromIntegral.capitalized + val otherName = toIntegral.capitalized + + return if (compareByDomainCapacity(toIntegral, fromIntegral) < 0) { + if (toIntegral == PrimitiveType.CHAR) { + """ + * Returns the `$otherName` with the numeric value equal to this value truncated to ${toIntegral.bitSize} bits. + */ + """ + } else { + """ + * If this value is in [$otherName.MIN_VALUE]..[$otherName.MAX_VALUE], the resulting `$otherName` value represents + * the same numerical value as this `$thisName`. + * + * The resulting `$otherName` value is represented by the least significant ${toIntegral.bitSize} bits of this `$thisName` value. + */ + """ + } + } else if (compareByDomainCapacity(toIntegral, fromIntegral) > 0) { + if (toIntegral == PrimitiveType.CHAR) { + """ + * Returns the `$otherName` with the numeric value equal to this value sign-extended to ${toIntegral.bitSize} bits. + */ + """ + } else { + """ + * The resulting `$otherName` value represents the same numerical value as this `$thisName`. + * + * The least significant ${fromIntegral.bitSize} bits of the resulting `$otherName` value are the same as the binary representation of this `$thisName` value, + * whereas the most significant ${toIntegral.bitSize - fromIntegral.bitSize} bits are filled with the bit sign of this value. + */ + """ + } + } else { // Short -> Char + """ + * Returns the `$otherName` with the numeric value equal to this value. + */ + """ + } + } + + private fun docForConversionFromIntegralToFloating(fromIntegral: PrimitiveType, toFloating: PrimitiveType): String { + require(fromIntegral.isIntegral) + require(toFloating.isFloatingPoint) + + val thisName = fromIntegral.capitalized + val otherName = toFloating.capitalized + + return if (fromIntegral == PrimitiveType.LONG || fromIntegral == PrimitiveType.INT && toFloating == PrimitiveType.FLOAT) { + """ + * The resulting value is the closest `$otherName` to this `$thisName` value. + * In case when this `$thisName` value is exactly between two `$otherName`s, + * the one with zero at least significant bit of mantissa is selected. + */ + """ + } else { + """ + * The resulting `$otherName` value represents the same numerical value as this `$thisName`. + */ + """ + } + } + + private fun generateConversions(kind: PrimitiveType) { + val thisName = kind.capitalized for (otherKind in PrimitiveType.exceptBoolean) { - val name = otherKind.capitalized - out.println(" public override fun to$name(): $name") + val otherName = otherKind.capitalized + val doc = if (kind == otherKind) { + " /** Returns this value. */" + } else { + val detail = if (kind in PrimitiveType.integral) { + if (otherKind.isIntegral) { + docForConversionFromIntegralToIntegral(kind, otherKind) + } else { + docForConversionFromIntegralToFloating(kind, otherKind) + } + } else { + if (otherKind.isIntegral) { + docForConversionFromFloatingToIntegral(kind, otherKind) + } else { + docForConversionFromFloatingToFloating(kind, otherKind) + } + } + + " /**\n * Converts this [$thisName] value to [$otherName].\n *\n" + detail.replaceIndent(" ") + } + out.println(doc) + out.println(" public override fun to$otherName(): $otherName") } }