Skip to content

Instantly share code, notes, and snippets.

@TheNullicorn
Last active March 5, 2022 22:49
Show Gist options
  • Select an option

  • Save TheNullicorn/41f9a56ad084ee8aac8f2138507b162b to your computer and use it in GitHub Desktop.

Select an option

Save TheNullicorn/41f9a56ad084ee8aac8f2138507b162b to your computer and use it in GitHub Desktop.
Kotlin utility for reversing the order of bits in an Int
/**
* Returns a Byte identical to the current one, but with the positions of the least-significant `n`
* bits reversed, where `n` = [width].
*
* This means that the bit at position `0` will be replaced with the value of the bit at position
* `width - 1`, and vice-versa.
*
* **Not to be confused with the [invert][Int.inv] function, which toggles all bits in place.**
*
* #### Examples:
* ```text
* 11100101.reversed(width = 4)
* 11101010
* └──┘
*
* =======================================================================
*
* 11100101.reversed() // width = 8 by default
* 10100111
* └──────┘
* ```
*
* @throws[IllegalArgumentException] if [width] exceeds [Byte.SIZE_BITS].
*/
internal fun Byte.reversed(width: Int = Byte.SIZE_BITS): Byte {
require(width <= Byte.SIZE_BITS) { "width cannot exceed ${Byte.SIZE_BITS}: $width" }
return toInt().reversed(width).toByte()
}
/**
* Returns a Short identical to the current one, but with the positions of the least-significant `n`
* bits reversed, where `n` = [width].
*
* This means that the bit at position `0` will be replaced with the value of the bit at position
* `width - 1`, and vice-versa.
*
* **Not to be confused with the [invert][Int.inv] function, which toggles all bits in place.**
*
* #### Examples:
* ```text
* 00011101_11000110.reversed(width = 8)
* 00011101_01100011
* └──────┘
*
* =======================================================================
*
* 00011101_11000110.reversed() // width = 16 by default
* 01100011_10111000
* └───────────────┘
* ```
*
* @throws[IllegalArgumentException] if [width] exceeds [Short.SIZE_BITS].
*/
internal fun Short.reversed(width: Int = Short.SIZE_BITS): Short {
require(width <= Short.SIZE_BITS) { "width cannot exceed ${Short.SIZE_BITS}: $width" }
return toInt().reversed(width).toShort()
}
/**
* Returns an Int identical to the current one, but with the positions of the least-significant `n`
* bits reversed, where `n` = [width].
*
* This means that the bit at position `0` will be replaced with the value of the bit at position
* `width - 1`, and vice-versa.
*
* **Not to be confused with the [invert][Int.inv] function, which toggles all bits in place.**
*
* #### Examples:
* ```text
* 11100001_00010000_00011101_11000110.reversed(width = 8)
* 11100001_00010000_00011101_01100011
* └──────┘
*
* =======================================================================
*
* 11100001_00010000_00011101_11000110.reversed() // width = 32 by default
* 01100011_10111000_00001000_10000111
* └─────────────────────────────────┘
* ```
*
* @throws[IllegalArgumentException] if [width] exceeds [Int.SIZE_BITS].
*/
internal fun Int.reversed(width: Int = Int.SIZE_BITS): Int {
require(width <= Int.SIZE_BITS) { "width cannot exceed ${Int.SIZE_BITS}: $width" }
var reverse = this
for (i in 0 until width) {
// The value of the non-reflected bit.
val sourceBit = this shr i and 1
// A mask with only the bit in the reflected position set.
val targetBit = 1 shl (width - i - 1)
// Set or clear the target bit depending on the source bit's current state.
reverse = if (sourceBit != 0)
reverse or targetBit
else
reverse and targetBit.inv()
}
return reverse
}
/**
* Returns a Long identical to the current one, but with the positions of the least-significant `n`
* bits reversed, where `n` = [width].
*
* This means that the bit at position `0` will be replaced with the value of the bit at position
* `width - 1`, and vice-versa.
*
* **Not to be confused with the [invert][Long.inv] function, which toggles all bits in place.**
*
* #### Examples:
* ```text
* 00110111_00011101_10100000_00010100_01110011_01100000_00101101_01010001.reversed(width = 16)
* 00110111_00011101_10100000_00010100_01110011_01100000_10001010_10110100
* └───────────────┘
*
* =======================================================================
*
* 00110111_00011101_10100000_00010100_01110011_01100000_00101101_01010001.reversed() // width = 64 by default
* 10001010_10110100_00000110_11001110_00101000_00000101_10111000_11101100
* └─────────────────────────────────────────────────────────────────────┘
* ```
*
* @throws[IllegalArgumentException] if [width] exceeds [Long.SIZE_BITS].
*/
internal fun Long.reversed(width: Int = Long.SIZE_BITS): Long {
require(width <= Long.SIZE_BITS) { "width cannot exceed ${Long.SIZE_BITS}: $width" }
var reverse = this
for (i in 0 until width) {
// The value of the non-reflected bit.
val sourceBit = this shr i and 1
// A mask with only the bit in the reflected position set.
val targetBit = 1L shl (width - i - 1)
// Set or clear the target bit depending on the source bit's current state.
reverse = if (sourceBit != 0L)
reverse or targetBit
else
reverse and targetBit.inv()
}
return reverse
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment