Generate coerceAtLeast, coerceAtMost and coerceIn extension functions for numbers and other Comparables.
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
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
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun <T: Comparable<T>> T.coerceAtLeast(minimumValue: T): T {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun Byte.coerceAtLeast(minimumValue: Byte): Byte {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun Double.coerceAtLeast(minimumValue: Double): Double {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun Float.coerceAtLeast(minimumValue: Float): Float {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun Int.coerceAtLeast(minimumValue: Int): Int {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun Long.coerceAtLeast(minimumValue: Long): Long {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun Short.coerceAtLeast(minimumValue: Short): Short {
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun <T: Comparable<T>> T.coerceAtMost(maximumValue: T): T {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun Byte.coerceAtMost(maximumValue: Byte): Byte {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun Double.coerceAtMost(maximumValue: Double): Double {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun Float.coerceAtMost(maximumValue: Float): Float {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun Int.coerceAtMost(maximumValue: Int): Int {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun Long.coerceAtMost(maximumValue: Long): Long {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this value is not greater than the specified [maximumValue].
|
||||
* @return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
*/
|
||||
public fun Short.coerceAtMost(maximumValue: Short): Short {
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun <T: Comparable<T>> T.coerceIn(minimumValue: T?, maximumValue: T?): T {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun Byte.coerceIn(minimumValue: Byte?, maximumValue: Byte?): Byte {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun Double.coerceIn(minimumValue: Double?, maximumValue: Double?): Double {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun Float.coerceIn(minimumValue: Float?, maximumValue: Float?): Float {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun Int.coerceIn(minimumValue: Int?, maximumValue: Int?): Int {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun Long.coerceIn(minimumValue: Long?, maximumValue: Long?): Long {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
public fun Short.coerceIn(minimumValue: Short?, maximumValue: Short?): Short {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun <T: Comparable<T>> T.coerceIn(range: Range<T>): T {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun Byte.coerceIn(range: ByteRange): Byte {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun Double.coerceIn(range: DoubleRange): Double {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun Float.coerceIn(range: FloatRange): Float {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun Int.coerceIn(range: IntRange): Int {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun Long.coerceIn(range: LongRange): Long {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.end if this value is greater than range.end.
|
||||
*/
|
||||
public fun Short.coerceIn(range: ShortRange): Short {
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package numbers
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.Test as test
|
||||
import kotlin.test.*
|
||||
|
||||
class CoercionTest {
|
||||
|
||||
fun usage() {
|
||||
val n = 1
|
||||
// infix usage
|
||||
val n1 = n coerceAtLeast 2
|
||||
// function usage
|
||||
val n2 = n.coerceAtLeast(2)
|
||||
|
||||
// infix with range
|
||||
val n3 = n coerceIn 2..5
|
||||
}
|
||||
|
||||
Test fun coercionsInt() {
|
||||
expect(5) { 5.coerceAtLeast(1) }
|
||||
expect(5) { 1.coerceAtLeast(5) }
|
||||
expect(1) { 5.coerceAtMost(1) }
|
||||
expect(1) { 1.coerceAtMost(5) }
|
||||
|
||||
for (value in 0..10) {
|
||||
expect(value) { value.coerceIn(null, null) }
|
||||
val min = 2
|
||||
val max = 5
|
||||
val range = min..max
|
||||
expect(value.coerceAtLeast(min)) { value.coerceIn(min, null) }
|
||||
expect(value.coerceAtMost(max)) { value.coerceIn(null, max) }
|
||||
expect(value.coerceAtLeast(min).coerceAtMost(max)) { value.coerceIn(min, max) }
|
||||
expect(value.coerceAtMost(max).coerceAtLeast(min)) { value coerceIn range }
|
||||
assertTrue((value coerceIn range) in range)
|
||||
}
|
||||
|
||||
fails { 1.coerceIn(1, 0) }
|
||||
fails { 1.coerceIn(1..0) }
|
||||
}
|
||||
|
||||
Test fun coercionsLong() {
|
||||
expect(5L) { 5L.coerceAtLeast(1L) }
|
||||
expect(5L) { 1L.coerceAtLeast(5L) }
|
||||
expect(1L) { 5L.coerceAtMost(1L) }
|
||||
expect(1L) { 1L.coerceAtMost(5L) }
|
||||
|
||||
for (value in 0L..10L) {
|
||||
expect(value) { value.coerceIn(null, null) }
|
||||
val min = 2L
|
||||
val max = 5L
|
||||
val range = min..max
|
||||
expect(value.coerceAtLeast(min)) { value.coerceIn(min, null) }
|
||||
expect(value.coerceAtMost(max)) { value.coerceIn(null, max) }
|
||||
expect(value.coerceAtLeast(min).coerceAtMost(max)) { value.coerceIn(min, max) }
|
||||
expect(value.coerceAtMost(max).coerceAtLeast(min)) { value coerceIn range }
|
||||
assertTrue((value coerceIn range) in range)
|
||||
}
|
||||
|
||||
fails { 1L.coerceIn(1L, 0L) }
|
||||
fails { 1L.coerceIn(1L..0L) }
|
||||
|
||||
}
|
||||
|
||||
Test fun coercionsDouble() {
|
||||
expect(5.0) { 5.0.coerceAtLeast(1.0) }
|
||||
expect(5.0) { 1.0.coerceAtLeast(5.0) }
|
||||
expect(1.0) { 5.0.coerceAtMost(1.0) }
|
||||
expect(1.0) { 1.0.coerceAtMost(5.0) }
|
||||
|
||||
for (value in 0.0..10.0) {
|
||||
expect(value) { value.coerceIn(null, null) }
|
||||
val min = 2.0
|
||||
val max = 5.0
|
||||
val range = min..max
|
||||
expect(value.coerceAtLeast(min)) { value.coerceIn(min, null) }
|
||||
expect(value.coerceAtMost(max)) { value.coerceIn(null, max) }
|
||||
expect(value.coerceAtLeast(min).coerceAtMost(max)) { value.coerceIn(min, max) }
|
||||
expect(value.coerceAtMost(max).coerceAtLeast(min)) { value coerceIn range }
|
||||
assertTrue((value coerceIn range) in range)
|
||||
}
|
||||
|
||||
fails { 1.0.coerceIn(1.0, 0.0) }
|
||||
fails { 1.0.coerceIn(1.0..0.0) }
|
||||
}
|
||||
|
||||
Test fun coercionsComparable() {
|
||||
val v = 0..10 map { ComparableNumber(it) }
|
||||
|
||||
expect(5) { v[5].coerceAtLeast(v[1]).value }
|
||||
expect(5) { v[1].coerceAtLeast(v[5]).value }
|
||||
expect(v[5]) { v[5].coerceAtLeast(ComparableNumber(5)) }
|
||||
|
||||
expect(1) { v[5].coerceAtMost(v[1]).value }
|
||||
expect(1) { v[1].coerceAtMost(v[5]).value }
|
||||
expect(v[1]) { v[1].coerceAtMost(ComparableNumber(1)) }
|
||||
|
||||
for (value in v) {
|
||||
expect(value) { value.coerceIn(null, null) }
|
||||
val min = v[2]
|
||||
val max = v[5]
|
||||
val range = min..max
|
||||
expect(value.coerceAtLeast(min)) { value.coerceIn(min, null) }
|
||||
expect(value.coerceAtMost(max)) { value.coerceIn(null, max) }
|
||||
expect(value.coerceAtLeast(min).coerceAtMost(max)) { value.coerceIn(min, max) }
|
||||
expect(value.coerceAtMost(max).coerceAtLeast(min)) { value coerceIn range }
|
||||
assertTrue((value coerceIn range) in range)
|
||||
}
|
||||
|
||||
fails { v[1].coerceIn(v[1], v[0]) }
|
||||
fails { v[1].coerceIn(v[1]..v[0]) }
|
||||
}
|
||||
}
|
||||
|
||||
private class ComparableNumber(public val value: Int) : Comparable<ComparableNumber> {
|
||||
override fun compareTo(other: ComparableNumber): Int = this.value - other.value
|
||||
override fun toString(): String = "CV$value"
|
||||
}
|
||||
@@ -29,15 +29,17 @@ fun generateCollectionsAPI(outDir: File) {
|
||||
build(builder, Sequences, numeric)
|
||||
}
|
||||
|
||||
for (numeric in listOf(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Byte, PrimitiveType.Short, PrimitiveType.Double, PrimitiveType.Float)) {
|
||||
for (numeric in numericPrimitives) {
|
||||
build(builder, ArraysOfObjects, numeric)
|
||||
build(builder, ArraysOfPrimitives, numeric)
|
||||
}
|
||||
builder.toString()
|
||||
}
|
||||
|
||||
comparables().writeTo(File(outDir, "_Comparables.kt")) { build() }
|
||||
|
||||
}
|
||||
|
||||
fun generateCollectionsJsAPI(outDir: File) {
|
||||
specialJS().writeTo(File(outDir, "kotlin_special.kt")) { build() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package templates
|
||||
|
||||
import templates.Family.*
|
||||
|
||||
fun comparables(): List<GenericFunction> {
|
||||
val templates = arrayListOf<GenericFunction>()
|
||||
|
||||
templates add f("coerceAtLeast(minimumValue: SELF)") {
|
||||
only(Primitives, Generic)
|
||||
only(*numericPrimitives)
|
||||
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.
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
return if (this < minimumValue) minimumValue else this
|
||||
"""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
templates add f("coerceAtMost(maximumValue: SELF)") {
|
||||
only(Primitives, Generic)
|
||||
only(*numericPrimitives)
|
||||
returns("SELF")
|
||||
typeParam("T: Comparable<T>")
|
||||
doc {
|
||||
"""
|
||||
Ensures that this value is not greater than the specified [maximumValue].
|
||||
|
||||
@return this value if it's greater than or equal to the [maximumValue] or the [maximumValue] otherwise.
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
return if (this > maximumValue) maximumValue else this
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("coerceIn(range: TRange)") {
|
||||
only(Primitives, Generic)
|
||||
only(*numericPrimitives)
|
||||
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.end if this value is greater than range.end.
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: ${'$'}range.")
|
||||
return if (this < range.start) range.start else if (this > range.end) range.end else this
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("coerceIn(minimumValue: SELF?, maximumValue: SELF?)") {
|
||||
only(Primitives, Generic)
|
||||
only(*numericPrimitives)
|
||||
returns("SELF")
|
||||
typeParam("T: Comparable<T>")
|
||||
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].
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
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
|
||||
"""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return templates
|
||||
}
|
||||
@@ -18,6 +18,8 @@ enum class Family {
|
||||
Strings
|
||||
RangesOfPrimitives
|
||||
ProgressionsOfPrimitives
|
||||
Primitives
|
||||
Generic
|
||||
}
|
||||
|
||||
enum class PrimitiveType(val name: String) {
|
||||
@@ -32,8 +34,11 @@ enum class PrimitiveType(val name: String) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class GenericFunction(val signature: String, val keyword: String = "fun") : Comparable<GenericFunction> {
|
||||
val defaultFamilies = array(Iterables, Sequences, ArraysOfObjects, ArraysOfPrimitives, Strings)
|
||||
val defaultPrimitives = PrimitiveType.values()
|
||||
val numericPrimitives = array(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Byte, PrimitiveType.Short, PrimitiveType.Double, PrimitiveType.Float)
|
||||
|
||||
var toNullableT: Boolean = false
|
||||
|
||||
@@ -42,7 +47,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
||||
val inlineFamilies = HashMap<Family, Boolean>()
|
||||
|
||||
val buildFamilies = HashSet(defaultFamilies.toList())
|
||||
private val buildPrimitives = HashSet(PrimitiveType.values().toList())
|
||||
private val buildPrimitives = HashSet(defaultPrimitives.toList())
|
||||
|
||||
var deprecate: String = ""
|
||||
val deprecates = hashMapOf<Family, String>()
|
||||
@@ -136,6 +141,11 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
||||
buildFamilies.addAll(families.toList())
|
||||
}
|
||||
|
||||
fun only(vararg primitives: PrimitiveType) {
|
||||
buildPrimitives.clear()
|
||||
buildPrimitives.addAll(primitives.toList())
|
||||
}
|
||||
|
||||
fun include(vararg families: Family) {
|
||||
buildFamilies.addAll(families.toList())
|
||||
}
|
||||
@@ -159,7 +169,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
||||
}
|
||||
|
||||
fun build(builder: StringBuilder, f: Family) {
|
||||
if (f == ArraysOfPrimitives || f == RangesOfPrimitives || f == ProgressionsOfPrimitives) {
|
||||
if (f == ArraysOfPrimitives || f == RangesOfPrimitives || f == ProgressionsOfPrimitives || f == Primitives) {
|
||||
for (primitive in buildPrimitives.sortBy { it.name() })
|
||||
build(builder, f, primitive)
|
||||
} else {
|
||||
@@ -202,6 +212,8 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
||||
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")
|
||||
Primitives -> primitive?.let { it.name } ?: throw IllegalArgumentException("Primitive should specify primitive type")
|
||||
Generic -> "T"
|
||||
else -> throw IllegalStateException("Invalid family")
|
||||
}
|
||||
|
||||
@@ -246,12 +258,24 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
||||
}
|
||||
"T" -> {
|
||||
when (f) {
|
||||
Generic -> "T"
|
||||
Strings -> "Char"
|
||||
Maps -> "Map.Entry<K, V>"
|
||||
else -> primitive?.name() ?: token
|
||||
}
|
||||
}
|
||||
"TProgression" -> primitive!!.name + "Progression"
|
||||
"TRange" -> {
|
||||
when (f) {
|
||||
Generic -> "Range<T>"
|
||||
else -> primitive!!.name + "Range"
|
||||
}
|
||||
}
|
||||
"TProgression" -> {
|
||||
when (f) {
|
||||
Generic -> "Progression<out T>"
|
||||
else -> primitive!!.name + "Progression"
|
||||
}
|
||||
}
|
||||
else -> token
|
||||
})
|
||||
}
|
||||
@@ -260,8 +284,16 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
||||
}
|
||||
|
||||
fun effectiveTypeParams(): List<String> {
|
||||
// TODO: Model for type parameter
|
||||
val types = ArrayList(typeParams)
|
||||
if (primitive == null && f != Strings) {
|
||||
if (f == Generic) {
|
||||
// ensure type parameter T, if it's not added to typeParams before
|
||||
if (!types.any { it == "T" || it.startsWith("T:")}) {
|
||||
types.add("T")
|
||||
}
|
||||
return types
|
||||
}
|
||||
else if (primitive == null && f != Strings) {
|
||||
val implicitTypeParameters = receiver.dropWhile { it != '<' }.drop(1).filterNot { it == ' ' }.takeWhile { it != '>' }.split(",")
|
||||
for (implicit in implicitTypeParameters.reverse()) {
|
||||
if (implicit != "*" && !types.any { it.startsWith(implicit) || it.startsWith("reified " + implicit) }) {
|
||||
|
||||
Reference in New Issue
Block a user