Skip to content

Instantly share code, notes, and snippets.

@fabriciovergara
Forked from jimschubert/.gitignore
Last active August 24, 2021 07:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabriciovergara/4c61a516fdd91c5490de9ba52a2da9b6 to your computer and use it in GitHub Desktop.
Save fabriciovergara/4c61a516fdd91c5490de9ba52a2da9b6 to your computer and use it in GitHub Desktop.
BitMask for Enum in Kotlin 1.5+
package utils
import utils.BitMask.Companion.enabledEnumValues
import utils.BitMask.Companion.contains
import utils.BitMask.Companion.plus
import utils.BitMask.Companion.toBitMask
@JvmInline
value class BitMask(val value: Long) {
companion object {
fun ordinal(value: Int): BitMask {
return BitMask((1 shl value).toLong())
}
fun Long.toBitMask(): BitMask {
return BitMask(this)
}
infix fun BitMask.or(other: Flag): BitMask {
return BitMask(value or other.mask.value)
}
infix operator fun BitMask.plus(other: BitMask): BitMask {
return BitMask(value or other.value)
}
infix operator fun BitMask.plus(other: Flag): BitMask {
return BitMask(value or other.mask.value)
}
infix fun <T : Flag> BitMask.contains(flag: T): Boolean {
return contains(flag.mask)
}
infix fun BitMask.contains(mask: BitMask): Boolean {
// an Undefined flag is a special case.
if (value == 0L || (value > 0L && mask.value == 0L)) return false
return value and mask.value == mask.value
}
infix fun <T : Flag> BitMask.unset(which: T): BitMask {
return BitMask(value xor which.mask.value)
}
infix fun <T : Flag> Flag.or(other: T): BitMask {
return BitMask(mask.value or other.mask.value)
}
infix fun Flag.and(other: Long): BitMask {
return BitMask(mask.value and other)
}
infix operator fun Flag.plus(other: Flag): BitMask {
return BitMask(mask.value or other.mask.value)
}
inline fun <reified T> BitMask.enabledEnumValues(): List<T> where T : Enum<T>, T : Flag {
return enumValues<T>().filter { this contains it }
}
}
interface Flag {
val mask: BitMask
}
}
enum class FlagType(override val mask: BitMask) : BitMask.Flag {
A(BitMask.ordinal(0)),
B(BitMask.ordinal(1)),
C(BitMask(4)),
D(BitMask(8))
}
fun main(args: Array<String>) {
val mask: BitMask = FlagType.A + FlagType.B + FlagType.D
val enabled: List<FlagType> = mask.enabledEnumValues()
println("mask values: ${FlagType.values().map { it.mask.value }}")
// mask values: [1, 2, 4, 8]
println("flags enabled: $enabled")
// flags enabled: [A, B, D]
println("flags disabled: ${enumValues<FlagType>().filterNot { enabled.contains(it) }}")
// flags disabled: [C]
println("mask contains FlagType.A: ${mask contains FlagType.A}")
// mask contains FlagType.A: true
println("mask contains FlagType.C: ${mask contains FlagType.C}")
// mask contains FlagType.C: false
println("value 12 flag: ${12L.toBitMask().enabledEnumValues<FlagType>()}")
// value 12 flag: [C, D]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment