monarch_dodra
Posted in reply to bearophile
| On Thursday, 2 January 2014 at 02:11:13 UTC, bearophile wrote:
> Seen this on Reddit:
>
> http://www.catb.org/esr/structure-packing/
>
> It could be useful to have in Phobos some template that given pair-name pairs (or a struct type) returns those fields in a better packed order (without using align()).
>
> See also:
> https://d.puremagic.com/issues/show_bug.cgi?id=8873
>
> Bye,
> bearophile
Using "decreasing alignment size" then "decreasing size", I threw this together:
//--------
import std.stdio
//Actual useage
struct Test
{
mixin PackedFields!(
int, "a",
char, "c1",
int, "b",
char, "c2",
ushort, "c",
char, "c3",
ushort, "d",
char[5], "arr",
);
}
void main()
{
//Proof of concept
packedFields!(
int, "a",
char, "c1",
int, "b",
char, "c2",
ushort, "c",
char, "c3",
ushort, "d",
char[5], "arr",
).writeln();
writeln(FieldTypeTuple!Test.stringof);
writeln(Test.sizeof);
}
//Actual code:
import std.algorithm;
import std.traits;
import std.range;
struct Data
{
uint aline;
uint size;
string type;
string name;
}
Data[] packedFieldsImpl(Args...)()
{
static if (Args.length)
{
auto ret = Data(Args[0].alignof, Args[0].sizeof, Args[0].stringof);
static if (Args.length > 1 && is(typeof(Args[1]) == string))
{
ret.name = Args[1];
return ret ~ packedFieldsImpl!(Args[2 .. $])();
}
else
return ret ~ packedFieldsImpl!(Args[1 .. $])();
}
return Data[].init;
}
string packedFields(Args...)()
{
auto data = packedFieldsImpl!Args();
multiSort!(
(a, b)=>a.aline > b.aline,
(a, b)=>a.size > b.size ,
)(data);
string ret;
foreach(ref dat; data)
{
ret ~= dat.type ~ " " ~ dat.name ~ ";\n";
}
return ret;
}
mixin template PackedFields(Args...)
{
mixin(packedFields!Args());
}
//--------
It produces:
//--------
int b;
int a;
ushort c;
ushort d;
char[5] arr;
char c2;
char c3;
char c1;
(int, int, ushort, ushort, char[5], char, char, char)
20
//--------
This technique uses basic ctfe + string mixin. It might be possible to avoid the ctfe altogether for pure meta? I'd have to compare the relative compiler cost.
The two questions I'm thinking are:
1) What is the cost of deploying this "large-scale".
2) Would it maybe be more convenient to have a "CheckPacked" template?
CheckPacked would have the same useage as PakedFields, but instead of re-ordering the fields, would simply validate them: This means lower cost on the compiler, and a better "what you see is what you get" layout. EG:
struct Test
{
mixin PackedFields!(
int, "a",
char, "c1",
int, "b", //HERE
char, "c2",
ushort, "c",
char, "c3",
ushort, "d",
char[5], "arr",
);
}
ERROR: field "b" of type int has higher alignment than field "c1" of type char. Please reorder.
struct Test
{
mixin PackedFields!(
int, "a",
int, "b",
ushort, "c",
ushort, "d",
char[5], "arr",
char, "c1",
char, "c2",
char, "c3",
);
}
//OK! Test is guaranteed optimally packed!
|