January 15, 2007 Re: Size of a class instance at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Got it! No, really, this time FOR SURE ^_^ The end solution is utterly evil, but is, AFAIK, correct. What I had to do in the end was to say that the size of a class instance is the maximum of: 1) size of the base class + if(implements interfaces) padding + interface count * pointer size, 2) max(class member alignof + sizeof) + if(implements interfaces) padding + interface count * pointer size I also added a minimum size of 2*pointer size to account for classes that don't have any member variables. Getting the padding for interfaces was fun: > struct Align > { > ubyte a; > void* b; > } > > const PTR_ALIGN = Align.tupleof[1].alignof; I *think* that's right. In any case, it's reporting the correct size for every test case I throw at it. Anything else that needs fixing? :P -- Daniel private struct Align { ubyte a; void* b; } private const PTR_ALIGN = Align.tupleof[1].alignof; private template AlignPad(size_t base, size_t aligned) { static if( aligned == 0 ) const AlignPad = base; else const AlignPad = ((base+PTR_ALIGN-1)/PTR_ALIGN)*PTR_ALIGN + aligned; } template InstanceSize(T) { static if( is( T == Object ) ) const InstanceSize = 2*(void*).sizeof; else const InstanceSize = Max!( AlignPad!( InstanceSize!(Super!(T)), InterfaceCount!(T)*(void*).sizeof), AlignPad!( InstanceSizeImpl!(T, 0), + InterfaceCount!(T)*(void*).sizeof)); } private template Super(T) { static if( is( T S == super ) ) alias First!(S) Super; else static assert(false, "Can't get super of "~T.mangleof); } private template First(T) { alias T First; } private template First(T, Ts...) { alias T First; } private template InstanceSizeImpl(T, size_t i) { static if( i < T.tupleof.length ) const InstanceSizeImpl = Max!( T.tupleof[i].offsetof + T.tupleof[i].sizeof, InstanceSizeImpl!(T, i+1)); else // This is necessary to account for classes without member // variables. const InstanceSizeImpl = 2*(void*).sizeof; } private template Max(size_t a, size_t b) { static if( a > b ) const Max = a; else const Max = b; } private template InstanceSizeAligned(T, size_t alignment) { static if( alignment == 0 ) const InstanceSizeAligned = InstanceSize!(T); else const uint InstanceSizeAligned = InstanceSizeAlignImpl!(T, alignment).result; } private template InstanceSizeAlignedImpl(T, size_t alignment) { private const base_size = InstanceSize!(T); const result = ((base_size+alignment-1)/alignment)*alignment; } private template InterfaceCount(T) { static if( is( T == Object ) ) const InterfaceCount = 0u; else static if( is( T S == super ) ) const InterfaceCount = InterfaceCountImpl!(S); } private template InterfaceCountImpl(TBase, TInterfaces...) { const InterfaceCountImpl = TInterfaces.length; } |
January 15, 2007 Re: Size of a class instance at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote: > > Got it! No, really, this time FOR SURE ^_^ > > The end solution is utterly evil, but is, AFAIK, correct. > > What I had to do in the end was to say that the size of a class instance is the maximum of: > > 1) size of the base class + if(implements interfaces) > padding + interface count * pointer size, > 2) max(class member alignof + sizeof) + if(implements interfaces) > padding + interface count * pointer size > > I also added a minimum size of 2*pointer size to account for classes that don't have any member variables. > > Getting the padding for interfaces was fun: > > > struct Align > > { > > ubyte a; > > void* b; > > } > > > > const PTR_ALIGN = Align.tupleof[1].alignof; Nifty! > I *think* that's right. In any case, it's reporting the correct size for every test case I throw at it. Anything else that needs fixing? :P One other nasty case is where the last member of a class is an 80-bit real, with padding that is different between Windows, Linux32, and Linux64. Does that work correctly? > > -- Daniel > > private > struct Align > { > ubyte a; > void* b; > } > > private > const PTR_ALIGN = Align.tupleof[1].alignof; > > private > template AlignPad(size_t base, size_t aligned) > { > static if( aligned == 0 ) > const AlignPad = base; > else > const AlignPad = ((base+PTR_ALIGN-1)/PTR_ALIGN)*PTR_ALIGN > + aligned; > } > > template InstanceSize(T) > { > static if( is( T == Object ) ) > const InstanceSize = 2*(void*).sizeof; > else > const InstanceSize = Max!( > AlignPad!( > InstanceSize!(Super!(T)), > InterfaceCount!(T)*(void*).sizeof), > > AlignPad!( > InstanceSizeImpl!(T, 0), > + InterfaceCount!(T)*(void*).sizeof)); > } > > private > template Super(T) > { > static if( is( T S == super ) ) > alias First!(S) Super; > else > static assert(false, "Can't get super of "~T.mangleof); > } > > private > template First(T) > { > alias T First; > } > > private > template First(T, Ts...) > { > alias T First; > } > > private > template InstanceSizeImpl(T, size_t i) > { > static if( i < T.tupleof.length ) > const InstanceSizeImpl = Max!( > T.tupleof[i].offsetof + T.tupleof[i].sizeof, > InstanceSizeImpl!(T, i+1)); > else > // This is necessary to account for classes without member > // variables. > const InstanceSizeImpl = 2*(void*).sizeof; > } > > private > template Max(size_t a, size_t b) > { > static if( a > b ) > const Max = a; > else > const Max = b; > } > > private > template InstanceSizeAligned(T, size_t alignment) > { > static if( alignment == 0 ) > const InstanceSizeAligned = InstanceSize!(T); > else > const uint InstanceSizeAligned > = InstanceSizeAlignImpl!(T, alignment).result; > } > > private > template InstanceSizeAlignedImpl(T, size_t alignment) > { > private const base_size = InstanceSize!(T); > const result = ((base_size+alignment-1)/alignment)*alignment; > } > > private > template InterfaceCount(T) > { > static if( is( T == Object ) ) > const InterfaceCount = 0u; > else static if( is( T S == super ) ) > const InterfaceCount = InterfaceCountImpl!(S); > } > > private > template InterfaceCountImpl(TBase, TInterfaces...) > { > const InterfaceCountImpl = TInterfaces.length; > } > |
January 15, 2007 Re: Size of a class instance at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | Don Clugston wrote:
> Daniel Keep wrote:
>> I *think* that's right. In any case, it's reporting the correct size for every test case I throw at it. Anything else that needs fixing? :P
>
>
> One other nasty case is where the last member of a class is an 80-bit real, with padding that is different between Windows, Linux32, and Linux64. Does that work correctly?
Well, I tried sticking a real into the test cases in various spots, and it seemed fine. That said, I'm not sure what the potential problem is; it currently determines the size of the member variables by finding the maximum of (member.alignof+member.sizeof) for every member variable. This means that, even if the last member is a real, that it will correctly account for any padding *before* the real, as well as its' full size.
Unless the compiler does really weird stuff like, for example, sticking in padding after a real that isn't part of its' ".sizeof" on non Windows platforms, I don't think it should be a problem.
That said, if you DO find anything amiss, I'd love to know :)
That reminds me. Walter: I know you're probably busy, but if you could just give this the once-over to verify that it's counting the bytes properly, that would be awesome.
-- Daniel
|
January 15, 2007 Re: Size of a class instance at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote: > Don Clugston wrote: >> Daniel Keep wrote: >>> I *think* that's right. In any case, it's reporting the correct size for every test case I throw at it. Anything else that needs fixing? :P >> >> >> One other nasty case is where the last member of a class is an 80-bit real, with padding that is different between Windows, Linux32, and Linux64. Does that work correctly? > > Well, I tried sticking a real into the test cases in various spots, and it seemed fine. That said, I'm not sure what the potential problem is; it currently determines the size of the member variables by finding the maximum of (member.alignof+member.sizeof) for every member variable. This means that, even if the last member is a real, that it will correctly account for any padding *before* the real, as well as its' full size. > > Unless the compiler does really weird stuff like, for example, sticking in padding after a real that isn't part of its' ".sizeof" on non Windows platforms, I don't think it should be a problem. That's exactly what I was worried about -- reals are followed by 0 bytes of padding on Windows, 2 on Linux32, and 6 on linux64. But it seems it is already included in sizeof; real.sizeof varies between platforms, even though the hardware is identical. real.alignof is constant for all of them. > That said, if you DO find anything amiss, I'd love to know :) > > That reminds me. Walter: I know you're probably busy, but if you could just give this the once-over to verify that it's counting the bytes properly, that would be awesome. > > -- Daniel |
Copyright © 1999-2021 by the D Language Foundation