Remove makeArray import
This commit is contained in:
parent
b90c56395c
commit
85380ac3fc
@ -15,53 +15,53 @@ module tanya.memory.allocator;
|
|||||||
*/
|
*/
|
||||||
interface Allocator
|
interface Allocator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns: Alignment offered.
|
* Returns: Alignment offered.
|
||||||
*/
|
*/
|
||||||
@property uint alignment() const shared pure nothrow @safe @nogc;
|
@property uint alignment() const shared pure nothrow @safe @nogc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates $(D_PARAM size) bytes of memory.
|
* Allocates $(D_PARAM size) bytes of memory.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* size = Amount of memory to allocate.
|
* size = Amount of memory to allocate.
|
||||||
*
|
*
|
||||||
* Returns: Pointer to the new allocated memory.
|
* Returns: Pointer to the new allocated memory.
|
||||||
*/
|
*/
|
||||||
void[] allocate(in size_t size) shared nothrow @nogc;
|
void[] allocate(in size_t size) shared nothrow @nogc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocates a memory block.
|
* Deallocates a memory block.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block to be freed.
|
* p = A pointer to the memory block to be freed.
|
||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* Returns: Whether the deallocation was successful.
|
||||||
*/
|
*/
|
||||||
bool deallocate(void[] p) shared nothrow @nogc;
|
bool deallocate(void[] p) shared nothrow @nogc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases or decreases the size of a memory block.
|
* Increases or decreases the size of a memory block.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block.
|
* p = A pointer to the memory block.
|
||||||
* size = Size of the reallocated block.
|
* size = Size of the reallocated block.
|
||||||
*
|
*
|
||||||
* Returns: Pointer to the allocated memory.
|
* Returns: Pointer to the allocated memory.
|
||||||
*/
|
*/
|
||||||
bool reallocate(ref void[] p, in size_t size) shared nothrow @nogc;
|
bool reallocate(ref void[] p, in size_t size) shared nothrow @nogc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reallocates a memory block in place if possible or returns
|
* Reallocates a memory block in place if possible or returns
|
||||||
* $(D_KEYWORD false). This function cannot be used to allocate or
|
* $(D_KEYWORD false). This function cannot be used to allocate or
|
||||||
* deallocate memory, so if $(D_PARAM p) is $(D_KEYWORD null) or
|
* deallocate memory, so if $(D_PARAM p) is $(D_KEYWORD null) or
|
||||||
* $(D_PARAM size) is `0`, it should return $(D_KEYWORD false).
|
* $(D_PARAM size) is `0`, it should return $(D_KEYWORD false).
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block.
|
* p = A pointer to the memory block.
|
||||||
* size = Size of the reallocated block.
|
* size = Size of the reallocated block.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
|
* Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
|
||||||
*/
|
*/
|
||||||
bool reallocateInPlace(ref void[] p, in size_t size) shared nothrow @nogc;
|
bool reallocateInPlace(ref void[] p, in size_t size) shared nothrow @nogc;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
module tanya.memory;
|
module tanya.memory;
|
||||||
|
|
||||||
import core.exception;
|
import core.exception;
|
||||||
public import std.experimental.allocator : make, makeArray;
|
public import std.experimental.allocator : make;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
public import tanya.memory.allocator;
|
public import tanya.memory.allocator;
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright: Eugene Wissner 2016.
|
* Copyright: Eugene Wissner 2016-2017.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
*/
|
*/
|
||||||
module tanya.memory.types;
|
module tanya.memory.types;
|
||||||
|
|
||||||
@ -23,345 +23,345 @@ import tanya.memory;
|
|||||||
* when the reference count goes down to zero, frees the underlying store.
|
* when the reference count goes down to zero, frees the underlying store.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Type of the reference-counted value.
|
* T = Type of the reference-counted value.
|
||||||
*/
|
*/
|
||||||
struct RefCounted(T)
|
struct RefCounted(T)
|
||||||
{
|
{
|
||||||
static if (is(T == class) || is(T == interface))
|
static if (is(T == class) || is(T == interface))
|
||||||
{
|
{
|
||||||
private alias Payload = T;
|
private alias Payload = T;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
private alias Payload = T*;
|
private alias Payload = T*;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Storage
|
private class Storage
|
||||||
{
|
{
|
||||||
private Payload payload;
|
private Payload payload;
|
||||||
private size_t counter = 1;
|
private size_t counter = 1;
|
||||||
|
|
||||||
private final size_t opUnary(string op)() pure nothrow @safe @nogc
|
private final size_t opUnary(string op)() pure nothrow @safe @nogc
|
||||||
if (op == "--" || op == "++")
|
if (op == "--" || op == "++")
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(counter > 0);
|
assert(counter > 0);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
mixin("return " ~ op ~ "counter;");
|
mixin("return " ~ op ~ "counter;");
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int opCmp(size_t counter) const pure nothrow @safe @nogc
|
private final int opCmp(size_t counter) const pure nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
if (this.counter > counter)
|
if (this.counter > counter)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (this.counter < counter)
|
else if (this.counter < counter)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int opEquals(size_t counter) const pure nothrow @safe @nogc
|
private final int opEquals(size_t counter) const pure nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
return this.counter == counter;
|
return this.counter == counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class RefCountedStorage : Storage
|
private final class RefCountedStorage : Storage
|
||||||
{
|
{
|
||||||
private shared Allocator allocator;
|
private shared Allocator allocator;
|
||||||
|
|
||||||
this(shared Allocator allocator) pure nothrow @safe @nogc
|
this(shared Allocator allocator) pure nothrow @safe @nogc
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
~this() nothrow @nogc
|
~this() nothrow @nogc
|
||||||
{
|
{
|
||||||
allocator.dispose(payload);
|
allocator.dispose(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Storage storage;
|
private Storage storage;
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
{
|
{
|
||||||
assert(storage is null || allocator_ !is null);
|
assert(storage is null || allocator_ !is null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes ownership over $(D_PARAM value), setting the counter to 1.
|
* Takes ownership over $(D_PARAM value), setting the counter to 1.
|
||||||
* $(D_PARAM value) may be a pointer, an object or a dynamic array.
|
* $(D_PARAM value) may be a pointer, an object or a dynamic array.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* value = Value whose ownership is taken over.
|
* value = Value whose ownership is taken over.
|
||||||
* allocator = Allocator used to destroy the $(D_PARAM value) and to
|
* allocator = Allocator used to destroy the $(D_PARAM value) and to
|
||||||
* allocate/deallocate internal storage.
|
* allocate/deallocate internal storage.
|
||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE allocator !is null)
|
* Precondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
this(Payload value, shared Allocator allocator = defaultAllocator)
|
this(Payload value, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
storage = allocator.make!RefCountedStorage(allocator);
|
storage = allocator.make!RefCountedStorage(allocator);
|
||||||
move(value, storage.payload);
|
move(value, storage.payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
this.allocator_ = allocator;
|
this.allocator_ = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases the reference counter by one.
|
* Increases the reference counter by one.
|
||||||
*/
|
*/
|
||||||
this(this)
|
this(this)
|
||||||
{
|
{
|
||||||
if (count != 0)
|
if (count != 0)
|
||||||
{
|
{
|
||||||
++storage;
|
++storage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decreases the reference counter by one.
|
* Decreases the reference counter by one.
|
||||||
*
|
*
|
||||||
* If the counter reaches 0, destroys the owned object.
|
* If the counter reaches 0, destroys the owned object.
|
||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
if (storage !is null && !(storage.counter && --storage))
|
if (storage !is null && !(storage.counter && --storage))
|
||||||
{
|
{
|
||||||
allocator_.dispose(storage);
|
allocator_.dispose(storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes ownership over $(D_PARAM rhs). Initializes this
|
* Takes ownership over $(D_PARAM rhs). Initializes this
|
||||||
* $(D_PSYMBOL RefCounted) if needed.
|
* $(D_PSYMBOL RefCounted) if needed.
|
||||||
*
|
*
|
||||||
* 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 the $(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 = $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref typeof(this) opAssign(Payload rhs)
|
ref typeof(this) opAssign(Payload rhs)
|
||||||
{
|
{
|
||||||
if (storage is null)
|
if (storage is null)
|
||||||
{
|
{
|
||||||
storage = allocator.make!RefCountedStorage(allocator);
|
storage = allocator.make!RefCountedStorage(allocator);
|
||||||
}
|
}
|
||||||
else if (storage > 1)
|
else if (storage > 1)
|
||||||
{
|
{
|
||||||
--storage;
|
--storage;
|
||||||
storage = allocator.make!RefCountedStorage(allocator);
|
storage = allocator.make!RefCountedStorage(allocator);
|
||||||
}
|
}
|
||||||
else if (cast(RefCountedStorage) storage is null)
|
else if (cast(RefCountedStorage) storage is null)
|
||||||
{
|
{
|
||||||
// Created with refCounted. Always destroyed togethter with the pointer.
|
// Created with refCounted. Always destroyed togethter with the pointer.
|
||||||
assert(storage.counter != 0);
|
assert(storage.counter != 0);
|
||||||
allocator.dispose(storage);
|
allocator.dispose(storage);
|
||||||
storage = allocator.make!RefCountedStorage(allocator);
|
storage = allocator.make!RefCountedStorage(allocator);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
allocator.dispose(storage.payload);
|
allocator.dispose(storage.payload);
|
||||||
}
|
}
|
||||||
move(rhs, storage.payload);
|
move(rhs, storage.payload);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
ref typeof(this) opAssign(typeof(null))
|
ref typeof(this) opAssign(typeof(null))
|
||||||
{
|
{
|
||||||
if (storage is null)
|
if (storage is null)
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
else if (storage > 1)
|
else if (storage > 1)
|
||||||
{
|
{
|
||||||
--storage;
|
--storage;
|
||||||
storage = null;
|
storage = null;
|
||||||
}
|
}
|
||||||
else if (cast(RefCountedStorage) storage is null)
|
else if (cast(RefCountedStorage) storage is null)
|
||||||
{
|
{
|
||||||
// Created with refCounted. Always destroyed togethter with the pointer.
|
// Created with refCounted. Always destroyed togethter with the pointer.
|
||||||
assert(storage.counter != 0);
|
assert(storage.counter != 0);
|
||||||
allocator.dispose(storage);
|
allocator.dispose(storage);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
allocator.dispose(storage.payload);
|
allocator.dispose(storage.payload);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
ref typeof(this) opAssign(typeof(this) rhs)
|
ref typeof(this) opAssign(typeof(this) rhs)
|
||||||
{
|
{
|
||||||
swap(allocator_, rhs.allocator_);
|
swap(allocator_, rhs.allocator_);
|
||||||
swap(storage, rhs.storage);
|
swap(storage, rhs.storage);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Reference to the owned object.
|
* Returns: Reference to the owned object.
|
||||||
*/
|
*/
|
||||||
inout(Payload) get() inout pure nothrow @safe @nogc
|
inout(Payload) get() inout pure nothrow @safe @nogc
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(count > 0, "Attempted to access an uninitialized reference.");
|
assert(count > 0, "Attempted to access an uninitialized reference.");
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
return storage.payload;
|
return storage.payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (isPointer!Payload)
|
static if (isPointer!Payload)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* op = Operation.
|
* op = Operation.
|
||||||
*
|
*
|
||||||
* Dereferences the pointer. It is defined only for pointers, not for
|
* Dereferences the pointer. It is defined only for pointers, not for
|
||||||
* reference types like classes, that can be accessed directly.
|
* reference types like classes, that can be accessed directly.
|
||||||
*
|
*
|
||||||
* Returns: Reference to the pointed value.
|
* Returns: Reference to the pointed value.
|
||||||
*/
|
*/
|
||||||
ref T opUnary(string op)()
|
ref T opUnary(string op)()
|
||||||
if (op == "*")
|
if (op == "*")
|
||||||
{
|
{
|
||||||
return *storage.payload;
|
return *storage.payload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Whether this $(D_PSYMBOL RefCounted) already has an internal
|
* Returns: Whether this $(D_PSYMBOL RefCounted) already has an internal
|
||||||
* storage.
|
* storage.
|
||||||
*/
|
*/
|
||||||
@property bool isInitialized() const
|
@property bool isInitialized() const
|
||||||
{
|
{
|
||||||
return storage !is null;
|
return storage !is null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: The number of $(D_PSYMBOL RefCounted) instances that share
|
* Returns: The number of $(D_PSYMBOL RefCounted) instances that share
|
||||||
* ownership over the same pointer (including $(D_KEYWORD this)).
|
* ownership over the same pointer (including $(D_KEYWORD this)).
|
||||||
* If this $(D_PSYMBOL RefCounted) isn't initialized, returns `0`.
|
* If this $(D_PSYMBOL RefCounted) isn't initialized, returns `0`.
|
||||||
*/
|
*/
|
||||||
@property size_t count() const
|
@property size_t count() const
|
||||||
{
|
{
|
||||||
return storage is null ? 0 : storage.counter;
|
return storage is null ? 0 : storage.counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin DefaultAllocator;
|
mixin DefaultAllocator;
|
||||||
alias get this;
|
alias get this;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator);
|
auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator);
|
||||||
auto val = rc.get;
|
auto val = rc.get;
|
||||||
|
|
||||||
*val = 8;
|
*val = 8;
|
||||||
assert(*rc.storage.payload == 8);
|
assert(*rc.storage.payload == 8);
|
||||||
|
|
||||||
val = null;
|
val = null;
|
||||||
assert(rc.storage.payload !is null);
|
assert(rc.storage.payload !is null);
|
||||||
assert(*rc.storage.payload == 8);
|
assert(*rc.storage.payload == 8);
|
||||||
|
|
||||||
*rc = 9;
|
*rc = 9;
|
||||||
assert(*rc.storage.payload == 9);
|
assert(*rc.storage.payload == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
private class A
|
private class A
|
||||||
{
|
{
|
||||||
uint *destroyed;
|
uint *destroyed;
|
||||||
|
|
||||||
this(ref uint destroyed) @nogc
|
this(ref uint destroyed) @nogc
|
||||||
{
|
{
|
||||||
this.destroyed = &destroyed;
|
this.destroyed = &destroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
~this() @nogc
|
~this() @nogc
|
||||||
{
|
{
|
||||||
++(*destroyed);
|
++(*destroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct B
|
private struct B
|
||||||
{
|
{
|
||||||
int prop;
|
int prop;
|
||||||
@disable this();
|
@disable this();
|
||||||
this(int param1) @nogc
|
this(int param1) @nogc
|
||||||
{
|
{
|
||||||
prop = param1;
|
prop = param1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unittest
|
private unittest
|
||||||
{
|
{
|
||||||
uint destroyed;
|
uint destroyed;
|
||||||
auto a = defaultAllocator.make!A(destroyed);
|
auto a = defaultAllocator.make!A(destroyed);
|
||||||
|
|
||||||
assert(destroyed == 0);
|
assert(destroyed == 0);
|
||||||
{
|
{
|
||||||
auto rc = RefCounted!A(a, defaultAllocator);
|
auto rc = RefCounted!A(a, defaultAllocator);
|
||||||
assert(rc.count == 1);
|
assert(rc.count == 1);
|
||||||
|
|
||||||
void func(RefCounted!A rc)
|
void func(RefCounted!A rc)
|
||||||
{
|
{
|
||||||
assert(rc.count == 2);
|
assert(rc.count == 2);
|
||||||
}
|
}
|
||||||
func(rc);
|
func(rc);
|
||||||
|
|
||||||
assert(rc.count == 1);
|
assert(rc.count == 1);
|
||||||
}
|
}
|
||||||
assert(destroyed == 1);
|
assert(destroyed == 1);
|
||||||
|
|
||||||
RefCounted!int rc;
|
RefCounted!int rc;
|
||||||
assert(rc.count == 0);
|
assert(rc.count == 0);
|
||||||
rc = defaultAllocator.make!int(8);
|
rc = defaultAllocator.make!int(8);
|
||||||
assert(rc.count == 1);
|
assert(rc.count == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unittest
|
private unittest
|
||||||
{
|
{
|
||||||
static assert(is(typeof(RefCounted!int.storage.payload) == int*));
|
static assert(is(typeof(RefCounted!int.storage.payload) == int*));
|
||||||
static assert(is(typeof(RefCounted!A.storage.payload) == A));
|
static assert(is(typeof(RefCounted!A.storage.payload) == A));
|
||||||
|
|
||||||
static assert(is(RefCounted!B));
|
static assert(is(RefCounted!B));
|
||||||
static assert(is(RefCounted!A));
|
static assert(is(RefCounted!A));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,85 +374,85 @@ private unittest
|
|||||||
* object).
|
* object).
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Type of the constructed object.
|
* T = Type of the constructed object.
|
||||||
* A = Types of the arguments to the constructor of $(D_PARAM T).
|
* A = Types of the arguments to the constructor of $(D_PARAM T).
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
* args = Constructor arguments of $(D_PARAM T).
|
* args = Constructor arguments of $(D_PARAM T).
|
||||||
*
|
*
|
||||||
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
||||||
*/
|
*/
|
||||||
RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
|
RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
|
||||||
if (!is(T == interface) && !isAbstractClass!T
|
if (!is(T == interface) && !isAbstractClass!T
|
||||||
&& !isArray!T && !isAssociativeArray!T)
|
&& !isArray!T && !isAssociativeArray!T)
|
||||||
{
|
{
|
||||||
auto rc = typeof(return)(allocator);
|
auto rc = typeof(return)(allocator);
|
||||||
|
|
||||||
immutable storageSize = alignedSize(stateSize!(RefCounted!T.Storage));
|
immutable storageSize = alignedSize(stateSize!(RefCounted!T.Storage));
|
||||||
immutable size = alignedSize(stateSize!T + storageSize);
|
immutable size = alignedSize(stateSize!T + storageSize);
|
||||||
|
|
||||||
auto mem = (() @trusted => allocator.allocate(size))();
|
auto mem = (() @trusted => allocator.allocate(size))();
|
||||||
if (mem is null)
|
if (mem is null)
|
||||||
{
|
{
|
||||||
onOutOfMemoryError();
|
onOutOfMemoryError();
|
||||||
}
|
}
|
||||||
scope (failure)
|
scope (failure)
|
||||||
{
|
{
|
||||||
() @trusted { allocator.deallocate(mem); }();
|
() @trusted { allocator.deallocate(mem); }();
|
||||||
}
|
}
|
||||||
rc.storage = emplace!(RefCounted!T.Storage)(mem[0 .. storageSize]);
|
rc.storage = emplace!(RefCounted!T.Storage)(mem[0 .. storageSize]);
|
||||||
|
|
||||||
static if (is(T == class))
|
static if (is(T == class))
|
||||||
{
|
{
|
||||||
rc.storage.payload = emplace!T(mem[storageSize .. $], args);
|
rc.storage.payload = emplace!T(mem[storageSize .. $], args);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto ptr = (() @trusted => (cast(T*) mem[storageSize .. $].ptr))();
|
auto ptr = (() @trusted => (cast(T*) mem[storageSize .. $].ptr))();
|
||||||
rc.storage.payload = emplace!T(ptr, args);
|
rc.storage.payload = emplace!T(ptr, args);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto rc = defaultAllocator.refCounted!int(5);
|
auto rc = defaultAllocator.refCounted!int(5);
|
||||||
assert(rc.count == 1);
|
assert(rc.count == 1);
|
||||||
|
|
||||||
void func(RefCounted!int param)
|
void func(RefCounted!int param)
|
||||||
{
|
{
|
||||||
if (param.count == 2)
|
if (param.count == 2)
|
||||||
{
|
{
|
||||||
func(param);
|
func(param);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(param.count == 3);
|
assert(param.count == 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func(rc);
|
func(rc);
|
||||||
|
|
||||||
assert(rc.count == 1);
|
assert(rc.count == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @nogc unittest
|
private @nogc unittest
|
||||||
{
|
{
|
||||||
struct E
|
struct E
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
auto b = defaultAllocator.refCounted!B(15);
|
auto b = defaultAllocator.refCounted!B(15);
|
||||||
static assert(is(typeof(b.storage.payload) == B*));
|
static assert(is(typeof(b.storage.payload) == B*));
|
||||||
static assert(is(typeof(b.prop) == int));
|
static assert(is(typeof(b.prop) == int));
|
||||||
static assert(!is(typeof(defaultAllocator.refCounted!B())));
|
static assert(!is(typeof(defaultAllocator.refCounted!B())));
|
||||||
|
|
||||||
static assert(is(typeof(defaultAllocator.refCounted!E())));
|
static assert(is(typeof(defaultAllocator.refCounted!E())));
|
||||||
static assert(!is(typeof(defaultAllocator.refCounted!E(5))));
|
static assert(!is(typeof(defaultAllocator.refCounted!E(5))));
|
||||||
{
|
{
|
||||||
auto rc = defaultAllocator.refCounted!B(3);
|
auto rc = defaultAllocator.refCounted!B(3);
|
||||||
assert(rc.get.prop == 3);
|
assert(rc.get.prop == 3);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto rc = defaultAllocator.refCounted!E();
|
auto rc = defaultAllocator.refCounted!E();
|
||||||
assert(rc.count);
|
assert(rc.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user