kevin.cianfarini
01/05/2023, 2:38 AMstatx
system call defines a bitmask for attributes of a file you'd like to get. I've come up with the following abstraction around this but am not pleased with it because it requires an additional allocation.
public value class FileStatusRequest internal constructor(internal val bitMask: UInt)
@FileRequestDsl public class FileStatusRequestBuilder internal constructor() {
private var bitMask: UInt = 0u
public fun requestFileSize() { bitMask = bitMask or STATX_SIZE }
public fun requestBlocksOccupied() { bitMask = bitMask or STATX_BLOCKS }
public fun build(): FileStatusRequest = FileStatusRequest(bitMask)
}
Swift has the OptionSet
protocol which could abstract bitmask operations quite nicely. A Kotlin equivalent might look like the following.
value class FileStatusRequest(internal var bitMask: UInt) : OptionSet<FileStatusTrait> {
override fun insert(trait: FileStatusTrait) { bitMask = bitMask or trait.statxMask }
override fun remove(trait: FileStatusTrait) { bitMask = bitMask and trait.statxMask.inv() }
}
enum class FileStatusTrait(internal val statxMask: UInt) { ... }
Has the stdlib team considered something like OptionSet
as a means of wrangling (mainly) bitmasks?kevin.cianfarini
01/05/2023, 2:39 AMvar
in a value class to present any benefit.ephemient
01/05/2023, 2:57 AM@JvmInline
value class StatxMask(val mask: Int) {
operator fun plus(other: StatxMask): StatxMask =
StatxMask(this.mask or other.mask)
operator fun minus(other: StatxMask): StatxMask =
StatxMask(this.mask and other.mask.inv())
}
val STATX_TYPE = StatxMask(platform.posix.STATX_TYPE)
// etc.
I don't see what you gain from a builderkevin.cianfarini
01/05/2023, 2:58 AMephemient
01/05/2023, 2:59 AMephemient
01/05/2023, 3:00 AMvalue class(var)
isn't going to happen. copy var
might, but isn't implemented. https://github.com/Kotlin/KEEP/blob/master/notes/value-classes.md#copyable-properties-of-immutable-typesCLOVIS
01/05/2023, 8:48 AMEnumSet
: it's a bit mask implementation based on an enum, which is very idiomatic in KotlinRob Elliot
01/05/2023, 9:58 AMEnumSet
to Kotlin - there's nothing native in it I can see.CLOVIS
01/05/2023, 9:59 AMkevin.cianfarini
01/05/2023, 1:19 PMkevin.cianfarini
01/05/2023, 1:25 PMRob Elliot
01/05/2023, 1:52 PMEnumSet
- I was thinking it would be a template for writing something similar in Kotlin, rather than something you could use out of the box, in which case of course it would be easy to expose the bitmask.kevin.cianfarini
01/05/2023, 1:53 PMCLOVIS
01/05/2023, 2:42 PMCLOVIS
01/05/2023, 2:43 PMRob Elliot
01/05/2023, 2:43 PMCLOVIS
01/05/2023, 2:44 PMkevin.cianfarini
01/05/2023, 4:22 PMkevin.cianfarini
01/05/2023, 4:23 PMCLOVIS
01/05/2023, 4:24 PMSet.plus
to return an EnumSet
, and you can do EnumSet<YourEnum>() + Field1 + Field2
with no allocations if EnumSet
is a value classkevin.cianfarini
01/05/2023, 4:33 PMsealed value class FileStatusRequest(internal val statxMask: UInt) : Set<FileStatusRequest> {
object FileSize : FileStatusRequest(STATX_SIZE)
object BlockCount : FileStatusRequest(STATX_BLOCKS)
value class Composite(mask: UInt) : FileStatusRequest(mask)
override operator fun plus(other: FileStatusRequest) = Composite(statxMask or other.statxMask)
override operator fun minus(other: FileStatusRequest) = Composite(statxMask and other.statxMask.inv())
// etc.
}
kevin.cianfarini
01/05/2023, 4:33 PMCLOVIS
01/05/2023, 4:36 PM@JvmInline value class Bitmask<T : Enum<T>>(val mask: UInt): Set<T> {
override operator fun plus(other: T) = Bitmask(mask or other.ordinal.toUInt())
// …
companion object {
fun noneOf<T: Enum<T>>() = Bitmask<T>(0u)
}
}
enum class FileStatus {
FileSize,
BlockCount,
}
// Usage:
val mask = noneOf<FileStatus>() + FileStatus.FileSize
CLOVIS
01/05/2023, 4:37 PMkevin.cianfarini
01/05/2023, 4:37 PMkevin.cianfarini
01/05/2023, 4:37 PMkevin.cianfarini
01/05/2023, 4:37 PMCLOVIS
01/05/2023, 4:37 PMEnum.ordinal
, but you get the point 🙂kevin.cianfarini
01/05/2023, 4:37 PMCLOVIS
01/05/2023, 4:37 PMCLOVIS
01/05/2023, 4:38 PMkevin.cianfarini
01/05/2023, 9:35 PMinterface OptionSet<Option> {
operator fun plus(other: Option): OptionSet<Option>
operator fun minus(other: Option): OptionSet<Option>
operator fun contains(element: Option): Boolean
}
value class FileStatusRequest private constructor(
internal val mask: UInt
) : OptionSet<FileStatusRequest> {
override fun plus(other: FileStatusRequest): FileStatusRequest = FileStatusRequest(
mask or other.mask
)
override fun minus(other: FileStatusRequest): FileStatusRequest = FileStatusRequest(
mask and other.mask.inv()
)
override fun contains(element: FileStatusRequest): Boolean {
return mask and element.mask == element.mask
}
companion object {
val Empty = FileStatusRequest(0u)
val First = FileStatusRequest(1u)
val Second = FileStatusRequest(2u)
}
}
FileStatusRequest.Empty + FileStatusRequest.First + FileStatusRequest.Second // mask: 3u
kevin.cianfarini
01/05/2023, 9:35 PMephemient
01/05/2023, 9:36 PMkevin.cianfarini
01/05/2023, 9:36 PMkevin.cianfarini
01/05/2023, 9:36 PMephemient
01/05/2023, 9:38 PM