Move memory/package.d into memory.allocator

This commit is contained in:
Eugen Wissner 2019-03-22 08:18:01 +01:00
parent a36b51f0c3
commit ad46afb10b
43 changed files with 489 additions and 537 deletions

View File

@ -8,7 +8,6 @@ language: d
d: d:
- dmd-2.085.0 - dmd-2.085.0
- dmd-2.084.1
- dmd-2.082.1 - dmd-2.082.1
env: env:

View File

@ -172,12 +172,10 @@ parameter is used)
### Supported compilers ### Supported compilers
| DMD | GCC | | DMD | GCC |
|:-------:|:---------------:| |:-----------------:|:---------------:|
| 2.085.0 | gdc-8 (2.081.2) | | 2.081.2 — 2.085.0 | gdc-8 (2.081.2) |
| 2.084.1 | gdc-7 (2.081.2) | | | gdc-7 (2.081.2) |
| 2.083.1 | |
| 2.082.1 | |
### Release management ### Release management

View File

@ -9,12 +9,6 @@ environment:
- DC: dmd - DC: dmd
DVersion: 2.085.0 DVersion: 2.085.0
arch: x86 arch: x86
- DC: dmd
DVersion: 2.084.1
arch: x64
- DC: dmd
DVersion: 2.084.1
arch: x86
- DC: dmd - DC: dmd
DVersion: 2.082.1 DVersion: 2.082.1
arch: x64 arch: x64

View File

@ -17,6 +17,9 @@
*/ */
module tanya.memory.allocator; module tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait;
/** /**
* Abstract class implementing a basic allocator. * Abstract class implementing a basic allocator.
*/ */
@ -79,3 +82,416 @@ package template GetPureInstance(T : Allocator)
alias GetPureInstance = shared(T) function() alias GetPureInstance = shared(T) function()
pure nothrow @nogc; pure nothrow @nogc;
} }
/**
* 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 (allocator !is null)
{
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; allocator !is null)
{
if (allocator_ is null)
{
allocator_ = defaultAllocator;
}
return allocator_;
}
/// ditto
@property shared(Allocator) allocator() const @nogc nothrow pure @trusted
out (allocator; allocator !is null)
{
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 : MmapPool;
defaultAllocator = MmapPool.instance;
}
else
{
import tanya.memory.mallocator : 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; allocator !is null)
{
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 (allocator !is null)
{
.allocator = allocator;
}
/**
* 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;
}
/**
* 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);
}
}
/**
* 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;
}
/**
* 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 (!isPolymorphicType!T && !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.
* E = Array element type.
* allocator = Allocator.
* n = Array size.
*
* Returns: Newly created array.
*
* Precondition: $(D_INLINECODE allocator !is null
* && n <= size_t.max / E.sizeof)
*/
T make(T : E[], E)(shared Allocator allocator, size_t n)
in (allocator !is null)
in (n <= size_t.max / E.sizeof)
{
auto ret = allocator.resize!E(null, n);
static if (hasElaborateDestructor!E)
{
for (auto range = ret; range.length != 0; range = range[1 .. $])
{
emplace!E(cast(void[]) range[0 .. 1], E.init);
}
}
else
{
ret[] = E.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);
}
/*
* Destroys the object.
* Returns the memory should be freed.
*/
package 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 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 void[] finalize(T)(ref T[] p)
{
destroyAllImpl!(T[], T)(p);
return p;
}
/**
* 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;
}

View File

@ -14,183 +14,10 @@
*/ */
module tanya.memory.lifetime; module tanya.memory.lifetime;
import tanya.memory : defaultAllocator;
import tanya.memory.allocator; import tanya.memory.allocator;
import tanya.meta.metafunction; import tanya.meta.metafunction;
import tanya.meta.trait; import tanya.meta.trait;
/**
* 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;
}
/*
* Destroys the object.
* Returns the memory should be freed.
*/
package(tanya.memory) 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.memory) 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.memory) void[] finalize(T)(ref T[] p)
{
destroyAllImpl!(T[], T)(p);
return p;
}
package(tanya) void destroyAllImpl(R, E)(R p) package(tanya) void destroyAllImpl(R, E)(R p)
{ {
static if (hasElaborateDestructor!E) static if (hasElaborateDestructor!E)
@ -202,136 +29,6 @@ package(tanya) void destroyAllImpl(R, E)(R 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;
}
/**
* 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 (!isPolymorphicType!T && !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.
* E = Array element type.
* allocator = Allocator.
* n = Array size.
*
* Returns: Newly created array.
*
* Precondition: $(D_INLINECODE allocator !is null
* && n <= size_t.max / E.sizeof)
*/
T make(T : E[], E)(shared Allocator allocator, size_t n)
in (allocator !is null)
in (n <= size_t.max / E.sizeof)
{
auto ret = allocator.resize!E(null, n);
static if (hasElaborateDestructor!E)
{
for (auto range = ret; range.length != 0; range = range[1 .. $])
{
emplace!E(cast(void[]) range[0 .. 1], E.init);
}
}
else
{
ret[] = E.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);
}
/** /**
* Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the * Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the
* given arguments. * given arguments.
@ -594,11 +291,7 @@ private void deinitialize(bool zero, T)(ref T value)
* Precondition: `&source !is &target`. * Precondition: `&source !is &target`.
*/ */
void moveEmplace(T)(ref T source, ref T target) @system void moveEmplace(T)(ref T source, ref T target) @system
in in (&source !is &target, "Source and target must be different")
{
assert(&source !is &target, "Source and target must be different");
}
do
{ {
static if (is(T == struct) || isStaticArray!T) static if (is(T == struct) || isStaticArray!T)
{ {

View File

@ -52,13 +52,9 @@ private enum alignMask = size_t.sizeof - 1;
* Precondition: $(D_INLINECODE source.length <= target.length). * Precondition: $(D_INLINECODE source.length <= target.length).
*/ */
void copy(const void[] source, void[] target) @nogc nothrow pure @trusted void copy(const void[] source, void[] target) @nogc nothrow pure @trusted
in in (source.length <= target.length)
{ in (source.length == 0 || source.ptr !is null)
assert(source.length <= target.length); in (target.length == 0 || target.ptr !is null)
assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null);
}
do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -102,11 +98,7 @@ private template filledBytes(ubyte Byte, ubyte I = 0)
* memory = Memory block. * memory = Memory block.
*/ */
void fill(ubyte c = 0)(void[] memory) @trusted void fill(ubyte c = 0)(void[] memory) @trusted
in in (memory.length == 0 || memory.ptr !is null)
{
assert(memory.length == 0 || memory.ptr !is null);
}
do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -152,13 +144,9 @@ do
* Precondition: $(D_INLINECODE source.length <= target.length). * Precondition: $(D_INLINECODE source.length <= target.length).
*/ */
void copyBackward(const void[] source, void[] target) @nogc nothrow pure @trusted void copyBackward(const void[] source, void[] target) @nogc nothrow pure @trusted
in in (source.length <= target.length)
{ in (source.length == 0 || source.ptr !is null)
assert(source.length <= target.length); in (target.length == 0 || target.ptr !is null)
assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null);
}
do
{ {
version (TanyaNative) version (TanyaNative)
{ {
@ -194,11 +182,7 @@ do
*/ */
inout(void[]) find(return inout void[] haystack, ubyte needle) inout(void[]) find(return inout void[] haystack, ubyte needle)
@nogc nothrow pure @trusted @nogc nothrow pure @trusted
in in (haystack.length == 0 || haystack.ptr !is null)
{
assert(haystack.length == 0 || haystack.ptr !is null);
}
do
{ {
auto length = haystack.length; auto length = haystack.length;
const size_t needleWord = size_t.max * needle; const size_t needleWord = size_t.max * needle;
@ -276,11 +260,7 @@ do
*/ */
inout(char[]) findNullTerminated(return inout char[] haystack) inout(char[]) findNullTerminated(return inout char[] haystack)
@nogc nothrow pure @trusted @nogc nothrow pure @trusted
in in (haystack.length == 0 || haystack.ptr !is null)
{
assert(haystack.length == 0 || haystack.ptr !is null);
}
do
{ {
auto length = haystack.length; auto length = haystack.length;
enum size_t highBits = filledBytes!(0x01, 0); enum size_t highBits = filledBytes!(0x01, 0);
@ -347,12 +327,8 @@ do
* $(D_KEYWORD false) otherwise. * $(D_KEYWORD false) otherwise.
*/ */
bool equal(const void[] r1, const void[] r2) @nogc nothrow pure @trusted bool equal(const void[] r1, const void[] r2) @nogc nothrow pure @trusted
in in (r1.length == 0 || r1.ptr !is null)
{ in (r2.length == 0 || r2.ptr !is null)
assert(r1.length == 0 || r1.ptr !is null);
assert(r2.length == 0 || r2.ptr !is null);
}
do
{ {
version (TanyaNative) version (TanyaNative)
{ {

View File

@ -16,117 +16,5 @@ module tanya.memory;
public import tanya.memory.allocator; public import tanya.memory.allocator;
public import tanya.memory.lifetime; public import tanya.memory.lifetime;
import tanya.meta.trait;
deprecated("Use tanya.meta.trait.stateSize instead") deprecated("Use tanya.meta.trait.stateSize instead")
public import tanya.meta.trait : stateSize; public import tanya.meta.trait : stateSize;
/**
* 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 (allocator !is null)
{
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; allocator !is null)
{
if (allocator_ is null)
{
allocator_ = defaultAllocator;
}
return allocator_;
}
/// ditto
@property shared(Allocator) allocator() const @nogc nothrow pure @trusted
out (allocator; allocator !is null)
{
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; allocator !is null)
{
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 (allocator !is null)
{
.allocator = allocator;
}
/**
* 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;
}

View File

@ -23,7 +23,8 @@
*/ */
module tanya.memory.smartref; module tanya.memory.smartref;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
private template Payload(T) private template Payload(T)

View File

@ -5,7 +5,7 @@
/** /**
* Event loop implementation for Linux. * Event loop implementation for Linux.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -30,7 +30,7 @@ import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.memory; import tanya.memory.allocator;
import tanya.network.socket; import tanya.network.socket;
extern (C) nothrow @nogc extern (C) nothrow @nogc

View File

@ -5,7 +5,7 @@
/** /**
* Event loop implementation for Windows. * Event loop implementation for Windows.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -26,7 +26,7 @@ import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.memory; import tanya.memory.allocator;
import tanya.network.socket; import tanya.network.socket;
import tanya.sys.windows.winbase; import tanya.sys.windows.winbase;

View File

@ -5,7 +5,7 @@
/* /*
* Event loop implementation for *BSD. * Event loop implementation for *BSD.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -58,7 +58,7 @@ import tanya.async.loop;
import tanya.async.transport; import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.memory; import tanya.memory.allocator;
import tanya.network.socket; import tanya.network.socket;
void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args) pure nothrow @nogc void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args) pure nothrow @nogc

View File

@ -5,7 +5,7 @@
/* /*
* This module contains base implementations for reactor event loops. * This module contains base implementations for reactor event loops.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -25,7 +25,7 @@ import tanya.async.transport;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.container.array; import tanya.container.array;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.memory; import tanya.memory.allocator;
import tanya.network.socket; import tanya.network.socket;
/** /**

View File

@ -7,7 +7,7 @@
* *
* Note: Available only on Windows. * Note: Available only on Windows.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -62,7 +62,7 @@
* } * }
* --- * ---
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -77,7 +77,7 @@ import tanya.async.watcher;
import tanya.bitmanip; import tanya.bitmanip;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.container.list; import tanya.container.list;
import tanya.memory; import tanya.memory.allocator;
import tanya.network.socket; import tanya.network.socket;
version (DisableBackends) version (DisableBackends)

View File

@ -5,7 +5,7 @@
/** /**
* This package provides asynchronous capabilities. * This package provides asynchronous capabilities.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -9,7 +9,7 @@
* When an event from the network arrives, a protocol method gets * When an event from the network arrives, a protocol method gets
* called and can respond to the event. * called and can respond to the event.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -6,7 +6,7 @@
* This module contains transports which are responsible for data dilvery * This module contains transports which are responsible for data dilvery
* between two parties of an asynchronous communication. * between two parties of an asynchronous communication.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -5,7 +5,7 @@
/** /**
* Watchers register user's interest in some event. * Watchers register user's interest in some event.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -19,7 +19,7 @@ import tanya.async.protocol;
import tanya.async.transport; import tanya.async.transport;
import tanya.container.buffer; import tanya.container.buffer;
import tanya.container.list; import tanya.container.list;
import tanya.memory; import tanya.memory.allocator;
import tanya.network.socket; import tanya.network.socket;
/** /**

View File

@ -17,7 +17,8 @@ module tanya.container.array;
import core.checkedint; import core.checkedint;
import tanya.algorithm.comparison; import tanya.algorithm.comparison;
import tanya.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range; import tanya.range;

View File

@ -14,7 +14,7 @@
*/ */
module tanya.container.buffer; module tanya.container.buffer;
import tanya.memory; import tanya.memory.allocator;
import tanya.meta.trait; import tanya.meta.trait;
version (unittest) version (unittest)

View File

@ -18,7 +18,8 @@ import tanya.algorithm.mutation;
import tanya.container.array; import tanya.container.array;
import tanya.container.entry; import tanya.container.entry;
import tanya.hash.lookup; import tanya.hash.lookup;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.primitive; import tanya.range.primitive;

View File

@ -17,7 +17,8 @@ module tanya.container.list;
import tanya.algorithm.comparison; import tanya.algorithm.comparison;
import tanya.container.entry; import tanya.container.entry;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.array; import tanya.range.array;

View File

@ -18,7 +18,8 @@ module tanya.container.set;
import tanya.container.array; import tanya.container.array;
import tanya.container.entry; import tanya.container.entry;
import tanya.hash.lookup; import tanya.hash.lookup;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.primitive; import tanya.range.primitive;

View File

@ -29,7 +29,8 @@ module tanya.container.string;
import tanya.algorithm.comparison; import tanya.algorithm.comparison;
import tanya.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.hash.lookup; import tanya.hash.lookup;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range.array; import tanya.range.array;

View File

@ -15,7 +15,7 @@
module tanya.conv; module tanya.conv;
import tanya.container.string; import tanya.container.string;
import tanya.memory; import tanya.memory.allocator;
deprecated("Use tanya.memory.lifetime.emplace instead") deprecated("Use tanya.memory.lifetime.emplace instead")
public import tanya.memory.lifetime : emplace; public import tanya.memory.lifetime : emplace;
import tanya.meta.trait; import tanya.meta.trait;
@ -64,12 +64,8 @@ if (isInputRange!R
&& isSomeChar!(ElementType!R) && isSomeChar!(ElementType!R)
&& isIntegral!T && isIntegral!T
&& isUnsigned!T) && isUnsigned!T)
in in (base >= 2)
{ in (base <= 36)
assert(base >= 2);
assert(base <= 36);
}
do
{ {
T boundary = cast(T) (T.max / base); T boundary = cast(T) (T.max / base);
if (range.empty) if (range.empty)

View File

@ -10,7 +10,7 @@
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/exception.d, * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/exception.d,
* tanya/exception.d) * tanya/exception.d)
*/ */
deprecated("Use tanya.memory.lifetimeinstead") deprecated("Use tanya.memory.allocator instead")
module tanya.exception; module tanya.exception;
public import tanya.memory.lifetime : onOutOfMemoryError, OutOfMemoryError; public import tanya.memory.allocator : onOutOfMemoryError, OutOfMemoryError;

View File

@ -1175,11 +1175,7 @@ private struct uint128
} }
Tuple!(uint128, uint128) divMod(ulong rhs) const @nogc nothrow pure @safe Tuple!(uint128, uint128) divMod(ulong rhs) const @nogc nothrow pure @safe
in in (rhs != uint128(), "Division by 0")
{
assert(rhs != uint128(), "Division by 0");
}
do
{ {
if (rhs == 1) if (rhs == 1)
{ {
@ -1279,11 +1275,7 @@ private int indexMismatch(ulong low, ulong high) @nogc nothrow pure @safe
private char[] errol2(double value, private char[] errol2(double value,
return ref char[512] buffer, return ref char[512] buffer,
out int exponent) @nogc nothrow pure @safe out int exponent) @nogc nothrow pure @safe
in in (value > 9.007199254740992e15 && value < 3.40282366920938e38)
{
assert(value > 9.007199254740992e15 && value < 3.40282366920938e38);
}
do
{ {
auto v = uint128(value); auto v = uint128(value);
auto leftBoundary = v + raise2ToExp((value - previous(value)) / 2.0); auto leftBoundary = v + raise2ToExp((value - previous(value)) / 2.0);
@ -1368,11 +1360,7 @@ do
private char[] errolFixed(double value, private char[] errolFixed(double value,
return ref char[512] buffer, return ref char[512] buffer,
out int exponent) @nogc nothrow pure @safe out int exponent) @nogc nothrow pure @safe
in in (value >= 16.0 && value <= 9.007199254740992e15)
{
assert(value >= 16.0 && value <= 9.007199254740992e15);
}
do
{ {
auto decimal = cast(ulong) value; auto decimal = cast(ulong) value;
auto n = cast(double) decimal; auto n = cast(double) decimal;

View File

@ -19,7 +19,8 @@ import tanya.algorithm.iteration;
import tanya.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.container.array; import tanya.container.array;
import tanya.encoding.ascii; import tanya.encoding.ascii;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform; import tanya.meta.transform;
import tanya.range; import tanya.range;

View File

@ -14,7 +14,7 @@
*/ */
module tanya.math.random; module tanya.math.random;
import tanya.memory; import tanya.memory.allocator;
import tanya.typecons; import tanya.typecons;
/// Maximum amount gathered from the entropy sources. /// Maximum amount gathered from the entropy sources.

View File

@ -16,7 +16,7 @@ module tanya.net.uri;
import tanya.conv; import tanya.conv;
import tanya.encoding.ascii; import tanya.encoding.ascii;
import tanya.memory; import tanya.memory.allocator;
/** /**
* Thrown if an invalid URI was specified. * Thrown if an invalid URI was specified.

View File

@ -5,7 +5,7 @@
/** /**
* Network programming. * Network programming.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -41,7 +41,7 @@
* For an example of an asynchronous server refer to the documentation of the * For an example of an asynchronous server refer to the documentation of the
* $(D_PSYMBOL tanya.async.loop) module. * $(D_PSYMBOL tanya.async.loop) module.
* *
* Copyright: Eugene Wissner 2016-2018. * Copyright: Eugene Wissner 2016-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -55,7 +55,7 @@ import core.time;
public import std.socket : SocketOption, SocketOptionLevel; public import std.socket : SocketOption, SocketOptionLevel;
import tanya.algorithm.comparison; import tanya.algorithm.comparison;
import tanya.bitmanip; import tanya.bitmanip;
import tanya.memory; import tanya.memory.allocator;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.os.error; import tanya.os.error;

View File

@ -296,11 +296,7 @@ struct Option(T)
/// ditto /// ditto
bool opEquals(U)(auto ref const U that) const bool opEquals(U)(auto ref const U that) const
if (ifTestable!(U, a => a == T.init) && !is(U == Option)) if (ifTestable!(U, a => a == T.init) && !is(U == Option))
in in (!isNothing)
{
assert(!isNothing);
}
do
{ {
return get == that; return get == that;
} }

View File

@ -13,7 +13,7 @@
* The functions can cause segmentation fault if the module is compiled * The functions can cause segmentation fault if the module is compiled
* in production mode and the condition fails. * in production mode and the condition fails.
* *
* Copyright: Eugene Wissner 2017-2018. * Copyright: Eugene Wissner 2017-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -22,7 +22,7 @@
*/ */
module tanya.test.assertion; module tanya.test.assertion;
import tanya.memory; import tanya.memory.allocator;
import tanya.meta.trait; import tanya.meta.trait;
/** /**

View File

@ -5,7 +5,7 @@
/** /**
* Test suite for $(D_KEYWORD unittest)-blocks. * Test suite for $(D_KEYWORD unittest)-blocks.
* *
* Copyright: Eugene Wissner 2017-2018. * Copyright: Eugene Wissner 2017-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -5,7 +5,7 @@
/** /**
* Range and generic type generators. * Range and generic type generators.
* *
* Copyright: Eugene Wissner 2018. * Copyright: Eugene Wissner 2018-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -6,7 +6,7 @@ module tanya.async.tests.loop;
import core.time; import core.time;
import tanya.async.loop; import tanya.async.loop;
import tanya.async.watcher; import tanya.async.watcher;
import tanya.memory; import tanya.memory.allocator;
private final class DummyWatcher : Watcher private final class DummyWatcher : Watcher
{ {

View File

@ -5,7 +5,7 @@ module tanya.container.tests.array;
import tanya.algorithm.comparison; import tanya.algorithm.comparison;
import tanya.container.array; import tanya.container.array;
import tanya.memory; import tanya.memory.allocator;
import tanya.test.stub; import tanya.test.stub;
// const arrays return usable ranges // const arrays return usable ranges

View File

@ -4,7 +4,7 @@
module tanya.container.tests.set; module tanya.container.tests.set;
import tanya.container.set; import tanya.container.set;
import tanya.memory; import tanya.memory.allocator;
import tanya.test.stub; import tanya.test.stub;
// Basic insertion logic. // Basic insertion logic.

View File

@ -4,7 +4,7 @@
module tanya.math.tests.random; module tanya.math.tests.random;
import tanya.math.random; import tanya.math.random;
import tanya.memory; import tanya.memory.allocator;
static if (is(PlatformEntropySource)) @nogc @system unittest static if (is(PlatformEntropySource)) @nogc @system unittest
{ {

View File

@ -3,7 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
module tanya.memory.tests.lifetime; module tanya.memory.tests.lifetime;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.lifetime;
import tanya.test.stub; import tanya.test.stub;
@nogc nothrow pure @safe unittest @nogc nothrow pure @safe unittest

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
module tanya.memory.tests.smartref; module tanya.memory.tests.smartref;
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.smartref; import tanya.memory.smartref;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.test.stub; import tanya.test.stub;

View File

@ -175,7 +175,7 @@ import tanya.range;
// Aggregate types // Aggregate types
@system unittest // Object.toString has no attributes. @system unittest // Object.toString has no attributes.
{ {
import tanya.memory; import tanya.memory.allocator;
import tanya.memory.smartref; import tanya.memory.smartref;
interface I interface I