Search code examples
javakotlinbit-manipulationbytebit

How to replace only 4 bits of 1 byte?


I know I can store and retrieve 2 numbers of 4 bits inside 1 Byte like this :

// Store both numbers in one byte
byte firstNumber = 10;
byte secondNumber = 15;
byte bothNumbers = (byte) ((firstNumber << 4) | secondNumber);

// Retreive the original numbers
firstNumber = (byte) ((bothNumbers >> 4) & (byte) 0x0F);
secondNumber = (byte) (bothNumbers & 0x0F);

But how can I overwrite one of the two numbers (let's say the first one (10)) without touching the last 4 bits (15)?

// Store both numbers in one byte
byte firstNumber = 10;
byte secondNumber = 15;
byte bothNumbers = (byte) ((firstNumber << 4) | secondNumber);

// Replacing one of the 2 numbers without touching the other
firstNumber = 13;
bothNumbers = ...

Solution

  • In Kotlin, you could create a value class to make it convenient to work with. It only compiles to a Byte, but you can conveniently treat it like a class instance/ boxable primitive.

    @JvmInline
    value class FourBitPair(val bothNumbers: Byte) {
        constructor(firstNumber: Byte, secondNumber: Byte):
                this((firstNumber.toInt() shl 4 or secondNumber.toInt()).toByte())
    
        val firstNumber: Byte get() = ((bothNumbers.toInt() shr 4) and 0xF).toByte()
        val secondNumber: Byte get() = (bothNumbers.toInt() and 0xF).toByte()
    
        operator fun component1() = firstNumber
        operator fun component2() = secondNumber
    
        fun withFirstNumber(newFirstNumber: Byte) = FourBitPair(newFirstNumber, secondNumber)
        fun withSecondNumber(newSecondNumber: Byte) = FourBitPair(firstNumber, newSecondNumber)
    
        override fun toString(): String = "[$firstNumber, $secondNumber]"
    }
    
    fun main() {
        val x: Byte = 3
        val y: Byte = 15
        var pair = FourBitPair(x, y)
        println(pair)
        pair = pair.withFirstNumber(13)
        println(pair)
        pair = pair.withSecondNumber(4)
        println(pair)
        val (first, second) = pair
        println(second)
        println(pair.bothNumbers)
    }
    

    Prints:

    [3, 15]
    [13, 15]
    [13, 4]
    4
    -44