On Wed, Jun 26, 2013 at 04:31:40PM +0200, cybervadim wrote:
> On Wednesday, 26 June 2013 at 14:26:03 UTC, H. S. Teoh wrote:
> >Yeah, I think the best approach would be one that doesn't require
> >changing a whole mass of code to support. Also, one that doesn't
> >require language changes would be far more likely to be accepted, as
> >the core D devs are leery of adding yet more complications to the
> >language.
> >
> >That's why I proposed that gc_alloc and gc_free be made into
> >thread-global function pointers, that can be swapped with a custom
> >allocator's version. This doesn't have to be visible to user code; it
> >can just be an implementation detail in std.allocator, for example.
> >It allows us to implement custom allocators across a block of code
> >that doesn't know (and doesn't need to know) what allocator will be
> >used.
> >
> 
> Yes, being able to change gc_alloc, gc_free would do the work. If
> runtime  remembers the stack of gc_alloc/gc_free functions like pushd,
> popd, that would simplify its usage.  I think this is a very nice and
> simple solution to the problem.

Adam's idea does this: tie each replacement of gc_alloc/gc_free to some
stack-based object, that automatically cleans up in the dtor. So
something along these lines:

        struct CustomAlloc(A) {
                void* function(size_t size) old_alloc;
                void  function(void* ptr)   old_free;

                this(A alloc) {
                        old_alloc = gc_alloc;
                        old_free  = gc_free;

                        gc_alloc = &A.alloc;
                        gc_free  = &A.free;
                }

                ~this() {
                        gc_alloc = old_alloc;
                        gc_free  = old_free;

                        // Cleans up, e.g., region allocator deletes the
                        // region
                        A.cleanup();
                }
        }

        class C {}

        void main() {
                auto c = new C();       // allocates using default allocator 
(GC)
                {
                        CustomAlloc!MyAllocator _;

                        // Everything from here on until end of block
                        // uses MyAllocator

                        auto d = new C();       // allocates using MyAllocator

                        {
                                CustomAlloc!AnotherAllocator _;
                                auto e = new C(); // allocates using 
AnotherAllocator

                                // End of scope: auto cleanup, gc_alloc and
                                // gc_free reverts back to MyAllocator
                        }

                        auto f = new C();       // allocates using MyAllocator

                        // End of scope: auto cleanup, gc_alloc and
                        // gc_free reverts back to default values
                }
                auto g = new C();       // allocates using default allocator
        }


So you effectively have an allocator stack, and user code never has to
directly manipulate gc_alloc/gc_free (which would be dangerous).


T

-- 
Almost all proofs have bugs, but almost all theorems are true. -- Paul Pedersen

Reply via email to