How would y'all represent bit fields? Aka convert ...
# getting-started
r
How would y'all represent bit fields? Aka convert them to the
Byte
to send them to the wire and back, and preferably a reasonable API along the way.
j
On the API side, probably a set of enum values, which you then convert to/from a byte when exchanging on the wire.
EnumSet
implementation actually does use a bit mask internally IIRC.
k
It does, for Enums that have 64 or fewer values.
r
No easy way to push it into a
Byte
though 😞
j
If you associate each value to a bit mask, it's actually not too hard. You can OR all values' masks from the set to create the Byte when sending, and you can AND all values from the enum to find the ones present in a given Byte that you received
r
How would I grab the position of an element of the
Enum
?
j
Well technically even without storing it, there is an
ordinal()
method generated for every enum class that gives the index of the current enum value within the declaration list. But you probably wouldn't use that, and be more explicit instead by declaring a mask like so:
Copy code
import java.util.EnumSet
import kotlin.experimental.*

enum class OpParameter(bitPosition: Int) {
    ISO_TYPE_A(0),
    ISO_TYPE_B(1),
    FELICA_212(2),
    FELICA_424(3),
    TOPAZ(4),
    CALYPSO(5),
    SRIX(6),
    RFU(7);

    val mask: Byte = (1 shl bitPosition).toByte()
    
    companion object {
        private val values = values()
        
        fun bitMaskToSet(bitMask: Byte) = values.filterTo(EnumSet.noneOf(OpParameter::class.java)) {
            bitMask and it.mask > 0
        }
    }
}

fun Set<OpParameter>.toBitMask(): Byte = fold(0.toByte()) { result, op -> result or op.mask }
See https://pl.kotl.in/7tF9cTjj-
r
Yeah, gotta go explicit, there's a few more positions
Copy code
interface Positional {
    abstract val position: Byte
    fun toByte(): Byte =  (1 shl position.toInt()).toByte()
}

enum class PICCOperating(override val position: Byte): Positional {
    ISO14443TypeA(0),
    ISO14443TypeB(1),
    FeliCa212Kbps(2),
    FeliCa424Kbps(3),
    Topaz(4),
    Calypso(5),
    SRIX(6),
}

fun <A> EnumSet<A>.toBitMask(): Byte where A: Enum<A>, A: Positional {
    return fold(0x00.toByte()) { b, e ->
        b or e.toByte()
    }
}
The names are a bit weird, I just copypastad them from the reference manual, easier to recognize that way 😄
thanks for the help!
👍 1
Now I wonder if I can do the other way round except with a ton of
if
statement 🤔
j
I have done that in my example, check the companion. I think you may have missed my initial edit, actually, but interestingly you came up with almost the same code
k
The 50-year-old C language has bit fields, like normal Int fields but occupying only a specified number of bits (e.g. 1 bit). Move forward 50 years and we have... not.
r
Not like you need it every day
Ah yeah, gotta go to sleep, thanks for the hint on the companion object 👨‍🦯
e
C has bit fields but does not define their layout, so it's not useful for interacting with external data - which is presumably this case
I don't know of many languages that do that in core, aside from Erlang. it turns out that outside of specific fields, it's just not something used very commonly. it's fine for these things to live in non-core libraries instead
r
This works:
Copy code
fun bitMaskToSet(bitMask: Byte): EnumSet<AutomaticPPICPolling> =
            values.filterTo(EnumSet.noneOf(AutomaticPPICPolling::class.java)) {
                val toBitMask = it.toBitMask()
                bitMask and toBitMask != 0.toByte()
            }
The
> 0
version behaves incorrectly with
0b10000000
- possibly because of a funny overflow?
e
0b10000000 == Byte.MIN_VALUE
is negative