Make allocators pure.
* Methods allocating/deallocating memory are pure.
* Allocator.instance is pure (once initialized, it always returns
  the same instance).
* defaultAllocator getter property is pure (should be set at the
  beginning, and always return the same instance after that).
This commit is contained in:
Eugen Wissner 2017-07-13 16:01:21 +02:00
parent 839c740cb1
commit 657f4a60d5
4 changed files with 93 additions and 52 deletions

View File

@ -33,7 +33,7 @@ interface Allocator
* *
* Returns: Pointer to the new allocated memory. * Returns: Pointer to the new allocated memory.
*/ */
void[] allocate(const size_t size) shared nothrow @nogc; void[] allocate(const size_t size) shared pure nothrow @nogc;
/** /**
* Deallocates a memory block. * Deallocates a memory block.
@ -43,7 +43,7 @@ interface Allocator
* *
* Returns: Whether the deallocation was successful. * Returns: Whether the deallocation was successful.
*/ */
bool deallocate(void[] p) shared nothrow @nogc; bool deallocate(void[] p) shared pure nothrow @nogc;
/** /**
* Increases or decreases the size of a memory block. * Increases or decreases the size of a memory block.
@ -54,7 +54,7 @@ interface Allocator
* *
* Returns: Pointer to the allocated memory. * Returns: Pointer to the allocated memory.
*/ */
bool reallocate(ref void[] p, const size_t size) shared nothrow @nogc; bool reallocate(ref void[] p, const size_t size) shared pure nothrow @nogc;
/** /**
* Reallocates a memory block in place if possible or returns * Reallocates a memory block in place if possible or returns
@ -69,5 +69,11 @@ interface Allocator
* Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise. * Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
*/ */
bool reallocateInPlace(ref void[] p, const size_t size) bool reallocateInPlace(ref void[] p, const size_t size)
shared nothrow @nogc; shared pure nothrow @nogc;
}
package template GetPureInstance(T : Allocator)
{
alias GetPureInstance = shared(T) function()
pure nothrow @nogc;
} }

View File

@ -21,6 +21,13 @@ import tanya.memory.allocator;
*/ */
final class Mallocator : Allocator final class Mallocator : Allocator
{ {
private alias MallocType = extern (C) void* function(size_t)
pure nothrow @system @nogc;
private alias FreeType = extern (C) void function(void*)
pure nothrow @system @nogc;
private alias ReallocType = extern (C) void* function(void*, size_t)
pure nothrow @system @nogc;
/** /**
* Allocates $(D_PARAM size) bytes of memory. * Allocates $(D_PARAM size) bytes of memory.
* *
@ -29,13 +36,13 @@ final class Mallocator : Allocator
* *
* Returns: The pointer to the new allocated memory. * Returns: The pointer to the new allocated memory.
*/ */
void[] allocate(const size_t size) shared nothrow @nogc void[] allocate(const size_t size) shared pure nothrow @nogc
{ {
if (size == 0) if (size == 0)
{ {
return null; return null;
} }
auto p = malloc(size + psize); auto p = (cast(MallocType) &malloc)(size + psize);
return p is null ? null : p[psize .. psize + size]; return p is null ? null : p[psize .. psize + size];
} }
@ -59,11 +66,11 @@ final class Mallocator : Allocator
* *
* Returns: Whether the deallocation was successful. * Returns: Whether the deallocation was successful.
*/ */
bool deallocate(void[] p) shared nothrow @nogc bool deallocate(void[] p) shared pure nothrow @nogc
{ {
if (p !is null) if (p !is null)
{ {
free(p.ptr - psize); (cast(FreeType) &free)(p.ptr - psize);
} }
return true; return true;
} }
@ -87,7 +94,8 @@ final class Mallocator : Allocator
* *
* Returns: $(D_KEYWORD false). * Returns: $(D_KEYWORD false).
*/ */
bool reallocateInPlace(ref void[] p, const size_t size) shared nothrow @nogc bool reallocateInPlace(ref void[] p, const size_t size)
shared pure nothrow @nogc
{ {
return false; return false;
} }
@ -108,7 +116,7 @@ final class Mallocator : Allocator
* *
* Returns: Whether the reallocation was successful. * Returns: Whether the reallocation was successful.
*/ */
bool reallocate(ref void[] p, const size_t size) shared nothrow @nogc bool reallocate(ref void[] p, const size_t size) shared pure nothrow @nogc
{ {
if (size == 0) if (size == 0)
{ {
@ -125,7 +133,7 @@ final class Mallocator : Allocator
} }
else else
{ {
auto r = realloc(p.ptr - psize, size + psize); auto r = (cast(ReallocType) &realloc)(p.ptr - psize, size + psize);
if (r !is null) if (r !is null)
{ {
@ -177,12 +185,7 @@ final class Mallocator : Allocator
assert(Mallocator.instance.alignment == (void*).alignof); assert(Mallocator.instance.alignment == (void*).alignof);
} }
/** static private shared(Mallocator) instantiate() nothrow @nogc
* Static allocator instance and initializer.
*
* Returns: The global $(D_PSYMBOL Allocator) instance.
*/
static @property ref shared(Mallocator) instance() @nogc nothrow
{ {
if (instance_ is null) if (instance_ is null)
{ {
@ -198,6 +201,16 @@ final class Mallocator : Allocator
return instance_; return instance_;
} }
/**
* Static allocator instance and initializer.
*
* Returns: The global $(D_PSYMBOL Allocator) instance.
*/
static @property shared(Mallocator) instance() pure nothrow @nogc
{
return (cast(GetPureInstance!Mallocator) &instantiate)();
}
/// ///
@nogc nothrow unittest @nogc nothrow unittest
{ {

View File

@ -167,7 +167,7 @@ final class MmapPool : Allocator
- MmapPool.alignment_ - MmapPool.alignment_
- BlockEntry.sizeof * 2 - BlockEntry.sizeof * 2
- RegionEntry.sizeof - RegionEntry.sizeof
- pageSize; - MmapPool.instance.pageSize;
assert(MmapPool.instance.allocate(tooMuchMemory) is null); assert(MmapPool.instance.allocate(tooMuchMemory) is null);
assert(MmapPool.instance.allocate(size_t.max) is null); assert(MmapPool.instance.allocate(size_t.max) is null);
@ -471,46 +471,52 @@ final class MmapPool : Allocator
MmapPool.instance.deallocate(p); MmapPool.instance.deallocate(p);
} }
/** static private shared(MmapPool) instantiate() nothrow @nogc
* Static allocator instance and initializer.
*
* Returns: Global $(D_PSYMBOL MmapPool) instance.
*/
static @property ref shared(MmapPool) instance() nothrow @nogc
{ {
if (instance_ is null) if (instance_ is null)
{ {
// Get system dependend page size. // Get system dependend page size.
version (Posix) version (Posix)
{ {
pageSize_ = sysconf(_SC_PAGE_SIZE); size_t pageSize = sysconf(_SC_PAGE_SIZE);
if (pageSize_ < 65536) if (pageSize < 65536)
{ {
pageSize_ = pageSize_ * 65536 / pageSize_; pageSize = pageSize * 65536 / pageSize;
} }
} }
else version (Windows) else version (Windows)
{ {
SYSTEM_INFO si; SYSTEM_INFO si;
GetSystemInfo(&si); GetSystemInfo(&si);
pageSize_ = si.dwPageSize; size_t pageSize = si.dwPageSize;
} }
const instanceSize = addAlignment(__traits(classInstanceSize, const instanceSize = addAlignment(__traits(classInstanceSize,
MmapPool)); MmapPool));
Region head; // Will become soon our region list head Region head; // Will become soon our region list head
void* data = initializeRegion(instanceSize, head); void* data = initializeRegion(instanceSize, head, pageSize);
if (data !is null) if (data !is null)
{ {
memcpy(data, typeid(MmapPool).initializer.ptr, instanceSize); memcpy(data, typeid(MmapPool).initializer.ptr, instanceSize);
instance_ = cast(shared MmapPool) data; instance_ = cast(shared MmapPool) data;
instance_.head = head; instance_.head = head;
instance_.pageSize = pageSize;
} }
} }
return instance_; return instance_;
} }
/**
* Static allocator instance and initializer.
*
* Returns: Global $(D_PSYMBOL MmapPool) instance.
*/
static @property shared(MmapPool) instance() pure nothrow @nogc
{
return (cast(GetPureInstance!MmapPool) &instantiate)();
}
/// ///
nothrow unittest nothrow unittest
{ {
@ -526,10 +532,12 @@ final class MmapPool : Allocator
* *
* Returns: A pointer to the data. * Returns: A pointer to the data.
*/ */
private static void* initializeRegion(const size_t size, ref Region head) private static void* initializeRegion(const size_t size,
ref Region head,
const size_t pageSize)
pure nothrow @nogc pure nothrow @nogc
{ {
const regionSize = calculateRegionSize(size); const regionSize = calculateRegionSize(size, pageSize);
if (regionSize < size) if (regionSize < size)
{ {
return null; return null;
@ -578,7 +586,7 @@ final class MmapPool : Allocator
private void* initializeRegion(const size_t size) shared pure nothrow @nogc private void* initializeRegion(const size_t size) shared pure nothrow @nogc
{ {
return initializeRegion(size, head); return initializeRegion(size, this.head, this.pageSize);
} }
/* /*
@ -594,11 +602,13 @@ final class MmapPool : Allocator
/* /*
* Params: * Params:
* x = Required space. * x = Required space.
* pageSize = Page size.
* *
* Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)). * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
*/ */
private static size_t calculateRegionSize(const size_t x) private static size_t calculateRegionSize(ref const size_t x,
ref const size_t pageSize)
pure nothrow @safe @nogc pure nothrow @safe @nogc
{ {
return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2) return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2)
@ -618,18 +628,10 @@ final class MmapPool : Allocator
assert(MmapPool.instance.alignment == MmapPool.alignment_); assert(MmapPool.instance.alignment == MmapPool.alignment_);
} }
private static @property size_t pageSize() pure nothrow @trusted @nogc
{
const pageSize = function size_t() nothrow @safe @nogc {
return pageSize_;
};
return (cast(size_t function() pure nothrow @safe @nogc) pageSize)();
}
private enum uint alignment_ = 8; private enum uint alignment_ = 8;
private shared static MmapPool instance_; private shared static MmapPool instance_;
private shared static size_t pageSize_; private shared size_t pageSize;
private shared struct RegionEntry private shared struct RegionEntry
{ {

View File

@ -36,7 +36,7 @@ mixin template DefaultAllocator()
* *
* Precondition: $(D_INLINECODE allocator_ !is null) * Precondition: $(D_INLINECODE allocator_ !is null)
*/ */
this(shared Allocator allocator) this(shared Allocator allocator) pure nothrow @safe @nogc
in in
{ {
assert(allocator !is null); assert(allocator !is null);
@ -54,7 +54,7 @@ mixin template DefaultAllocator()
* *
* Postcondition: $(D_INLINECODE allocator !is null) * Postcondition: $(D_INLINECODE allocator !is null)
*/ */
protected @property shared(Allocator) allocator() nothrow @safe @nogc protected @property shared(Allocator) allocator() pure nothrow @safe @nogc
out (allocator) out (allocator)
{ {
assert(allocator !is null); assert(allocator !is null);
@ -69,7 +69,7 @@ mixin template DefaultAllocator()
} }
/// Ditto. /// Ditto.
@property shared(Allocator) allocator() const nothrow @trusted @nogc @property shared(Allocator) allocator() const pure nothrow @trusted @nogc
out (allocator) out (allocator)
{ {
assert(allocator !is null); assert(allocator !is null);
@ -85,25 +85,44 @@ mixin template DefaultAllocator()
} }
// From druntime // From druntime
private extern (C) void _d_monitordelete(Object h, bool det) nothrow @nogc; extern (C)
private void _d_monitordelete(Object h, bool det) pure nothrow @nogc;
shared Allocator allocator; shared Allocator allocator;
shared static this() nothrow @trusted @nogc shared static this() nothrow @nogc
{ {
allocator = MmapPool.instance; allocator = MmapPool.instance;
} }
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc private shared(Allocator) getAllocatorInstance() nothrow @nogc
{
return allocator;
}
/**
* Returns: Default allocator.
*
* Postcondition: $(D_INLINECODE allocator !is null).
*/
@property shared(Allocator) defaultAllocator() pure nothrow @trusted @nogc
out (allocator) out (allocator)
{ {
assert(allocator !is null); assert(allocator !is null);
} }
body body
{ {
return allocator; return (cast(GetPureInstance!Allocator) &getAllocatorInstance)();
} }
/**
* Sets the default allocator.
*
* Params:
* allocator = $(D_PSYMBOL Allocator) instance.
*
* Precondition: $(D_INLINECODE allocator !is null).
*/
@property void defaultAllocator(shared(Allocator) allocator) nothrow @safe @nogc @property void defaultAllocator(shared(Allocator) allocator) nothrow @safe @nogc
in in
{ {
@ -271,7 +290,8 @@ package(tanya) void[] finalize(T)(ref T p)
// shouldn't throw and if it does, it is an error anyway. // shouldn't throw and if it does, it is an error anyway.
if (c.destructor) if (c.destructor)
{ {
(cast(void function (Object) nothrow @safe @nogc) c.destructor)(ob); alias DtorType = void function(Object) pure nothrow @safe @nogc;
(cast(DtorType) c.destructor)(ob);
} }
} }
while ((c = c.base) !is null); while ((c = c.base) !is null);
@ -322,7 +342,7 @@ private unittest
} }
// Works with interfaces. // Works with interfaces.
private unittest private pure unittest
{ {
interface I interface I
{ {