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

org.jglrxavpok.hephaistos.mca.LongCompactor.kt Maven / Gradle / Ivy

There is a newer version: 2.6.1
Show newest version
package org.jglrxavpok.hephaistos.mca

import org.jglrxavpok.hephaistos.collections.ImmutableLongArray
import kotlin.math.ceil
import kotlin.math.floor

/**
 * Compresses the given ints into a long array, at the given lengthInBits bitrate.
 *
 * lengthInBits must be at least 1
 */
fun compress(data: IntArray, lengthInBits: Int): ImmutableLongArray {
    val compacted = LongArray(ceil(data.size*lengthInBits/64.0).toInt())
    var bitIndex = 0
    val maxMask = (1L shl lengthInBits) -1

    for(i in data.indices) {
        val value = data[i] and 0b11111_1111

        val beginLongIndex = bitIndex / 64
        val endLongIndex = (bitIndex + lengthInBits-1) / 64

        if(beginLongIndex != endLongIndex) { // split over two longs
            val overshoot = (bitIndex+lengthInBits) % 64
            val highMask = (1 shl overshoot) -1
            val mask = ((1 shl lengthInBits-overshoot)-1).toLong()
            compacted[beginLongIndex] = compacted[beginLongIndex] and (maxMask shl bitIndex%64).inv() or (value.toLong() and mask shl (bitIndex%64))
            compacted[endLongIndex] = compacted[endLongIndex] or ((value.toLong() and maxMask shr (64-(bitIndex%64))) and highMask.toLong())
        } else {
            compacted[beginLongIndex] = compacted[beginLongIndex] and (maxMask shl bitIndex%64).inv() or (value.toLong() and maxMask shl (bitIndex%64))
        }
        bitIndex += lengthInBits
    }
    return ImmutableLongArray(*compacted)
}

/**
 * Decompresses compressed 'data' into a int array, with lengthInBits bits per int.
 */
fun decompress(data: ImmutableLongArray, lengthInBits: Int): IntArray {
    var bitIndex = 0
    val count = (data.size.toLong()*64 / lengthInBits).toInt()
    val result = IntArray(count)
    val maxMask = (1L shl lengthInBits) -1

    for(i in result.indices) {
        val beginLongIndex = bitIndex / 64
        val endLongIndex = (bitIndex + lengthInBits-1) / 64

        val value: Int = if(beginLongIndex != endLongIndex) { // split over two longs
            val overshoot = (bitIndex+lengthInBits) % 64
            val lowMask = (1L shl lengthInBits-overshoot) -1
            val highMask = (1L shl overshoot) -1
            val low = data[beginLongIndex] shr (bitIndex % 64) and lowMask
            val high = data[endLongIndex] and highMask
            (low or (high shl lengthInBits-overshoot)).toInt()
        } else {
            ((data[beginLongIndex] shr (bitIndex%64)) and maxMask).toInt()
        }

        result[bitIndex/lengthInBits] = value

        bitIndex += lengthInBits
    }
    return result
}

/**
 * Unpacks int values of 'lengthInBits' bits from a long array.
 * Contrary to decompress, this method will produce unused bits and do not overflow remaining bits to the next long.
 *
 * (ie 2 >32 bit long values will produce two longs, but the highest bits of each long will be unused)
 */
fun unpack(longs: ImmutableLongArray, lengthInBits: Int): IntArray {
    val intPerLong = floor(64.0 / lengthInBits)
    val intCount = ceil(longs.size * intPerLong).toInt()
    val ints = IntArray(intCount)
    val intPerLongCeil = ceil(intPerLong).toInt()
    val mask = (1 shl lengthInBits)-1L
    for(i in ints.indices) {
        val longIndex = i / intPerLongCeil
        val subIndex = i % intPerLongCeil
        val value = ((longs[longIndex] shr (subIndex*lengthInBits)) and mask).toInt()
        ints[i] = value
    }
    return ints
}

/**
 * Packs ints into a long array. Produces unused bits and does not partially overflow to next long on boundaries.
 */
fun pack(ints: IntArray, lengthInBits: Int): ImmutableLongArray {
    val intPerLong = floor(64.0 / lengthInBits).toInt()
    val longCount = ceil(ints.size / intPerLong.toDouble()).toInt()
    val longs = LongArray(longCount)
    val mask = (1 shl lengthInBits)-1L
    for(i in longs.indices) {
        var long = 0L
        for(intIndex in 0 until intPerLong) {
            val bitIndex = intIndex * lengthInBits
            val intActualIndex = intIndex+i*intPerLong
            if(intActualIndex < ints.size) {
                val value = (ints[intActualIndex].toLong() and mask) shl bitIndex
                long = long or (value)
            }
        }
        longs[i] = long
    }
    return ImmutableLongArray(*longs)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy