On 9/24/13 1:02 PM, Dmitry Olshansky wrote:
24-Sep-2013 19:56, Andrei Alexandrescu пишет:
It could, but as I mentioned to Manu - at this level any cost is
significant. Even changing from a compile-time constant to a global
static dynamically-initialized constant has a cost. Making alignment an
instance variable turns stateless allocators into stateful ones.
Hm most could just get away with an enum. Am I missing something?
Right now I do things like:
struct DopeAllocator(Allocator, Dope)
{
static assert(Allocator.alignment >= Dope.alignof,
"DopeAllocator does not work with allocators offering a smaller"
" alignment than the dope alignment.");
static assert(!hasElaborateDestructor!Dope,
"DopeAllocator: ellaborate destructors for Dope not implemented.");
enum alignment = Dope.alignof;
...
}
Such code would be significantly more involved if Allocator had the
freedom to define alignment as either an enum, a static method, or a
member function.
(Background: DopeAllocator!(A, D) allocates an object of type D just
before every allocation and offers user code access to it. Allocations
are made using A.)
I'm hoping to get away with a static function "static uint alignment()"
that (a) is CTFEable for most allocators/platforms, (b) uses a
dynamically-initialized static constant for a few. Then derived
allocators will inherit CTFEability.
A check for CTFE-ablity might do the trick. The run-time dependent ones
usually would immediately hit a wall that is a sys-call or WinAPI.
It does. It's just some more work. Guess I'd need to put it in.
Would a per-allocator-type alignment suffice?
I see alignment as an inherent property of the way an allocator acquires
memory.
The question remains, is it a property of the allocator _object_ or a
property of the allocator _type_? I.e. do we need to support allocators
that store alignment as a nonstatic member variable?
Sad but true one can't determine the actual alignment of some
important ones at CTFE. Even worse adapters would in turn depend on
these system-specific run-time values such as half a page, 2 cache lines
etc.
auto my2PageAligner = AligningAllocator(page_size*2, rootAllocator)
where page_size is calculated elsewhere.
That can be made to work, it's just that page_size would be a static
variable that the user must set (not a template argument).
The global GC does offer manual deallocation. It's the presence of
collect() that indicates tracing abilities. If deallocateAll() is
present, user code must assume it will be called during destruction.
I was looking into how some library would have to tweak its code based
on presence/absence of some methods. For instance if there is collect,
it doesn't have to call deallocate (even if present). If not then it has
to call deallocate (again if present). Ditto with deallocateAll with or
without explicit deallocate.
Yah, my std.allocator prototype has a bunch of such logic.
expand should do the trick. I think that nicely saves on primitives
count. But we may have to add a 'shrink' if you are so bent on never
decreasing size in expand :)
And ... reallocate doesn't cut it as long as there is no big red tape on
it that says - if decreasing the size reallocation it is ALWAYS in-place
(it might not be true for some allocators - e.g. realloc doesn't
guarantee even this IIRC).
OK, I'm willing to add the optional method shrink(void[], size_t
newSize) if expand() and realloc() are insufficient. Indeed realloc()
does not guarantee immovability, and we also shouldn't because
Mallocator must be compatible the C API.
Andrei