-
-
Save fabriciovergara/4c61a516fdd91c5490de9ba52a2da9b6 to your computer and use it in GitHub Desktop.
BitMask for Enum in Kotlin 1.5+
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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