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

commonMain.BitSet.kt Maven / Gradle / Ivy

package com.juul.tuulbox.encoding

public interface BitSet {
    public operator fun get(index: Int): Boolean
    public operator fun set(index: Int, value: Boolean): BitSet
    public fun asPrimitive(): T

    /** Extracts [count] bits at [offset]. e.g. `0b00001100.extract(2, 2) = 0b11 = 0x03`. */
    public fun extract(offset: Int, count: Int): T
}

/** Extracts [range] bits. e.g. `0b00001100.extract(2..3) = 0b11 = 0x03`. */
public fun  BitSet.extract(range: IntRange): T =
    extract(range.first, range.last - range.first + 1)

// Would kill for C++ templates right about now. Which is not something I can normally say.

public val Int.bits: BitSet get() = IntBitSet(this)
public val Long.bits: BitSet get() = LongBitSet(this)

public data class IntBitSet(private var buffer: Int) : BitSet {
    override operator fun get(index: Int): Boolean {
        require(index in 0 until 32)
        val mask = 1 shl index
        return (buffer and mask) == mask
    }

    override operator fun set(index: Int, value: Boolean): IntBitSet = this.apply {
        require(index in 0 until 32)
        buffer = when (value) {
            true -> buffer or (1 shl index)
            false -> buffer and (1 shl index).inv()
        }
    }

    override fun asPrimitive(): Int = buffer

    override fun extract(offset: Int, count: Int): Int {
        require(offset in 0 until 32) { "Offset expected 0-31 but got $offset" }
        require(count in 0 until 32 - offset + 1) { "count expected 0-${32 - offset + 1} but got $count" }
        return (buffer ushr offset) and flatBitMask(count)
    }
}

public data class LongBitSet(private var buffer: Long) : BitSet {
    override operator fun get(index: Int): Boolean {
        require(index in 0 until 64)
        val mask = 1L shl index
        return (buffer and mask) == mask
    }

    override operator fun set(index: Int, value: Boolean): LongBitSet = this.apply {
        require(index in 0 until 64)
        buffer = when (value) {
            true -> buffer or (1L shl index)
            false -> buffer and (1L shl index).inv()
        }
    }

    override fun asPrimitive(): Long = buffer

    override fun extract(offset: Int, count: Int): Long {
        require(offset in 0 until 64) { "Offset expected 0-63 but got $offset" }
        require(count in 0 until 64 - offset + 1) { "count expected 0-${64 - offset + 1} but got $count" }
        return (buffer ushr offset) and flatLongBitMask(count)
    }
}

/** Create an [Int] mask of `count` length e.g. flatBitMask(3) = 0b00000111`. */
public fun flatBitMask(count: Int): Int {
    require(count in 0..32) { "count expected 0-32 but got $count" }
    return if (count == 32) -1 else (1 shl count) - 1
}

/** Create a [Long] mask of `count` length e.g. flatLongBitMask(3) = 0b00000111L`. */
public fun flatLongBitMask(count: Int): Long {
    require(count in 0..64) { "count expected 0-64 but got $count" }
    return if (count == 64) -1L else (1L shl count) - 1L
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy