Safe size conversions for int types
This commit is contained in:
parent
4f63a229e1
commit
af6396fbcb
@ -0,0 +1,438 @@
|
||||
@file:JvmName("IntConversions_Size")
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package ru.landrafhomyak.kotlin.multiplatform_switches
|
||||
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/********************************** extend *****************************************/
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Short].
|
||||
*
|
||||
* The resulting [Short] value represents the same numerical value as this [Byte].
|
||||
*/
|
||||
public inline fun Byte.asShort(): Short = this.toShort()
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Int].
|
||||
*
|
||||
* The resulting [Int] value represents the same numerical value as this [Byte].
|
||||
*/
|
||||
public inline fun Byte.asInt(): Int = this.toInt()
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Long].
|
||||
*
|
||||
* The resulting [Long] value represents the same numerical value as this [Byte].
|
||||
*/
|
||||
public inline fun Byte.asLong(): Long = this.toLong()
|
||||
|
||||
/**
|
||||
* Converts this [UByte] value to [UShort].
|
||||
*
|
||||
* The resulting [UShort] value represents the same numerical value as this [UByte].
|
||||
*/
|
||||
public inline fun UByte.asUShort(): UShort = this.toUShort()
|
||||
|
||||
/**
|
||||
* Converts this [UByte] value to [UInt].
|
||||
*
|
||||
* The resulting [UInt] value represents the same numerical value as this [UByte].
|
||||
*/
|
||||
public inline fun UByte.asUInt(): UInt = this.toUInt()
|
||||
|
||||
/**
|
||||
* Converts this [UByte] value to [ULong].
|
||||
*
|
||||
* The resulting [ULong] value represents the same numerical value as this [UByte].
|
||||
*/
|
||||
public inline fun UByte.asULong(): ULong = this.toULong()
|
||||
|
||||
/**
|
||||
* Converts this [Short] value to [Int].
|
||||
*
|
||||
* The resulting [Int] value represents the same numerical value as this [Short].
|
||||
*/
|
||||
public inline fun Short.asInt(): Int = this.toInt()
|
||||
|
||||
/**
|
||||
* Converts this [Short] value to [Long].
|
||||
*
|
||||
* The resulting [Long] value represents the same numerical value as this [Short].
|
||||
*/
|
||||
public inline fun Short.asLong(): Long = this.toLong()
|
||||
|
||||
/**
|
||||
* Converts this [UShort] value to [UInt].
|
||||
*
|
||||
* The resulting [UInt] value represents the same numerical value as this [UShort].
|
||||
*/
|
||||
public inline fun UShort.asUInt(): UInt = this.toUInt()
|
||||
|
||||
/**
|
||||
* Converts this [UShort] value to [ULong].
|
||||
*
|
||||
* The resulting [ULong] value represents the same numerical value as this [UShort].
|
||||
*/
|
||||
public inline fun UShort.asULong(): ULong = this.toULong()
|
||||
|
||||
/**
|
||||
* Converts this [Int] value to [Long].
|
||||
*
|
||||
* The resulting [Long] value represents the same numerical value as this [Int].
|
||||
*/
|
||||
public inline fun Int.asLong(): Long = this.toLong()
|
||||
|
||||
/**
|
||||
* Converts this [UInt] value to [ULong].
|
||||
*
|
||||
* The resulting [ULong] value represents the same numerical value as this [UInt].
|
||||
*/
|
||||
public inline fun UInt.asULong(): ULong = this.toULong()
|
||||
|
||||
|
||||
/******************************** trims (or null) ****************************/
|
||||
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun Short.asByteOrNull(): Byte? = if (this in (Byte.MIN_VALUE.asShort())..(Byte.MAX_VALUE.asShort())) this.toByte() else null
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [UShort] value to [UByte].
|
||||
*
|
||||
* If this value is in 0..[UByte.MAX_VALUE], the resulting [UByte] value represents
|
||||
* the same numerical value as this [UShort].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun UShort.asUByteOrNull(): UByte? = if (this <= UByte.MAX_VALUE.asUShort()) this.toUByte() else null
|
||||
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun Int.asByteOrNull(): Byte? = if (this in (Byte.MIN_VALUE.asInt())..(Byte.MAX_VALUE.asInt())) this.toByte() else null
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun Int.asShortOrNull(): Short? = if (this in (Short.MIN_VALUE.asInt())..(Short.MAX_VALUE.asInt())) this.toShort() else null
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [UInt] value to [UByte].
|
||||
*
|
||||
* If this value is in [UByte.MIN_VALUE]..[UByte.MAX_VALUE], the resulting [UByte] value represents
|
||||
* the same numerical value as this [UInt].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun UInt.asUByteOrNull(): UByte? = if (this <= UByte.MAX_VALUE.asUInt()) this.toUByte() else null
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun UInt.asUShortOrNull(): UShort? = if (this <= UShort.MAX_VALUE.asUInt()) this.toUShort() else null
|
||||
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun Long.asByteOrNull(): Byte? = if (this in (Byte.MIN_VALUE.asLong())..(Byte.MAX_VALUE.asLong())) this.toByte() else null
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun Long.asShortOrNull(): Short? = if (this in (Short.MIN_VALUE.asLong())..(Short.MAX_VALUE.asLong())) this.toShort() else null
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [Long] value to [Int].
|
||||
*
|
||||
* If this value is in [Short.MIN_VALUE]..[Short.MAX_VALUE], the resulting [Int] value represents
|
||||
* the same numerical value as this [Long].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun Long.asIntOrNull(): Int? = if (this in (Int.MIN_VALUE.asLong())..(Int.MAX_VALUE.asLong())) this.toInt() else null
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [ULong] value to [UByte].
|
||||
*
|
||||
* If this value is in [UByte.MIN_VALUE]..[UByte.MAX_VALUE], the resulting [UByte] value represents
|
||||
* the same numerical value as this [ULong].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun ULong.asUByteOrNull(): UByte? = if (this in (UByte.MIN_VALUE.asULong())..(UByte.MAX_VALUE.asULong())) this.toUByte() else null
|
||||
|
||||
/**
|
||||
* Converts this [ULong] value to [UShort].
|
||||
*
|
||||
* If this value is in [UShort.MIN_VALUE]..[UShort.MAX_VALUE], the resulting [UShort] value represents
|
||||
* the same numerical value as this [ULong].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun ULong.asUShortOrNull(): UShort? = if (this in (UShort.MIN_VALUE.asULong())..(UShort.MAX_VALUE.asULong())) this.toUShort() else null
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [ULong] value to [UInt].
|
||||
*
|
||||
* If this value is in [UShort.MIN_VALUE]..[UShort.MAX_VALUE], the resulting [UInt] value represents
|
||||
* the same numerical value as this [ULong].
|
||||
* Otherwise `null` returned.
|
||||
*/
|
||||
public inline fun ULong.asUIntOrNull(): UInt? = if (this in (UInt.MIN_VALUE.asULong())..(UInt.MAX_VALUE.asULong())) this.toUInt() else null
|
||||
|
||||
|
||||
/********************************************* Conversion error formatters ****************************************/
|
||||
|
||||
@Suppress("FunctionName")
|
||||
private inline fun <reified W, reified N> _formatTrimOverflowS(value: W, min: N, max: N) =
|
||||
"Can't convert ${W::class.simpleName!!} value to ${N::class.simpleName!!} because $value !in ${min}..${max}"
|
||||
|
||||
@Suppress("FunctionName")
|
||||
private inline fun <reified W, reified N> _formatTrimOverflowU(value: W, max: N) =
|
||||
"Can't convert ${W::class.simpleName!!} value to ${N::class.simpleName!!} because $value > $max"
|
||||
|
||||
|
||||
public fun Short.formatAsByteError(): String = _formatTrimOverflowS<Short, Byte>(this, Byte.MIN_VALUE, Byte.MAX_VALUE)
|
||||
|
||||
public fun UShort.formatAsUByteError(): String = _formatTrimOverflowU<UShort, UByte>(this, UByte.MAX_VALUE)
|
||||
|
||||
public fun Int.formatAsByteError(): String = _formatTrimOverflowS<Int, Byte>(this, Byte.MIN_VALUE, Byte.MAX_VALUE)
|
||||
|
||||
public fun Int.formatAsShortError(): String = _formatTrimOverflowS<Int, Short>(this, Short.MIN_VALUE, Short.MAX_VALUE)
|
||||
|
||||
public fun UInt.formatAsUByteError(): String = _formatTrimOverflowU<UInt, UByte>(this, UByte.MAX_VALUE)
|
||||
|
||||
public fun UInt.formatAsUShortError(): String = _formatTrimOverflowU<UInt, UShort>(this, UShort.MAX_VALUE)
|
||||
|
||||
public fun Long.formatAsByteError(): String = _formatTrimOverflowS<Long, Byte>(this, Byte.MIN_VALUE, Byte.MAX_VALUE)
|
||||
|
||||
public fun Long.formatAsShortError(): String = _formatTrimOverflowS<Long, Short>(this, Short.MIN_VALUE, Short.MAX_VALUE)
|
||||
|
||||
public fun Long.formatAsIntError(): String = _formatTrimOverflowS<Long, Int>(this, Int.MIN_VALUE, Int.MAX_VALUE)
|
||||
|
||||
public fun ULong.formatAsUByteError(): String = _formatTrimOverflowU<ULong, UByte>(this, UByte.MAX_VALUE)
|
||||
|
||||
public fun ULong.formatAsUShortError(): String = _formatTrimOverflowU<ULong, UShort>(this, UShort.MAX_VALUE)
|
||||
|
||||
public fun ULong.formatAsUIntError(): String = _formatTrimOverflowU<ULong, UInt>(this, UInt.MAX_VALUE)
|
||||
|
||||
/******************************** trims (or exception) ****************************/
|
||||
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun Short.asByteOrThrow(exception: (Short) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsByteError()) }): Byte {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asByteOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this [UShort] value to [UByte].
|
||||
*
|
||||
* If this value is in 0..[UByte.MAX_VALUE], the resulting [UByte] value represents
|
||||
* the same numerical value as this [UShort].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun UShort.asByteOrThrow(exception: (UShort) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsUByteError()) }): UByte {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asUByteOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun Int.asByteOrThrow(exception: (Int) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsByteError()) }): Byte {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asByteOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun Int.asShortOrThrow(exception: (Int) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsShortError()) }): Short {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asShortOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this [UInt] value to [UByte].
|
||||
*
|
||||
* If this value is in 0..[UByte.MAX_VALUE], the resulting [UByte] value represents
|
||||
* the same numerical value as this [UInt].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun UInt.asUByteOrThrow(exception: (UInt) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsUByteError()) }): UByte {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asUByteOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [UInt] value to [UShort].
|
||||
*
|
||||
* If this value is in 0..[UShort.MAX_VALUE], the resulting [UShort] value represents
|
||||
* the same numerical value as this [UShort].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun UInt.asUShortOrThrow(exception: (UInt) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsUShortError()) }): UShort {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asUShortOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun Long.asByteOrThrow(exception: (Long) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsByteError()) }): Byte {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asByteOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun Long.asShortOrThrow(exception: (Long) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsShortError()) }): Short {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asShortOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun Long.asIntOrThrow(exception: (Long) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsIntError()) }): Int {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asIntOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this [ULong] value to [UByte].
|
||||
*
|
||||
* If this value is in 0..[UByte.MAX_VALUE], the resulting [UByte] value represents
|
||||
* the same numerical value as this [ULong].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun ULong.asUByteOrThrow(exception: (ULong) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsUByteError()) }): UByte {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asUByteOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [ULong] value to [UShort].
|
||||
*
|
||||
* If this value is in 0..[UShort.MAX_VALUE], the resulting [UShort] value represents
|
||||
* the same numerical value as this [ULong].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun ULong.asUShortOrThrow(exception: (ULong) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsUShortError()) }): UShort {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asUShortOrNull() ?: exception(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts this [ULong] value to [UInt].
|
||||
*
|
||||
* If this value is in 0..[UInt.MAX_VALUE], the resulting [UInt] value represents
|
||||
* the same numerical value as this [ULong].
|
||||
* Otherwise [exception] function called (by default throws [IllegalArgumentException]).
|
||||
*/
|
||||
public inline fun ULong.asUIntOrThrow(exception: (ULong) -> Nothing = { b -> throw IllegalArgumentException(b.formatAsUIntError()) }): UInt {
|
||||
contract {
|
||||
callsInPlace(exception, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
return this.asUIntOrNull() ?: exception(this)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user