January 31, 2010
I like the idea of saving memory, I don't care for the implementation; all those if's which won't be branch predictable, I expect, and adds seem like they'll make looking up each element quite a bit more expensive.  Not to mention the amount of code repetition.  The repetition is easy to fix, but I don't have a good solution yet for the cost.

The easy solution (quickly written and untested, and actually increases the runtime cost since it makes all the property functions cost as much as the worst case):

void* calcPosition(uint mask)
{
    // NOTE: why does this use size_t explicitly rather than auto?
    size_t off = New.sizeof;
    auto flags = n.flags & mask;

    if (flags & MItlsctor)      off += o.tlsctor.sizeof;
    if (flags & MItlsdtor)      off += o.tlsdtor.sizeof;
    if (flags & MIxgetMembers)  off += o.xgetMembers.sizeof;
    if (flags & MIctor)         off += o.ctor.sizeof;
    if (flags & MIdtor)         off += o.ctor.sizeof;
    if (flags & MIictor)        off += o.ictor.sizeof;
    if (flags & MIunitTest)     off += o.unitTest.sizeof;

    if (flags & MIimportedModules)
    {
        auto plength = cast(size_t*)(cast(void*)(&this) + off);
        off += size_t.sizeof + *plength * plength.sizeof;
    }

    if (flags & MIlocalClasses)
    {
        auto plength = cast(size_t*)(cast(void*)(&this) + off);
        off += size_t.sizeof + *plength * plength.sizeof;
    }

    return cast(void*)(&this) + off;
}

Which you can call with:

@property string name()
{
    if (isNew)
    {
        auto p - cast(immutable(char)*)(calcPosition(MASKname))
        auto len = strlen(p);
        return p[0 .. len];
    }
    else
        return o.name
}

Obviously, you'll need to add the MAKS* enum to parallel the MI* enums.

One way to solve the efficiency issue, at the cost of some memory would be to build a table of offsets.  Given the 7 fixed size elements, that's just 128 combinations of fields.  Since the size of the largest offset is less than a byte, we can just use 7 bytes to hold the offset of each field.  That's not a large table.  Given that table, you could pick up the offset by something like:

size_t off = table[((n.flags >> 3) & MImask)*7 + MIfieldnumtolookup]]

I haven't thought it through well enough, but rearranging the 2 lengths for the last two fields to be before the variable length data might help a little since they could be included in the above table.

Anyway, food for thought.

Later,
Brad
January 31, 2010
I agree my solution isn't too clever, and there's too much copy/paste; my first thought was to make it work and see how much it saves. It shaves 30,000 bytes off of phobos.lib, about 1%. Haven't tried it in an app to see.

Didn't think the performance matters much, except for the TLS ctors/dtors, which is why they are first. The rest are only done on startup, and will get lost in the noise. So I think your design is better.

Brad Roberts wrote:
> I like the idea of saving memory, I don't care for the implementation; all those if's which won't be branch predictable, I expect, and adds seem like they'll make looking up each element quite a bit more expensive.  Not to mention the amount of code repetition.  The repetition is easy to fix, but I don't have a good solution yet for the cost.
>
> The easy solution (quickly written and untested, and actually increases the runtime cost since it makes all the property functions cost as much as the worst case):
>
> void* calcPosition(uint mask)
> {
>     // NOTE: why does this use size_t explicitly rather than auto?
>     size_t off = New.sizeof;
>     auto flags = n.flags & mask;
>
>     if (flags & MItlsctor)      off += o.tlsctor.sizeof;
>     if (flags & MItlsdtor)      off += o.tlsdtor.sizeof;
>     if (flags & MIxgetMembers)  off += o.xgetMembers.sizeof;
>     if (flags & MIctor)         off += o.ctor.sizeof;
>     if (flags & MIdtor)         off += o.ctor.sizeof;
>     if (flags & MIictor)        off += o.ictor.sizeof;
>     if (flags & MIunitTest)     off += o.unitTest.sizeof;
>
>     if (flags & MIimportedModules)
>     {
>         auto plength = cast(size_t*)(cast(void*)(&this) + off);
>         off += size_t.sizeof + *plength * plength.sizeof;
>     }
>
>     if (flags & MIlocalClasses)
>     {
>         auto plength = cast(size_t*)(cast(void*)(&this) + off);
>         off += size_t.sizeof + *plength * plength.sizeof;
>     }
>
>     return cast(void*)(&this) + off;
> }
>
> Which you can call with:
>
> @property string name()
> {
>     if (isNew)
>     {
>         auto p - cast(immutable(char)*)(calcPosition(MASKname))
>         auto len = strlen(p);
>         return p[0 .. len];
>     }
>     else
>         return o.name
> }
>
> Obviously, you'll need to add the MAKS* enum to parallel the MI* enums.
>
> One way to solve the efficiency issue, at the cost of some memory would be to build a table of offsets.  Given the 7 fixed size elements, that's just 128 combinations of fields.  Since the size of the largest offset is less than a byte, we can just use 7 bytes to hold the offset of each field.  That's not a large table.  Given that table, you could pick up the offset by something like:
>
> size_t off = table[((n.flags >> 3) & MImask)*7 + MIfieldnumtolookup]]
>
> I haven't thought it through well enough, but rearranging the 2 lengths for the last two fields to be before the variable length data might help a little since they could be included in the above table.
>
> Anyway, food for thought.
>
> Later,
> Brad
> _______________________________________________
> dmd-beta mailing list
> dmd-beta at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-beta
>
>
>