Struct field reordering

monarch_dodra monarchdodra at gmail.com
Thu Jan 2 08:44:57 PST 2014


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!


More information about the Digitalmars-d-learn mailing list