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!

Reply via email to