Bitfield accessors
bearophile
bearophileHUGS at lycos.com
Tue Nov 27 06:10:37 PST 2007
For reference, this is my last version so far, I think this solves both a bug, and makes it faster at runtime, but it needs much more testing:
// By Jarrett Billingsley <kb3ctd2 at yahoo.com>
// Improved by leonardo maffi, V1.1, Nov 26 2007
// This code needs much more testing
template Bitfield(alias data, Args...) {
static assert(!(Args.length & 1), "Bitfield arguments must be an even number");
static assert(data.sizeof*8 >= _SumLens!(Args),
"The sum of bit fields is bigger than data.sizeof*8");
const char[] Bitfield = _BitfieldShim!((typeof(data)).stringof, data, Args).Ret;
}
private template _SumLens(Args...) {
static if(Args.length == 0)
const uint _SumLens = 0;
else {
static assert(Args[1] > 0, "Bitfield '" ~ Args[0] ~ "' is <= 0");
const uint _SumLens = Args[1] + _SumLens!(Args[2 .. $]);
}
}
// 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.
private template _BitfieldShim(char[] typeStr, alias data, Args...) {
const char[] Name = data.stringof;
const char[] Ret = _BitfieldImpl!(data, typeStr, Name, 0, Args).Ret;
}
private template _BitfieldImpl(alias data, 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];
static if (data.sizeof < 8) {
const int Mask = _bitmask32(Size);
const char[] Shift1 = "0x" ~ _intToStr32(~(Mask << offset), 16);
} else {
const long Mask = _bitmask64(Size);
const char[] Shift1 = "0x" ~ _intToStr64(~(Mask << offset), 16);
}
const char[] Getter = "public " ~ typeStr ~ " " ~ Name ~ "() { return (" ~
nameStr ~ " >> " ~ _itoh(offset) ~ ") & " ~ _itoh(Mask) ~ "; }\n";
const char[] Setter = "public void " ~ Name ~ "(" ~ typeStr ~ " val) { " ~
nameStr ~ " = (" ~ nameStr ~ " & " ~ Shift1 ~
") | ((val & " ~ _itoh(Mask) ~ ") << " ~ _itoh(offset) ~ "); }\n\n";
const char[] Ret = Getter ~ Setter ~
_BitfieldImpl!(data, typeStr, nameStr, offset + Size, Args[2 .. $]).Ret;
}
}
private int _bitmask32(int size) {
return (1 << size) - 1;
}
private long _bitmask64(long size) {
return (1L << size) - 1;
}
private char[] _itoa(long i) {
if (i < 0)
return "-" ~ _intToStr64(-i, 10);
else
return _intToStr64(i, 10);
}
private char[] _itoh(long i) {
return "0x" ~ _intToStr64(i, 16);
}
private char[] _intToStr32(uint i, int base) {
const CONV_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz";
if (i >= base)
return _intToStr32(i / base, base) ~ CONV_CHARS[i % base];
else
return "" ~ CONV_CHARS[i % base];
}
private char[] _intToStr64(ulong i, int base) {
const CONV_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz";
if (i >= base)
return _intToStr64(i / base, base) ~ CONV_CHARS[i % base];
else
return "" ~ CONV_CHARS[i % base];
}
//=======================================================================
struct SomeStruct {
uint flags;
mixin(Bitfield!(flags, "sign", 1, "biasedExponent", 8, "significand", 23));
}
import std.stdio;
void main() {
uint flags;
char[] r1a = Bitfield!(flags, "sign", 1, "biasedExponent", 8, "significand", 23);
char[] r1b =
"public uint sign() { return (flags >> 0x0) & 0x1; }
public void sign(uint val) { flags = (flags & 0xfffffffe) | ((val & 0x1) << 0x0); }
public uint biasedExponent() { return (flags >> 0x1) & 0xff; }
public void biasedExponent(uint val) { flags = (flags & 0xfffffe01) | ((val & 0xff) << 0x1); }
public uint significand() { return (flags >> 0x9) & 0x7fffff; }
public void significand(uint val) { flags = (flags & 0x1ff) | ((val & 0x7fffff) << 0x9); }
";
assert(r1a == r1b);
//writefln( Bitfield!(flags, "sign", 1, "biasedExponent", 8, "significand", 24) ); // raises error
ubyte otto;
char[] r2a = Bitfield!(otto, "sign", 1, "seven", 7);
char[] r2b =
"public ubyte sign() { return (otto >> 0x0) & 0x1; }
public void sign(ubyte val) { otto = (otto & 0xfffffffe) | ((val & 0x1) << 0x0); }
public ubyte seven() { return (otto >> 0x1) & 0x7f; }
public void seven(ubyte val) { otto = (otto & 0xffffff01) | ((val & 0x7f) << 0x1); }
";
assert(r2a == r2b);
ubyte d1;
writefln(Bitfield!(d1, "f1", 3, "s1", 5));
ushort d2;
writefln(Bitfield!(d2, "f2", 9, "s2", 7));
uint d3;
writefln(Bitfield!(d3, "f3", 17, "s3", 15));
ulong d4;
writefln(Bitfield!(d4, "f4", 31, "s4", 33));
}
Bye,
bearophile
More information about the Digitalmars-d-learn
mailing list