How to abstract a C bit fields with Odin's `bit_set`?

I am binding LMDB, and it makes extensive use of C bit sets as flags.
I would like to create a zero-cost abstraction with Odin’s bit_set.

For example lets take the following flags in (ported from header files):

Env_Flag :: enum c.uint {
	NOFLAGS      = 0,
	FIXEDMAP     = 0x01,
	NOSUBDIR     = 0x4000,
	RDONLY       = 0x20000,
	WRITEMAP     = 0x80000,
	NOMETASYNC   = 0x40000,
	NOSYNC       = 0x10000,
	MAPASYNC     = 0x100000,
	NOTLS        = 0x200000,
	NOLOCK       = 0x400000,
	NORDAHEAD    = 0x800000,
	NOMEMINIT    = 0x1000000,
	PREVSNAPSHOT = 0x2000000,
}

I know that by doing the following I loose the bites value, and I would then need to check each flag manually, but how can I avoid that?

Flags := bit_set[Env_flags]

Is there a way to “cast” the set into an uint without manually checking for the values?

1 Like

Do log2 of the value.

Env_Flags :: distinct bit_set[Env_Flag; c.uint]

Env_Flag :: enum c.uint {
	FIXEDMAP     = 0,
	NOSUBDIR     = 14,
	RDONLY       = 17,
	WRITEMAP     = 19,
	NOMETASYNC   = 18,
	NOSYNC       = 16,
	MAPASYNC     = 20,
	NOTLS        = 21,
	NOLOCK       = 22,
	NORDAHEAD    = 23,
	NOMEMINIT    = 24,
	PREVSNAPSHOT = 25,
}
4 Likes

You can make it “easier” by using the constant_log2 intrinsic like so:

import "base:intrinsics"

log2 :: intrinsics.constant_log2

Env_Flag :: enum c.uint {
    FIXEDMAP = log2(0x01),
    NOSUBDIR = log2(0x4000),
    // ...
}
2 Likes

Thank you guys, that is the solution I was looking for!

2 Likes