module traits_getPointerBitmap; import core.stdc.stdio; // version = RTInfo; // debug = LOG; version(RTInfo) import gc.rtinfo; else enum bool RTInfoMark__Monitor = false; // is __monitor GC allocated? enum bytesPerPtr = (size_t.sizeof); enum bytesPerBitmapWord = bytesPerPtr * bytesPerPtr * 8; template allocatedSize(T) { static if (is (T == class)) enum allocatedSize = __traits(classInstanceSize, T); else enum allocatedSize = T.sizeof; } bool testBit(const(size_t)* p, size_t biti) { enum BITS_SHIFT = (size_t.sizeof == 8 ? 6 : 5); enum BITS_MASK = (bytesPerPtr - 1); return (p[biti >> BITS_SHIFT] & (1 << (biti & BITS_MASK))) != 0; } void __testType(T)(size_t[] expected) { // check compile time info enum bits = (T.sizeof + bytesPerPtr - 1) / bytesPerPtr; enum words = (T.sizeof + bytesPerBitmapWord - 1) / bytesPerBitmapWord; version(RTInfo) enum info = RTInfoImpl2!(Unqual!T); // we want the array, not the pointer else enum info = __traits(getPointerBitmap,T); // we want the array, not the pointer debug(LOG) writef("%-20s:", T.stringof); debug(LOG) writef(" CT:%s", info); debug(LOG) writef(" EXP:%d %s", allocatedSize!T, expected); assert(info[0] == allocatedSize!T); assert(info[1..$] == expected); assert(words == expected.length); debug(LOG) writeln(); } /////////////////////////////////////// struct S(T, aliasTo = void) { static if(!is(aliasTo == void)) { aliasTo a; alias a this; } size_t x; T t = void; void* p; } template tOff(T) { enum tOff = T.t.offsetof / bytesPerPtr; } template pOff(T) { enum pOff = T.p.offsetof / bytesPerPtr; } class C(T, aliasTo = void) { static if(!is(aliasTo == void)) { aliasTo a; alias a this; } size_t x; T t = void; void* p; } /////////////////////////////////////// void _testType(T)(size_t[] expected) { __testType!(T)(expected); __testType!(const(T))(expected); __testType!(immutable(T))(expected); version(RTInfo) {} else // Unqual does not work with shared(T[N]) __testType!(shared(T))(expected); } void testType(T)(size_t[] expected) { _testType!(T)(expected); // generate bit pattern for S!T assert(expected.length == 1); size_t[] sexp; sexp ~= (expected[0] << tOff!(S!T)) | (1 << pOff!((S!T))); _testType!(S!T)(sexp); // prepend Object sexp[0] = (expected[0] << tOff!(S!(T, Object))) | (1 << pOff!(S!(T, Object))) | 1; _testType!(S!(T, Object))(sexp); // prepend string sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr _testType!(S!(T, string))(sexp); // generate bit pattern for C!T C!T ct = null; size_t mutexBit = (RTInfoMark__Monitor ? 2 : 0); size_t ctpOff = ct.p.offsetof / bytesPerPtr; size_t cttOff = ct.t.offsetof / bytesPerPtr; sexp[0] = (expected[0] << cttOff) | (1 << ctpOff) | mutexBit; _testType!(C!(T))(sexp); C!(T, string) cts = null; size_t ctspOff = cts.p.offsetof / bytesPerPtr; size_t ctstOff = cts.t.offsetof / bytesPerPtr; // generate bit pattern for C!T sexp[0] = (expected[0] << ctstOff) | (1 << ctspOff) | mutexBit | 0b1000; // arr ptr _testType!(C!(T, string))(sexp); } /////////////////////////////////////// alias void[2*size_t.sizeof] void2; alias size_t[3] int3; alias size_t*[3] pint3; alias string[3] sint3; alias string[3][2] sint3_2; alias int delegate() dg; alias int function() fn; alias typeof(null) NullType; // span multiple bitmap elements struct Large { size_t[30] data1; void* p1; size_t[1] val1; size_t[28] data2; void* p2; size_t[3] val2; size_t[16] data3; void* p3; size_t[15] val3; } class N { struct Nested { // no outer for structs size_t x; void* p1; Large* s; void foo() {} // need member fnction to not be POD } class CNested { // implicit vtptr,monitor size_t x; void* p1; size_t y; // implicit outer } class CNestedDerived : CNested { size_t[3] z; void* p; } } union U { size_t[4] data; Large*[] arr; // { length, ptr } struct { size_t d1; size_t d2; size_t d3; void* p; } } void testRTInfo() { testType!(bool) ([ 0b0 ]); testType!(ubyte) ([ 0b0 ]); testType!(short) ([ 0b0 ]); testType!(int) ([ 0b0 ]); testType!(long) ([ 0b00 ]); testType!(double) ([ 0b00 ]); testType!(dg) ([ 0b01 ]); testType!(fn) ([ 0b0 ]); testType!(S!fn) ([ 0b100 ]); testType!(NullType) ([ 0b0 ]); static if (__traits(compiles, __vector(float[4]))) testType!(__vector(float[4])) ([ 0b00 ]); testType!(Object[int]) ([ 0b1 ]); testType!(Object[]) ([ 0b10 ]); testType!(string) ([ 0b10 ]); testType!(int3) ([ 0b000 ]); testType!(pint3) ([ 0b111 ]); testType!(sint3) ([ 0b101010 ]); testType!(sint3_2) ([ 0b101010101010 ]); testType!(void2) ([ 0b11 ]); testType!(U) ([ 0b1010 ]); version(D_LP64) _testType!(Large) ([ 0x1000_0000__4000_0000, 0x0001_0000 ]); else _testType!(Large) ([ 0x4000_0000, 0x1000_0000, 0x0001_0000 ]); _testType!(N.CNested) ([ 0b101000 ]); _testType!(N.CNestedDerived) ([ 0b1000101000 ]); testType!(N.Nested) ([ 0b110 ]); struct SFNested { size_t[2] d; void* p1; fn f; // implicite outer void foo() {} // need member fnction to not be POD } class CFNested { // implicit vtptr,monitor size_t[2] d; void* p1; // implicite outer } testType!(SFNested) ([ 0b10100 ]); _testType!(CFNested) ([ 0b110000 ]); } void main() { testRTInfo(); }