Bitfield accessors
Jarrett Billingsley
kb3ctd2 at yahoo.com
Mon Nov 19 06:09:57 PST 2007
"bearophile" <bearophileHUGS at lycos.com> wrote in message
news:fhrpoi$1i2a$1 at digitalmars.com...
> Until D gains C-style bitfields it can be created a compile-time function
> that returns the pairs of methods that take/return
> ubyte/ushort/uint/ulong, to be used by a mixin. Something like:
>
> union TyIntFloat {
> int i; // as integer
> float f; // as float
> // as bit fields:
> mixin(Bitfields!("i
> sign 1
> biasedexponent 8
> significand 23"));
> }
>
> Here "i" is the name of the unsigned integral variable to be splitted in
> bit fields.
> std.string.split works at compile time too, it can be used to split the
> input string.
> Something like that can be useful in Tango too (if not already present),
> but I presume it's difficult to make it optimize the code produced.
>
> That
> Bitfields!("i sign 1 biasedexponent 8 significand 23")
> is supposed to return a string of code that contains six methods like:
> "
> uint sign() { return i & ...; }
> void sign(uint x) { i = ...; }
> uint biasedexponent() { return ...; }
> void biasedexponent(uint x) { i = ...; }
> uint significand() { return ...; }
> void significand(uint x) { i = ...; }
> "
>
> The sum of the numbers is cheeked to be 8, 16, 32 or 64. According to such
> total that "i" variable and the input/output values have type as ubyte,
> ushort, uint or ulong.
>
> Bye and thank you,
> bearophile
I actually came up with this for a D OS kernel my friends and I are working
on. It looks like this:
struct SomeStruct
{
uint flags;
mixin(Bitfield!(flags, "sign", 1, "biasedExponent", 8, "significand",
23));
}
The implementation:
template Bitfield(alias data, Args...)
{
static assert(!(Args.length & 1), "Bitfield arguments must be an even
number");
const char[] Bitfield = BitfieldShim!((typeof(data)).stringof, data,
Args).Ret;
}
// Odd bug in D templates -- putting "data.stringof" as a template argument
gives it the
// string of the type, rather than the string of the symbol. This shim
works around that.
template BitfieldShim(char[] typeStr, alias data, Args...)
{
const char[] Name = data.stringof;
const char[] Ret = BitfieldImpl!(typeStr, Name, 0, Args).Ret;
}
template BitfieldImpl(char[] typeStr, char[] nameStr, int offset, Args...)
{
static if(Args.length == 0)
const char[] Ret = "";
else
{
const char[] Name = Args[0];
const int Size = Args[1];
const int Mask = Bitmask!(Size);
const char[] Getter = "public " ~ typeStr ~ " " ~ Name ~ "() {
return ( " ~
nameStr ~ " >> " ~ Itoh!(offset) ~ " ) & " ~ Itoh!(Mask) ~
"; }";
const char[] Setter = "public void " ~ Name ~ "(" ~ typeStr ~ " val)
{ " ~
nameStr ~ " = (" ~ nameStr ~ " & " ~ Itoh!(~(Mask << offset)) ~
") | ((val & " ~
Itoh!(Mask) ~ ") << " ~ Itoh!(offset) ~ "); }";
const char[] Ret = Getter ~ Setter ~ BitfieldImpl!(typeStr, nameStr,
offset + Size, Args[2 .. $]).Ret;
}
}
template Itoa(int i)
{
static if(i < 0)
const char[] Itoa = "-" ~ IntToStr!(-i, 10);
else
const char[] Itoa = IntToStr!(i, 10);
}
template Itoh(int i)
{
const char[] Itoh = "0x" ~ IntToStr!(i, 16);
}
template Digits(int i)
{
const char[] Digits = "0123456789abcdefghijklmnopqrstuvwxyz"[0 .. i];
}
template IntToStr(ulong i, int base)
{
static if(i >= base)
const char[] IntToStr = IntToStr!(i / base, base) ~ Digits!(base)[i
% base];
else
const char[] IntToStr = "" ~ Digits!(base)[i % base];
}
template Bitmask(int size)
{
const int Bitmask = (1 << size) - 1;
}
More information about the Digitalmars-d-learn
mailing list