phobos icon indicating copy to clipboard operation
phobos copied to clipboard

Add Layout abstraction

Open andralex opened this issue 6 years ago • 19 comments

This is much more useful and usable than Fields or RepresentationTypeTuple, which lose the essential information of offsets in data fields.

andralex avatar Feb 16 '18 23:02 andralex

Thanks for your pull request, @andralex!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

dlang-bot avatar Feb 16 '18 23:02 dlang-bot

Eh, we should relax the style checker a bit:

std/traits.d(2803:19)[error]: Expected `{` instead of `;`
std/traits.d(2803:19)[warn]: Empty declaration
std/traits.d(2804:24)[error]: Expected `{` instead of `;`
std/traits.d(2804:24)[warn]: Empty declaration
std/traits.d(8357:1)[error]: Expected `}` instead of `EOF`
std/traits.d(8357:1)[error]: Expected `}` instead of `EOF

in reference to:

// Intentionally undefined and undocumented.
struct __Vtable(C);
struct __Bookkeeping(C);

cc @wilzbach

andralex avatar Feb 17 '18 00:02 andralex

The design and implementation look good and compact, but I'm uneasy about the static array expansion being more or less useless as it can generate enormous tuples.

WalterBright avatar Feb 17 '18 03:02 WalterBright

This implementation will have rather bad compile-time performance. Please count how many instances will be created for a Layout with 4,8,32 fields.

UplinkCoder avatar Feb 17 '18 04:02 UplinkCoder

sadly it does not seem to work @andralex please try:

{
    struct S
    {
        uint u;
        char[64] c64;
        long l1, l2, l3, l4, l5, l6;
        union {
            S* s;
            S*[32] s32;
        }
    }

    pragma(msg, __traits(allMembers, Layout!S));
}

UplinkCoder avatar Feb 17 '18 05:02 UplinkCoder

Ideas for tests missing:

  • align(1) struct S { byte a; int b; byte c; int d;}
  • align(2) struct S { byte a; int b; byte c; int d;}
  • struct S { byte a; align(1) int b; byte c; int d;}
  • Test Layout!(const S2). Specify that Layout discards all qualifiers on the types, also of struct members. Test with struct S1 { int a; const S2 b} (note the inner const)
  • Test with abstract class, class inheritance, interfaces.
  • extern(C++) types
  • Layout!int and Layout!(int[]) and Layout!(int[5]) (test errors or sane behavior)
  • Sorting for union of these structs: align(1) struct S1 { byte a; int b; char c; char d; }; align(1) struct S2 { short a; short b; long c; byte d; }; align(1) struct S3 { int a; double b; }; (intentionally many different types, but avoiding pointers because size_t is variable).
  • Perhaps important to take into account when testing that size_t can be 16bits.

JohanEngelen avatar Feb 17 '18 10:02 JohanEngelen

This is great feedback you guys, thanks.

andralex avatar Feb 17 '18 13:02 andralex

@JohanEngelen I figure it's a mistake to eliminate qualifiers (with Unqual). Due to immutable, immutable and mutable structures do not have compatible layout - e.g. you can't seat one on top of the other. Will change it such that qualifiers are preserved.

Also: currently the layout is sorted by offset first, order of declaration second. But the order of declaration is irrelevant. Better find a canonical order - will sort by offset first, type second. Are there better ways to sort types than by .stringof?

andralex avatar Feb 17 '18 13:02 andralex

All: how do I compare that two layouts are identical? is(Layout!A == Layout!B) does not work because the instantiation of Layout is not a type. What is the right way to compare that two instantiations of a template are identical? Thx!

andralex avatar Feb 17 '18 13:02 andralex

@andralex template instantiation is pure, so you can compare the template args for equality instead (recursively if necessary, as a template arg could be a template). Use std.traits.TemplateArgsOf or some similar method.

I prefer to just use a struct instead of a template to avoid this problem altogether.

John-Colvin avatar Feb 17 '18 15:02 John-Colvin

template instantiation is pure [...] @John-Colvin only if you are playing nice :p

UplinkCoder avatar Feb 17 '18 15:02 UplinkCoder

@andralex I think we have a isSame template. which should do some sort of compare for you.

UplinkCoder avatar Feb 17 '18 15:02 UplinkCoder

@UplinkCoder I assume you mean https://dlang.org/spec/traits.html#isSame

John-Colvin avatar Feb 17 '18 15:02 John-Colvin

@andralex I'd like to see a usecase for this.

UplinkCoder avatar Feb 17 '18 16:02 UplinkCoder

@andralex static if/static assert doesn't work?

JackStouffer avatar Feb 18 '18 03:02 JackStouffer

Also: currently the layout is sorted by offset first, order of declaration second. But the order of declaration is irrelevant. Better find a canonical order - will sort by offset first, type second. Are there better ways to sort types than by .stringof?

Any advantages to secondary sorting with .sizeof?

Also, suggestion to name DecomposedLayoutOf (e.g.) - as it may make the reader more aware of purpose and how "Layout"ing is done (i.e. it decomposes the struct transitively)

aliak00 avatar Feb 18 '18 18:02 aliak00

Eh, we should relax the style checker a bit:

https://github.com/dlang/phobos/pull/6197

wilzbach avatar Feb 19 '18 06:02 wilzbach

Why implement your own compile-time mergesort - what's wrong with std.meta.staticSort? Also, is there a great benefit to having the result be one long AliasSeq instead of having a struct or template instance with Type and offset fields? For comparison, here's how I would have implemented this (including names, since that's been requested): https://gist.github.com/Biotronic/6182f24eabb444bca90f29d7a82bd428

Biotronic avatar Feb 19 '18 12:02 Biotronic

This will be a powerful tool for the allocators, allowing us to create at compile time a smart mapping between types and allocators. For each group of objects with identical layouts, we can use the same allocator, allowing for safe memory reuse.

jercaianu avatar Feb 19 '18 21:02 jercaianu