blob: a42299bc09a34373cc86a57900d9eb6c3dbc421b [file] [log] [blame]
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package templates
import templates.Family.*
object ComparableOps : TemplateGroupBase() {
init {
defaultBuilder {
specialFor(Unsigned) {
since("1.3")
annotation("@ExperimentalUnsignedTypes")
}
}
}
private val Family.sourceFileRanges: SourceFile
get() = when (this) {
Generic, Primitives -> SourceFile.Ranges
Unsigned -> SourceFile.URanges
else -> error(this)
}
private val Family.sourceFileComparisons: SourceFile
get() = when (this) {
Generic, Primitives -> SourceFile.Comparisons
Unsigned -> SourceFile.UComparisons
else -> error(this)
}
private val Family.sampleSuffix: String
get() = when (this) {
Primitives -> ""
Unsigned -> "Unsigned"
Generic -> "Comparable"
else -> error(this)
}
private val numericPrimitives = PrimitiveType.numericPrimitives.sortedBy { it.capacity }.toSet()
private val intPrimitives = setOf(PrimitiveType.Int, PrimitiveType.Long)
private val shortIntPrimitives = setOf(PrimitiveType.Byte, PrimitiveType.Short)
private val uintPrimitives = setOf(PrimitiveType.UInt, PrimitiveType.ULong)
val f_coerceAtLeast = fn("coerceAtLeast(minimumValue: SELF)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileRanges)
returns("SELF")
typeParam("T : Comparable<T>")
doc {
"""
Ensures that this value is not less than the specified [minimumValue].
@return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
"""
}
sample("samples.comparisons.ComparableOps.coerceAtLeast${f.sampleSuffix}")
body {
"""
return if (this < minimumValue) minimumValue else this
"""
}
}
val f_coerceAtMost = fn("coerceAtMost(maximumValue: SELF)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileRanges)
returns("SELF")
typeParam("T : Comparable<T>")
doc {
"""
Ensures that this value is not greater than the specified [maximumValue].
@return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
"""
}
sample("samples.comparisons.ComparableOps.coerceAtMost${f.sampleSuffix}")
body {
"""
return if (this > maximumValue) maximumValue else this
"""
}
}
val f_coerceIn_range_primitive = fn("coerceIn(range: ClosedRange<T>)") {
include(Generic)
include(Primitives, intPrimitives)
include(Unsigned, uintPrimitives)
} builder {
sourceFile(f.sourceFileRanges)
returns("SELF")
typeParam("T : Comparable<T>")
doc {
"""
Ensures that this value lies in the specified [range].
@return this value if it's in the [range], or `range.start` if this value is less than `range.start`, or `range.endInclusive` if this value is greater than `range.endInclusive`.
"""
}
sample("samples.comparisons.ComparableOps.coerceIn${f.sampleSuffix}")
body {
"""
if (range is ClosedFloatingPointRange) {
return this.coerceIn<T>(range)
}
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: ${'$'}range.")
return when {
this < range.start -> range.start
this > range.endInclusive -> range.endInclusive
else -> this
}
"""
}
}
val f_coerceIn_fpRange = fn("coerceIn(range: ClosedFloatingPointRange<T>)") {
include(Generic)
} builder {
sourceFile(f.sourceFileRanges)
since("1.1")
returns("SELF")
typeParam("T : Comparable<T>")
doc {
"""
Ensures that this value lies in the specified [range].
@return this value if it's in the [range], or `range.start` if this value is less than `range.start`, or `range.endInclusive` if this value is greater than `range.endInclusive`.
"""
}
sample("samples.comparisons.ComparableOps.coerceInFloatingPointRange")
body(Generic) {
"""
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: ${'$'}range.")
return when {
// this < start equiv to this <= start && !(this >= start)
range.lessThanOrEquals(this, range.start) && !range.lessThanOrEquals(range.start, this) -> range.start
// this > end equiv to this >= end && !(this <= end)
range.lessThanOrEquals(range.endInclusive, this) && !range.lessThanOrEquals(this, range.endInclusive) -> range.endInclusive
else -> this
}
"""
}
}
val f_minOf_2 = fn("minOf(a: T, b: T)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
typeParam("T : Comparable<T>")
returns("T")
receiver("")
doc {
"""
Returns the smaller of two values.
If values are equal, returns the first one.
"""
}
val defaultImpl = "if (a <= b) a else b"
body { "return $defaultImpl" }
specialFor(Primitives, Unsigned) {
doc { "Returns the smaller of two values." }
}
// TODO: Add a note about NaN propagation for floats.
specialFor(Primitives) {
inlineOnly()
var convertBack = "to$primitive()"
on(Platform.JS) {
suppress("DEPRECATION_ERROR")
convertBack = "unsafeCast<$primitive>()"
}
on(Platform.JVM) {
body { "return Math.min(a, b)" }
}
on(Platform.JS) {
body { "return Math.min(a, b)" }
if (primitive == PrimitiveType.Long) {
inline(suppressWarning = true)
body { "return $defaultImpl" }
}
}
if (primitive in shortIntPrimitives) {
body { "return Math.min(a.toInt(), b.toInt()).$convertBack" }
on(Platform.Native) {
body { "return minOf(a.toInt(), b.toInt()).$convertBack" }
}
}
if (primitive?.isFloatingPoint() == true) {
on(Platform.Native) {
body {
"""
return when {
a.isNaN() -> a
b.isNaN() -> b
else -> if (a.compareTo(b) <= 0) a else b
}
"""
}
}
}
}
specialFor(Generic) {
on(Platform.JS) { /* just to make expect, KT-22520 */ }
}
}
val f_minOf_3 = fn("minOf(a: T, b: T, c: T)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
typeParam("T : Comparable<T>")
returns("T")
receiver("")
specialFor(Primitives, Unsigned) { inlineOnly() }
// TODO: Add a note about NaN propagation for floats.
doc {
"""
Returns the smaller of three values.
"""
}
body {
"return minOf(a, minOf(b, c))"
}
specialFor(Primitives, Generic) {
on(Platform.JS) { /* just to make expect, KT-22520 */ }
}
specialFor(Primitives) {
if (primitive in shortIntPrimitives) {
body { "return minOf(a.toInt(), minOf(b.toInt(), c.toInt())).to$primitive()" }
on(Platform.JVM) {
body { "return Math.min(a.toInt(), Math.min(b.toInt(), c.toInt())).to$primitive()" }
}
on(Platform.JS) {
suppress("DEPRECATION_ERROR")
body { "return Math.min(a.toInt(), b.toInt(), c.toInt()).unsafeCast<$primitive>()" }
}
}
else if (primitive != PrimitiveType.Long) {
on(Platform.JS) {
suppress("DEPRECATION_ERROR")
body { "return Math.min(a, b, c)" }
}
}
}
}
val f_minOf_2_comparator = fn("minOf(a: T, b: T, comparator: Comparator<in T>)") {
include(Generic)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
returns("T")
receiver("")
doc {
"""
Returns the smaller of two values according to the order specified by the given [comparator].
If values are equal, returns the first one.
"""
}
body {
"return if (comparator.compare(a, b) <= 0) a else b"
}
}
val f_minOf_3_comparator = fn("minOf(a: T, b: T, c: T, comparator: Comparator<in T>)") {
include(Generic)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
returns("T")
receiver("")
doc {
"""
Returns the smaller of three values according to the order specified by the given [comparator].
"""
}
body {
"return minOf(a, minOf(b, c, comparator), comparator)"
}
}
val f_maxOf_2 = fn("maxOf(a: T, b: T)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
typeParam("T : Comparable<T>")
returns("T")
receiver("")
doc {
"""
Returns the greater of two values.
If values are equal, returns the first one.
"""
}
val defaultImpl = "if (a >= b) a else b"
body { "return $defaultImpl" }
specialFor(Primitives, Unsigned) {
doc { "Returns the greater of two values." }
}
// TODO: Add a note about NaN propagation for floats.
specialFor(Primitives) {
inlineOnly()
var convertBack = "to$primitive()"
on(Platform.JS) {
suppress("DEPRECATION_ERROR")
convertBack = "unsafeCast<$primitive>()"
}
on(Platform.JVM) {
body { "return Math.max(a, b)" }
}
on(Platform.JS) {
body { "return Math.max(a, b)" }
if (primitive == PrimitiveType.Long) {
inline(suppressWarning = true)
body { "return $defaultImpl" }
}
}
if (primitive in shortIntPrimitives) {
body { "return Math.max(a.toInt(), b.toInt()).$convertBack" }
on(Platform.Native) {
body { "return maxOf(a.toInt(), b.toInt()).$convertBack" }
}
}
if (primitive?.isFloatingPoint() == true) {
on(Platform.Native) {
body {
"""
return if (a.compareTo(b) >= 0) a else b
"""
}
}
}
}
specialFor(Generic) {
on(Platform.JS) { /* just to make expect, KT-22520 */ }
}
}
val f_maxOf_3 = fn("maxOf(a: T, b: T, c: T)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
typeParam("T : Comparable<T>")
returns("T")
receiver("")
specialFor(Primitives, Unsigned) { inlineOnly() }
// TODO: Add a note about NaN propagation for floats.
doc {
"""
Returns the greater of three values.
"""
}
body {
"return maxOf(a, maxOf(b, c))"
}
specialFor(Primitives, Generic) {
on(Platform.JS) { /* just to make expect, KT-22520 */ }
}
specialFor(Primitives) {
if (primitive in shortIntPrimitives) {
body { "return maxOf(a.toInt(), maxOf(b.toInt(), c.toInt())).to$primitive()" }
on(Platform.JVM) {
body { "return Math.max(a.toInt(), Math.max(b.toInt(), c.toInt())).to$primitive()" }
}
on(Platform.JS) {
suppress("DEPRECATION_ERROR")
body { "return Math.max(a.toInt(), b.toInt(), c.toInt()).unsafeCast<$primitive>()" }
}
}
else if (primitive != PrimitiveType.Long) {
on(Platform.JS) {
suppress("DEPRECATION_ERROR")
body { "return Math.max(a, b, c)" }
}
}
}
}
val f_maxOf_2_comparator = fn("maxOf(a: T, b: T, comparator: Comparator<in T>)") {
include(Generic)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
returns("T")
receiver("")
doc {
"""
Returns the greater of two values according to the order specified by the given [comparator].
If values are equal, returns the first one.
"""
}
body {
"return if (comparator.compare(a, b) >= 0) a else b"
}
}
val f_maxOf_3_comparator = fn("maxOf(a: T, b: T, c: T, comparator: Comparator<in T>)") {
include(Generic)
} builder {
sourceFile(f.sourceFileComparisons)
since("1.1")
returns("T")
receiver("")
doc {
"""
Returns the greater of three values according to the order specified by the given [comparator].
"""
}
body {
"return maxOf(a, maxOf(b, c, comparator), comparator)"
}
}
val f_coerceIn_min_max = fn("coerceIn(minimumValue: SELF, maximumValue: SELF)") {
include(Generic)
include(Primitives, numericPrimitives)
include(Unsigned)
} builder {
sourceFile(f.sourceFileRanges)
specialFor(Generic) { signature("coerceIn(minimumValue: SELF?, maximumValue: SELF?)", notForSorting = true) }
typeParam("T : Comparable<T>")
returns("SELF")
doc {
"""
Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
@return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
"""
}
sample("samples.comparisons.ComparableOps.coerceIn${f.sampleSuffix}")
body(Primitives, Unsigned) {
"""
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum ${'$'}maximumValue is less than minimum ${'$'}minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
"""
}
body(Generic) {
"""
if (minimumValue !== null && maximumValue !== null) {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum ${'$'}maximumValue is less than minimum ${'$'}minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
}
else {
if (minimumValue !== null && this < minimumValue) return minimumValue
if (maximumValue !== null && this > maximumValue) return maximumValue
}
return this
"""
}
}
}