Remove makeArray import

This commit is contained in:
Eugen Wissner 2017-03-19 06:54:59 +01:00
parent b90c56395c
commit 85380ac3fc
3 changed files with 395 additions and 395 deletions

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);
} }
} }