1 module nxt.aggregate_layout; 2 3 // version = show; 4 5 @safe: 6 7 void printLayout(T)() 8 if (is(T == struct) || 9 is(T == class) || 10 is(T == union)) 11 { 12 import std.stdio; 13 import std.string; 14 15 writefln("=== Memory layout of '%s'" ~ 16 " (.sizeof: %s, .alignof: %s) ===", 17 T.stringof, T.sizeof, T.alignof); 18 19 /* Prints a single line of layout information. */ 20 void printLine(size_t offset, string info) { 21 writefln("%4s: %s", offset, info); 22 } 23 24 /* Prints padding information if padding is actually 25 * observed. */ 26 void maybePrintPaddingInfo(size_t expectedOffset, 27 size_t actualOffset) { 28 if (expectedOffset < actualOffset) { 29 /* There is some padding because the actual offset 30 * is beyond the expected one. */ 31 32 const paddingSize = actualOffset - expectedOffset; 33 34 printLine(expectedOffset, 35 format("... %s-byte PADDING", 36 paddingSize)); 37 } 38 } 39 40 /* This is the expected offset of the next member if there 41 * were no padding bytes before that member. */ 42 size_t noPaddingOffset = 0; 43 44 /* Note: __traits(allMembers) is a 'string' collection of 45 * names of the members of a type. */ 46 foreach (memberName; __traits(allMembers, T)) { 47 mixin (format("alias member = %s.%s;", 48 T.stringof, memberName)); 49 50 const offset = member.offsetof; 51 maybePrintPaddingInfo(noPaddingOffset, offset); 52 53 const typeName = typeof(member).stringof; 54 printLine(offset, 55 format("%s %s", typeName, memberName)); 56 57 noPaddingOffset = offset + member.sizeof; 58 } 59 60 maybePrintPaddingInfo(noPaddingOffset, T.sizeof); 61 } 62 63 version(show) 64 @safe unittest 65 { 66 struct S 67 { 68 int i; // 4 bytes 69 short s; // 2 byte 70 bool b; // 1 byte 71 } 72 static assert(S.sizeof == 8); 73 static assert(S.alignof == 4); 74 align(4) struct T 75 { 76 align(4) S s; 77 align(1) char c; 78 } 79 static assert(T.alignof == 4); 80 // TODO: static assert(T.sizeof == 8); 81 printLayout!(T)(); 82 } 83 84 // https://forum.dlang.org/post/jzrztbyzgxlkplslcoaj@forum.dlang.org 85 @safe pure unittest 86 { 87 struct S 88 { 89 int i; // 4 bytes 90 short s; // 2 byte 91 bool b; // 1 byte 92 } 93 static assert(S.sizeof == 8); 94 static assert(S.alignof == 4); 95 96 struct T 97 { 98 union 99 { 100 S s; 101 struct 102 { 103 align(1): 104 ubyte[7] _ignore_me; 105 char c; 106 } 107 } 108 } 109 110 static assert(T.alignof == 4); 111 static assert(T.sizeof == 8); 112 static assert(T.c.offsetof == 7); 113 }