summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/tanya/algorithm/iteration.d2
-rw-r--r--source/tanya/algorithm/mutation.d289
-rw-r--r--source/tanya/container/array.d1
-rw-r--r--source/tanya/container/entry.d2
-rw-r--r--source/tanya/container/list.d1
-rw-r--r--source/tanya/conv.d271
-rw-r--r--source/tanya/functional.d68
-rw-r--r--source/tanya/memory/allocator.d81
-rw-r--r--source/tanya/memory/lifecycle.d360
-rw-r--r--source/tanya/memory/mallocator.d233
-rw-r--r--source/tanya/memory/mmappool.d657
-rw-r--r--source/tanya/memory/op.d437
-rw-r--r--source/tanya/memory/package.d203
-rw-r--r--source/tanya/memory/smartref.d914
-rw-r--r--source/tanya/net/ip.d1
-rw-r--r--source/tanya/range/adapter.d2
-rw-r--r--source/tanya/range/primitive.d2
-rw-r--r--source/tanya/test/assertion.d105
-rw-r--r--source/tanya/test/package.d18
-rw-r--r--source/tanya/test/stub.d373
-rw-r--r--source/tanya/typecons.d4
21 files changed, 23 insertions, 4001 deletions
diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d
index 7eae9cd..fcfb1c0 100644
--- a/source/tanya/algorithm/iteration.d
+++ b/source/tanya/algorithm/iteration.d
@@ -21,7 +21,7 @@
module tanya.algorithm.iteration;
import tanya.algorithm.comparison;
-import tanya.algorithm.mutation;
+import tanya.memory.lifecycle;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range;
diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d
index f0c156d..ddb2743 100644
--- a/source/tanya/algorithm/mutation.d
+++ b/source/tanya/algorithm/mutation.d
@@ -14,284 +14,21 @@
*/
module tanya.algorithm.mutation;
-import tanya.conv;
static import tanya.memory.op;
+static import tanya.memory.lifecycle;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range;
version (unittest) import tanya.test.stub;
-private void deinitialize(bool zero, T)(ref T value)
-{
- static if (is(T == U[S], U, size_t S))
- {
- foreach (ref e; value)
- {
- deinitialize!zero(e);
- }
- }
- else
- {
- static if (isNested!T)
- {
- // Don't override the context pointer.
- enum size_t size = T.sizeof - (void*).sizeof;
- }
- else
- {
- enum size_t size = T.sizeof;
- }
- static if (zero)
- {
- tanya.memory.op.fill!0((cast(void*) &value)[0 .. size]);
- }
- else
- {
- tanya.memory.op.copy(typeid(T).initializer()[0 .. size],
- (&value)[0 .. 1]);
- }
- }
-}
-
-/**
- * Moves $(D_PARAM source) into $(D_PARAM target) assuming that
- * $(D_PARAM target) isn't initialized.
- *
- * Moving the $(D_PARAM source) copies it into the $(D_PARAM target) and places
- * the $(D_PARAM source) into a valid but unspecified state, which means that
- * after moving $(D_PARAM source) can be destroyed or assigned a new value, but
- * accessing it yields an unspecified value. No postblits or destructors are
- * called. If the $(D_PARAM target) should be destroyed before, use
- * $(D_PSYMBOL move).
- *
- * $(D_PARAM source) and $(D_PARAM target) must be different objects.
- *
- * Params:
- * T = Object type.
- * source = Source object.
- * target = Target object.
- *
- * See_Also: $(D_PSYMBOL move),
- * $(D_PSYMBOL hasElaborateCopyConstructor),
- * $(D_PSYMBOL hasElaborateDestructor).
- *
- * Precondition: `&source !is &target`.
- */
-void moveEmplace(T)(ref T source, ref T target) @system
-in
-{
- assert(&source !is &target, "Source and target must be different");
-}
-do
-{
- static if (is(T == struct) || isStaticArray!T)
- {
- tanya.memory.op.copy((&source)[0 .. 1], (&target)[0 .. 1]);
-
- static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T)
- {
- static if (__VERSION__ >= 2083) // __traits(isZeroInit) available.
- {
- deinitialize!(__traits(isZeroInit, T))(source);
- }
- else
- {
- if (typeid(T).initializer().ptr is null)
- {
- deinitialize!true(source);
- }
- else
- {
- deinitialize!false(source);
- }
- }
- }
- }
- else
- {
- target = source;
- }
-}
-
-///
-@nogc nothrow pure @system unittest
-{
- static struct S
- {
- int member = 5;
-
- this(this) @nogc nothrow pure @safe
- {
- assert(false);
- }
- }
- S source, target = void;
- moveEmplace(source, target);
- assert(target.member == 5);
+deprecated("Use tanya.memory.lifecycle.swap instead")
+alias swap = tanya.memory.lifecycle.swap;
- int x1 = 5, x2;
- moveEmplace(x1, x2);
- assert(x2 == 5);
-}
+deprecated("Use tanya.memory.lifecycle.moveEmplace instead")
+alias moveEmplace = tanya.memory.lifecycle.moveEmplace;
-// Is pure.
-@nogc nothrow pure @system unittest
-{
- struct S
- {
- this(this)
- {
- }
- }
- S source, target = void;
- static assert(is(typeof({ moveEmplace(source, target); })));
-}
-
-// Moves nested.
-@nogc nothrow pure @system unittest
-{
- struct Nested
- {
- void method() @nogc nothrow pure @safe
- {
- }
- }
- Nested source, target = void;
- moveEmplace(source, target);
- assert(source == target);
-}
-
-// Emplaces static arrays.
-@nogc nothrow pure @system unittest
-{
- static struct S
- {
- size_t member;
- this(size_t i) @nogc nothrow pure @safe
- {
- this.member = i;
- }
- ~this() @nogc nothrow pure @safe
- {
- }
- }
- S[2] source = [ S(5), S(5) ], target = void;
- moveEmplace(source, target);
- assert(source[0].member == 0);
- assert(target[0].member == 5);
- assert(source[1].member == 0);
- assert(target[1].member == 5);
-}
-
-/**
- * Moves $(D_PARAM source) into $(D_PARAM target) assuming that
- * $(D_PARAM target) isn't initialized.
- *
- * Moving the $(D_PARAM source) copies it into the $(D_PARAM target) and places
- * the $(D_PARAM source) into a valid but unspecified state, which means that
- * after moving $(D_PARAM source) can be destroyed or assigned a new value, but
- * accessing it yields an unspecified value. $(D_PARAM target) is destroyed before
- * the new value is assigned. If $(D_PARAM target) isn't initialized and
- * therefore shouldn't be destroyed, $(D_PSYMBOL moveEmplace) can be used.
- *
- * If $(D_PARAM target) isn't specified, $(D_PSYMBOL move) returns the source
- * as rvalue without calling its copy constructor or destructor.
- *
- * $(D_PARAM source) and $(D_PARAM target) are the same object,
- * $(D_PSYMBOL move) does nothing.
- *
- * Params:
- * T = Object type.
- * source = Source object.
- * target = Target object.
- *
- * See_Also: $(D_PSYMBOL moveEmplace).
- */
-void move(T)(ref T source, ref T target)
-{
- if ((() @trusted => &source is &target)())
- {
- return;
- }
- static if (hasElaborateDestructor!T)
- {
- target.__xdtor();
- }
- (() @trusted => moveEmplace(source, target))();
-}
-
-/// ditto
-T move(T)(ref T source) @trusted
-{
- static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T)
- {
- T target = void;
- moveEmplace(source, target);
- return target;
- }
- else
- {
- return source;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct S
- {
- int member = 5;
-
- this(this) @nogc nothrow pure @safe
- {
- assert(false);
- }
- }
- S source, target = void;
- move(source, target);
- assert(target.member == 5);
- assert(move(target).member == 5);
-
- int x1 = 5, x2;
- move(x1, x2);
- assert(x2 == 5);
- assert(move(x2) == 5);
-}
-
-// Moves if source is target.
-@nogc nothrow pure @safe unittest
-{
- int x = 5;
- move(x, x);
- assert(x == 5);
-}
-
-/**
- * Exchanges the values of $(D_PARAM a) and $(D_PARAM b).
- *
- * $(D_PSYMBOL swap) moves the contents of $(D_PARAM a) and $(D_PARAM b)
- * without calling its postblits or destructors.
- *
- * Params:
- * a = The first object.
- * b = The second object.
- */
-void swap(T)(ref T a, ref T b) @trusted
-{
- T tmp = void;
- moveEmplace(a, tmp);
- moveEmplace(b, a);
- moveEmplace(tmp, b);
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int a = 3, b = 5;
- swap(a, b);
- assert(a == 5);
- assert(b == 3);
-}
+deprecated("Use tanya.memory.lifecycle.move instead")
+alias move = tanya.memory.lifecycle.move;
/**
* Copies the $(D_PARAM source) range into the $(D_PARAM target) range.
@@ -494,7 +231,7 @@ if (isInputRange!Range && hasLvalueElements!Range
for (; !range.empty; range.popFront())
{
ElementType!Range* p = &range.front;
- emplace!(ElementType!Range)(cast(void[]) (p[0 .. 1]), value);
+ tanya.memory.lifecycle.emplace!(ElementType!Range)(cast(void[]) (p[0 .. 1]), value);
}
}
else
@@ -577,13 +314,7 @@ if (isInputRange!Range && hasLvalueElements!Range)
void destroyAll(Range)(Range range)
if (isInputRange!Range && hasLvalueElements!Range)
{
- static if (hasElaborateDestructor!(ElementType!Range))
- {
- foreach (ref e; range)
- {
- destroy(e);
- }
- }
+ tanya.memory.lifecycle.destroyAllImpl!(Range, ElementType!Range)(range);
}
///
@@ -632,7 +363,7 @@ if (isForwardRange!Range && hasSwappableElements!Range)
while (!front.empty && !next.empty && !sameHead(front, next))
{
- swap(front.front, next.front);
+ tanya.memory.lifecycle.swap(front.front, next.front);
front.popFront();
next.popFront();
diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d
index 2b3adfa..1c6842f 100644
--- a/source/tanya/container/array.d
+++ b/source/tanya/container/array.d
@@ -17,7 +17,6 @@ module tanya.container.array;
import core.checkedint;
import tanya.algorithm.comparison;
import tanya.algorithm.mutation;
-import tanya.functional;
import tanya.memory;
import tanya.meta.trait;
import tanya.meta.transform;
diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d
index 1e7e28f..408849a 100644
--- a/source/tanya/container/entry.d
+++ b/source/tanya/container/entry.d
@@ -14,9 +14,9 @@
*/
module tanya.container.entry;
-import tanya.algorithm.mutation;
import tanya.container.array;
import tanya.memory.allocator;
+import tanya.memory.lifecycle;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.typecons;
diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d
index 09a5c9f..e6e01d5 100644
--- a/source/tanya/container/list.d
+++ b/source/tanya/container/list.d
@@ -16,7 +16,6 @@
module tanya.container.list;
import tanya.algorithm.comparison;
-import tanya.algorithm.mutation;
import tanya.container.entry;
import tanya.memory;
import tanya.meta.trait;
diff --git a/source/tanya/conv.d b/source/tanya/conv.d
index a78c2bb..f602e01 100644
--- a/source/tanya/conv.d
+++ b/source/tanya/conv.d
@@ -14,15 +14,13 @@
*/
module tanya.conv;
-import tanya.algorithm.mutation;
import tanya.container.string;
-import tanya.format;
import tanya.memory;
-import tanya.memory.op;
+deprecated("Use tanya.memory.lifecycle.emplace instead")
+public import tanya.memory.lifecycle : emplace;
import tanya.meta.trait;
import tanya.meta.transform;
-import tanya.range.array;
-import tanya.range.primitive;
+import tanya.range;
version (unittest)
{
@@ -31,269 +29,6 @@ version (unittest)
}
/**
- * Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the
- * given arguments.
- *
- * If $(D_PARAM T) is a $(D_KEYWORD class), emplace returns a class reference
- * of type $(D_PARAM T), otherwise a pointer to the constructed object is
- * returned.
- *
- * If $(D_PARAM T) is a nested class inside another class, $(D_PARAM outer)
- * should be an instance of the outer class.
- *
- * $(D_PARAM args) are arguments for the constructor of $(D_PARAM T). If
- * $(D_PARAM T) isn't an aggregate type and doesn't have a constructor,
- * $(D_PARAM memory) can be initialized to `args[0]` if `Args.length == 1`,
- * `Args[0]` should be implicitly convertible to $(D_PARAM T) then.
- *
- * Params:
- * T = Constructed type.
- * U = Type of the outer class if $(D_PARAM T) is a nested class.
- * Args = Types of the constructor arguments if $(D_PARAM T) has a constructor
- * or the type of the initial value.
- * outer = Outer class instance if $(D_PARAM T) is a nested class.
- * args = Constructor arguments if $(D_PARAM T) has a constructor or the
- * initial value.
- *
- * Returns: New instance of type $(D_PARAM T) constructed in $(D_PARAM memory).
- *
- * Precondition: `memory.length == stateSize!T`.
- * Postcondition: $(D_PARAM memory) and the result point to the same memory.
- */
-T emplace(T, U, Args...)(void[] memory, U outer, auto ref Args args)
-if (!isAbstractClass!T && isInnerClass!T && is(typeof(T.outer) == U))
-in (memory.length >= stateSize!T)
-out (result; memory.ptr is (() @trusted => cast(void*) result)())
-{
- copy(typeid(T).initializer, memory);
-
- auto result = (() @trusted => cast(T) memory.ptr)();
- result.outer = outer;
-
- static if (is(typeof(result.__ctor(args))))
- {
- result.__ctor(args);
- }
-
- return result;
-}
-
-/// ditto
-T emplace(T, Args...)(void[] memory, auto ref Args args)
-if (is(T == class) && !isAbstractClass!T && !isInnerClass!T)
-in (memory.length == stateSize!T)
-out (result; memory.ptr is (() @trusted => cast(void*) result)())
-{
- copy(typeid(T).initializer, memory);
-
- auto result = (() @trusted => cast(T) memory.ptr)();
- static if (is(typeof(result.__ctor(args))))
- {
- result.__ctor(args);
- }
- return result;
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- import tanya.memory : stateSize;
-
- class C
- {
- int i = 5;
- class Inner
- {
- int i;
-
- this(int param) pure nothrow @safe @nogc
- {
- this.i = param;
- }
- }
- }
- ubyte[stateSize!C] memory1;
- ubyte[stateSize!(C.Inner)] memory2;
-
- auto c = emplace!C(memory1);
- assert(c.i == 5);
-
- auto inner = emplace!(C.Inner)(memory2, c, 8);
- assert(c.i == 5);
- assert(inner.i == 8);
- assert(inner.outer is c);
-}
-
-/// ditto
-T* emplace(T, Args...)(void[] memory, auto ref Args args)
-if (!isAggregateType!T && (Args.length <= 1))
-in (memory.length >= T.sizeof)
-out (result; memory.ptr is result)
-{
- auto result = (() @trusted => cast(T*) memory.ptr)();
- static if (Args.length == 1)
- {
- *result = T(args[0]);
- }
- else
- {
- *result = T.init;
- }
- return result;
-}
-
-private void initializeOne(T)(ref void[] memory, ref T* result) @trusted
-{
- static if (!hasElaborateAssign!T && isAssignable!T)
- {
- *result = T.init;
- }
- else static if (__VERSION__ >= 2083 // __traits(isZeroInit) available.
- && __traits(isZeroInit, T))
- {
- memory.ptr[0 .. T.sizeof].fill!0;
- }
- else
- {
- static immutable T init = T.init;
- copy((&init)[0 .. 1], memory);
- }
-}
-
-/// ditto
-T* emplace(T, Args...)(void[] memory, auto ref Args args)
-if (!isPolymorphicType!T && isAggregateType!T)
-in (memory.length >= T.sizeof)
-out (result; memory.ptr is result)
-{
- auto result = (() @trusted => cast(T*) memory.ptr)();
-
- static if (Args.length == 0)
- {
- static assert(is(typeof({ static T t; })),
- "Default constructor is disabled");
- initializeOne(memory, result);
- }
- else static if (is(typeof(result.__ctor(args))))
- {
- initializeOne(memory, result);
- result.__ctor(args);
- }
- else static if (Args.length == 1 && is(typeof({ T t = args[0]; })))
- {
- ((ref arg) @trusted =>
- copy((cast(void*) &arg)[0 .. T.sizeof], memory))(args[0]);
- static if (hasElaborateCopyConstructor!T)
- {
- result.__postblit();
- }
- }
- else static if (is(typeof({ T t = T(args); })))
- {
- auto init = T(args);
- (() @trusted => moveEmplace(init, *result))();
- }
- else
- {
- static assert(false,
- "Unable to construct value with the given arguments");
- }
- return result;
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- ubyte[4] memory;
-
- auto i = emplace!int(memory);
- static assert(is(typeof(i) == int*));
- assert(*i == 0);
-
- i = emplace!int(memory, 5);
- assert(*i == 5);
-
- static struct S
- {
- int i;
- @disable this();
- @disable this(this);
- this(int i) @nogc nothrow pure @safe
- {
- this.i = i;
- }
- }
- auto s = emplace!S(memory, 8);
- static assert(is(typeof(s) == S*));
- assert(s.i == 8);
-}
-
-// Handles "Cannot access frame pointer" error.
-@nogc nothrow pure @safe unittest
-{
- struct F
- {
- ~this() @nogc nothrow pure @safe
- {
- }
- }
- static assert(is(typeof(emplace!F((void[]).init))));
-}
-
-// Can emplace structs without a constructor
-@nogc nothrow pure @safe unittest
-{
- static assert(is(typeof(emplace!WithDtor(null, WithDtor()))));
- static assert(is(typeof(emplace!WithDtor(null))));
-}
-
-// Doesn't call a destructor on uninitialized elements
-@nogc nothrow pure @system unittest
-{
- static struct SWithDtor
- {
- private bool canBeInvoked = false;
- ~this() @nogc nothrow pure @safe
- {
- assert(this.canBeInvoked);
- }
- }
- void[SWithDtor.sizeof] memory = void;
- auto actual = emplace!SWithDtor(memory[], SWithDtor(true));
- assert(actual.canBeInvoked);
-}
-
-// Initializes structs if no arguments are given
-@nogc nothrow pure @safe unittest
-{
- static struct SEntry
- {
- byte content;
- }
- ubyte[1] mem = [3];
-
- assert(emplace!SEntry(cast(void[]) mem[0 .. 1]).content == 0);
-}
-
-// Postblit is called when emplacing a struct
-@nogc nothrow pure @system unittest
-{
- static struct S
- {
- bool called = false;
- this(this) @nogc nothrow pure @safe
- {
- this.called = true;
- }
- }
- S target;
- S* sp = &target;
-
- emplace!S(sp[0 .. 1], S());
- assert(target.called);
-}
-
-/**
* Thrown if a type conversion fails.
*/
final class ConvException : Exception
diff --git a/source/tanya/functional.d b/source/tanya/functional.d
index f628a51..9a1c3a1 100644
--- a/source/tanya/functional.d
+++ b/source/tanya/functional.d
@@ -2,77 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-/**
+/*
* Functions that manipulate other functions and their argument lists.
*
- * Copyright: Eugene Wissner 2018.
+ * Copyright: Eugene Wissner 2018-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/functional.d,
* tanya/functional.d)
*/
+deprecated("Use tanya.memory.lifecycle instead")
module tanya.functional;
-import tanya.algorithm.mutation;
-import tanya.meta.metafunction;
-
-/**
- * Forwards its argument list preserving $(D_KEYWORD ref) and $(D_KEYWORD out)
- * storage classes.
- *
- * $(D_PSYMBOL forward) accepts a list of variables or literals. It returns an
- * argument list of the same length that can be for example passed to a
- * function accepting the arguments of this type.
- *
- * Params:
- * args = Argument list.
- *
- * Returns: $(D_PARAM args) with their original storage classes.
- */
-template forward(args...)
-{
- static if (args.length == 0)
- {
- alias forward = AliasSeq!();
- }
- else static if (__traits(isRef, args[0]) || __traits(isOut, args[0]))
- {
- static if (args.length == 1)
- {
- alias forward = args[0];
- }
- else
- {
- alias forward = AliasSeq!(args[0], forward!(args[1 .. $]));
- }
- }
- else
- {
- @property auto forwardOne()
- {
- return move(args[0]);
- }
- static if (args.length == 1)
- {
- alias forward = forwardOne;
- }
- else
- {
- alias forward = AliasSeq!(forwardOne, forward!(args[1 .. $]));
- }
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static assert(is(typeof((int i) { int v = forward!i; })));
- static assert(is(typeof((ref int i) { int v = forward!i; })));
- static assert(is(typeof({
- void f(int i, ref int j, out int k)
- {
- f(forward!(i, j, k));
- }
- })));
-}
+public import tanya.memory.lifecycle : forward;
diff --git a/source/tanya/memory/allocator.d b/source/tanya/memory/allocator.d
deleted file mode 100644
index 3d05a37..0000000
--- a/source/tanya/memory/allocator.d
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * This module contains the interface for implementing custom allocators.
- *
- * Allocators are classes encapsulating memory allocation strategy. This allows
- * to decouple memory management from the algorithms and the data.
- *
- * Copyright: Eugene Wissner 2016-2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/allocator.d,
- * tanya/memory/allocator.d)
- */
-module tanya.memory.allocator;
-
-/**
- * Abstract class implementing a basic allocator.
- */
-interface Allocator
-{
- /**
- * Returns: Alignment offered.
- */
- @property uint alignment() const shared pure nothrow @safe @nogc;
-
- /**
- * Allocates $(D_PARAM size) bytes of memory.
- *
- * Params:
- * size = Amount of memory to allocate.
- *
- * Returns: Pointer to the new allocated memory.
- */
- void[] allocate(size_t size) shared pure nothrow @nogc;
-
- /**
- * Deallocates a memory block.
- *
- * Params:
- * p = A pointer to the memory block to be freed.
- *
- * Returns: Whether the deallocation was successful.
- */
- bool deallocate(void[] p) shared pure nothrow @nogc;
-
- /**
- * Increases or decreases the size of a memory block.
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: Pointer to the allocated memory.
- */
- bool reallocate(ref void[] p, size_t size) shared pure nothrow @nogc;
-
- /**
- * Reallocates a memory block in place if possible or returns
- * $(D_KEYWORD false). This function cannot be used to allocate or
- * deallocate memory, so if $(D_PARAM p) is $(D_KEYWORD null) or
- * $(D_PARAM size) is `0`, it should return $(D_KEYWORD false).
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
- */
- bool reallocateInPlace(ref void[] p, size_t size)
- shared pure nothrow @nogc;
-}
-
-package template GetPureInstance(T : Allocator)
-{
- alias GetPureInstance = shared(T) function()
- pure nothrow @nogc;
-}
diff --git a/source/tanya/memory/lifecycle.d b/source/tanya/memory/lifecycle.d
deleted file mode 100644
index 2221af3..0000000
--- a/source/tanya/memory/lifecycle.d
+++ /dev/null
@@ -1,360 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Lifecycle management functions, types and related exceptions.
- *
- * Copyright: Eugene Wissner 2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/init.d,
- * tanya/memory/init.d)
- */
-module tanya.memory.lifecycle;
-
-import tanya.algorithm.mutation;
-import tanya.conv;
-import tanya.memory;
-import tanya.meta.trait;
-import tanya.range.primitive;
-
-/**
- * Error thrown if memory allocation fails.
- */
-final class OutOfMemoryError : Error
-{
- /**
- * Constructs new error.
- *
- * Params:
- * msg = The message for the exception.
- * file = The file where the exception occurred.
- * line = The line number where the exception occurred.
- * next = The previous exception in the chain of exceptions, if any.
- */
- this(string msg = "Out of memory",
- string file = __FILE__,
- size_t line = __LINE__,
- Throwable next = null) @nogc nothrow pure @safe
- {
- super(msg, file, line, next);
- }
-
- /// ditto
- this(string msg,
- Throwable next,
- string file = __FILE__,
- size_t line = __LINE__) @nogc nothrow pure @safe
- {
- super(msg, file, line, next);
- }
-}
-
-/**
- * Allocates $(D_PSYMBOL OutOfMemoryError) in a static storage and throws it.
- *
- * Params:
- * msg = Custom error message.
- *
- * Throws: $(D_PSYMBOL OutOfMemoryError).
- */
-void onOutOfMemoryError(string msg = "Out of memory")
-@nogc nothrow pure @trusted
-{
- static ubyte[stateSize!OutOfMemoryError] memory;
- alias PureType = OutOfMemoryError function(string) @nogc nothrow pure;
- throw (cast(PureType) () => emplace!OutOfMemoryError(memory))(msg);
-}
-
-// From druntime
-extern (C)
-private void _d_monitordelete(Object h, bool det) @nogc nothrow pure;
-
-/*
- * Internal function used to create, resize or destroy a dynamic array. It
- * may throw $(D_PSYMBOL OutOfMemoryError). The new
- * allocated part of the array isn't initialized. This function can be trusted
- * only in the data structures that can ensure that the array is
- * allocated/rellocated/deallocated with the same allocator.
- *
- * Params:
- * T = Element type of the array being created.
- * allocator = The allocator used for getting memory.
- * array = A reference to the array being changed.
- * length = New array length.
- *
- * Returns: $(D_PARAM array).
- */
-package(tanya) T[] resize(T)(shared Allocator allocator,
- auto ref T[] array,
- const size_t length) @trusted
-{
- if (length == 0)
- {
- if (allocator.deallocate(array))
- {
- return null;
- }
- else
- {
- onOutOfMemoryError();
- }
- }
-
- void[] buf = array;
- if (!allocator.reallocate(buf, length * T.sizeof))
- {
- onOutOfMemoryError();
- }
- // Casting from void[] is unsafe, but we know we cast to the original type.
- array = cast(T[]) buf;
-
- return array;
-}
-
-@nogc nothrow pure @safe unittest
-{
- int[] p;
-
- p = defaultAllocator.resize(p, 20);
- assert(p.length == 20);
-
- p = defaultAllocator.resize(p, 30);
- assert(p.length == 30);
-
- p = defaultAllocator.resize(p, 10);
- assert(p.length == 10);
-
- p = defaultAllocator.resize(p, 0);
- assert(p is null);
-}
-
-/*
- * Destroys the object.
- * Returns the memory should be freed.
- */
-package(tanya) void[] finalize(T)(ref T* p)
-{
- if (p is null)
- {
- return null;
- }
- static if (hasElaborateDestructor!T)
- {
- destroy(*p);
- }
- return (cast(void*) p)[0 .. T.sizeof];
-}
-
-package(tanya) void[] finalize(T)(ref T p)
-if (isPolymorphicType!T)
-{
- if (p is null)
- {
- return null;
- }
- static if (is(T == interface))
- {
- version(Windows)
- {
- import core.sys.windows.unknwn : IUnknown;
- static assert(!is(T : IUnknown), "COM interfaces can't be destroyed in "
- ~ __PRETTY_FUNCTION__);
- }
- auto ob = cast(Object) p;
- }
- else
- {
- alias ob = p;
- }
- auto ptr = cast(void*) ob;
- auto support = ptr[0 .. typeid(ob).initializer.length];
-
- auto ppv = cast(void**) ptr;
- if (!*ppv)
- {
- return null;
- }
- auto pc = cast(ClassInfo*) *ppv;
- scope (exit)
- {
- *ppv = null;
- }
-
- auto c = *pc;
- do
- {
- // Assume the destructor is @nogc. Leave it nothrow since the destructor
- // shouldn't throw and if it does, it is an error anyway.
- if (c.destructor)
- {
- alias DtorType = void function(Object) pure nothrow @safe @nogc;
- (cast(DtorType) c.destructor)(ob);
- }
- }
- while ((c = c.base) !is null);
-
- if (ppv[1]) // if monitor is not null
- {
- _d_monitordelete(cast(Object) ptr, true);
- }
- return support;
-}
-
-package(tanya) void[] finalize(T)(ref T[] p)
-{
- destroyAll(p);
- return p;
-}
-
-/**
- * Destroys and deallocates $(D_PARAM p) of type $(D_PARAM T).
- * It is assumed the respective entities had been allocated with the same
- * allocator.
- *
- * Params:
- * T = Type of $(D_PARAM p).
- * allocator = Allocator the $(D_PARAM p) was allocated with.
- * p = Object or array to be destroyed.
- */
-void dispose(T)(shared Allocator allocator, auto ref T p)
-{
- () @trusted { allocator.deallocate(finalize(p)); }();
- p = null;
-}
-
-@nogc nothrow pure @system unittest
-{
- static struct S
- {
- ~this() @nogc nothrow pure @safe
- {
- }
- }
- auto p = cast(S[]) defaultAllocator.allocate(S.sizeof);
-
- defaultAllocator.dispose(p);
-}
-
-// Works with interfaces.
-@nogc nothrow pure @safe unittest
-{
- interface I
- {
- }
- class C : I
- {
- }
- auto c = defaultAllocator.make!C();
- I i = c;
-
- defaultAllocator.dispose(i);
- defaultAllocator.dispose(i);
-}
-
-/**
- * Constructs a new class instance of type $(D_PARAM T) using $(D_PARAM args)
- * as the parameter list for the constructor of $(D_PARAM T).
- *
- * Params:
- * T = Class type.
- * 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 T).
- *
- * Precondition: $(D_INLINECODE allocator !is null)
- */
-T make(T, A...)(shared Allocator allocator, auto ref A args)
-if (is(T == class))
-in (allocator !is null)
-{
- auto mem = (() @trusted => allocator.allocate(stateSize!T))();
- if (mem is null)
- {
- onOutOfMemoryError();
- }
- scope (failure)
- {
- () @trusted { allocator.deallocate(mem); }();
- }
-
- return emplace!T(mem[0 .. stateSize!T], args);
-}
-
-/**
- * Constructs a value object of type $(D_PARAM T) using $(D_PARAM args)
- * as the parameter list for the constructor of $(D_PARAM T) and returns a
- * pointer to the new object.
- *
- * Params:
- * T = Object type.
- * A = Types of the arguments to the constructor of $(D_PARAM T).
- * allocator = Allocator.
- * args = Constructor arguments of $(D_PARAM T).
- *
- * Returns: Pointer to the created object.
- *
- * Precondition: $(D_INLINECODE allocator !is null)
- */
-T* make(T, A...)(shared Allocator allocator, auto ref A args)
-if (!is(T == interface)
- && !is(T == class)
- && !isAssociativeArray!T
- && !isArray!T)
-in (allocator !is null)
-{
- auto mem = (() @trusted => allocator.allocate(stateSize!T))();
- if (mem is null)
- {
- onOutOfMemoryError();
- }
- scope (failure)
- {
- () @trusted { allocator.deallocate(mem); }();
- }
- return emplace!T(mem[0 .. stateSize!T], args);
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int* i = defaultAllocator.make!int(5);
- assert(*i == 5);
- defaultAllocator.dispose(i);
-}
-
-/**
- * Constructs a new array with $(D_PARAM n) elements.
- *
- * Params:
- * T = Array type.
- * allocator = Allocator.
- * n = Array size.
- *
- * Returns: Newly created array.
- *
- * Precondition: $(D_INLINECODE allocator !is null
- * && n <= size_t.max / ElementType!T.sizeof)
- */
-T make(T)(shared Allocator allocator, const size_t n)
-if (isArray!T)
-in (allocator !is null)
-in (n <= size_t.max / ElementType!T.sizeof)
-{
- auto ret = allocator.resize!(ElementType!T)(null, n);
- ret.uninitializedFill(ElementType!T.init);
- return ret;
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int[] i = defaultAllocator.make!(int[])(2);
- assert(i.length == 2);
- assert(i[0] == int.init && i[1] == int.init);
- defaultAllocator.dispose(i);
-}
diff --git a/source/tanya/memory/mallocator.d b/source/tanya/memory/mallocator.d
deleted file mode 100644
index fdf7ede..0000000
--- a/source/tanya/memory/mallocator.d
+++ /dev/null
@@ -1,233 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Allocator based on $(D_PSYMBOL malloc), $(D_PSYMBOL realloc) and
- * $(D_PSYMBOL free).
- *
- * Copyright: Eugene Wissner 2017-2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/mallocator.d,
- * tanya/memory/mallocator.d)
- */
-module tanya.memory.mallocator;
-
-version (TanyaNative)
-{
-}
-else:
-
-import core.stdc.stdlib;
-import tanya.memory.allocator;
-
-/**
- * Wrapper for $(D_PSYMBOL malloc)/$(D_PSYMBOL realloc)/$(D_PSYMBOL free) from
- * the C standard library.
- */
-final class Mallocator : Allocator
-{
- private alias MallocType = extern (C) void* function(size_t)
- @nogc nothrow pure @system;
- private alias FreeType = extern (C) void function(void*)
- @nogc nothrow pure @system;
- private alias ReallocType = extern (C) void* function(void*, size_t)
- @nogc nothrow pure @system;
-
- /**
- * Allocates $(D_PARAM size) bytes of memory.
- *
- * Params:
- * size = Amount of memory to allocate.
- *
- * Returns: The pointer to the new allocated memory.
- */
- void[] allocate(size_t size) @nogc nothrow pure shared @system
- {
- if (size == 0)
- {
- return null;
- }
- auto p = (cast(MallocType) &malloc)(size + psize);
-
- return p is null ? null : p[psize .. psize + size];
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- auto p = Mallocator.instance.allocate(20);
- assert(p.length == 20);
- Mallocator.instance.deallocate(p);
-
- p = Mallocator.instance.allocate(0);
- assert(p.length == 0);
- }
-
- /**
- * Deallocates a memory block.
- *
- * Params:
- * p = A pointer to the memory block to be freed.
- *
- * Returns: Whether the deallocation was successful.
- */
- bool deallocate(void[] p) @nogc nothrow pure shared @system
- {
- if (p !is null)
- {
- (cast(FreeType) &free)(p.ptr - psize);
- }
- return true;
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- void[] p;
- assert(Mallocator.instance.deallocate(p));
-
- p = Mallocator.instance.allocate(10);
- assert(Mallocator.instance.deallocate(p));
- }
-
- /**
- * Reallocating in place isn't supported.
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: $(D_KEYWORD false).
- */
- bool reallocateInPlace(ref void[] p, size_t size)
- @nogc nothrow pure shared @system
- {
- cast(void) size;
- return false;
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- void[] p;
- assert(!Mallocator.instance.reallocateInPlace(p, 8));
- }
-
- /**
- * Increases or decreases the size of a memory block.
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: Whether the reallocation was successful.
- */
- bool reallocate(ref void[] p, size_t size)
- @nogc nothrow pure shared @system
- {
- if (size == 0)
- {
- if (deallocate(p))
- {
- p = null;
- return true;
- }
- }
- else if (p is null)
- {
- p = allocate(size);
- return p is null ? false : true;
- }
- else
- {
- auto r = (cast(ReallocType) &realloc)(p.ptr - psize, size + psize);
-
- if (r !is null)
- {
- p = r[psize .. psize + size];
- return true;
- }
- }
- return false;
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- void[] p;
-
- assert(Mallocator.instance.reallocate(p, 20));
- assert(p.length == 20);
-
- assert(Mallocator.instance.reallocate(p, 30));
- assert(p.length == 30);
-
- assert(Mallocator.instance.reallocate(p, 10));
- assert(p.length == 10);
-
- assert(Mallocator.instance.reallocate(p, 0));
- assert(p is null);
- }
-
- // Fails with false
- @nogc nothrow pure @system unittest
- {
- void[] p = Mallocator.instance.allocate(20);
- void[] oldP = p;
- assert(!Mallocator.instance.reallocate(p, size_t.max - Mallocator.psize * 2));
- assert(oldP is p);
- Mallocator.instance.deallocate(p);
- }
-
- /**
- * Returns: The alignment offered.
- */
- @property uint alignment() const @nogc nothrow pure @safe shared
- {
- return (void*).alignof;
- }
-
- private nothrow @nogc unittest
- {
- assert(Mallocator.instance.alignment == (void*).alignof);
- }
-
- static private shared(Mallocator) instantiate() @nogc nothrow @system
- {
- if (instance_ is null)
- {
- const size = __traits(classInstanceSize, Mallocator) + psize;
- void* p = malloc(size);
-
- if (p !is null)
- {
- p[psize .. size] = typeid(Mallocator).initializer[];
- instance_ = cast(shared Mallocator) p[psize .. size].ptr;
- }
- }
- return instance_;
- }
-
- /**
- * Static allocator instance and initializer.
- *
- * Returns: The global $(D_PSYMBOL Allocator) instance.
- */
- static @property shared(Mallocator) instance() @nogc nothrow pure @system
- {
- return (cast(GetPureInstance!Mallocator) &instantiate)();
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- assert(instance is instance);
- }
-
- private enum ushort psize = 8;
-
- private shared static Mallocator instance_;
-}
diff --git a/source/tanya/memory/mmappool.d b/source/tanya/memory/mmappool.d
deleted file mode 100644
index 5c42241..0000000
--- a/source/tanya/memory/mmappool.d
+++ /dev/null
@@ -1,657 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * Native allocator.
- *
- * Copyright: Eugene Wissner 2016-2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/mmappool.d,
- * tanya/memory/mmappool.d)
- */
-module tanya.memory.mmappool;
-
-version (TanyaNative):
-
-import mir.linux._asm.unistd;
-import tanya.memory.allocator;
-import tanya.memory.op;
-import tanya.os.error;
-import tanya.sys.linux.syscall;
-import tanya.sys.posix.mman;
-
-private void* mapMemory(const size_t length) @nogc nothrow pure @system
-{
- auto p = syscall_(0,
- length,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1,
- 0,
- NR_mmap);
- return p == -ErrorCode.noMemory ? null : cast(void*) p;
-}
-
-private bool unmapMemory(shared void* addr, const size_t length)
-@nogc nothrow pure @system
-{
- return syscall_(cast(ptrdiff_t) addr, length, NR_munmap) == 0;
-}
-
-/*
- * This allocator allocates memory in regions (multiple of 64 KB for example).
- * Each region is then splitted in blocks. So it doesn't request the memory
- * from the operating system on each call, but only if there are no large
- * enough free blocks in the available regions.
- * Deallocation works in the same way. Deallocation doesn't immediately
- * gives the memory back to the operating system, but marks the appropriate
- * block as free and only if all blocks in the region are free, the complete
- * region is deallocated.
- *
- * <pre>
- * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- * | | | | | || | | |
- * | |prev <----------- | || | | |
- * | R | B | | B | || R | B | |
- * | E | L | | L | next E | L | |
- * | G | O | DATA | O | FREE ---> G | O | DATA |
- * | I | C | | C | <--- I | C | |
- * | O | K | | K | prev O | K | |
- * | N | -----------> next| || N | | |
- * | | | | | || | | |
- * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- * </pre>
- */
-final class MmapPool : Allocator
-{
- version (none)
- {
- @nogc nothrow pure @system invariant
- {
- for (auto r = &head; *r !is null; r = &((*r).next))
- {
- auto block = cast(Block) (cast(void*) *r + RegionEntry.sizeof);
- do
- {
- assert(block.prev is null || block.prev.next is block);
- assert(block.next is null || block.next.prev is block);
- assert(block.region is *r);
- }
- while ((block = block.next) !is null);
- }
- }
- }
-
- /*
- * Allocates $(D_PARAM size) bytes of memory.
- *
- * Params:
- * size = Amount of memory to allocate.
- *
- * Returns: Pointer to the new allocated memory.
- */
- void[] allocate(size_t size) @nogc nothrow pure shared @system
- {
- if (size == 0)
- {
- return null;
- }
- const dataSize = addAlignment(size);
- if (dataSize < size)
- {
- return null;
- }
-
- void* data = findBlock(dataSize);
- if (data is null)
- {
- data = initializeRegion(dataSize);
- }
-
- return data is null ? null : data[0 .. size];
- }
-
- @nogc nothrow pure @system unittest
- {
- auto p = MmapPool.instance.allocate(20);
- assert(p);
- MmapPool.instance.deallocate(p);
-
- p = MmapPool.instance.allocate(0);
- assert(p.length == 0);
- }
-
- @nogc nothrow pure @system unittest
- {
- // allocate() check.
- size_t tooMuchMemory = size_t.max
- - MmapPool.alignment_
- - BlockEntry.sizeof * 2
- - RegionEntry.sizeof
- - pageSize;
- assert(MmapPool.instance.allocate(tooMuchMemory) is null);
-
- assert(MmapPool.instance.allocate(size_t.max) is null);
-
- // initializeRegion() check.
- tooMuchMemory = size_t.max - MmapPool.alignment_;
- assert(MmapPool.instance.allocate(tooMuchMemory) is null);
- }
-
- /*
- * Search for a block large enough to keep $(D_PARAM size) and split it
- * into two blocks if the block is too large.
- *
- * Params:
- * size = Minimum size the block should have (aligned).
- *
- * Returns: Data the block points to or $(D_KEYWORD null).
- */
- private void* findBlock(const ref size_t size)
- @nogc nothrow pure shared @system
- {
- Block block1;
- RegionLoop: for (auto r = head; r !is null; r = r.next)
- {
- block1 = cast(Block) (cast(void*) r + RegionEntry.sizeof);
- do
- {
- if (block1.free && block1.size >= size)
- {
- break RegionLoop;
- }
- }
- while ((block1 = block1.next) !is null);
- }
- if (block1 is null)
- {
- return null;
- }
- else if (block1.size >= size + alignment_ + BlockEntry.sizeof)
- { // Split the block if needed
- Block block2 = cast(Block) (cast(void*) block1 + BlockEntry.sizeof + size);
- block2.prev = block1;
- block2.next = block1.next;
- block2.free = true;
- block2.size = block1.size - BlockEntry.sizeof - size;
- block2.region = block1.region;
-
- if (block1.next !is null)
- {
- block1.next.prev = block2;
- }
- block1.next = block2;
- block1.size = size;
- }
- block1.free = false;
- block1.region.blocks = block1.region.blocks + 1;
-
- return cast(void*) block1 + BlockEntry.sizeof;
- }
-
- // Merge block with the next one.
- private void mergeNext(Block block) const @nogc nothrow pure @safe shared
- {
- block.size = block.size + BlockEntry.sizeof + block.next.size;
- if (block.next.next !is null)
- {
- block.next.next.prev = block;
- }
- block.next = block.next.next;
- }
-
- /*
- * Deallocates a memory block.
- *
- * Params:
- * p = A pointer to the memory block to be freed.
- *
- * Returns: Whether the deallocation was successful.
- */
- bool deallocate(void[] p) @nogc nothrow pure shared @system
- {
- if (p.ptr is null)
- {
- return true;
- }
-
- Block block = cast(Block) (p.ptr - BlockEntry.sizeof);
- if (block.region.blocks <= 1)
- {
- if (block.region.prev !is null)
- {
- block.region.prev.next = block.region.next;
- }
- else // Replace the list head. It is being deallocated
- {
- head = block.region.next;
- }
- if (block.region.next !is null)
- {
- block.region.next.prev = block.region.prev;
- }
- return unmapMemory(block.region, block.region.size);
- }
- // Merge blocks if neigbours are free.
- if (block.next !is null && block.next.free)
- {
- mergeNext(block);
- }
- if (block.prev !is null && block.prev.free)
- {
- block.prev.size = block.prev.size + BlockEntry.sizeof + block.size;
- if (block.next !is null)
- {
- block.next.prev = block.prev;
- }
- block.prev.next = block.next;
- }
- else
- {
- block.free = true;
- }
- block.region.blocks = block.region.blocks - 1;
- return true;
- }
-
- @nogc nothrow pure @system unittest
- {
- auto p = MmapPool.instance.allocate(20);
-
- assert(MmapPool.instance.deallocate(p));
- }
-
- /*
- * Reallocates a memory block in place if possible or returns
- * $(D_KEYWORD false). This function cannot be used to allocate or
- * deallocate memory, so if $(D_PARAM p) is $(D_KEYWORD null) or
- * $(D_PARAM size) is `0`, it should return $(D_KEYWORD false).
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
- */
- bool reallocateInPlace(ref void[] p, size_t size)
- @nogc nothrow pure shared @system
- {
- if (p is null || size == 0)
- {
- return false;
- }
- if (size <= p.length)
- {
- // Leave the block as is.
- p = p.ptr[0 .. size];
- return true;
- }
- Block block1 = cast(Block) (p.ptr - BlockEntry.sizeof);
-
- if (block1.size >= size)
- {
- // Enough space in the current block.
- p = p.ptr[0 .. size];
- return true;
- }
- const dataSize = addAlignment(size);
- const pAlignment = addAlignment(p.length);
- assert(pAlignment >= p.length, "Invalid memory chunk length");
- const delta = dataSize - pAlignment;
-
- if (block1.next is null
- || !block1.next.free
- || dataSize < size
- || block1.next.size + BlockEntry.sizeof < delta)
- {
- /* - It is the last block in the region
- * - The next block isn't free
- * - The next block is too small
- * - Requested size is too large
- */
- return false;
- }
- if (block1.next.size >= delta + alignment_)
- {
- // Move size from block2 to block1.
- block1.next.size = block1.next.size - delta;
- block1.size = block1.size + delta;
-
- auto block2 = cast(Block) (p.ptr + dataSize);
- if (block1.next.next !is null)
- {
- block1.next.next.prev = block2;
- }
- copyBackward((cast(void*) block1.next)[0 .. BlockEntry.sizeof],
- (cast(void*) block2)[0 .. BlockEntry.sizeof]);
- block1.next = block2;
- }
- else
- {
- // The next block has enough space, but is too small for further
- // allocations. Merge it with the current block.
- mergeNext(block1);
- }
-
- p = p.ptr[0 .. size];
- return true;
- }
-
- @nogc nothrow pure @system unittest
- {
- void[] p;
- assert(!MmapPool.instance.reallocateInPlace(p, 5));
- assert(p is null);
-
- p = MmapPool.instance.allocate(1);
- auto orig = p.ptr;
-
- assert(MmapPool.instance.reallocateInPlace(p, 2));
- assert(p.length == 2);
- assert(p.ptr == orig);
-
- assert(MmapPool.instance.reallocateInPlace(p, 4));
- assert(p.length == 4);
- assert(p.ptr == orig);
-
- assert(MmapPool.instance.reallocateInPlace(p, 2));
- assert(p.length == 2);
- assert(p.ptr == orig);
-
- MmapPool.instance.deallocate(p);
- }
-
- /*
- * Increases or decreases the size of a memory block.
- *
- * Params:
- * p = A pointer to the memory block.
- * size = Size of the reallocated block.
- *
- * Returns: Whether the reallocation was successful.
- */
- bool reallocate(ref void[] p, size_t size)
- @nogc nothrow pure shared @system
- {
- if (size == 0)
- {
- if (deallocate(p))
- {
- p = null;
- return true;
- }
- return false;
- }
- else if (reallocateInPlace(p, size))
- {
- return true;
- }
- // Can't reallocate in place, allocate a new block,
- // copy and delete the previous one.
- void[] reallocP = allocate(size);
- if (reallocP is null)
- {
- return false;
- }
- if (p !is null)
- {
- copy(p[0 .. min(p.length, size)], reallocP);
- deallocate(p);
- }
- p = reallocP;
-
- return true;
- }
-
- @nogc nothrow pure @system unittest
- {
- void[] p;
- MmapPool.instance.reallocate(p, 10 * int.sizeof);
- (cast(int[]) p)[7] = 123;
-
- assert(p.length == 40);
-
- MmapPool.instance.reallocate(p, 8 * int.sizeof);
-
- assert(p.length == 32);
- assert((cast(int[]) p)[7] == 123);
-
- MmapPool.instance.reallocate(p, 20 * int.sizeof);
- (cast(int[]) p)[15] = 8;
-
- assert(p.length == 80);
- assert((cast(int[]) p)[15] == 8);
- assert((cast(int[]) p)[7] == 123);
-
- MmapPool.instance.reallocate(p, 8 * int.sizeof);
-
- assert(p.length == 32);
- assert((cast(int[]) p)[7] == 123);
-
- MmapPool.instance.deallocate(p);
- }
-
- static private shared(MmapPool) instantiate() @nogc nothrow @system
- {
- if (instance_ is null)
- {
- const instanceSize = addAlignment(__traits(classInstanceSize,
- MmapPool));
-
- Region head; // Will become soon our region list head
- void* data = initializeRegion(instanceSize, head);
- if (data !is null)
- {
- copy(typeid(MmapPool).initializer, data[0 .. instanceSize]);
- instance_ = cast(shared MmapPool) data;
- instance_.head = head;
- }
- }
- return instance_;
- }
-
- /*
- * Static allocator instance and initializer.
- *
- * Returns: Global $(D_PSYMBOL MmapPool) instance.
- */
- static @property shared(MmapPool) instance() @nogc nothrow pure @system
- {
- return (cast(GetPureInstance!MmapPool) &instantiate)();
- }
-
- @nogc nothrow pure @system unittest
- {
- assert(instance is instance);
- }
-
- /*
- * Initializes a region for one element.
- *
- * Params:
- * size = Aligned size of the first data block in the region.
- * head = Region list head.
- *
- * Returns: A pointer to the data.
- */
- private static void* initializeRegion(const size_t size, ref Region head)
- @nogc nothrow pure @system
- {
- const regionSize = calculateRegionSize(size);
- if (regionSize < size)
- {
- return null;
- }
-
- void* p = mapMemory(regionSize);
- if (p is null)
- {
- return null;
- }
-
- Region region = cast(Region) p;
- region.blocks = 1;
- region.size = regionSize;
-
- // Set the pointer to the head of the region list
- if (head !is null)
- {
- head.prev = region;
- }
- region.next = head;
- region.prev = null;
- head = region;
-
- // Initialize the data block
- void* memoryPointer = p + RegionEntry.sizeof;
- Block block1 = cast(Block) memoryPointer;
- block1.size = size;
- block1.free = false;
-
- // It is what we want to return
- void* data = memoryPointer + BlockEntry.sizeof;
-
- // Free block after data
- memoryPointer = data + size;
- Block block2 = cast(Block) memoryPointer;
- block1.prev = block2.next = null;
- block1.next = block2;
- block2.prev = block1;
- block2.size = regionSize - size - RegionEntry.sizeof - BlockEntry.sizeof * 2;
- block2.free = true;
- block1.region = block2.region = region;
-
- return data;
- }
-
- private void* initializeRegion(const size_t size)
- @nogc nothrow pure shared @system
- {
- return initializeRegion(size, this.head);
- }
-
- /*
- * Params:
- * x = Space to be aligned.
- *
- * Returns: Aligned size of $(D_PARAM x).
- */
- private static size_t addAlignment(const size_t x) @nogc nothrow pure @safe
- {
- return (x - 1) / alignment_ * alignment_ + alignment_;
- }
-
- /*
- * Params:
- * x = Required space.
- *
- * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
- */
- private static size_t calculateRegionSize(ref const size_t x)
- @nogc nothrow pure @safe
- {
- return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2)
- / pageSize * pageSize + pageSize;
- }
-
- /*
- * Returns: Alignment offered.
- */
- @property uint alignment() const @nogc nothrow pure @safe shared
- {
- return alignment_;
- }
-
- @nogc nothrow pure @system unittest
- {
- assert(MmapPool.instance.alignment == MmapPool.alignment_);
- }
-
- private enum uint alignment_ = 8;
-
- private shared static MmapPool instance_;
-
- // Page size.
- enum size_t pageSize = 65536;
-
- private shared struct RegionEntry
- {
- Region prev;
- Region next;
- uint blocks;
- size_t size;
- }
- private alias Region = shared RegionEntry*;
- private shared Region head;
-
- private shared struct BlockEntry
- {
- Block prev;
- Block next;
- Region region;
- size_t size;
- bool free;
- }
- private alias Block = shared BlockEntry*;
-}
-
-// A lot of allocations/deallocations, but it is the minimum caused a
-// segmentation fault because MmapPool reallocateInPlace moves a block wrong.
-@nogc nothrow pure @system unittest
-{
- auto a = MmapPool.instance.allocate(16);
- auto d = MmapPool.instance.allocate(16);
- auto b = MmapPool.instance.allocate(16);
- auto e = MmapPool.instance.allocate(16);
- auto c = MmapPool.instance.allocate(16);
- auto f = MmapPool.instance.allocate(16);
-
- MmapPool.instance.deallocate(a);
- MmapPool.instance.deallocate(b);
- MmapPool.instance.deallocate(c);
-
- a = MmapPool.instance.allocate(50);
- MmapPool.instance.reallocateInPlace(a, 64);
- MmapPool.instance.deallocate(a);
-
- a = MmapPool.instance.allocate(1);
- auto tmp1 = MmapPool.instance.allocate(1);
- auto h1 = MmapPool.instance.allocate(1);
- auto tmp2 = cast(ubyte[]) MmapPool.instance.allocate(1);
-
- auto h2 = MmapPool.instance.allocate(2);
- tmp1 = MmapPool.instance.allocate(1);
- MmapPool.instance.deallocate(h2);
- MmapPool.instance.deallocate(h1);
-
- h2 = MmapPool.instance.allocate(2);
- h1 = MmapPool.instance.allocate(1);
- MmapPool.instance.deallocate(h2);
-
- auto rep = cast(void[]) tmp2;
- MmapPool.instance.reallocate(rep, tmp1.length);
- tmp2 = cast(ubyte[]) rep;
-
- MmapPool.instance.reallocate(tmp1, 9);
-
- rep = cast(void[]) tmp2;
- MmapPool.instance.reallocate(rep, tmp1.length);
- tmp2 = cast(ubyte[]) rep;
- MmapPool.instance.reallocate(tmp1, 17);
-
- tmp2[$ - 1] = 0;
-
- MmapPool.instance.deallocate(tmp1);
-
- b = MmapPool.instance.allocate(16);
-
- MmapPool.instance.deallocate(h1);
- MmapPool.instance.deallocate(a);
- MmapPool.instance.deallocate(b);
- MmapPool.instance.deallocate(d);
- MmapPool.instance.deallocate(e);
- MmapPool.instance.deallocate(f);
-}
diff --git a/source/tanya/memory/op.d b/source/tanya/memory/op.d
deleted file mode 100644
index 6005329..0000000
--- a/source/tanya/memory/op.d
+++ /dev/null
@@ -1,437 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Set of operations on memory blocks.
- *
- * Copyright: Eugene Wissner 2017-2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/op.d,
- * tanya/memory/op.d)
- */
-module tanya.memory.op;
-
-version (TanyaNative)
-{
- extern private void fillMemory(void[], size_t) pure nothrow @system @nogc;
-
- extern private void copyMemory(const void[], void[])
- pure nothrow @system @nogc;
-
- extern private void moveMemory(const void[], void[])
- pure nothrow @system @nogc;
-
- extern private bool equalMemory(const void[], const void[])
- pure nothrow @system @nogc;
-}
-else
-{
- import core.stdc.string;
-}
-
-version (TanyaNative)
-{
- @nogc nothrow pure @system unittest
- {
- ubyte[2] buffer = 1;
- fillMemory(buffer[1 .. $], 0);
- assert(buffer[0] == 1 && buffer[1] == 0);
- }
-
- @nogc nothrow pure @safe unittest
- {
- assert(equal(null, null));
- }
-}
-
-private enum alignMask = size_t.sizeof - 1;
-
-/**
- * Copies $(D_PARAM source) into $(D_PARAM target).
- *
- * $(D_PARAM source) and $(D_PARAM target) shall not overlap so that
- * $(D_PARAM source) points ahead of $(D_PARAM target).
- *
- * $(D_PARAM target) shall have enough space for $(D_INLINECODE source.length)
- * elements.
- *
- * Params:
- * source = Memory to copy from.
- * target = Destination memory.
- *
- * See_Also: $(D_PSYMBOL copyBackward).
- *
- * Precondition: $(D_INLINECODE source.length <= target.length).
- */
-void copy(const void[] source, void[] target) @nogc nothrow pure @trusted
-in
-{
- assert(source.length <= target.length);
- assert(source.length == 0 || source.ptr !is null);
- assert(target.length == 0 || target.ptr !is null);
-}
-do
-{
- version (TanyaNative)
- {
- copyMemory(source, target);
- }
- else
- {
- memcpy(target.ptr, source.ptr, source.length);
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- ubyte[9] target;
- source.copy(target);
- assert(equal(source, target));
-}
-
-@nogc nothrow pure @safe unittest
-{
- {
- ubyte[0] source, target;
- source.copy(target);
- }
- {
- ubyte[1] source = [1];
- ubyte[1] target;
- source.copy(target);
- assert(target[0] == 1);
- }
- {
- ubyte[8] source = [1, 2, 3, 4, 5, 6, 7, 8];
- ubyte[8] target;
- source.copy(target);
- assert(equal(source, target));
- }
-}
-
-/*
- * size_t value each of which bytes is set to `Byte`.
- */
-private template filledBytes(ubyte Byte, ubyte I = 0)
-{
- static if (I == size_t.sizeof)
- {
- enum size_t filledBytes = Byte;
- }
- else
- {
- enum size_t filledBytes = (filledBytes!(Byte, I + 1) << 8) | Byte;
- }
-}
-
-/**
- * Fills $(D_PARAM memory) with the single byte $(D_PARAM c).
- *
- * Param:
- * c = The value to fill $(D_PARAM memory) with.
- * memory = Memory block.
- */
-void fill(ubyte c = 0)(void[] memory) @trusted
-in
-{
- assert(memory.length == 0 || memory.ptr !is null);
-}
-do
-{
- version (TanyaNative)
- {
- fillMemory(memory, filledBytes!c);
- }
- else
- {
- memset(memory.ptr, c, memory.length);
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- memory.fill!0();
- foreach (ubyte v; memory)
- {
- assert(v == 0);
- }
-}
-
-/**
- * Copies starting from the end of $(D_PARAM source) into the end of
- * $(D_PARAM target).
- *
- * $(D_PSYMBOL copyBackward) copies the elements in reverse order, but the
- * order of elements in the $(D_PARAM target) is exactly the same as in the
- * $(D_PARAM source).
- *
- * $(D_PARAM source) and $(D_PARAM target) shall not overlap so that
- * $(D_PARAM target) points ahead of $(D_PARAM source).
- *
- * $(D_PARAM target) shall have enough space for $(D_INLINECODE source.length)
- * elements.
- *
- * Params:
- * source = Memory to copy from.
- * target = Destination memory.
- *
- * See_Also: $(D_PSYMBOL copy).
- *
- * Precondition: $(D_INLINECODE source.length <= target.length).
- */
-void copyBackward(const void[] source, void[] target) @nogc nothrow pure @trusted
-in
-{
- assert(source.length <= target.length);
- assert(source.length == 0 || source.ptr !is null);
- assert(target.length == 0 || target.ptr !is null);
-}
-do
-{
- version (TanyaNative)
- {
- moveMemory(source, target);
- }
- else
- {
- memmove(target.ptr, source.ptr, source.length);
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- ubyte[6] mem = [ 'a', 'a', 'b', 'b', 'c', 'c' ];
- ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ];
-
- copyBackward(mem[0 .. 4], mem[2 .. $]);
- assert(equal(expected, mem));
-}
-
-@nogc nothrow pure @safe unittest
-{
- ubyte[9] r1 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ];
- ubyte[9] r2;
-
- copyBackward(r1, r2);
- assert(equal(r1, r2));
-}
-
-/**
- * Finds the first occurrence of $(D_PARAM needle) in $(D_PARAM haystack) if
- * any.
- *
- * Params:
- * haystack = Memory block.
- * needle = A byte.
- *
- * Returns: The subrange of $(D_PARAM haystack) whose first element is the
- * first occurrence of $(D_PARAM needle). If $(D_PARAM needle)
- * couldn't be found, an empty `inout void[]` is returned.
- */
-inout(void[]) find(return inout void[] haystack, ubyte needle)
-@nogc nothrow pure @trusted
-in
-{
- assert(haystack.length == 0 || haystack.ptr !is null);
-}
-do
-{
- auto length = haystack.length;
- const size_t needleWord = size_t.max * needle;
- enum size_t highBits = filledBytes!(0x01, 0);
- enum size_t mask = filledBytes!(0x80, 0);
-
- // Align
- auto bytes = cast(inout(ubyte)*) haystack;
- while (length > 0 && ((cast(size_t) bytes) & 3) != 0)
- {
- if (*bytes == needle)
- {
- return bytes[0 .. length];
- }
- ++bytes;
- --length;
- }
-
- // Check if some of the words has the needle
- auto words = cast(inout(size_t)*) bytes;
- while (length >= size_t.sizeof)
- {
- if ((((*words ^ needleWord) - highBits) & (~*words) & mask) != 0)
- {
- break;
- }
- ++words;
- length -= size_t.sizeof;
- }
-
- // Find the exact needle position in the word
- bytes = cast(inout(ubyte)*) words;
- while (length > 0)
- {
- if (*bytes == needle)
- {
- return bytes[0 .. length];
- }
- ++bytes;
- --length;
- }
-
- return haystack[$ .. $];
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];
-
- assert(equal(find(haystack, 'a'), haystack[]));
- assert(equal(find(haystack, 'b'), haystack[1 .. $]));
- assert(equal(find(haystack, 'c'), haystack[2 .. $]));
- assert(equal(find(haystack, 'd'), haystack[3 .. $]));
- assert(equal(find(haystack, 'e'), haystack[4 .. $]));
- assert(equal(find(haystack, 'f'), haystack[5 .. $]));
- assert(equal(find(haystack, 'h'), haystack[8 .. $]));
- assert(find(haystack, 'i').length == 0);
-
- assert(find(null, 'a').length == 0);
-}
-
-/**
- * Looks for `\0` in the $(D_PARAM haystack) and returns the part of the
- * $(D_PARAM haystack) ahead of it.
- *
- * Returns $(D_KEYWORD null) if $(D_PARAM haystack) doesn't contain a null
- * character.
- *
- * Params:
- * haystack = Memory block.
- *
- * Returns: The subrange that spans all bytes before the null character or
- * $(D_KEYWORD null) if the $(D_PARAM haystack) doesn't contain any.
- */
-inout(char[]) findNullTerminated(return inout char[] haystack)
-@nogc nothrow pure @trusted
-in
-{
- assert(haystack.length == 0 || haystack.ptr !is null);
-}
-do
-{
- auto length = haystack.length;
- enum size_t highBits = filledBytes!(0x01, 0);
- enum size_t mask = filledBytes!(0x80, 0);
-
- // Align
- auto bytes = cast(inout(ubyte)*) haystack;
- while (length > 0 && ((cast(size_t) bytes) & 3) != 0)
- {
- if (*bytes == '\0')
- {
- return haystack[0 .. haystack.length - length];
- }
- ++bytes;
- --length;
- }
-
- // Check if some of the words contains 0
- auto words = cast(inout(size_t)*) bytes;
- while (length >= size_t.sizeof)
- {
- if (((*words - highBits) & (~*words) & mask) != 0)
- {
- break;
- }
- ++words;
- length -= size_t.sizeof;
- }
-
- // Find the exact 0 position in the word
- bytes = cast(inout(ubyte)*) words;
- while (length > 0)
- {
- if (*bytes == '\0')
- {
- return haystack[0 .. haystack.length - length];
- }
- ++bytes;
- --length;
- }
-
- return null;
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- assert(equal(findNullTerminated("abcdef\0gh"), "abcdef"));
- assert(equal(findNullTerminated("\0garbage"), ""));
- assert(equal(findNullTerminated("\0"), ""));
- assert(equal(findNullTerminated("cstring\0"), "cstring"));
- assert(findNullTerminated(null) is null);
- assert(findNullTerminated("abcdef") is null);
-}
-
-/**
- * Compares two memory areas $(D_PARAM r1) and $(D_PARAM r2) for equality.
- *
- * Params:
- * r1 = First memory block.
- * r2 = Second memory block.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM r1) and $(D_PARAM r2) are equal,
- * $(D_KEYWORD false) otherwise.
- */
-bool equal(const void[] r1, const void[] r2) @nogc nothrow pure @trusted
-in
-{
- assert(r1.length == 0 || r1.ptr !is null);
- assert(r2.length == 0 || r2.ptr !is null);
-}
-do
-{
- version (TanyaNative)
- {
- return equalMemory(r1, r2);
- }
- else
- {
- return r1.length == r2.length
- && memcmp(r1.ptr, r2.ptr, r1.length) == 0;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- assert(equal("asdf", "asdf"));
- assert(!equal("asd", "asdf"));
- assert(!equal("asdf", "asd"));
- assert(!equal("asdf", "qwer"));
-}
-
-// Compares unanligned memory
-@nogc nothrow pure @safe unittest
-{
- ubyte[16] r1 = [
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- ];
- ubyte[16] r2 = [
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- ];
-
- assert(equal(r1, r2));
- assert(equal(r1[1 .. $], r2[1 .. $]));
- assert(equal(r1[0 .. $ - 1], r2[0 .. $ - 1]));
- assert(equal(r1[0 .. 8], r2[0 .. 8]));
-}
diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d
deleted file mode 100644
index 8526b5a..0000000
--- a/source/tanya/memory/package.d
+++ /dev/null
@@ -1,203 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Dynamic memory management.
- *
- * Copyright: Eugene Wissner 2016-2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/package.d,
- * tanya/memory/package.d)
- */
-module tanya.memory;
-
-import tanya.conv;
-public import tanya.memory.allocator;
-public import tanya.memory.lifecycle;
-import tanya.meta.trait;
-
-/**
- * The mixin generates common methods for classes and structs using
- * allocators. It provides a protected member, constructor and a read-only property,
- * that checks if an allocator was already set and sets it to the default
- * one, if not (useful for structs which don't have a default constructor).
- */
-mixin template DefaultAllocator()
-{
- /// Allocator.
- protected shared Allocator allocator_;
-
- /**
- * Params:
- * allocator = The allocator should be used.
- *
- * Precondition: $(D_INLINECODE allocator_ !is null)
- */
- this(shared Allocator allocator) @nogc nothrow pure @safe
- in
- {
- assert(allocator !is null);
- }
- do
- {
- this.allocator_ = allocator;
- }
-
- /**
- * This property checks if the allocator was set in the constructor
- * and sets it to the default one, if not.
- *
- * Returns: Used allocator.
- *
- * Postcondition: $(D_INLINECODE allocator !is null)
- */
- @property shared(Allocator) allocator() @nogc nothrow pure @safe
- out (allocator)
- {
- assert(allocator !is null);
- }
- do
- {
- if (allocator_ is null)
- {
- allocator_ = defaultAllocator;
- }
- return allocator_;
- }
-
- /// ditto
- @property shared(Allocator) allocator() const @nogc nothrow pure @trusted
- out (allocator)
- {
- assert(allocator !is null);
- }
- do
- {
- if (allocator_ is null)
- {
- return defaultAllocator;
- }
- return cast(shared Allocator) allocator_;
- }
-}
-
-shared Allocator allocator;
-
-private shared(Allocator) getAllocatorInstance() @nogc nothrow
-{
- if (allocator is null)
- {
- version (TanyaNative)
- {
- import tanya.memory.mmappool;
- defaultAllocator = MmapPool.instance;
- }
- else
- {
- import tanya.memory.mallocator;
- defaultAllocator = Mallocator.instance;
- }
- }
- return allocator;
-}
-
-/**
- * Returns: Default allocator.
- *
- * Postcondition: $(D_INLINECODE allocator !is null).
- */
-@property shared(Allocator) defaultAllocator() @nogc nothrow pure @trusted
-out (allocator)
-{
- assert(allocator !is null);
-}
-do
-{
- return (cast(GetPureInstance!Allocator) &getAllocatorInstance)();
-}
-
-/**
- * Sets the default allocator.
- *
- * Params:
- * allocator = $(D_PSYMBOL Allocator) instance.
- *
- * Precondition: $(D_INLINECODE allocator !is null).
- */
-@property void defaultAllocator(shared(Allocator) allocator) @nogc nothrow @safe
-in
-{
- assert(allocator !is null);
-}
-do
-{
- .allocator = allocator;
-}
-
-/**
- * Returns the size in bytes of the state that needs to be allocated to hold an
- * object of type $(D_PARAM T).
- *
- * There is a difference between the `.sizeof`-property and
- * $(D_PSYMBOL stateSize) if $(D_PARAM T) is a class or an interface.
- * `T.sizeof` is constant on the given architecture then and is the same as
- * `size_t.sizeof` and `ptrdiff_t.sizeof`. This is because classes and
- * interfaces are reference types and `.sizeof` returns the size of the
- * reference which is the same as the size of a pointer. $(D_PSYMBOL stateSize)
- * returns the size of the instance itself.
- *
- * The size of a dynamic array is `size_t.sizeof * 2` since a dynamic array
- * stores its length and a data pointer. The size of the static arrays is
- * calculated differently since they are value types. It is the array length
- * multiplied by the element size.
- *
- * `stateSize!void` is `1` since $(D_KEYWORD void) is mostly used as a synonym
- * for $(D_KEYWORD byte)/$(D_KEYWORD ubyte) in `void*`.
- *
- * Params:
- * T = Object type.
- *
- * Returns: Size of an instance of type $(D_PARAM T).
- */
-template stateSize(T)
-{
- static if (isPolymorphicType!T)
- {
- enum size_t stateSize = __traits(classInstanceSize, T);
- }
- else
- {
- enum size_t stateSize = T.sizeof;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static assert(stateSize!int == 4);
- static assert(stateSize!bool == 1);
- static assert(stateSize!(int[]) == (size_t.sizeof * 2));
- static assert(stateSize!(short[3]) == 6);
-
- static struct Empty
- {
- }
- static assert(stateSize!Empty == 1);
- static assert(stateSize!void == 1);
-}
-
-/**
- * Params:
- * size = Raw size.
- * alignment = Alignment.
- *
- * Returns: Aligned size.
- */
-size_t alignedSize(const size_t size, const size_t alignment = 8)
-pure nothrow @safe @nogc
-{
- return (size - 1) / alignment * alignment + alignment;
-}
diff --git a/source/tanya/memory/smartref.d b/source/tanya/memory/smartref.d
deleted file mode 100644
index 90271e7..0000000
--- a/source/tanya/memory/smartref.d
+++ /dev/null
@@ -1,914 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Smart pointers.
- *
- * A smart pointer is an object that wraps a raw pointer or a reference
- * (class, dynamic array) to manage its lifetime.
- *
- * This module provides two kinds of lifetime management strategies:
- * $(UL
- * $(LI Reference counting)
- * $(LI Unique ownership)
- * )
- *
- * Copyright: Eugene Wissner 2016-2019.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/smartref.d,
- * tanya/memory/smartref.d)
- */
-module tanya.memory.smartref;
-
-import tanya.algorithm.mutation;
-import tanya.conv;
-import tanya.memory;
-import tanya.meta.trait;
-import tanya.range.primitive;
-version (unittest) import tanya.test.stub;
-
-private template Payload(T)
-{
- static if (isPolymorphicType!T || isArray!T)
- {
- alias Payload = T;
- }
- else
- {
- alias Payload = T*;
- }
-}
-
-private final class RefCountedStore(T)
-{
- T payload;
- size_t counter = 1;
-
- size_t opUnary(string op)()
- if (op == "--" || op == "++")
- in
- {
- assert(this.counter > 0);
- }
- do
- {
- mixin("return " ~ op ~ "counter;");
- }
-
- int opCmp(const size_t counter)
- {
- if (this.counter > counter)
- {
- return 1;
- }
- else if (this.counter < counter)
- {
- return -1;
- }
- else
- {
- return 0;
- }
- }
-}
-
-private void separateDeleter(T)(RefCountedStore!T storage,
- shared Allocator allocator)
-{
- allocator.dispose(storage.payload);
- allocator.dispose(storage);
-}
-
-private void unifiedDeleter(T)(RefCountedStore!T storage,
- shared Allocator allocator)
-{
- auto ptr1 = finalize(storage);
- auto ptr2 = finalize(storage.payload);
- allocator.deallocate(ptr1.ptr[0 .. ptr1.length + ptr2.length]);
-}
-
-/**
- * Reference-counted object containing a $(D_PARAM T) value as payload.
- * $(D_PSYMBOL RefCounted) keeps track of all references of an object, and
- * when the reference count goes down to zero, frees the underlying store.
- *
- * Params:
- * T = Type of the reference-counted value.
- */
-struct RefCounted(T)
-{
- private alias Storage = RefCountedStore!(Payload!T);
-
- private Storage storage;
- private void function(Storage storage,
- shared Allocator allocator) @nogc deleter;
-
- invariant
- {
- assert(this.storage is null || this.allocator_ !is null);
- assert(this.storage is null || this.deleter !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(Payload!T value, shared Allocator allocator = defaultAllocator)
- {
- this(allocator);
- this.storage = allocator.make!Storage();
- this.deleter = &separateDeleter!(Payload!T);
-
- this.storage.payload = value;
- }
-
- /// ditto
- this(shared Allocator allocator)
- in
- {
- assert(allocator !is null);
- }
- do
- {
- this.allocator_ = allocator;
- }
-
- /**
- * Increases the reference counter by one.
- */
- this(this)
- {
- if (count != 0)
- {
- ++this.storage;
- }
- }
-
- /**
- * Decreases the reference counter by one.
- *
- * If the counter reaches 0, destroys the owned object.
- */
- ~this()
- {
- if (this.storage !is null && !(this.storage > 0 && --this.storage))
- {
- deleter(this.storage, allocator);
- }
- }
-
- /**
- * Takes ownership over $(D_PARAM rhs). Initializes this
- * $(D_PSYMBOL RefCounted) if needed.
- *
- * If it is the last reference of the previously owned object,
- * it will be destroyed.
- *
- * To reset $(D_PSYMBOL RefCounted) 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 RefCounted) and assign it.
- *
- * Params:
- * rhs = New object.
- *
- * Returns: $(D_KEYWORD this).
- */
- ref typeof(this) opAssign(Payload!T rhs)
- {
- if (this.storage is null)
- {
- this.storage = allocator.make!Storage();
- this.deleter = &separateDeleter!(Payload!T);
- }
- else if (this.storage > 1)
- {
- --this.storage;
- this.storage = allocator.make!Storage();
- this.deleter = &separateDeleter!(Payload!T);
- }
- else
- {
- finalize(this.storage.payload);
- this.storage.payload = Payload!T.init;
- }
- this.storage.payload = rhs;
- return this;
- }
-
- /// ditto
- ref typeof(this) opAssign(typeof(null))
- {
- if (this.storage is null)
- {
- return this;
- }
- else if (this.storage > 1)
- {
- --this.storage;
- }
- else
- {
- deleter(this.storage, allocator);
- }
- this.storage = null;
-
- return this;
- }
-
- /// ditto
- ref typeof(this) opAssign(typeof(this) rhs)
- {
- swap(this.allocator_, rhs.allocator_);
- swap(this.storage, rhs.storage);
- swap(this.deleter, rhs.deleter);
- return this;
- }
-
- /**
- * Returns: Reference to the owned object.
- *
- * Precondition: $(D_INLINECODE cound > 0).
- */
- inout(Payload!T) get() inout
- in
- {
- assert(count > 0, "Attempted to access an uninitialized reference");
- }
- do
- {
- return this.storage.payload;
- }
-
- version (D_Ddoc)
- {
- /**
- * Dereferences the pointer. It is defined only for pointers, not for
- * reference types like classes, that can be accessed directly.
- *
- * Params:
- * op = Operation.
- *
- * Returns: Reference to the pointed value.
- */
- ref inout(T) opUnary(string op)() inout
- if (op == "*");
- }
- else static if (isPointer!(Payload!T))
- {
- ref inout(T) opUnary(string op)() inout
- if (op == "*")
- {
- return *this.storage.payload;
- }
- }
-
- /**
- * Returns: Whether this $(D_PSYMBOL RefCounted) already has an internal
- * storage.
- */
- @property bool isInitialized() const
- {
- return this.storage !is null;
- }
-
- /**
- * Returns: The number of $(D_PSYMBOL RefCounted) instances that share
- * ownership over the same pointer (including $(D_KEYWORD this)).
- * If this $(D_PSYMBOL RefCounted) isn't initialized, returns `0`.
- */
- @property size_t count() const
- {
- return this.storage is null ? 0 : this.storage.counter;
- }
-
- mixin DefaultAllocator;
- alias get this;
-}
-
-///
-@nogc @system unittest
-{
- auto rc = RefCounted!int(defaultAllocator.make!int(5), defaultAllocator);
- auto val = rc.get();
-
- *val = 8;
- assert(*rc.storage.payload == 8);
-
- val = null;
- assert(rc.storage.payload !is null);
- assert(*rc.storage.payload == 8);
-
- *rc = 9;
- assert(*rc.storage.payload == 9);
-}
-
-@nogc @system unittest
-{
- auto rc = defaultAllocator.refCounted!int(5);
- rc = defaultAllocator.make!int(7);
- assert(*rc == 7);
-}
-
-@nogc @system unittest
-{
- RefCounted!int rc;
- assert(!rc.isInitialized);
- rc = null;
- assert(!rc.isInitialized);
-}
-
-@nogc @system unittest
-{
- auto rc = defaultAllocator.refCounted!int(5);
-
- void func(RefCounted!int param) @nogc
- {
- assert(param.count == 2);
- param = defaultAllocator.make!int(7);
- assert(param.count == 1);
- assert(*param == 7);
- }
- func(rc);
- assert(rc.count == 1);
- assert(*rc == 5);
-}
-
-@nogc @system unittest
-{
- RefCounted!int rc;
-
- void func(RefCounted!int param) @nogc
- {
- assert(param.count == 0);
- param = defaultAllocator.make!int(7);
- assert(param.count == 1);
- assert(*param == 7);
- }
- func(rc);
- assert(rc.count == 0);
-}
-
-@nogc @system unittest
-{
- RefCounted!int rc1, rc2;
- static assert(is(typeof(rc1 = rc2)));
-}
-
-version (unittest)
-{
- private class A
- {
- uint *destroyed;
-
- this(ref uint destroyed) @nogc
- {
- this.destroyed = &destroyed;
- }
-
- ~this() @nogc
- {
- ++(*destroyed);
- }
- }
-
- private struct B
- {
- int prop;
- @disable this();
- this(int param1) @nogc
- {
- prop = param1;
- }
- }
-}
-
-@nogc @system unittest
-{
- uint destroyed;
- auto a = defaultAllocator.make!A(destroyed);
-
- assert(destroyed == 0);
- {
- auto rc = RefCounted!A(a, defaultAllocator);
- assert(rc.count == 1);
-
- void func(RefCounted!A rc) @nogc @system
- {
- assert(rc.count == 2);
- }
- func(rc);
-
- assert(rc.count == 1);
- }
- assert(destroyed == 1);
-
- RefCounted!int rc;
- assert(rc.count == 0);
- rc = defaultAllocator.make!int(8);
- assert(rc.count == 1);
-}
-
-@nogc @system unittest
-{
- auto rc = RefCounted!int(defaultAllocator);
- assert(!rc.isInitialized);
- assert(rc.allocator is defaultAllocator);
-}
-
-@nogc @system unittest
-{
- auto rc = defaultAllocator.refCounted!int(5);
- assert(rc.count == 1);
-
- void func(RefCounted!int rc) @nogc
- {
- 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);
-}
-
-@nogc @system unittest
-{
- auto rc = defaultAllocator.refCounted!int(5);
- assert(*rc == 5);
-
- void func(RefCounted!int rc) @nogc
- {
- assert(rc.count == 2);
- rc = defaultAllocator.refCounted!int(4);
- assert(*rc == 4);
- assert(rc.count == 1);
- }
- func(rc);
- assert(*rc == 5);
-}
-
-@nogc nothrow pure @safe unittest
-{
- static assert(is(typeof(RefCounted!int.storage.payload) == int*));
- static assert(is(typeof(RefCounted!A.storage.payload) == A));
-
- static assert(is(RefCounted!B));
- static assert(is(RefCounted!A));
-}
-
-/**
- * Constructs a new object of type $(D_PARAM T) and wraps it in a
- * $(D_PSYMBOL RefCounted) using $(D_PARAM args) as the parameter list for
- * the constructor of $(D_PARAM T).
- *
- * This function is more efficient than the using of $(D_PSYMBOL RefCounted)
- * directly, since it allocates only ones (the internal storage and the
- * object).
- *
- * 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 RefCounted!T).
- *
- * Precondition: $(D_INLINECODE allocator !is null)
- */
-RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
-if (!is(T == interface) && !isAbstractClass!T
- && !isAssociativeArray!T && !isArray!T)
-in
-{
- assert(allocator !is null);
-}
-do
-{
- auto rc = typeof(return)(allocator);
-
- const storageSize = alignedSize(stateSize!(RefCounted!T.Storage));
- const size = alignedSize(stateSize!T + storageSize);
-
- auto mem = (() @trusted => allocator.allocate(size))();
- if (mem is null)
- {
- onOutOfMemoryError();
- }
- scope (failure)
- {
- () @trusted { allocator.deallocate(mem); }();
- }
- rc.storage = emplace!(RefCounted!T.Storage)(mem[0 .. storageSize]);
- rc.storage.payload = emplace!T(mem[storageSize .. $], args);
-
- rc.deleter = &unifiedDeleter!(Payload!T);
- return rc;
-}
-
-/**
- * Constructs a new array with $(D_PARAM size) elements and wraps it in a
- * $(D_PSYMBOL RefCounted).
- *
- * Params:
- * T = Array type.
- * size = Array size.
- * allocator = Allocator.
- *
- * Returns: Newly created $(D_PSYMBOL RefCounted!T).
- *
- * Precondition: $(D_INLINECODE allocator !is null
- * && size <= size_t.max / ElementType!T.sizeof)
- */
-RefCounted!T refCounted(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);
-}
-do
-{
- return RefCounted!T(allocator.make!T(size), allocator);
-}
-
-///
-@nogc @system unittest
-{
- auto rc = defaultAllocator.refCounted!int(5);
- assert(rc.count == 1);
-
- void func(RefCounted!int param) @nogc
- {
- if (param.count == 2)
- {
- func(param);
- }
- else
- {
- assert(param.count == 3);
- }
- }
- func(rc);
-
- assert(rc.count == 1);
-}
-
-@nogc @system unittest
-{
- struct E
- {
- }
- auto b = defaultAllocator.refCounted!B(15);
- static assert(is(typeof(b.storage.payload) == B*));
- static assert(is(typeof(b.prop) == int));
- static assert(!is(typeof(defaultAllocator.refCounted!B())));
-
- static assert(is(typeof(defaultAllocator.refCounted!E())));
- static assert(!is(typeof(defaultAllocator.refCounted!E(5))));
- {
- auto rc = defaultAllocator.refCounted!B(3);
- assert(rc.get().prop == 3);
- }
- {
- auto rc = defaultAllocator.refCounted!E();
- assert(rc.count);
- }
-}
-
-@nogc @system unittest
-{
- auto rc = defaultAllocator.refCounted!(int[])(5);
- assert(rc.length == 5);
-}
-
-@nogc @system unittest
-{
- auto p1 = defaultAllocator.make!int(5);
- auto p2 = p1;
- auto rc = RefCounted!int(p1, defaultAllocator);
- assert(rc.get() is p2);
-}
-
-@nogc @system unittest
-{
- size_t destroyed;
- {
- auto rc = defaultAllocator.refCounted!WithDtor(destroyed);
- }
- assert(destroyed == 1);
-}
-
-/**
- * $(D_PSYMBOL Unique) stores an object that gets destroyed at the end of its scope.
- *
- * Params:
- * T = Value type.
- */
-struct Unique(T)
-{
- private Payload!T 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(Payload!T value, shared Allocator allocator = defaultAllocator)
- {
- this(allocator);
- this.payload = value;
- }
-
- /// ditto
- this(shared Allocator allocator)
- in
- {
- assert(allocator !is null);
- }
- do
- {
- this.allocator_ = allocator;
- }
-
- /**
- * $(D_PSYMBOL Unique) is noncopyable.
- */
- @disable this(this);
-
- /**
- * Destroys the owned object.
- */
- ~this()
- {
- allocator.dispose(this.payload);
- }
-
- /**
- * Initialized this $(D_PARAM Unique) and takes ownership over
- * $(D_PARAM rhs).
- *
- * To reset $(D_PSYMBOL Unique) 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 Unique) and assign it.
- *
- * Params:
- * rhs = New object.
- *
- * Returns: $(D_KEYWORD this).
- */
- ref typeof(this) opAssign(Payload!T rhs)
- {
- allocator.dispose(this.payload);
- this.payload = rhs;
- 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;
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- auto rc = defaultAllocator.unique!int(5);
- rc = defaultAllocator.make!int(7);
- assert(*rc == 7);
- }
-
- /**
- * Returns: Reference to the owned object.
- */
- inout(Payload!T) get() inout
- {
- return this.payload;
- }
-
- version (D_Ddoc)
- {
- /**
- * Dereferences the pointer. It is defined only for pointers, not for
- * reference types like classes, that can be accessed directly.
- *
- * Params:
- * op = Operation.
- *
- * Returns: Reference to the pointed value.
- */
- ref inout(T) opUnary(string op)() inout
- if (op == "*");
- }
- else static if (isPointer!(Payload!T))
- {
- ref inout(T) opUnary(string op)() inout
- if (op == "*")
- {
- return *this.payload;
- }
- }
-
- /**
- * Returns: Whether this $(D_PSYMBOL Unique) holds some value.
- */
- @property bool isInitialized() const
- {
- return this.payload !is null;
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- Unique!int u;
- assert(!u.isInitialized);
- }
-
- /**
- * Sets the internal pointer to $(D_KEYWORD). The allocator isn't changed.
- *
- * Returns: Reference to the owned object.
- */
- Payload!T release()
- {
- auto payload = this.payload;
- this.payload = null;
- return payload;
- }
-
- ///
- @nogc nothrow pure @system unittest
- {
- auto u = defaultAllocator.unique!int(5);
- assert(u.isInitialized);
-
- auto i = u.release();
- assert(*i == 5);
- assert(!u.isInitialized);
- }
-
- mixin DefaultAllocator;
- alias get this;
-}
-
-///
-@nogc nothrow pure @system unittest
-{
- auto p = defaultAllocator.make!int(5);
- auto s = Unique!int(p, defaultAllocator);
- assert(*s == 5);
-}
-
-///
-@nogc nothrow @system unittest
-{
- static bool destroyed;
-
- static struct F
- {
- ~this() @nogc nothrow @safe
- {
- destroyed = true;
- }
- }
- {
- auto s = Unique!F(defaultAllocator.make!F(), defaultAllocator);
- }
- assert(destroyed);
-}
-
-/**
- * Constructs a new object of type $(D_PARAM T) and wraps it in a
- * $(D_PSYMBOL Unique) 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 Unique!T).
- *
- * Precondition: $(D_INLINECODE allocator !is null)
- */
-Unique!T unique(T, A...)(shared Allocator allocator, auto ref A args)
-if (!is(T == interface) && !isAbstractClass!T
- && !isAssociativeArray!T && !isArray!T)
-in
-{
- assert(allocator !is null);
-}
-do
-{
- auto payload = allocator.make!(T, A)(args);
- return Unique!T(payload, allocator);
-}
-
-/**
- * Constructs a new array with $(D_PARAM size) elements and wraps it in a
- * $(D_PSYMBOL Unique).
- *
- * Params:
- * T = Array type.
- * size = Array size.
- * allocator = Allocator.
- *
- * Returns: Newly created $(D_PSYMBOL Unique!T).
- *
- * Precondition: $(D_INLINECODE allocator !is null
- * && size <= size_t.max / ElementType!T.sizeof)
- */
-Unique!T unique(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);
-}
-do
-{
- auto payload = allocator.resize!(ElementType!T)(null, size);
- return Unique!T(payload, allocator);
-}
-
-@nogc nothrow pure @safe unittest
-{
- static assert(is(typeof(defaultAllocator.unique!B(5))));
- static assert(is(typeof(defaultAllocator.unique!(int[])(5))));
-}
-
-@nogc nothrow pure @system unittest
-{
- auto s = defaultAllocator.unique!int(5);
- assert(*s == 5);
-
- s = null;
- assert(s is null);
-}
-
-@nogc nothrow pure @system unittest
-{
- auto s = defaultAllocator.unique!int(5);
- assert(*s == 5);
-
- s = defaultAllocator.unique!int(4);
- assert(*s == 4);
-}
-
-@nogc nothrow pure @system unittest
-{
- auto p1 = defaultAllocator.make!int(5);
- auto p2 = p1;
-
- auto rc = Unique!int(p1, defaultAllocator);
- assert(rc.get() is p2);
-}
-
-@nogc nothrow pure @system unittest
-{
- auto rc = Unique!int(defaultAllocator);
- assert(rc.allocator is defaultAllocator);
-}
diff --git a/source/tanya/net/ip.d b/source/tanya/net/ip.d
index 2296eac..2afdfe8 100644
--- a/source/tanya/net/ip.d
+++ b/source/tanya/net/ip.d
@@ -21,6 +21,7 @@ import tanya.container.string;
import tanya.conv;
import tanya.encoding.ascii;
import tanya.format;
+import tanya.memory.lifecycle;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.net.iface;
diff --git a/source/tanya/range/adapter.d b/source/tanya/range/adapter.d
index 13f4c1e..bc20e10 100644
--- a/source/tanya/range/adapter.d
+++ b/source/tanya/range/adapter.d
@@ -15,7 +15,7 @@
module tanya.range.adapter;
import tanya.algorithm.mutation;
-import tanya.functional;
+import tanya.memory.lifecycle;
import tanya.meta.trait;
import tanya.range;
diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d
index ae604e9..0b192b0 100644
--- a/source/tanya/range/primitive.d
+++ b/source/tanya/range/primitive.d
@@ -15,7 +15,7 @@
module tanya.range.primitive;
import tanya.algorithm.comparison;
-import tanya.algorithm.mutation;
+import tanya.memory.lifecycle;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range.array;
diff --git a/source/tanya/test/assertion.d b/source/tanya/test/assertion.d
deleted file mode 100644
index 10105d7..0000000
--- a/source/tanya/test/assertion.d
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Additional assertions.
- *
- * This module provides functions that assert whether a given expression
- * satisfies some complex condition, that can't be tested with
- * $(D_KEYWORD assert) in a single line. Internally all the functions
- * just evaluate the expression and call $(D_KEYWORD assert).
- *
- * The functions can cause segmentation fault if the module is compiled
- * in production mode and the condition fails.
- *
- * Copyright: Eugene Wissner 2017-2018.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/assertion.d,
- * tanya/test/assertion.d)
- */
-module tanya.test.assertion;
-
-import tanya.memory;
-import tanya.meta.trait;
-
-/**
- * Asserts whether the function $(D_PARAM expr) throws an exception of type
- * $(D_PARAM E). If it does, the exception is catched and properly destroyed.
- * If it doesn't, an assertion error is thrown. If the exception doesn't match
- * $(D_PARAM E) type, it isn't catched and escapes.
- *
- * Params:
- * E = Expected exception type.
- * T = Throwing function type.
- * Args = Argument types of the throwing function.
- * expr = Throwing function.
- * args = Arguments for $(D_PARAM expr).
- */
-void assertThrown(E : Exception, T, Args...)(T expr, auto ref Args args)
-if (isSomeFunction!T)
-{
- try
- {
- cast(void) expr(args);
- assert(false, "Expected exception not thrown");
- }
- catch (E exception)
- {
- defaultAllocator.dispose(exception);
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- // If you want to test that an expression throws, you can wrap it into an
- // arrow function.
- static struct CtorThrows
- {
- this(int i) @nogc pure @safe
- {
- throw defaultAllocator.make!Exception();
- }
- }
- assertThrown!Exception(() => CtorThrows(8));
-}
-
-/**
- * Asserts that the function $(D_PARAM expr) doesn't throw.
- *
- * If it does, the thrown exception is catched, properly destroyed and an
- * assertion error is thrown instead.
- *
- * Params:
- * T = Tested function type.
- * Args = Argument types of $(D_PARAM expr).
- * expr = Tested function.
- * args = Arguments for $(D_PARAM expr).
- */
-void assertNotThrown(T, Args...)(T expr, auto ref Args args)
-if (isSomeFunction!T)
-{
- try
- {
- cast(void) expr(args);
- }
- catch (Exception exception)
- {
- defaultAllocator.dispose(exception);
- assert(false, "Unexpected exception thrown");
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- // If you want to test that an expression doesn't throw, you can wrap it
- // into an arrow function.
- static struct S
- {
- }
- assertNotThrown(() => S());
-}
diff --git a/source/tanya/test/package.d b/source/tanya/test/package.d
deleted file mode 100644
index ab6f861..0000000
--- a/source/tanya/test/package.d
+++ /dev/null
@@ -1,18 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Test suite for $(D_KEYWORD unittest)-blocks.
- *
- * Copyright: Eugene Wissner 2017-2018.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/package.d,
- * tanya/test/package.d)
- */
-module tanya.test;
-
-public import tanya.test.assertion;
-public import tanya.test.stub;
diff --git a/source/tanya/test/stub.d b/source/tanya/test/stub.d
deleted file mode 100644
index e1f8dcb..0000000
--- a/source/tanya/test/stub.d
+++ /dev/null
@@ -1,373 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Range and generic type generators.
- *
- * Copyright: Eugene Wissner 2018.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/stub.d,
- * tanya/test/stub.d)
- */
-module tanya.test.stub;
-
-/**
- * Attribute signalizing that the generated range should contain the given
- * number of elements.
- *
- * $(D_PSYMBOL Count) should be always specified with some value and not as a
- * type, so $(D_INLINECODE Count(1)) instead just $(D_INLINECODE Count),
- * otherwise you can just omit $(D_PSYMBOL Count) and it will default to 0.
- *
- * $(D_PSYMBOL Count) doesn't generate `.length` property - use
- * $(D_PSYMBOL Length) for that.
- *
- * If neither $(D_PSYMBOL Length) nor $(D_PSYMBOL Infinite) is given,
- * $(D_ILNINECODE Count(0)) is assumed.
- *
- * This attribute conflicts with $(D_PSYMBOL Infinite) and $(D_PSYMBOL Length).
- */
-struct Count
-{
- /// Original range length.
- size_t count = 0;
-
- @disable this();
-
- /**
- * Constructs the attribute with the given length.
- *
- * Params:
- * count = Original range length.
- */
- this(size_t count) @nogc nothrow pure @safe
- {
- this.count = count;
- }
-}
-
-/**
- * Attribute signalizing that the generated range should be infinite.
- *
- * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Length).
- */
-struct Infinite
-{
-}
-
-/**
- * Generates `.length` property for the range.
- *
- * The length of the range can be specified as a constructor argument,
- * otherwise it is 0.
- *
- * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Infinite).
- */
-struct Length
-{
- /// Original range length.
- size_t length = 0;
-}
-
-/**
- * Attribute signalizing that the generated range should return values by
- * reference.
- *
- * This atribute affects the return values of `.front`, `.back` and `[]`.
- */
-struct WithLvalueElements
-{
-}
-
-/**
- * Generates an input range.
- *
- * Params:
- * E = Element type.
- */
-mixin template InputRangeStub(E = int)
-{
- import tanya.meta.metafunction : Alias;
- import tanya.meta.trait : evalUDA, getUDAs, hasUDA;
-
- /*
- * Aliases for the attribute lookups to access them faster
- */
- private enum bool infinite = hasUDA!(typeof(this), Infinite);
- private enum bool withLvalueElements = hasUDA!(typeof(this),
- WithLvalueElements);
- private alias Count = getUDAs!(typeof(this), .Count);
- private alias Length = getUDAs!(typeof(this), .Length);
-
- static if (Count.length != 0)
- {
- private enum size_t count = Count[0].count;
-
- static assert (!infinite,
- "Range cannot have count and be infinite at the same time");
- static assert (Length.length == 0,
- "Range cannot have count and length at the same time");
- }
- else static if (Length.length != 0)
- {
- private enum size_t count = evalUDA!(Length[0]).length;
-
- static assert (!infinite,
- "Range cannot have length and be infinite at the same time");
- }
- else static if (!infinite)
- {
- private enum size_t count = 0;
- }
-
- /*
- * Member generation
- */
- static if (infinite)
- {
- enum bool empty = false;
- }
- else
- {
- private size_t length_ = count;
-
- @property bool empty() const @nogc nothrow pure @safe
- {
- return this.length_ == 0;
- }
- }
-
- static if (withLvalueElements)
- {
- private E* element; // Pointer to enable range copying in save()
- }
-
- void popFront() @nogc nothrow pure @safe
- in (!empty)
- {
- static if (!infinite)
- {
- --this.length_;
- }
- }
-
- static if (withLvalueElements)
- {
- ref E front() @nogc nothrow pure @safe
- in (!empty)
- {
- return *this.element;
- }
- }
- else
- {
- E front() @nogc nothrow pure @safe
- in (!empty)
- {
- return E.init;
- }
- }
-
- static if (Length.length != 0)
- {
- size_t length() const @nogc nothrow pure @safe
- {
- return this.length_;
- }
- }
-}
-
-/**
- * Generates a forward range.
- *
- * This mixin includes input range primitives as well, but can be combined with
- * $(D_PSYMBOL RandomAccessRangeStub).
- *
- * Params:
- * E = Element type.
- */
-mixin template ForwardRangeStub(E = int)
-{
- static if (!is(typeof(this.InputRangeMixin) == void))
- {
- mixin InputRangeStub!E InputRangeMixin;
- }
-
- auto save() @nogc nothrow pure @safe
- {
- return this;
- }
-}
-
-/**
- * Generates a bidirectional range.
- *
- * This mixin includes forward range primitives as well, but can be combined with
- * $(D_PSYMBOL RandomAccessRangeStub).
- *
- * Params:
- * E = Element type.
- */
-mixin template BidirectionalRangeStub(E = int)
-{
- mixin ForwardRangeStub!E;
-
- void popBack() @nogc nothrow pure @safe
- in (!empty)
- {
- static if (!infinite)
- {
- --this.length_;
- }
- }
-
- static if (withLvalueElements)
- {
- ref E back() @nogc nothrow pure @safe
- in (!empty)
- {
- return *this.element;
- }
- }
- else
- {
- E back() @nogc nothrow pure @safe
- in (!empty)
- {
- return E.init;
- }
- }
-}
-
-/**
- * Generates a random-access range.
- *
- * This mixin includes input range primitives as well, but can be combined with
- * $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub).
- *
- * Note that a random-access range also requires $(D_PSYMBOL Length) or
- * $(D_PARAM Infinite) by definition.
- *
- * Params:
- * E = Element type.
- */
-mixin template RandomAccessRangeStub(E = int)
-{
- static if (!is(typeof(this.InputRangeMixin) == void))
- {
- mixin InputRangeStub!E InputRangeMixin;
- }
-
- static if (withLvalueElements)
- {
- ref E opIndex(size_t) @nogc nothrow pure @safe
- {
- return *this.element;
- }
- }
- else
- {
- E opIndex(size_t) @nogc nothrow pure @safe
- {
- return E.init;
- }
- }
-}
-
-/**
- * Struct with a disabled postblit constructor.
- *
- * $(D_PSYMBOL NonCopyable) can be used as an attribute for
- * $(D_PSYMBOL StructStub) or as a standalone type.
- */
-struct NonCopyable
-{
- @disable this(this);
-}
-
-/**
- * Struct with an elaborate destructor.
- *
- * $(D_PSYMBOL WithDtor) can be used as an attribute for
- * $(D_PSYMBOL StructStub) or as a standalone type.
- *
- * When used as a standalone object the constructor of $(D_PSYMBOL WithDtor)
- * accepts an additional `counter` argument, which is incremented by the
- * destructor. $(D_PSYMBOL WithDtor) stores a pointer to the passed variable,
- * so the variable can be investigated after the struct isn't available
- * anymore.
- */
-struct WithDtor
-{
- size_t* counter;
-
- this(ref size_t counter) @nogc nothrow pure @trusted
- {
- this.counter = &counter;
- }
-
- ~this() @nogc nothrow pure @safe
- {
- if (this.counter !is null)
- {
- ++*this.counter;
- }
- }
-}
-
-/**
- * Struct supporting hashing.
- *
- * $(D_PSYMBOL Hashable) can be used as an attribute for
- * $(D_PSYMBOL StructStub) or as a standalone type.
- *
- * The constructor accepts an additional parameter, which is returned by the
- * `toHash()`-function. `0U` is returned if no hash value is given.
- */
-struct Hashable
-{
- size_t hash;
-
- size_t toHash() const @nogc nothrow pure @safe
- {
- return this.hash;
- }
-}
-
-/**
- * Generates a $(D_KEYWORD struct) with common functionality.
- *
- * To specify the needed functionality use user-defined attributes on the
- * $(D_KEYWORD struct) $(D_PSYMBOL StructStub) is mixed in.
- *
- * Supported attributes are: $(D_PSYMBOL NonCopyable), $(D_PSYMBOL Hashable),
- * $(D_PSYMBOL WithDtor).
- */
-mixin template StructStub()
-{
- import tanya.meta.trait : evalUDA, getUDAs, hasUDA;
-
- static if (hasUDA!(typeof(this), NonCopyable))
- {
- @disable this(this);
- }
-
- private alias Hashable = getUDAs!(typeof(this), .Hashable);
- static if (Hashable.length > 0)
- {
- size_t toHash() const @nogc nothrow pure @safe
- {
- return evalUDA!(Hashable[0]).hash;
- }
- }
-
- static if (hasUDA!(typeof(this), WithDtor))
- {
- ~this() @nogc nothrow pure @safe
- {
- }
- }
-}
diff --git a/source/tanya/typecons.d b/source/tanya/typecons.d
index 1407c62..fa09831 100644
--- a/source/tanya/typecons.d
+++ b/source/tanya/typecons.d
@@ -17,10 +17,8 @@
*/
module tanya.typecons;
-import tanya.algorithm.mutation;
-import tanya.conv;
import tanya.format;
-import tanya.functional;
+import tanya.memory.lifecycle;
import tanya.meta.metafunction;
import tanya.meta.trait;
version (unittest) import tanya.test.stub;