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