-
Enhancement
-
Resolution: Fixed
-
P4
-
16
-
b03
I propose a rewrite of the GrowableArray classes.
Two main goals:
1) Allow a GrowableArray instance to be allocated on the stack or embedded in other objects. This removes one of the two indirections when operating on the arrays.
Today all GrowableArray instances that allocates the data array from the CHeap are enforced to be allocated on CHeap, and vice versa.
If you try to allocate it in the thread's resource area, in an arena, on the stack, or embedded in another object, an assert triggers.
It makes sense to block resource area and arena instantiations, because the GrowableArray destructor won't be run, and the CHeap allocated data array will leak.
For stack allocated instances the destructor will be run, the memory will be handed back. For embedded instances it all depends on how the parent instance was allocated.
Another reason why there's a one-to-one mapping of CHeap GrowableArray instances and CHeap allocated data arrays: There's no proper support for copying of the data array, and the destruction of the source GrowableArray would destroy the data array.
This might be changed some day, but for now this could be handled, by adding a check in the copy constructor and assignment operator.
2) Make the GrowableArray instances smaller. The main motivation is to be able to leverage the implementation of (1) and embed instances in other objects.
This allows us to write size sensitive classes, without having to resort to an extra indirection that the original CHeap-based GrowableArray requires.
The current fields of the product builds are:
int _len;
int _max;
Arena* _arena;
MEMFLAGS _memflags;
E* _data;
resulting in a size of 32 bytes: 4 + 4 + 8 + 8 + 8. The _memflags size is due to alignment requirements for the _data field.
By combining _arena and _memflags, this can be reduced to 24 bytes.
By having a specialized CHeap version we can encode the MEMFLAGS as a template parameter, and get rid of the _arena field, this is then reduced to 16 bytes.
Two main goals:
1) Allow a GrowableArray instance to be allocated on the stack or embedded in other objects. This removes one of the two indirections when operating on the arrays.
Today all GrowableArray instances that allocates the data array from the CHeap are enforced to be allocated on CHeap, and vice versa.
If you try to allocate it in the thread's resource area, in an arena, on the stack, or embedded in another object, an assert triggers.
It makes sense to block resource area and arena instantiations, because the GrowableArray destructor won't be run, and the CHeap allocated data array will leak.
For stack allocated instances the destructor will be run, the memory will be handed back. For embedded instances it all depends on how the parent instance was allocated.
Another reason why there's a one-to-one mapping of CHeap GrowableArray instances and CHeap allocated data arrays: There's no proper support for copying of the data array, and the destruction of the source GrowableArray would destroy the data array.
This might be changed some day, but for now this could be handled, by adding a check in the copy constructor and assignment operator.
2) Make the GrowableArray instances smaller. The main motivation is to be able to leverage the implementation of (1) and embed instances in other objects.
This allows us to write size sensitive classes, without having to resort to an extra indirection that the original CHeap-based GrowableArray requires.
The current fields of the product builds are:
int _len;
int _max;
Arena* _arena;
MEMFLAGS _memflags;
E* _data;
resulting in a size of 32 bytes: 4 + 4 + 8 + 8 + 8. The _memflags size is due to alignment requirements for the _data field.
By combining _arena and _memflags, this can be reduced to 24 bytes.
By having a specialized CHeap version we can encode the MEMFLAGS as a template parameter, and get rid of the _arena field, this is then reduced to 16 bytes.