Move memory functions into memory.lifecycle
- move - moveEmplace - forward - emplace - swap
This commit is contained in:
parent
85d7a2b9ca
commit
5ab99cf887
@ -23,7 +23,7 @@ matrix:
|
|||||||
include:
|
include:
|
||||||
- name: D-Scanner
|
- name: D-Scanner
|
||||||
d: dmd-$LATEST
|
d: dmd-$LATEST
|
||||||
env: DSCANNER=0.6.0
|
env: DSCANNER=0.7.0
|
||||||
os: linux
|
os: linux
|
||||||
- name: DDoc
|
- name: DDoc
|
||||||
d: dmd-$LATEST
|
d: dmd-$LATEST
|
||||||
@ -32,7 +32,7 @@ matrix:
|
|||||||
allow_failures:
|
allow_failures:
|
||||||
- name: D-Scanner
|
- name: D-Scanner
|
||||||
d: dmd-$LATEST
|
d: dmd-$LATEST
|
||||||
env: DSCANNER=0.6.0
|
env: DSCANNER=0.7.0
|
||||||
os: linux
|
os: linux
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@ -53,12 +53,14 @@ script:
|
|||||||
dub build :sys -b ddox --compiler=$DC;
|
dub build :sys -b ddox --compiler=$DC;
|
||||||
dub build :os -b ddox --compiler=$DC;
|
dub build :os -b ddox --compiler=$DC;
|
||||||
dub build :encoding -b ddox --compiler=$DC;
|
dub build :encoding -b ddox --compiler=$DC;
|
||||||
|
dub build :memory -b ddox --compiler=$DC;
|
||||||
dub build -b ddox --compiler=$DC;
|
dub build -b ddox --compiler=$DC;
|
||||||
elif [ -z "$DSCANNER" ]; then
|
elif [ -z "$DSCANNER" ]; then
|
||||||
dub test :meta -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
dub test :meta -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
||||||
dub test :sys -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
dub test :sys -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
||||||
dub test :os -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
dub test :os -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
||||||
dub test :encoding -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
dub test :encoding -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
||||||
|
dub test :memory -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
||||||
dub test -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
dub test -b ${UNITTEST:-unittest} --arch=$ARCH --compiler=$DC;
|
||||||
else
|
else
|
||||||
dub fetch dscanner --version=$DSCANNER;
|
dub fetch dscanner --version=$DSCANNER;
|
||||||
|
@ -61,4 +61,5 @@ test_script:
|
|||||||
- dub test :sys -b unittest --arch=%Darch% --compiler=%DC%
|
- dub test :sys -b unittest --arch=%Darch% --compiler=%DC%
|
||||||
- dub test :os -b unittest --arch=%Darch% --compiler=%DC%
|
- dub test :os -b unittest --arch=%Darch% --compiler=%DC%
|
||||||
- dub test :encoding -b unittest --arch=%Darch% --compiler=%DC%
|
- dub test :encoding -b unittest --arch=%Darch% --compiler=%DC%
|
||||||
|
- dub test :memory -b unittest --arch=%Darch% --compiler=%DC%
|
||||||
- dub test -b unittest --arch=%Darch% --compiler=%DC%
|
- dub test -b unittest --arch=%Darch% --compiler=%DC%
|
||||||
|
6
dub.json
6
dub.json
@ -13,7 +13,8 @@
|
|||||||
"tanya:meta": "*",
|
"tanya:meta": "*",
|
||||||
"tanya:sys": "*",
|
"tanya:sys": "*",
|
||||||
"tanya:os": "*",
|
"tanya:os": "*",
|
||||||
"tanya:encoding": "*"
|
"tanya:encoding": "*",
|
||||||
|
"tanya:memory": "*"
|
||||||
},
|
},
|
||||||
|
|
||||||
"dependencies-linux": {
|
"dependencies-linux": {
|
||||||
@ -24,7 +25,8 @@
|
|||||||
"./meta",
|
"./meta",
|
||||||
"./sys",
|
"./sys",
|
||||||
"./os",
|
"./os",
|
||||||
"./encoding"
|
"./encoding",
|
||||||
|
"./memory"
|
||||||
],
|
],
|
||||||
|
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
@ -5,5 +5,12 @@
|
|||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tanya:meta": "*"
|
"tanya:meta": "*"
|
||||||
}
|
},
|
||||||
|
|
||||||
|
"sourcePaths": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"importPaths": [
|
||||||
|
"."
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/encoding/ascii.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/encoding/tanya/encoding/ascii.d,
|
||||||
* tanya/encoding/ascii.d)
|
* tanya/encoding/ascii.d)
|
||||||
*/
|
*/
|
||||||
module tanya.encoding.ascii;
|
module tanya.encoding.ascii;
|
@ -9,7 +9,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/encoding/package.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/encoding/tanya/encoding/package.d,
|
||||||
* tanya/encoding/package.d)
|
* tanya/encoding/package.d)
|
||||||
*/
|
*/
|
||||||
module tanya.encoding;
|
module tanya.encoding;
|
18
memory/dub.json
Normal file
18
memory/dub.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "memory",
|
||||||
|
"description": "Tools for manual memory management (allocators, smart pointers)",
|
||||||
|
"targetType": "library",
|
||||||
|
|
||||||
|
"dependencies": {
|
||||||
|
"tanya:meta": "*",
|
||||||
|
"tanya:os": "*",
|
||||||
|
"tanya:sys": "*"
|
||||||
|
},
|
||||||
|
|
||||||
|
"sourcePaths": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"importPaths": [
|
||||||
|
"."
|
||||||
|
]
|
||||||
|
}
|
@ -12,7 +12,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/allocator.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/memory/tanya/memory/allocator.d,
|
||||||
* tanya/memory/allocator.d)
|
* tanya/memory/allocator.d)
|
||||||
*/
|
*/
|
||||||
module tanya.memory.allocator;
|
module tanya.memory.allocator;
|
984
memory/tanya/memory/lifecycle.d
Normal file
984
memory/tanya/memory/lifecycle.d
Normal file
@ -0,0 +1,984 @@
|
|||||||
|
/* 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/memory/tanya/memory/lifecycle.d,
|
||||||
|
* tanya/memory/lifecycle.d)
|
||||||
|
*/
|
||||||
|
module tanya.memory.lifecycle;
|
||||||
|
|
||||||
|
import tanya.memory : defaultAllocator;
|
||||||
|
import tanya.memory.allocator;
|
||||||
|
import tanya.meta.trait;
|
||||||
|
import tanya.meta.metafunction;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.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)
|
||||||
|
{
|
||||||
|
static if (hasElaborateDestructor!E)
|
||||||
|
{
|
||||||
|
foreach (ref e; p)
|
||||||
|
{
|
||||||
|
destroy(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 (!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
|
||||||
|
* 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)())
|
||||||
|
{
|
||||||
|
import tanya.memory.op : copy;
|
||||||
|
|
||||||
|
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)())
|
||||||
|
{
|
||||||
|
import tanya.memory.op : copy;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
import tanya.memory.op : copy, fill;
|
||||||
|
|
||||||
|
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]; })))
|
||||||
|
{
|
||||||
|
import tanya.memory.op : copy;
|
||||||
|
|
||||||
|
((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 = ⌖
|
||||||
|
|
||||||
|
emplace!S(sp[0 .. 1], S());
|
||||||
|
assert(target.called);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
import tanya.memory.op : copy, fill;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
fill!0((cast(void*) &value)[0 .. size]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
import tanya.memory.op : copy;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
int x1 = 5, x2;
|
||||||
|
moveEmplace(x1, x2);
|
||||||
|
assert(x2 == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
@ -10,7 +10,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/mallocator.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/memory/tanya/memory/mallocator.d,
|
||||||
* tanya/memory/mallocator.d)
|
* tanya/memory/mallocator.d)
|
||||||
*/
|
*/
|
||||||
module tanya.memory.mallocator;
|
module tanya.memory.mallocator;
|
@ -9,7 +9,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/mmappool.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/memory/tanya/memory/mmappool.d,
|
||||||
* tanya/memory/mmappool.d)
|
* tanya/memory/mmappool.d)
|
||||||
*/
|
*/
|
||||||
module tanya.memory.mmappool;
|
module tanya.memory.mmappool;
|
||||||
@ -398,7 +398,7 @@ final class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
if (p !is null)
|
if (p !is null)
|
||||||
{
|
{
|
||||||
copy(p[0 .. min(p.length, size)], reallocP);
|
copy(p[0 .. p.length < size ? p.length : size], reallocP);
|
||||||
deallocate(p);
|
deallocate(p);
|
||||||
}
|
}
|
||||||
p = reallocP;
|
p = reallocP;
|
@ -9,7 +9,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/op.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/memory/tanya/memory/op.d,
|
||||||
* tanya/memory/op.d)
|
* tanya/memory/op.d)
|
||||||
*/
|
*/
|
||||||
module tanya.memory.op;
|
module tanya.memory.op;
|
@ -9,15 +9,16 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/package.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/memory/tanya/memory/package.d,
|
||||||
* tanya/memory/package.d)
|
* tanya/memory/package.d)
|
||||||
*/
|
*/
|
||||||
module tanya.memory;
|
module tanya.memory;
|
||||||
|
|
||||||
import tanya.conv;
|
|
||||||
public import tanya.memory.allocator;
|
public import tanya.memory.allocator;
|
||||||
public import tanya.memory.lifecycle;
|
public import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
|
deprecated("Use tanya.meta.trait.stateSize instead")
|
||||||
|
public import tanya.meta.trait : stateSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mixin generates common methods for classes and structs using
|
* The mixin generates common methods for classes and structs using
|
||||||
@ -37,11 +38,7 @@ mixin template DefaultAllocator()
|
|||||||
* Precondition: $(D_INLINECODE allocator_ !is null)
|
* Precondition: $(D_INLINECODE allocator_ !is null)
|
||||||
*/
|
*/
|
||||||
this(shared Allocator allocator) @nogc nothrow pure @safe
|
this(shared Allocator allocator) @nogc nothrow pure @safe
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.allocator_ = allocator;
|
this.allocator_ = allocator;
|
||||||
}
|
}
|
||||||
@ -55,11 +52,7 @@ mixin template DefaultAllocator()
|
|||||||
* Postcondition: $(D_INLINECODE allocator !is null)
|
* Postcondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
@property shared(Allocator) allocator() @nogc nothrow pure @safe
|
@property shared(Allocator) allocator() @nogc nothrow pure @safe
|
||||||
out (allocator)
|
out (allocator; allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
if (allocator_ is null)
|
if (allocator_ is null)
|
||||||
{
|
{
|
||||||
@ -70,11 +63,7 @@ mixin template DefaultAllocator()
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
@property shared(Allocator) allocator() const @nogc nothrow pure @trusted
|
@property shared(Allocator) allocator() const @nogc nothrow pure @trusted
|
||||||
out (allocator)
|
out (allocator; allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
if (allocator_ is null)
|
if (allocator_ is null)
|
||||||
{
|
{
|
||||||
@ -110,11 +99,7 @@ private shared(Allocator) getAllocatorInstance() @nogc nothrow
|
|||||||
* Postcondition: $(D_INLINECODE allocator !is null).
|
* Postcondition: $(D_INLINECODE allocator !is null).
|
||||||
*/
|
*/
|
||||||
@property shared(Allocator) defaultAllocator() @nogc nothrow pure @trusted
|
@property shared(Allocator) defaultAllocator() @nogc nothrow pure @trusted
|
||||||
out (allocator)
|
out (allocator; allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return (cast(GetPureInstance!Allocator) &getAllocatorInstance)();
|
return (cast(GetPureInstance!Allocator) &getAllocatorInstance)();
|
||||||
}
|
}
|
||||||
@ -128,67 +113,11 @@ do
|
|||||||
* Precondition: $(D_INLINECODE allocator !is null).
|
* Precondition: $(D_INLINECODE allocator !is null).
|
||||||
*/
|
*/
|
||||||
@property void defaultAllocator(shared(Allocator) allocator) @nogc nothrow @safe
|
@property void defaultAllocator(shared(Allocator) allocator) @nogc nothrow @safe
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
.allocator = allocator;
|
.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:
|
* Params:
|
||||||
* size = Raw size.
|
* size = Raw size.
|
@ -18,21 +18,18 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/memory/smartref.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/memory/tanya/memory/smartref.d,
|
||||||
* tanya/memory/smartref.d)
|
* tanya/memory/smartref.d)
|
||||||
*/
|
*/
|
||||||
module tanya.memory.smartref;
|
module tanya.memory.smartref;
|
||||||
|
|
||||||
import tanya.algorithm.mutation;
|
|
||||||
import tanya.conv;
|
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.range.primitive;
|
|
||||||
version (unittest) import tanya.test.stub;
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
private template Payload(T)
|
private template Payload(T)
|
||||||
{
|
{
|
||||||
static if (isPolymorphicType!T || isArray!T)
|
static if (isPolymorphicType!T || isDynamicArray!T)
|
||||||
{
|
{
|
||||||
alias Payload = T;
|
alias Payload = T;
|
||||||
}
|
}
|
||||||
@ -529,23 +526,19 @@ do
|
|||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Array type.
|
* T = Array type.
|
||||||
|
* E = Array element type.
|
||||||
* size = Array size.
|
* size = Array size.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*
|
*
|
||||||
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE allocator !is null
|
* Precondition: $(D_INLINECODE allocator !is null
|
||||||
* && size <= size_t.max / ElementType!T.sizeof)
|
* && size <= size_t.max / E.sizeof)
|
||||||
*/
|
*/
|
||||||
RefCounted!T refCounted(T)(shared Allocator allocator, const size_t size)
|
RefCounted!T refCounted(T : E[], E)(shared Allocator allocator, size_t size)
|
||||||
@trusted
|
@trusted
|
||||||
if (isArray!T)
|
in (allocator !is null)
|
||||||
in
|
in (size <= size_t.max / E.sizeof)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
assert(size <= size_t.max / ElementType!T.sizeof);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return RefCounted!T(allocator.make!T(size), allocator);
|
return RefCounted!T(allocator.make!T(size), allocator);
|
||||||
}
|
}
|
||||||
@ -852,25 +845,21 @@ do
|
|||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Array type.
|
* T = Array type.
|
||||||
|
* E = Array element type.
|
||||||
* size = Array size.
|
* size = Array size.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*
|
*
|
||||||
* Returns: Newly created $(D_PSYMBOL Unique!T).
|
* Returns: Newly created $(D_PSYMBOL Unique!T).
|
||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE allocator !is null
|
* Precondition: $(D_INLINECODE allocator !is null
|
||||||
* && size <= size_t.max / ElementType!T.sizeof)
|
* && size <= size_t.max / E.sizeof)
|
||||||
*/
|
*/
|
||||||
Unique!T unique(T)(shared Allocator allocator, const size_t size)
|
Unique!T unique(T : E[], E)(shared Allocator allocator, size_t size)
|
||||||
@trusted
|
@trusted
|
||||||
if (isArray!T)
|
in (allocator !is null)
|
||||||
in
|
in (size <= size_t.max / E.sizeof)
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
auto payload = allocator.resize!E(null, size);
|
||||||
assert(size <= size_t.max / ElementType!T.sizeof);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto payload = allocator.resize!(ElementType!T)(null, size);
|
|
||||||
return Unique!T(payload, allocator);
|
return Unique!T(payload, allocator);
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "meta",
|
"name": "meta",
|
||||||
"description": "Template metaprogramming",
|
"description": "Template metaprogramming",
|
||||||
"targetType": "library"
|
"targetType": "library",
|
||||||
|
|
||||||
|
"sourcePaths": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"importPaths": [
|
||||||
|
"."
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
* It contains different algorithms for iterating, searching and modifying
|
* It contains different algorithms for iterating, searching and modifying
|
||||||
* template arguments.
|
* template arguments.
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/metafunction.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/metafunction.d,
|
||||||
* tanya/meta/metafunction.d)
|
* tanya/meta/metafunction.d)
|
||||||
*/
|
*/
|
||||||
module tanya.meta.metafunction;
|
module tanya.meta.metafunction;
|
@ -9,11 +9,11 @@
|
|||||||
* to transform from one type to another. It has also different algorithms for
|
* to transform from one type to another. It has also different algorithms for
|
||||||
* iterating, searching and modifying template arguments.
|
* iterating, searching and modifying template arguments.
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/package.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/package.d,
|
||||||
* tanya/meta/package.d)
|
* tanya/meta/package.d)
|
||||||
*/
|
*/
|
||||||
module tanya.meta;
|
module tanya.meta;
|
@ -8,11 +8,11 @@
|
|||||||
* Templates in this module are used to obtain type information at compile
|
* Templates in this module are used to obtain type information at compile
|
||||||
* time.
|
* time.
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/trait.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/trait.d,
|
||||||
* tanya/meta/trait.d)
|
* tanya/meta/trait.d)
|
||||||
*/
|
*/
|
||||||
module tanya.meta.trait;
|
module tanya.meta.trait;
|
||||||
@ -2692,6 +2692,58 @@ if (is(T == class))
|
|||||||
static assert(classInstanceAlignment!C2 == S.alignof);
|
static assert(classInstanceAlignment!C2 == S.alignof);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether $(D_INLINECODE pred(T)) can be used as condition in an
|
* Tests whether $(D_INLINECODE pred(T)) can be used as condition in an
|
||||||
* $(D_KEYWORD if)-statement or a ternary operator.
|
* $(D_KEYWORD if)-statement or a ternary operator.
|
@ -9,11 +9,11 @@
|
|||||||
* types. They take some type as argument and return a different type after
|
* types. They take some type as argument and return a different type after
|
||||||
* perfoming the specified transformation.
|
* perfoming the specified transformation.
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/transform.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/transform.d,
|
||||||
* tanya/meta/transform.d)
|
* tanya/meta/transform.d)
|
||||||
*/
|
*/
|
||||||
module tanya.meta.transform;
|
module tanya.meta.transform;
|
@ -5,5 +5,12 @@
|
|||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tanya:meta": "*"
|
"tanya:meta": "*"
|
||||||
}
|
},
|
||||||
|
|
||||||
|
"sourcePaths": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"importPaths": [
|
||||||
|
"."
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/os/error.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/error.d,
|
||||||
* tanya/os/error.d)
|
* tanya/os/error.d)
|
||||||
*/
|
*/
|
||||||
module tanya.os.error;
|
module tanya.os.error;
|
@ -10,7 +10,7 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/os/package.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/package.d,
|
||||||
* tanya/os/package.d)
|
* tanya/os/package.d)
|
||||||
*/
|
*/
|
||||||
module tanya.os;
|
module tanya.os;
|
@ -21,7 +21,7 @@
|
|||||||
module tanya.algorithm.iteration;
|
module tanya.algorithm.iteration;
|
||||||
|
|
||||||
import tanya.algorithm.comparison;
|
import tanya.algorithm.comparison;
|
||||||
import tanya.algorithm.mutation;
|
import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
|
@ -14,284 +14,21 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.algorithm.mutation;
|
module tanya.algorithm.mutation;
|
||||||
|
|
||||||
import tanya.conv;
|
|
||||||
static import tanya.memory.op;
|
static import tanya.memory.op;
|
||||||
|
static import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
version (unittest) import tanya.test.stub;
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
private void deinitialize(bool zero, T)(ref T value)
|
deprecated("Use tanya.memory.lifecycle.swap instead")
|
||||||
{
|
alias swap = tanya.memory.lifecycle.swap;
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
deprecated("Use tanya.memory.lifecycle.moveEmplace instead")
|
||||||
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that
|
alias moveEmplace = tanya.memory.lifecycle.moveEmplace;
|
||||||
* $(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)
|
deprecated("Use tanya.memory.lifecycle.move instead")
|
||||||
{
|
alias move = tanya.memory.lifecycle.move;
|
||||||
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);
|
|
||||||
|
|
||||||
int x1 = 5, x2;
|
|
||||||
moveEmplace(x1, x2);
|
|
||||||
assert(x2 == 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the $(D_PARAM source) range into the $(D_PARAM target) range.
|
* 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())
|
for (; !range.empty; range.popFront())
|
||||||
{
|
{
|
||||||
ElementType!Range* p = &range.front;
|
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
|
else
|
||||||
@ -577,13 +314,7 @@ if (isInputRange!Range && hasLvalueElements!Range)
|
|||||||
void destroyAll(Range)(Range range)
|
void destroyAll(Range)(Range range)
|
||||||
if (isInputRange!Range && hasLvalueElements!Range)
|
if (isInputRange!Range && hasLvalueElements!Range)
|
||||||
{
|
{
|
||||||
static if (hasElaborateDestructor!(ElementType!Range))
|
tanya.memory.lifecycle.destroyAllImpl!(Range, ElementType!Range)(range);
|
||||||
{
|
|
||||||
foreach (ref e; range)
|
|
||||||
{
|
|
||||||
destroy(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -632,7 +363,7 @@ if (isForwardRange!Range && hasSwappableElements!Range)
|
|||||||
|
|
||||||
while (!front.empty && !next.empty && !sameHead(front, next))
|
while (!front.empty && !next.empty && !sameHead(front, next))
|
||||||
{
|
{
|
||||||
swap(front.front, next.front);
|
tanya.memory.lifecycle.swap(front.front, next.front);
|
||||||
front.popFront();
|
front.popFront();
|
||||||
next.popFront();
|
next.popFront();
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ 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.functional;
|
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.entry;
|
module tanya.container.entry;
|
||||||
|
|
||||||
import tanya.algorithm.mutation;
|
|
||||||
import tanya.container.array;
|
import tanya.container.array;
|
||||||
import tanya.memory.allocator;
|
import tanya.memory.allocator;
|
||||||
|
import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.typecons;
|
import tanya.typecons;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
module tanya.container.list;
|
module tanya.container.list;
|
||||||
|
|
||||||
import tanya.algorithm.comparison;
|
import tanya.algorithm.comparison;
|
||||||
import tanya.algorithm.mutation;
|
|
||||||
import tanya.container.entry;
|
import tanya.container.entry;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
|
@ -14,15 +14,13 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.conv;
|
module tanya.conv;
|
||||||
|
|
||||||
import tanya.algorithm.mutation;
|
|
||||||
import tanya.container.string;
|
import tanya.container.string;
|
||||||
import tanya.format;
|
|
||||||
import tanya.memory;
|
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.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.array;
|
import tanya.range;
|
||||||
import tanya.range.primitive;
|
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
@ -30,269 +28,6 @@ version (unittest)
|
|||||||
import tanya.test.stub;
|
import tanya.test.stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = ⌖
|
|
||||||
|
|
||||||
emplace!S(sp[0 .. 1], S());
|
|
||||||
assert(target.called);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if a type conversion fails.
|
* Thrown if a type conversion fails.
|
||||||
*/
|
*/
|
||||||
|
@ -2,77 +2,17 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Functions that manipulate other functions and their argument lists.
|
* 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/,
|
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/functional.d,
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/functional.d,
|
||||||
* tanya/functional.d)
|
* tanya/functional.d)
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.memory.lifecycle instead")
|
||||||
module tanya.functional;
|
module tanya.functional;
|
||||||
|
|
||||||
import tanya.algorithm.mutation;
|
public import tanya.memory.lifecycle : forward;
|
||||||
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));
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -21,6 +21,7 @@ import tanya.container.string;
|
|||||||
import tanya.conv;
|
import tanya.conv;
|
||||||
import tanya.encoding.ascii;
|
import tanya.encoding.ascii;
|
||||||
import tanya.format;
|
import tanya.format;
|
||||||
|
import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.net.iface;
|
import tanya.net.iface;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
module tanya.range.adapter;
|
module tanya.range.adapter;
|
||||||
|
|
||||||
import tanya.algorithm.mutation;
|
import tanya.algorithm.mutation;
|
||||||
import tanya.functional;
|
import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
module tanya.range.primitive;
|
module tanya.range.primitive;
|
||||||
|
|
||||||
import tanya.algorithm.comparison;
|
import tanya.algorithm.comparison;
|
||||||
import tanya.algorithm.mutation;
|
import tanya.memory.lifecycle;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.array;
|
import tanya.range.array;
|
||||||
|
@ -17,10 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.typecons;
|
module tanya.typecons;
|
||||||
|
|
||||||
import tanya.algorithm.mutation;
|
|
||||||
import tanya.conv;
|
|
||||||
import tanya.format;
|
import tanya.format;
|
||||||
import tanya.functional;
|
import tanya.memory.lifecycle;
|
||||||
import tanya.meta.metafunction;
|
import tanya.meta.metafunction;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
version (unittest) import tanya.test.stub;
|
version (unittest) import tanya.test.stub;
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sys",
|
"name": "sys",
|
||||||
"description": "Low-level operating system bindings and definitions",
|
"description": "Low-level operating system bindings and definitions",
|
||||||
"targetType": "library"
|
"targetType": "library",
|
||||||
|
|
||||||
|
"sourcePaths": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"importPaths": [
|
||||||
|
"."
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/linux/syscall.d,
|
|
||||||
* tanya/sys/linux/syscall.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.linux.syscall;
|
module tanya.sys.linux.syscall;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/posix/ioctl.d,
|
|
||||||
* tanya/sys/posix/ioctl.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.posix.ioctl;
|
module tanya.sys.posix.ioctl;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/posix/mman.d,
|
|
||||||
* tanya/sys/posix/mman.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.posix.mman;
|
module tanya.sys.posix.mman;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/posix/net/if_.d,
|
|
||||||
* tanya/sys/posix/net/if_.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.posix.net.if_;
|
module tanya.sys.posix.net.if_;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/posix/socket.d,
|
|
||||||
* tanya/sys/posix/socket.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.posix.socket;
|
module tanya.sys.posix.socket;
|
||||||
|
|
@ -20,8 +20,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/def.d,
|
|
||||||
* tanya/sys/windows/def.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.windows.def;
|
module tanya.sys.windows.def;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/ifdef.d,
|
|
||||||
* tanya/sys/windows/ifdef.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.windows.ifdef;
|
module tanya.sys.windows.ifdef;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/iphlpapi.d,
|
|
||||||
* tanya/sys/windows/iphlpapi.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.windows.iphlpapi;
|
module tanya.sys.windows.iphlpapi;
|
||||||
|
|
@ -7,8 +7,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/package.d,
|
|
||||||
* tanya/sys/windows/package.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.windows;
|
module tanya.sys.windows;
|
||||||
|
|
@ -9,8 +9,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/winbase.d,
|
|
||||||
* tanya/sys/windows/winbase.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.windows.winbase;
|
module tanya.sys.windows.winbase;
|
||||||
|
|
@ -9,8 +9,6 @@
|
|||||||
* 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)
|
||||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/winsock2.d,
|
|
||||||
* tanya/sys/windows/winsock2.d)
|
|
||||||
*/
|
*/
|
||||||
module tanya.sys.windows.winsock2;
|
module tanya.sys.windows.winsock2;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user