Add memory.types.Scoped
This commit is contained in:
		@@ -18,7 +18,7 @@ import std.range;
 | 
				
			|||||||
import std.traits;
 | 
					import std.traits;
 | 
				
			||||||
import tanya.memory;
 | 
					import tanya.memory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package(tanya) final class RefCountedStore(T)
 | 
					final class RefCountedStore(T)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    T payload;
 | 
					    T payload;
 | 
				
			||||||
    size_t counter = 1;
 | 
					    size_t counter = 1;
 | 
				
			||||||
@@ -34,7 +34,7 @@ package(tanya) final class RefCountedStore(T)
 | 
				
			|||||||
        mixin("return " ~ op ~ "counter;");
 | 
					        mixin("return " ~ op ~ "counter;");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int opCmp(size_t counter)
 | 
					    int opCmp(const size_t counter)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (this.counter > counter)
 | 
					        if (this.counter > counter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -50,7 +50,7 @@ package(tanya) final class RefCountedStore(T)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int opEquals(size_t counter)
 | 
					    int opEquals(const size_t counter)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return this.counter == counter;
 | 
					        return this.counter == counter;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -118,7 +118,12 @@ struct RefCounted(T)
 | 
				
			|||||||
        this(allocator);
 | 
					        this(allocator);
 | 
				
			||||||
        this.storage = allocator.make!Storage();
 | 
					        this.storage = allocator.make!Storage();
 | 
				
			||||||
        this.deleter = &separateDeleter!Payload;
 | 
					        this.deleter = &separateDeleter!Payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        move(value, this.storage.payload);
 | 
					        move(value, this.storage.payload);
 | 
				
			||||||
 | 
					        static if (__traits(isRef, value))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            value = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Ditto.
 | 
					    /// Ditto.
 | 
				
			||||||
@@ -139,7 +144,7 @@ struct RefCounted(T)
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (count != 0)
 | 
					        if (count != 0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ++storage;
 | 
					            ++this.storage;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,7 +157,7 @@ struct RefCounted(T)
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (this.storage !is null && !(this.storage.counter && --this.storage))
 | 
					        if (this.storage !is null && !(this.storage.counter && --this.storage))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            deleter(storage, allocator);
 | 
					            deleter(this.storage, allocator);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -163,14 +168,16 @@ struct RefCounted(T)
 | 
				
			|||||||
     * If it is the last reference of the previously owned object,
 | 
					     * If it is the last reference of the previously owned object,
 | 
				
			||||||
     * it will be destroyed.
 | 
					     * it will be destroyed.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * To reset the $(D_PSYMBOL RefCounted) assign $(D_KEYWORD null).
 | 
					     * To reset $(D_PSYMBOL RefCounted) assign $(D_KEYWORD null).
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * If the allocator wasn't set before, $(D_PSYMBOL defaultAllocator) will
 | 
					     * If the allocator wasn't set before, $(D_PSYMBOL defaultAllocator) will
 | 
				
			||||||
     * be used. If you need a different allocator, create a new
 | 
					     * be used. If you need a different allocator, create a new
 | 
				
			||||||
     * $(D_PSYMBOL RefCounted) and assign it.
 | 
					     * $(D_PSYMBOL RefCounted) and assign it.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Params:
 | 
					     * Params:
 | 
				
			||||||
     *  rhs = $(D_KEYWORD this).
 | 
					     *  rhs = New object.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Returns: $(D_KEYWORD this).
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    ref typeof(this) opAssign()(auto ref Payload rhs)
 | 
					    ref typeof(this) opAssign()(auto ref Payload rhs)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -187,8 +194,6 @@ struct RefCounted(T)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Created with refCounted. Always destroyed togethter with the pointer.
 | 
					 | 
				
			||||||
            assert(this.storage.counter != 0);
 | 
					 | 
				
			||||||
            finalize(this.storage.payload);
 | 
					            finalize(this.storage.payload);
 | 
				
			||||||
            this.storage.payload = Payload.init;
 | 
					            this.storage.payload = Payload.init;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -206,15 +211,13 @@ struct RefCounted(T)
 | 
				
			|||||||
        else if (this.storage > 1)
 | 
					        else if (this.storage > 1)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            --this.storage;
 | 
					            --this.storage;
 | 
				
			||||||
            this.storage = null;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Created with refCounted. Always destroyed togethter with the pointer.
 | 
					            deleter(this.storage, allocator);
 | 
				
			||||||
            assert(this.storage.counter != 0);
 | 
					 | 
				
			||||||
            finalize(this.storage.payload);
 | 
					 | 
				
			||||||
            this.storage.payload = Payload.init;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        this.storage = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this;
 | 
					        return this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -229,6 +232,8 @@ struct RefCounted(T)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns: Reference to the owned object.
 | 
					     * Returns: Reference to the owned object.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Precondition: $(D_INLINECODE cound > 0).
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    inout(Payload) get() inout pure nothrow @safe @nogc
 | 
					    inout(Payload) get() inout pure nothrow @safe @nogc
 | 
				
			||||||
    in
 | 
					    in
 | 
				
			||||||
@@ -240,7 +245,7 @@ struct RefCounted(T)
 | 
				
			|||||||
        return storage.payload;
 | 
					        return storage.payload;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static if (isPointer!Payload)
 | 
					    version (D_Ddoc)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Params:
 | 
					         * Params:
 | 
				
			||||||
@@ -251,6 +256,11 @@ struct RefCounted(T)
 | 
				
			|||||||
         *
 | 
					         *
 | 
				
			||||||
         * Returns: Reference to the pointed value.
 | 
					         * Returns: Reference to the pointed value.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
 | 
					        ref T opUnary(string op)()
 | 
				
			||||||
 | 
					            if (op == "*");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else static if (isPointer!Payload)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        ref T opUnary(string op)()
 | 
					        ref T opUnary(string op)()
 | 
				
			||||||
            if (op == "*")
 | 
					            if (op == "*")
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -352,6 +362,44 @@ private unittest
 | 
				
			|||||||
    assert(rc.count == 1);
 | 
					    assert(rc.count == 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto rc = defaultAllocator.refCounted!int(5);
 | 
				
			||||||
 | 
					    assert(rc.count == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void func(RefCounted!int rc)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(rc.count == 2);
 | 
				
			||||||
 | 
					        rc = null;
 | 
				
			||||||
 | 
					        assert(!rc.isInitialized);
 | 
				
			||||||
 | 
					        assert(rc.count == 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(rc.count == 1);
 | 
				
			||||||
 | 
					    func(rc);
 | 
				
			||||||
 | 
					    assert(rc.count == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = null;
 | 
				
			||||||
 | 
					    assert(!rc.isInitialized);
 | 
				
			||||||
 | 
					    assert(rc.count == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto rc = defaultAllocator.refCounted!int(5);
 | 
				
			||||||
 | 
					    assert(*rc == 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void func(RefCounted!int rc)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(rc.count == 2);
 | 
				
			||||||
 | 
					        rc = defaultAllocator.refCounted!int(4);
 | 
				
			||||||
 | 
					        assert(*rc == 4);
 | 
				
			||||||
 | 
					        assert(rc.count == 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    func(rc);
 | 
				
			||||||
 | 
					    assert(*rc == 5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private unittest
 | 
					private unittest
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    static assert(is(typeof(RefCounted!int.storage.payload) == int*));
 | 
					    static assert(is(typeof(RefCounted!int.storage.payload) == int*));
 | 
				
			||||||
@@ -420,7 +468,7 @@ body
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Constructs a new array with $(D_PARAM size) elements and wraps it in a
 | 
					 * Constructs a new array with $(D_PARAM size) elements and wraps it in a
 | 
				
			||||||
 * $(D_PSYMBOL RefCounted) using.
 | 
					 * $(D_PSYMBOL RefCounted).
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Params:
 | 
					 * Params:
 | 
				
			||||||
 *  T         = Array type.
 | 
					 *  T         = Array type.
 | 
				
			||||||
@@ -432,7 +480,8 @@ body
 | 
				
			|||||||
 * Precondition: $(D_INLINECODE allocator !is null
 | 
					 * Precondition: $(D_INLINECODE allocator !is null
 | 
				
			||||||
 *                           && size <= size_t.max / ElementType!T.sizeof)
 | 
					 *                           && size <= size_t.max / ElementType!T.sizeof)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 RefCounted!T refCounted(T)(shared Allocator allocator, const size_t size)
 | 
					RefCounted!T refCounted(T)(shared Allocator allocator, const size_t size)
 | 
				
			||||||
 | 
					@trusted
 | 
				
			||||||
    if (isArray!T)
 | 
					    if (isArray!T)
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -441,8 +490,7 @@ in
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
body
 | 
					body
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto payload = cast(T) allocator.allocate(ElementType!T.sizeof * size);
 | 
					    auto payload = allocator.resize!(ElementType!T)(null, size);
 | 
				
			||||||
    initializeAll(payload);
 | 
					 | 
				
			||||||
    return RefCounted!T(payload, allocator);
 | 
					    return RefCounted!T(payload, allocator);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -512,3 +560,257 @@ private @nogc unittest
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    assert(destroyed);
 | 
					    assert(destroyed);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * $(D_PSYMBOL Scoped) stores an object that gets destroyed at the end of its scope.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *  T = Value type.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct Scoped(T)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static if (is(T == class) || is(T == interface) || isArray!T)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private alias Payload = T;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private alias Payload = T*;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private Payload payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    invariant
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(payload is null || allocator_ !is null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Takes ownership over $(D_PARAM value), setting the counter to 1.
 | 
				
			||||||
 | 
					     * $(D_PARAM value) may be a pointer, an object or a dynamic array.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Params:
 | 
				
			||||||
 | 
					     *  value     = Value whose ownership is taken over.
 | 
				
			||||||
 | 
					     *  allocator = Allocator used to destroy the $(D_PARAM value) and to
 | 
				
			||||||
 | 
					     *              allocate/deallocate internal storage.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Precondition: $(D_INLINECODE allocator !is null)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    this()(auto ref Payload value,
 | 
				
			||||||
 | 
					           shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this(allocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        move(value, this.payload);
 | 
				
			||||||
 | 
					        static if (__traits(isRef, value))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            value = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Ditto.
 | 
				
			||||||
 | 
					    this(shared Allocator allocator)
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(allocator !is null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    body
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.allocator_ = allocator;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * $(D_PSYMBOL Scoped) is noncopyable.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @disable this(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Destroys the owned object.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ~this()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this.payload !is null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            allocator.dispose(this.payload);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Initialized this $(D_PARAM Scoped) and takes ownership over
 | 
				
			||||||
 | 
					     * $(D_PARAM rhs).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * To reset $(D_PSYMBOL Scoped) assign $(D_KEYWORD null).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * If the allocator wasn't set before, $(D_PSYMBOL defaultAllocator) will
 | 
				
			||||||
 | 
					     * be used. If you need a different allocator, create a new
 | 
				
			||||||
 | 
					     * $(D_PSYMBOL Scoped) and assign it.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Params:
 | 
				
			||||||
 | 
					     *  rhs = New object.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Returns: $(D_KEYWORD this).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ref typeof(this) opAssign()(auto ref Payload rhs)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        allocator.dispose(this.payload);
 | 
				
			||||||
 | 
					        move(rhs, this.payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Ditto.
 | 
				
			||||||
 | 
					    ref typeof(this) opAssign(typeof(null))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        allocator.dispose(this.payload);
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Ditto.
 | 
				
			||||||
 | 
					    ref typeof(this) opAssign(typeof(this) rhs)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        swap(this.allocator_, rhs.allocator_);
 | 
				
			||||||
 | 
					        swap(this.payload, rhs.payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns: Reference to the owned object.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    inout(Payload) get() inout pure nothrow @safe @nogc
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return payload;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    version (D_Ddoc)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Params:
 | 
				
			||||||
 | 
					         *  op = Operation. 
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Dereferences the pointer. It is defined only for pointers, not for
 | 
				
			||||||
 | 
					         * reference types like classes, that can be accessed directly.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Returns: Reference to the pointed value.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        ref T opUnary(string op)()
 | 
				
			||||||
 | 
					            if (op == "*");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else static if (isPointer!Payload)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ref T opUnary(string op)()
 | 
				
			||||||
 | 
					            if (op == "*")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return *payload;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mixin DefaultAllocator;
 | 
				
			||||||
 | 
					    alias get this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					@nogc unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto p = defaultAllocator.make!int(5);
 | 
				
			||||||
 | 
					    auto s = Scoped!int(p, defaultAllocator);
 | 
				
			||||||
 | 
					    assert(p is null);
 | 
				
			||||||
 | 
					    assert(*s == 5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					@nogc unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static bool destroyed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct F
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ~this() @nogc
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            destroyed = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto s = Scoped!F(defaultAllocator.make!F(), defaultAllocator);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(destroyed);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Constructs a new object of type $(D_PARAM T) and wraps it in a
 | 
				
			||||||
 | 
					 * $(D_PSYMBOL Scoped) using $(D_PARAM args) as the parameter list for
 | 
				
			||||||
 | 
					 * the constructor of $(D_PARAM T).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *  T         = Type of the constructed object.
 | 
				
			||||||
 | 
					 *  A         = Types of the arguments to the constructor of $(D_PARAM T).
 | 
				
			||||||
 | 
					 *  allocator = Allocator.
 | 
				
			||||||
 | 
					 *  args      = Constructor arguments of $(D_PARAM T).
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Returns: Newly created $(D_PSYMBOL Scoped!T).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Precondition: $(D_INLINECODE allocator !is null)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Scoped!T scoped(T, A...)(shared Allocator allocator, auto ref A args)
 | 
				
			||||||
 | 
					    if (!is(T == interface) && !isAbstractClass!T
 | 
				
			||||||
 | 
					     && !isAssociativeArray!T && !isArray!T)
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(allocator !is null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					body
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto payload = allocator.make!(T, shared Allocator, A)(args);
 | 
				
			||||||
 | 
					    return Scoped!T(payload, allocator);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Constructs a new array with $(D_PARAM size) elements and wraps it in a
 | 
				
			||||||
 | 
					 * $(D_PSYMBOL Scoped).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *  T         = Array type.
 | 
				
			||||||
 | 
					 *  size      = Array size.
 | 
				
			||||||
 | 
					 *  allocator = Allocator.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: Newly created $(D_PSYMBOL Scoped!T).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Precondition: $(D_INLINECODE allocator !is null
 | 
				
			||||||
 | 
					 *                           && size <= size_t.max / ElementType!T.sizeof)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Scoped!T scoped(T)(shared Allocator allocator, const size_t size)
 | 
				
			||||||
 | 
					@trusted
 | 
				
			||||||
 | 
					    if (isArray!T)
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(allocator !is null);
 | 
				
			||||||
 | 
					    assert(size <= size_t.max / ElementType!T.sizeof);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					body
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto payload = allocator.resize!(ElementType!T)(null, size);
 | 
				
			||||||
 | 
					    return Scoped!T(payload, allocator);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static assert(is(typeof(defaultAllocator.scoped!B(5))));
 | 
				
			||||||
 | 
					    static assert(is(typeof(defaultAllocator.scoped!(int[])(5))));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto s = defaultAllocator.scoped!int(5);
 | 
				
			||||||
 | 
					    assert(*s == 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = null;
 | 
				
			||||||
 | 
					    assert(s is null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto s = defaultAllocator.scoped!int(5);
 | 
				
			||||||
 | 
					    assert(*s == 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = defaultAllocator.scoped!int(4);
 | 
				
			||||||
 | 
					    assert(*s == 4);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user