All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.korlibs.number.Int53.kt Maven / Gradle / Ivy

The newest version!
package korlibs.number

import korlibs.number.internal.*
import kotlin.contracts.*
import kotlin.math.*

inline class Int53Array(val raw: DoubleArray) : Iterable {
    inline val indices: IntRange get() = raw.indices

    constructor(size: Int, value: Int53 = Int53.ZERO) : this(DoubleArray(size) { value.value })
    companion object {
        inline operator fun invoke(size: Int, gen: (Int) -> Int53): Int53Array = Int53Array(DoubleArray(size) { gen(it).value })
    }

    inline val size: Int get() = raw.size
    inline operator fun get(index: Int): Int53 = Int53(raw[index])
    inline operator fun set(index: Int, value: Int53) { raw[index] = value.value }
    override fun iterator(): Iterator = object : Iterator {
        var index = 0
        override fun hasNext(): Boolean = index < raw.size
        override fun next(): Int53 = this@Int53Array[index].also { index++ }
    }

    override fun toString(): String = "IntArray64($size)"
}

inline fun  int53ArrayOf(vararg values: T): Int53Array = Int53Array(values.size) { values[it] }
inline fun int53ArrayOf(vararg values: Int): Int53Array = Int53Array(values.size) { values[it].toInt53() }
inline fun int53ArrayOf(vararg values: Long): Int53Array = Int53Array(values.size) { values[it].toInt53() }

fun Int53Array.copyOf(newSize: Int = this.size): Int53Array = Int53Array(raw.copyOf(newSize))
fun Int53Array.copyOfRange(fromIndex: Int, toIndex: Int): Int53Array = Int53Array(raw.copyOfRange(fromIndex, toIndex))
public fun Int53Array.getOrNull(index: Int): Int53? = if (index in indices) get(index) else null
//@kotlin.internal.InlineOnly
@OptIn(ExperimentalContracts::class)
public inline fun Int53Array.getOrElse(index: Int, defaultValue: (Int) -> Int53): Int53 {
    contract { callsInPlace(defaultValue, InvocationKind.AT_MOST_ONCE) }
    return if (index in indices) get(index) else defaultValue(index)
}

infix fun Int53Array?.contentEquals(other: Int53Array?): Boolean = this?.raw.contentEquals(other?.raw)
fun Int53Array?.contentHashCode(): Int = this?.raw.contentHashCode()
fun Int53Array?.contentToString(): String = if (this == null) "null" else "[" + this.raw.joinToString(", ") { it.toString() } + "]"

/**
 * Represents and integral value of 52-bits + sign using a Double as internal representation.
 * Trying to avoid allocations on the JS target by not using [Long] when 53 bits is enough.
 */
//@Deprecated("")
public inline class Int53(public val value: Double) : Comparable {
    public companion object {
        // Double.fromBits(0x000FFFFFFFFFFFFFL)
        //val MAX_VALUE = Int53(Double.fromBits(0x000FFFFFFFFFFFFFL)) // 2**52 - 1
        public val ZERO: Int53 = Int53(0.0)
        public val MAX_VALUE: Int53 = Int53(4503599627370495.0) // 2**52 - 1
        public val MIN_VALUE: Int53 = Int53(-4503599627370495.0) // -(2**52 - 1)
        private val MAX_UINT32 = 4294967295.0
        public fun fromDoubleClamped(value: Double): Int53 = when {
            value > MAX_VALUE.value -> MAX_VALUE
            value < MIN_VALUE.value -> MIN_VALUE
            else -> Int53(if (value < 0.0) ceil(value) else floor(value))
        }
        // @TODO: Do not use Long to do this
        public fun fromLowHigh(low: Int, high: Int): Int53 {
            return Int53(low.toUInt().toDouble() + (high.toUInt().toDouble() * pot(32)))

            //return (low.toLong() or ((high and 0x1FFFFF).signExtend(21).toLong() shl 32)).toInt53()

            //if ((high and 0x80000) != 0) {
            //    // Negative
            //    val uhigh = ((high).inv() and 0xFFFFF).toDouble()
            //    val ulow = low.inv().toUInt().toDouble()
            //    val svalue = -(ulow + (uhigh * 4294967296)) - 1
            //    return fromDoubleClamped(svalue)
            //} else {
            //    return fromDoubleClamped(low.toUInt().toDouble() + ((high and 0xFFFFF) * 4294967296))
            //}
        }

        @PublishedApi internal val POWS = DoubleArray(64) { 2.0.pow(it) }

        inline fun pot(index: Int): Double = POWS[index and 0x3F]
        //inline fun pot(index: Int): Double = 2.0.pow(index)
    }

    // @TODO: Do not use Long to do this
    //val high: Int get() = ((double.toRawBits() ushr 32) and 20.mask().toLong()).toInt()
    public val high: Int get() = ((long ushr 32) and 21.mask().toLong()).toInt()
    public val low: Int get() {
        return long.toInt()
        //return floor(value.absoluteValue % pot(32)).toInt()
        //var v = this
        //val llow = (v % 0x10000).toInt()
        //v /= 0x10000
        //val lhigh = (v % 0x10000).toInt()
        //return llow or (lhigh shl 16)
    }

    public operator fun unaryMinus(): Int53 = Int53(-value)
    public operator fun unaryPlus(): Int53 = Int53(+value)

    // @TODO: handle overflows
    public operator fun plus(other: Double): Int53 = fromDoubleClamped(this.value + other)
    public operator fun plus(other: Int): Int53 = this + other.toDouble()
    public operator fun plus(other: Int53): Int53 = this + other.toDouble()
    public operator fun plus(other: Float): Int53 = this + other.toDouble()

    public operator fun minus(other: Double): Int53 = fromDoubleClamped(this.value - other)
    public operator fun minus(other: Int): Int53 = this - other.toDouble()
    public operator fun minus(other: Int53): Int53 = this - other.toDouble()
    public operator fun minus(other: Float): Int53 = this - other.toDouble()

    public operator fun times(other: Double): Int53 = fromDoubleClamped(this.value * other)
    public operator fun times(other: Int): Int53 = this * other.toDouble()
    public operator fun times(other: Int53): Int53 = this * other.toDouble()
    public operator fun times(other: Float): Int53 = this * other.toDouble()

    public operator fun div(other: Double): Int53 = fromDoubleClamped(this.value / other)
    public operator fun div(other: Int): Int53 = this / other.toDouble()
    public operator fun div(other: Int53): Int53 = this / other.toDouble()
    public operator fun div(other: Float): Int53 = this / other.toDouble()

    public operator fun rem(other: Double): Int53 = fromDoubleClamped(this.value % other.toDouble())
    public operator fun rem(other: Int): Int53 = this % other.toDouble()
    public operator fun rem(other: Int53): Int53 = this % other.toDouble()
    public operator fun rem(other: Float): Int53 = this % other.toDouble()

    public infix fun and(other: Int53): Int53 = Int53.fromLowHigh(this.low and other.low, this.high and other.high)
    public infix fun or(other: Int53): Int53 = Int53.fromLowHigh(this.low or other.low, this.high or other.high)
    public infix fun xor(other: Int53): Int53 = Int53.fromLowHigh(this.low xor other.low, this.high xor other.high)
    public fun inv(): Int53 = Int53.fromLowHigh(this.low.inv(), this.high.inv())
    public infix fun shl(shift: Int): Int53 = floor(value * pot(shift)).toInt53()
    public infix fun ushr(shift: Int): Int53 = floor(value / pot(shift)).toInt53()

    public fun insert(value: Int, offset: Int, count: Int): Int53 {
        //val mask = count.mask().toInt53() shl offset
        //val ovalue = (value.toInt53() shl offset) and mask
        //return (this and mask.inv()) or ovalue
        return clear(offset, count).insertNoClear(value, offset, count)
    }

    public fun insert(value: Boolean, offset: Int): Int53 = insert(if (value) 1 else 0, offset, 1)

    //return this and (count.mask().toInt53() shl offset).inv()
    public fun clear(offset: Int, count: Int): Int53 {
        val offsetMul = pot(offset)
        return this - ((floor(value / offsetMul) % pot(count)) * offsetMul)
    }

    public fun insertNoClear(value: Int, offset: Int, count: Int): Int53 = Int53(this.value + ((value and count.mask()).toDouble() * pot(offset)))
    public fun insertNoClear(value: Boolean, offset: Int): Int53 = insertNoClear(if (value) 1 else 0, offset, 1)
    //return (value.toLong() ushr offset).toInt() and bits.mask()
    fun extract(offset: Int, bits: Int): Int = (floor(value / pot(offset)) % pot(bits)).toInt()
    //fun extract(offset: Int, bits: Int): Int = (value.toLong() ushr offset).toInt() and bits.mask()
    fun extract(offset: Int): Boolean = extract(offset, 1) != 0
    fun extractSigned(offset: Int, bits: Int): Int {
        val shift = (32 - bits)
        return (extract(offset, bits) shl shift) shr shift
    }

    public val int: Int get() = value.toInt()
    public val long: Long get() = value.toLong()
    public val double: Double get() = value

    public fun toInt(): Int = int
    public fun toLong(): Long = long
    public fun toDouble(): Double = double

    public fun compareTo(other: Double): Int = this.value.compareTo(other)
    public fun compareTo(other: Int): Int = this.compareTo(other.toDouble())
    override fun compareTo(other: Int53): Int = this.compareTo(other.toDouble())
    public fun compareTo(other: Float): Int = this.compareTo(other.toDouble())

    // @TODO: We are casting to Long that might allocate on JS
    override fun toString(): String = value.toLong().toString().removeSuffix(".0")
}

public inline fun String.toInt53(): Int53 = this.toDouble().toInt53()
public inline fun String.toInt53OrNull(): Int53? = this.toDoubleOrNull()?.toInt53()
public inline fun Int.toInt53(): Int53 = Int53.fromDoubleClamped(this.toDouble())
public inline fun Double.toInt53(): Int53 = Int53.fromDoubleClamped(this)
public inline fun Long.toInt53(): Int53 = Int53.fromDoubleClamped(this.toDouble())
public inline fun Number.toInt53(): Int53 = Int53.fromDoubleClamped(this.toDouble())




© 2015 - 2024 Weber Informatics LLC | Privacy Policy