Make allocators shared
This commit is contained in:
		@@ -12,8 +12,6 @@ module tanya.container.buffer;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import tanya.memory;
 | 
					import tanya.memory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
version (unittest)
 | 
					version (unittest)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private int fillBuffer(void* buffer,
 | 
						private int fillBuffer(void* buffer,
 | 
				
			||||||
@@ -42,7 +40,6 @@ version (unittest)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
interface Buffer
 | 
					interface Buffer
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Returns: The size of the internal buffer.
 | 
						 * Returns: The size of the internal buffer.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@@ -74,7 +71,6 @@ interface Buffer
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class ReadBuffer : Buffer
 | 
					class ReadBuffer : Buffer
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// Internal buffer.
 | 
						/// Internal buffer.
 | 
				
			||||||
	protected ubyte[] _buffer;
 | 
						protected ubyte[] _buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +83,7 @@ class ReadBuffer : Buffer
 | 
				
			|||||||
	/// Size by which the buffer will grow.
 | 
						/// Size by which the buffer will grow.
 | 
				
			||||||
	protected immutable size_t blockSize;
 | 
						protected immutable size_t blockSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Allocator allocator;
 | 
						private shared Allocator allocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	invariant
 | 
						invariant
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -107,7 +103,7 @@ class ReadBuffer : Buffer
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(size_t size = 8192,
 | 
						this(size_t size = 8192,
 | 
				
			||||||
	     size_t minAvailable = 1024,
 | 
						     size_t minAvailable = 1024,
 | 
				
			||||||
	     Allocator allocator = defaultAllocator)
 | 
						     shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.allocator = allocator;
 | 
							this.allocator = allocator;
 | 
				
			||||||
		this.minAvailable = minAvailable;
 | 
							this.minAvailable = minAvailable;
 | 
				
			||||||
@@ -294,7 +290,6 @@ class ReadBuffer : Buffer
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class WriteBuffer : Buffer
 | 
					class WriteBuffer : Buffer
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// Internal buffer.
 | 
						/// Internal buffer.
 | 
				
			||||||
	protected ubyte[] _buffer;
 | 
						protected ubyte[] _buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -310,7 +305,7 @@ class WriteBuffer : Buffer
 | 
				
			|||||||
	/// The position of the free area in the buffer.
 | 
						/// The position of the free area in the buffer.
 | 
				
			||||||
	protected size_t position;
 | 
						protected size_t position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Allocator allocator;
 | 
						private shared Allocator allocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	invariant
 | 
						invariant
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -325,7 +320,7 @@ class WriteBuffer : Buffer
 | 
				
			|||||||
	 * 	       will grow.
 | 
						 * 	       will grow.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(size_t size = 8192,
 | 
						this(size_t size = 8192,
 | 
				
			||||||
	     Allocator allocator = defaultAllocator)
 | 
						     shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.allocator = allocator;
 | 
							this.allocator = allocator;
 | 
				
			||||||
		blockSize = size;
 | 
							blockSize = size;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,6 @@ import tanya.memory;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class SList(T)
 | 
					class SList(T)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new $(D_PSYMBOL SList).
 | 
						 * Creates a new $(D_PSYMBOL SList).
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -28,7 +27,7 @@ class SList(T)
 | 
				
			|||||||
	 * 	allocator = The allocator should be used for the element
 | 
						 * 	allocator = The allocator should be used for the element
 | 
				
			||||||
	 * 	            allocations.
 | 
						 * 	            allocations.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(Allocator allocator = defaultAllocator)
 | 
						this(shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.allocator = allocator;
 | 
							this.allocator = allocator;
 | 
				
			||||||
        reset();
 | 
					        reset();
 | 
				
			||||||
@@ -241,7 +240,7 @@ class SList(T)
 | 
				
			|||||||
	 * Params:
 | 
						 * Params:
 | 
				
			||||||
	 * 	dg = $(D_KEYWORD foreach) body.
 | 
						 * 	dg = $(D_KEYWORD foreach) body.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	int opApply(int delegate(ref size_t i, ref T) @nogc dg)
 | 
						int opApply(int delegate(ref size_t i, ref T) dg)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int result;
 | 
							int result;
 | 
				
			||||||
		size_t i;
 | 
							size_t i;
 | 
				
			||||||
@@ -280,7 +279,7 @@ class SList(T)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
						/// Ditto.
 | 
				
			||||||
	int opApply(int delegate(ref T) @nogc dg)
 | 
						int opApply(int delegate(ref T) dg)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int result;
 | 
							int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -389,7 +388,7 @@ class SList(T)
 | 
				
			|||||||
	/// Current position in the list.
 | 
						/// Current position in the list.
 | 
				
			||||||
	protected Entry* position;
 | 
						protected Entry* position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Allocator allocator;
 | 
						private shared Allocator allocator;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Stuff
 | 
					interface Stuff
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,6 @@ import tanya.memory;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class Queue(T)
 | 
					class Queue(T)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new $(D_PSYMBOL Queue).
 | 
						 * Creates a new $(D_PSYMBOL Queue).
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -28,7 +27,7 @@ class Queue(T)
 | 
				
			|||||||
	 * 	allocator = The allocator should be used for the element
 | 
						 * 	allocator = The allocator should be used for the element
 | 
				
			||||||
	 * 	            allocations.
 | 
						 * 	            allocations.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(Allocator allocator = defaultAllocator)
 | 
						this(shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.allocator = allocator;
 | 
							this.allocator = allocator;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -207,7 +206,7 @@ class Queue(T)
 | 
				
			|||||||
	/// The last element of the list.
 | 
						/// The last element of the list.
 | 
				
			||||||
	protected Entry* rear;
 | 
						protected Entry* rear;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Allocator allocator;
 | 
						private shared Allocator allocator;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,6 @@ module tanya.container.vector;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import tanya.memory;
 | 
					import tanya.memory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * One dimensional array. It allocates automatically if needed.
 | 
					 * One dimensional array. It allocates automatically if needed.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -34,7 +32,6 @@ import tanya.memory;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class Vector(T)
 | 
					class Vector(T)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new $(D_PSYMBOL Vector).
 | 
						 * Creates a new $(D_PSYMBOL Vector).
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -43,14 +40,14 @@ class Vector(T)
 | 
				
			|||||||
	 * 	allocator = The allocator should be used for the element
 | 
						 * 	allocator = The allocator should be used for the element
 | 
				
			||||||
	 * 	            allocations.
 | 
						 * 	            allocations.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(size_t length, Allocator allocator = defaultAllocator)
 | 
						this(size_t length, shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.allocator = allocator;
 | 
							this.allocator = allocator;
 | 
				
			||||||
		vector = makeArray!T(allocator, length);
 | 
							vector = makeArray!T(allocator, length);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
						/// Ditto.
 | 
				
			||||||
	this(Allocator allocator = defaultAllocator)
 | 
						this(shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this(0, allocator);
 | 
							this(0, allocator);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -194,7 +191,7 @@ class Vector(T)
 | 
				
			|||||||
	 * Params:
 | 
						 * Params:
 | 
				
			||||||
	 * 	dg = $(D_KEYWORD foreach) body.
 | 
						 * 	dg = $(D_KEYWORD foreach) body.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	int opApply(int delegate(ref T) @nogc dg)
 | 
						int opApply(int delegate(ref T) dg)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int result;
 | 
							int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -211,7 +208,7 @@ class Vector(T)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
						/// Ditto.
 | 
				
			||||||
	int opApply(int delegate(ref size_t i, ref T) @nogc dg)
 | 
						int opApply(int delegate(ref size_t i, ref T) dg)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int result;
 | 
							int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -408,7 +405,7 @@ class Vector(T)
 | 
				
			|||||||
	/// Container.
 | 
						/// Container.
 | 
				
			||||||
	protected T[] vector;
 | 
						protected T[] vector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Allocator allocator;
 | 
						private shared Allocator allocator;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ enum Mode
 | 
				
			|||||||
ubyte[] applyPadding(ref ubyte[] input,
 | 
					ubyte[] applyPadding(ref ubyte[] input,
 | 
				
			||||||
                     in Mode mode,
 | 
					                     in Mode mode,
 | 
				
			||||||
                     in ushort blockSize,
 | 
					                     in ushort blockSize,
 | 
				
			||||||
                     Allocator allocator = defaultAllocator)
 | 
					                     shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assert(blockSize > 0 && blockSize <= 256);
 | 
						assert(blockSize > 0 && blockSize <= 256);
 | 
				
			||||||
@@ -204,7 +204,7 @@ unittest
 | 
				
			|||||||
ref ubyte[] removePadding(ref ubyte[] input,
 | 
					ref ubyte[] removePadding(ref ubyte[] input,
 | 
				
			||||||
                      in Mode mode,
 | 
					                      in Mode mode,
 | 
				
			||||||
                      in ushort blockSize,
 | 
					                      in ushort blockSize,
 | 
				
			||||||
                      Allocator allocator = defaultAllocator)
 | 
					                      shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assert(input.length != 0);
 | 
						assert(input.length != 0);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,8 +28,6 @@ import core.sys.posix.netinet.in_;
 | 
				
			|||||||
import core.time;
 | 
					import core.time;
 | 
				
			||||||
import std.algorithm.comparison;
 | 
					import std.algorithm.comparison;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern (C) nothrow
 | 
					extern (C) nothrow
 | 
				
			||||||
{ // TODO: Make a pull request for Phobos to mark this extern functions as @nogc.
 | 
					{ // TODO: Make a pull request for Phobos to mark this extern functions as @nogc.
 | 
				
			||||||
    int epoll_create1(int __flags);
 | 
					    int epoll_create1(int __flags);
 | 
				
			||||||
@@ -42,7 +40,6 @@ private enum maxEvents = 128;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class EpollLoop : Loop
 | 
					class EpollLoop : Loop
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Initializes the loop.
 | 
						 * Initializes the loop.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@@ -108,7 +105,7 @@ class EpollLoop : Loop
 | 
				
			|||||||
	 * 	protocolFactory = Protocol factory.
 | 
						 * 	protocolFactory = Protocol factory.
 | 
				
			||||||
	 * 	socket          = Socket.
 | 
						 * 	socket          = Socket.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected override void acceptConnection(Protocol delegate() @nogc protocolFactory,
 | 
						protected override void acceptConnection(Protocol delegate() protocolFactory,
 | 
				
			||||||
	                                         int socket)
 | 
						                                         int socket)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sockaddr_in client_addr;
 | 
							sockaddr_in client_addr;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@ import core.sys.posix.unistd;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class SocketTransport : DuplexTransport
 | 
					class SocketTransport : DuplexTransport
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	private int socket_ = -1;
 | 
						private int socket_ = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Protocol protocol_;
 | 
						private Protocol protocol_;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,8 +29,6 @@ static if (UseEpoll)
 | 
				
			|||||||
    import tanya.event.internal.epoll;
 | 
					    import tanya.event.internal.epoll;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Events.
 | 
					 * Events.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -49,7 +47,6 @@ alias EventMask = BitFlags!Event;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
abstract class Loop
 | 
					abstract class Loop
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// Pending watchers.
 | 
						/// Pending watchers.
 | 
				
			||||||
	protected Queue!Watcher pendings;
 | 
						protected Queue!Watcher pendings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,7 +201,7 @@ abstract class Loop
 | 
				
			|||||||
	 * 	protocolFactory = Protocol factory.
 | 
						 * 	protocolFactory = Protocol factory.
 | 
				
			||||||
	 * 	socket          = Socket.
 | 
						 * 	socket          = Socket.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected void acceptConnection(Protocol delegate() @nogc protocolFactory,
 | 
						protected void acceptConnection(Protocol delegate() protocolFactory,
 | 
				
			||||||
	                                int socket);
 | 
						                                int socket);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Whether the event loop should be stopped.
 | 
						/// Whether the event loop should be stopped.
 | 
				
			||||||
@@ -219,7 +216,6 @@ abstract class Loop
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class BadLoopException : Exception
 | 
					class BadLoopException : Exception
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Params:
 | 
						 * Params:
 | 
				
			||||||
	 * 	file = The file where the exception occurred.
 | 
						 * 	file = The file where the exception occurred.
 | 
				
			||||||
@@ -227,7 +223,7 @@ class BadLoopException : Exception
 | 
				
			|||||||
	 * 	next = The previous exception in the chain of exceptions, if any.
 | 
						 * 	next = The previous exception in the chain of exceptions, if any.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(string file = __FILE__, size_t line = __LINE__, Throwable next = null)
 | 
						this(string file = __FILE__, size_t line = __LINE__, Throwable next = null)
 | 
				
			||||||
	pure @safe nothrow const
 | 
						pure @safe nothrow const @nogc
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		super("Event loop cannot be initialized.", file, line, next);
 | 
							super("Event loop cannot be initialized.", file, line, next);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ import tanya.event.protocol;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class TransportException : Exception
 | 
					class TransportException : Exception
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Params:
 | 
						 * Params:
 | 
				
			||||||
	 * 	msg  = Message to output.
 | 
						 * 	msg  = Message to output.
 | 
				
			||||||
@@ -29,7 +28,7 @@ class TransportException : Exception
 | 
				
			|||||||
	this(string msg,
 | 
						this(string msg,
 | 
				
			||||||
	     string file = __FILE__,
 | 
						     string file = __FILE__,
 | 
				
			||||||
	     size_t line = __LINE__,
 | 
						     size_t line = __LINE__,
 | 
				
			||||||
	     Throwable next = null) pure @safe nothrow const
 | 
						     Throwable next = null) pure @safe nothrow const @nogc
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		super(msg, file, line, next);
 | 
							super(msg, file, line, next);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -40,7 +39,6 @@ class TransportException : Exception
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
interface Transport
 | 
					interface Transport
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Returns: Protocol.
 | 
						 * Returns: Protocol.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@@ -78,7 +76,6 @@ interface Transport
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
interface ReadTransport : Transport
 | 
					interface ReadTransport : Transport
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Returns: Underlying output buffer.
 | 
						 * Returns: Underlying output buffer.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@@ -103,7 +100,6 @@ interface ReadTransport : Transport
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
interface WriteTransport : Transport
 | 
					interface WriteTransport : Transport
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Returns: Underlying input buffer.
 | 
						 * Returns: Underlying input buffer.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,6 @@ import std.functional;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
abstract class Watcher
 | 
					abstract class Watcher
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
    /// Whether the watcher is active.
 | 
					    /// Whether the watcher is active.
 | 
				
			||||||
    bool active;
 | 
					    bool active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,7 +32,6 @@ abstract class Watcher
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class ConnectionWatcher : Watcher
 | 
					class ConnectionWatcher : Watcher
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// Watched file descriptor.
 | 
						/// Watched file descriptor.
 | 
				
			||||||
    private int socket_;
 | 
					    private int socket_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,7 +39,7 @@ class ConnectionWatcher : Watcher
 | 
				
			|||||||
	protected Protocol delegate() protocolFactory;
 | 
						protected Protocol delegate() protocolFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Callback.
 | 
						/// Callback.
 | 
				
			||||||
	package void delegate(Protocol delegate() @nogc protocolFactory,
 | 
						package void delegate(Protocol delegate() protocolFactory,
 | 
				
			||||||
	                      int socket) accept;
 | 
						                      int socket) accept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	invariant
 | 
						invariant
 | 
				
			||||||
@@ -54,27 +52,27 @@ class ConnectionWatcher : Watcher
 | 
				
			|||||||
	 * 	protocolFactory = Function returning a new $(D_PSYMBOL Protocol) instance.
 | 
						 * 	protocolFactory = Function returning a new $(D_PSYMBOL Protocol) instance.
 | 
				
			||||||
	 * 	socket          = Socket.
 | 
						 * 	socket          = Socket.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(Protocol function() @nogc protocolFactory, int socket)
 | 
						this(Protocol function() protocolFactory, int socket)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.protocolFactory = toDelegate(protocolFactory);
 | 
							this.protocolFactory = toDelegate(protocolFactory);
 | 
				
			||||||
		socket_ = socket;
 | 
							socket_ = socket;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
						/// Ditto.
 | 
				
			||||||
	this(Protocol delegate() @nogc protocolFactory, int socket)
 | 
						this(Protocol delegate() protocolFactory, int socket)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.protocolFactory = protocolFactory;
 | 
							this.protocolFactory = protocolFactory;
 | 
				
			||||||
		socket_ = socket;
 | 
							socket_ = socket;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
						/// Ditto.
 | 
				
			||||||
	protected this(Protocol function() @nogc protocolFactory)
 | 
						protected this(Protocol function() protocolFactory)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.protocolFactory = toDelegate(protocolFactory);
 | 
							this.protocolFactory = toDelegate(protocolFactory);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
						/// Ditto.
 | 
				
			||||||
	protected this(Protocol delegate() @nogc protocolFactory)
 | 
						protected this(Protocol delegate() protocolFactory)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		this.protocolFactory = protocolFactory;
 | 
							this.protocolFactory = protocolFactory;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -90,7 +88,7 @@ class ConnectionWatcher : Watcher
 | 
				
			|||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Returns: Application protocol factory.
 | 
						 * Returns: Application protocol factory.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	@property inout(Protocol delegate() @nogc) protocol() inout
 | 
						@property inout(Protocol delegate()) protocol() inout
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return protocolFactory;
 | 
							return protocolFactory;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -107,7 +105,6 @@ class ConnectionWatcher : Watcher
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class IOWatcher : ConnectionWatcher
 | 
					class IOWatcher : ConnectionWatcher
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// References a watcher or a transport.
 | 
						/// References a watcher or a transport.
 | 
				
			||||||
	DuplexTransport transport_;
 | 
						DuplexTransport transport_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,7 +113,7 @@ class IOWatcher : ConnectionWatcher
 | 
				
			|||||||
	 * 	protocolFactory = Function returning application specific protocol.
 | 
						 * 	protocolFactory = Function returning application specific protocol.
 | 
				
			||||||
	 * 	transport       = Transport.
 | 
						 * 	transport       = Transport.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(Protocol delegate() @nogc protocolFactory,
 | 
						this(Protocol delegate() protocolFactory,
 | 
				
			||||||
		 DuplexTransport transport)
 | 
							 DuplexTransport transport)
 | 
				
			||||||
	in
 | 
						in
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -143,7 +140,7 @@ class IOWatcher : ConnectionWatcher
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
	 * Returns: $(D_KEYWORD this).
 | 
						 * Returns: $(D_KEYWORD this).
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
	IOWatcher opCall(Protocol delegate() @nogc protocolFactory,
 | 
						IOWatcher opCall(Protocol delegate() protocolFactory,
 | 
				
			||||||
	                 DuplexTransport transport) @safe pure nothrow
 | 
						                 DuplexTransport transport) @safe pure nothrow
 | 
				
			||||||
	in
 | 
						in
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,49 +10,75 @@
 | 
				
			|||||||
 */  
 | 
					 */  
 | 
				
			||||||
module tanya.memory.allocator;
 | 
					module tanya.memory.allocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import std.experimental.allocator;
 | 
				
			||||||
 | 
					import std.traits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This interface should be similar to $(D_PSYMBOL
 | 
					 * Allocator interface.
 | 
				
			||||||
 * std.experimental.allocator.IAllocator), but usable in
 | 
					 | 
				
			||||||
 * $(D_KEYWORD @nogc)-code.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
interface Allocator
 | 
					interface Allocator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					    /**
 | 
				
			||||||
	/**
 | 
					     * Allocates $(D_PARAM size) bytes of memory.
 | 
				
			||||||
	 * Allocates $(D_PARAM s) bytes of memory.
 | 
					     *
 | 
				
			||||||
	 *
 | 
					     * Params:
 | 
				
			||||||
	 * Params:
 | 
					     *     size = Amount of memory to allocate.
 | 
				
			||||||
	 * 	s = Amount of memory to allocate.
 | 
					     *
 | 
				
			||||||
	 *
 | 
					     * Returns: The pointer to the new allocated memory.
 | 
				
			||||||
	 * Returns: The pointer to the new allocated memory.
 | 
					     */
 | 
				
			||||||
	 */
 | 
					    void[] allocate(size_t size) shared;
 | 
				
			||||||
    void[] allocate(size_t s) @safe;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
	 * Deallocates a memory block.
 | 
					     * Deallocates a memory block.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Params:
 | 
					     * Params:
 | 
				
			||||||
	 * 	p = A pointer to the memory block to be freed.
 | 
					     *     p = A pointer to the memory block to be freed.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Returns: Whether the deallocation was successful.
 | 
					     * Returns: Whether the deallocation was successful.
 | 
				
			||||||
	 */
 | 
					     */
 | 
				
			||||||
    bool deallocate(void[] p) @safe;
 | 
					    bool deallocate(void[] p) shared;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					    /**
 | 
				
			||||||
	 * Increases or decreases the size of a memory block.
 | 
					     * Increases or decreases the size of a memory block.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Params:
 | 
					     * Params:
 | 
				
			||||||
	 * 	p    = A pointer to the memory block.
 | 
					     *     p    = A pointer to the memory block.
 | 
				
			||||||
	 * 	size = Size of the reallocated block.
 | 
					     *     size = Size of the reallocated block.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Returns: Whether the reallocation was successful.
 | 
					     * Returns: Whether the reallocation was successful.
 | 
				
			||||||
	 */
 | 
					     */
 | 
				
			||||||
	bool reallocate(ref void[] p, size_t s) @safe;
 | 
					    bool reallocate(ref void[] p, size_t size) shared;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					    /**
 | 
				
			||||||
     * Static allocator instance and initializer.
 | 
					     * Returns: The alignment offered.
 | 
				
			||||||
	 *
 | 
					     */
 | 
				
			||||||
	 * Returns: An $(D_PSYMBOL Allocator) instance.
 | 
					    @property immutable(uint) alignment() shared const @safe pure nothrow;
 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	static @property Allocator instance() @safe;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
 | 
				
			||||||
 | 
					 *          not be reallocated. In the latter
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool resizeArray(T)(shared Allocator allocator,
 | 
				
			||||||
 | 
					                    ref T[] array,
 | 
				
			||||||
 | 
					                    in size_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void[] buf = array;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!allocator.reallocate(buf, length * T.sizeof))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    array = cast(T[]) buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum bool isFinalizable(T) = is(T == class) || is(T == interface)
 | 
				
			||||||
 | 
					                           || hasElaborateDestructor!T || isDynamicArray!T;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,8 +26,6 @@ else version (Posix)
 | 
				
			|||||||
	import core.sys.posix.pthread;
 | 
						import core.sys.posix.pthread;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
version (Windows)
 | 
					version (Windows)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	package alias Mutex = CRITICAL_SECTION;
 | 
						package alias Mutex = CRITICAL_SECTION;
 | 
				
			||||||
@@ -42,12 +40,12 @@ else version (Posix)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@property void defaultAllocator(Allocator allocator) @safe nothrow
 | 
					@property void defaultAllocator(shared Allocator allocator) @safe nothrow
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_defaultAllocator = allocator;
 | 
						_defaultAllocator = allocator;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@property Allocator defaultAllocator() @safe nothrow
 | 
					@property shared(Allocator) defaultAllocator() @safe nothrow
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return _defaultAllocator;
 | 
						return _defaultAllocator;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -204,4 +202,4 @@ bool resizeArray(T, A)(auto ref A allocator, ref T[] array, in size_t length)
 | 
				
			|||||||
enum bool isFinalizable(T) = is(T == class) || is(T == interface)
 | 
					enum bool isFinalizable(T) = is(T == class) || is(T == interface)
 | 
				
			||||||
                          || hasElaborateDestructor!T || isDynamicArray!T;
 | 
					                          || hasElaborateDestructor!T || isDynamicArray!T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private Allocator _defaultAllocator;
 | 
					private shared Allocator _defaultAllocator;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,24 +11,29 @@
 | 
				
			|||||||
module tanya.memory.ullocator;
 | 
					module tanya.memory.ullocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import tanya.memory.allocator;
 | 
					import tanya.memory.allocator;
 | 
				
			||||||
 | 
					import core.atomic;
 | 
				
			||||||
 | 
					import core.exception;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					version (Posix)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
version (Posix):
 | 
					    import core.stdc.errno;
 | 
				
			||||||
 | 
					    import core.sys.posix.sys.mman;
 | 
				
			||||||
import core.sys.posix.sys.mman;
 | 
					    import core.sys.posix.unistd;
 | 
				
			||||||
import core.sys.posix.unistd;
 | 
					}
 | 
				
			||||||
 | 
					else version (Windows)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    import core.sys.windows.winbase;
 | 
				
			||||||
 | 
					    import core.sys.windows.windows;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allocator for Posix systems with mmap/munmap support.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This allocator allocates memory in regions (multiple of 4 KB for example).
 | 
					 * This allocator allocates memory in regions (multiple of 4 KB for example).
 | 
				
			||||||
 * Each region is then splitted in blocks. So it doesn't request the memory
 | 
					 * Each region is then splitted in blocks. So it doesn't request the memory
 | 
				
			||||||
 * from the operating system on each call, but only if there are no large
 | 
					 * from the operating system on each call, but only if there are no large
 | 
				
			||||||
 * enought free blocks in the available regions.
 | 
					 * enough free blocks in the available regions.
 | 
				
			||||||
 * Deallocation works in the same way. Deallocation doesn't immediately
 | 
					 * Deallocation works in the same way. Deallocation doesn't immediately
 | 
				
			||||||
 * gives the memory back to the operating system, but marks the appropriate
 | 
					 * gives the memory back to the operating system, but marks the appropriate
 | 
				
			||||||
 * block as free and only if all blocks in the region are free, the complet
 | 
					 * block as free and only if all blocks in the region are free, the complete
 | 
				
			||||||
 * region is deallocated.
 | 
					 * region is deallocated.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * ----------------------------------------------------------------------------
 | 
					 * ----------------------------------------------------------------------------
 | 
				
			||||||
@@ -42,382 +47,440 @@ import core.sys.posix.unistd;
 | 
				
			|||||||
 * |  N   |    -----------> next|            ||   N  |     |                  |
 | 
					 * |  N   |    -----------> next|            ||   N  |     |                  |
 | 
				
			||||||
 * |      |     |         |     |            ||      |     |                  |
 | 
					 * |      |     |         |     |            ||      |     |                  |
 | 
				
			||||||
 * --------------------------------------------------- ------------------------
 | 
					 * --------------------------------------------------- ------------------------
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TODO:
 | 
				
			||||||
 | 
					 *     $(UL
 | 
				
			||||||
 | 
					 *         $(LI Thread safety (core.atomic.cas))
 | 
				
			||||||
 | 
					 *         $(LI If two neighbour blocks are free, they can be merged)
 | 
				
			||||||
 | 
					 *         $(LI Reallocation shoud check if there is enough free space in the
 | 
				
			||||||
 | 
					 *              next block instead of always moving the memory)
 | 
				
			||||||
 | 
					 *         $(LI Make 64 KB regions mininmal region size on Linux)
 | 
				
			||||||
 | 
					 *     )
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class Ullocator : Allocator
 | 
					class Ullocator : Allocator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					    @disable this();
 | 
				
			||||||
	@disable this();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shared static this() @safe nothrow
 | 
					    shared static this()
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		pageSize = sysconf(_SC_PAGE_SIZE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Allocates $(D_PARAM size) bytes of memory.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Params:
 | 
					 | 
				
			||||||
	 * 	size = Amount of memory to allocate.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Returns: The pointer to the new allocated memory.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
    void[] allocate(size_t size) @trusted nothrow
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		immutable dataSize = addAlignment(size);
 | 
					        version (Posix)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
		void* data = findBlock(dataSize);
 | 
					            pageSize = sysconf(_SC_PAGE_SIZE);
 | 
				
			||||||
		if (data is null)
 | 
					        }
 | 
				
			||||||
		{
 | 
					        else version (Windows)
 | 
				
			||||||
			data = initializeRegion(dataSize);
 | 
					        {
 | 
				
			||||||
		}
 | 
					            SYSTEM_INFO si;
 | 
				
			||||||
 | 
					            GetSystemInfo(&si);
 | 
				
			||||||
		return data is null ? null : data[0..size];
 | 
					            pageSize = si.dwPageSize;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
					 | 
				
			||||||
	unittest
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto p = Ullocator.instance.allocate(20);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert(p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Ullocator.instance.deallocate(p);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Search for a block large enough to keep $(D_PARAM size) and split it
 | 
					 | 
				
			||||||
	 * into two blocks if the block is too large.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Params:
 | 
					 | 
				
			||||||
	 * 	size = Minimum size the block should have.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Returns: Data the block points to or $(D_KEYWORD null).
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	private void* findBlock(size_t size) nothrow
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Block block1;
 | 
					 | 
				
			||||||
		RegionLoop: for (auto r = head; r !is null; r = r.next)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			block1 = cast(Block) (cast(void*) r + regionEntrySize);
 | 
					 | 
				
			||||||
			do
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				if (block1.free && block1.size >= size)
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					break RegionLoop;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			while ((block1 = block1.next) !is null);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (block1 is null)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return null;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else if (block1.size >= size + alignment + blockEntrySize)
 | 
					 | 
				
			||||||
		{ // Split the block if needed
 | 
					 | 
				
			||||||
			Block block2 = cast(Block) (cast(void*) block1 + blockEntrySize + size);
 | 
					 | 
				
			||||||
			block2.prev = block1;
 | 
					 | 
				
			||||||
			if (block1.next is null)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				block2.next = null;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				block2.next = block1.next.next;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			block1.next = block2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			block1.free = false;
 | 
					 | 
				
			||||||
			block2.free = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			block2.size = block1.size - blockEntrySize - size;
 | 
					 | 
				
			||||||
			block1.size = size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			block2.region = block1.region;
 | 
					 | 
				
			||||||
			++block1.region.blocks;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			block1.free = false;
 | 
					 | 
				
			||||||
			++block1.region.blocks;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return cast(void*) block1 + blockEntrySize;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
	 * Deallocates a memory block.
 | 
					     * Allocates $(D_PARAM size) bytes of memory.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Params:
 | 
					     * Params:
 | 
				
			||||||
	 * 	p = A pointer to the memory block to be freed.
 | 
					     *     size = Amount of memory to allocate.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Returns: Whether the deallocation was successful.
 | 
					     * Returns: The pointer to the new allocated memory.
 | 
				
			||||||
	 */
 | 
					     */
 | 
				
			||||||
    bool deallocate(void[] p) @trusted nothrow
 | 
					    void[] allocate(size_t size) shared @nogc @trusted nothrow
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		if (p is null)
 | 
					        if (!size)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			return true;
 | 
					            return null;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
 | 
					        immutable dataSize = addAlignment(size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Block block = cast(Block) (p.ptr - blockEntrySize);
 | 
					        void* data = findBlock(dataSize);
 | 
				
			||||||
		if (block.region.blocks <= 1)
 | 
					        if (data is null)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			if (block.region.prev !is null)
 | 
					            data = initializeRegion(dataSize);
 | 
				
			||||||
			{
 | 
					        }
 | 
				
			||||||
				block.region.prev.next = block.region.next;
 | 
					
 | 
				
			||||||
			}
 | 
					        return data is null ? null : data[0..size];
 | 
				
			||||||
			else // Replace the list head. It is being deallocated
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				head = block.region.next;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (block.region.next !is null)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				block.region.next.prev = block.region.prev;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return munmap(block.region, block.region.size) == 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			block.free = true;
 | 
					 | 
				
			||||||
			--block.region.blocks;
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
					    ///
 | 
				
			||||||
	unittest
 | 
					    @nogc @safe nothrow unittest
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		auto p = Ullocator.instance.allocate(20);
 | 
					        auto p = Ullocator.instance.allocate(20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert(Ullocator.instance.deallocate(p));
 | 
					        assert(p);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					        Ullocator.instance.deallocate(p);
 | 
				
			||||||
	 * Increases or decreases the size of a memory block.
 | 
					    }
 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Params:
 | 
					 | 
				
			||||||
	 * 	p    = A pointer to the memory block.
 | 
					 | 
				
			||||||
	 * 	size = Size of the reallocated block.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Returns: Whether the reallocation was successful.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	bool reallocate(ref void[] p, size_t size) @trusted nothrow
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (size == p.length)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto reallocP = allocate(size);
 | 
					    /**
 | 
				
			||||||
		if (reallocP is null)
 | 
					     * Search for a block large enough to keep $(D_PARAM size) and split it
 | 
				
			||||||
		{
 | 
					     * into two blocks if the block is too large.
 | 
				
			||||||
			return false;
 | 
					     *
 | 
				
			||||||
		}
 | 
					     * Params:
 | 
				
			||||||
 | 
					     *     size = Minimum size the block should have.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Returns: Data the block points to or $(D_KEYWORD null).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void* findBlock(size_t size) shared @nogc nothrow
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Block block1;
 | 
				
			||||||
 | 
					        RegionLoop: for (auto r = head; r !is null; r = r.next)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            block1 = cast(Block) (cast(void*) r + regionEntrySize);
 | 
				
			||||||
 | 
					            do
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (block1.free && block1.size >= size)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    break RegionLoop;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            while ((block1 = block1.next) !is null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (block1 is null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (block1.size >= size + alignment + blockEntrySize)
 | 
				
			||||||
 | 
					        { // Split the block if needed
 | 
				
			||||||
 | 
					            Block block2 = cast(Block) (cast(void*) block1 + blockEntrySize + size);
 | 
				
			||||||
 | 
					            block2.prev = block1;
 | 
				
			||||||
 | 
					            if (block1.next is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                block2.next = null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                block2.next = block1.next.next;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            block1.next = block2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p !is null)
 | 
					            block1.free = false;
 | 
				
			||||||
		{
 | 
					            block2.free = true;
 | 
				
			||||||
			if (size > p.length)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				reallocP[0..p.length] = p[0..$];
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				reallocP[0..size] = p[0..size];
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			deallocate(p);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		p = reallocP;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return true;
 | 
					            block2.size = block1.size - blockEntrySize - size;
 | 
				
			||||||
	}
 | 
					            block1.size = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
					            block2.region = block1.region;
 | 
				
			||||||
	unittest
 | 
					            atomicOp!"+="(block1.region.blocks, 1);
 | 
				
			||||||
	{
 | 
					        }
 | 
				
			||||||
		void[] p;
 | 
					        else
 | 
				
			||||||
		Ullocator.instance.reallocate(p, 10 * int.sizeof);
 | 
					        {
 | 
				
			||||||
		(cast(int[]) p)[7] = 123;
 | 
					            block1.free = false;
 | 
				
			||||||
 | 
					            atomicOp!"+="(block1.region.blocks, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return cast(void*) block1 + blockEntrySize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert(p.length == 40);
 | 
					    /**
 | 
				
			||||||
 | 
					     * Deallocates a memory block.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Params:
 | 
				
			||||||
 | 
					     *     p = A pointer to the memory block to be freed.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Returns: Whether the deallocation was successful.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool deallocate(void[] p) shared @nogc @trusted nothrow
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (p is null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ullocator.instance.reallocate(p, 8 * int.sizeof);
 | 
					        Block block = cast(Block) (p.ptr - blockEntrySize);
 | 
				
			||||||
 | 
					        if (block.region.blocks <= 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (block.region.prev !is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                block.region.prev.next = block.region.next;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else // Replace the list head. It is being deallocated
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                head = block.region.next;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (block.region.next !is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                block.region.next.prev = block.region.prev;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            version (Posix)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return munmap(cast(void*) block.region, block.region.size) == 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            version (Windows)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return VirtualFree(cast(void*) block.region, 0, MEM_RELEASE) == 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            block.free = true;
 | 
				
			||||||
 | 
					            atomicOp!"-="(block.region.blocks, 1);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert(p.length == 32);
 | 
					    ///
 | 
				
			||||||
		assert((cast(int[]) p)[7] == 123);
 | 
					    @nogc @safe nothrow unittest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto p = Ullocator.instance.allocate(20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ullocator.instance.reallocate(p, 20 * int.sizeof);
 | 
					        assert(Ullocator.instance.deallocate(p));
 | 
				
			||||||
		(cast(int[]) p)[15] = 8;
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert(p.length == 80);
 | 
					    /**
 | 
				
			||||||
		assert((cast(int[]) p)[15] == 8);
 | 
					     * Increases or decreases the size of a memory block.
 | 
				
			||||||
		assert((cast(int[]) p)[7] == 123);
 | 
					     *
 | 
				
			||||||
 | 
					     * Params:
 | 
				
			||||||
 | 
					     *     p    = A pointer to the memory block.
 | 
				
			||||||
 | 
					     *     size = Size of the reallocated block.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Returns: Whether the reallocation was successful.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool reallocate(ref void[] p, size_t size) shared @nogc @trusted nothrow
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        void[] reallocP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ullocator.instance.reallocate(p, 8 * int.sizeof);
 | 
					        if (size == p.length)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (size > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            reallocP = allocate(size);
 | 
				
			||||||
 | 
					            if (reallocP is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert(p.length == 32);
 | 
					        if (p !is null)
 | 
				
			||||||
		assert((cast(int[]) p)[7] == 123);
 | 
					        {
 | 
				
			||||||
 | 
					            if (size > p.length)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                reallocP[0..p.length] = p[0..$];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (size > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                reallocP[0..size] = p[0..size];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            deallocate(p);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        p = reallocP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ullocator.instance.deallocate(p);
 | 
					        return true;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					    ///
 | 
				
			||||||
 | 
					    @nogc @safe nothrow unittest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        void[] p;
 | 
				
			||||||
 | 
					        Ullocator.instance.reallocate(p, 10 * int.sizeof);
 | 
				
			||||||
 | 
					        (cast(int[]) p)[7] = 123;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(p.length == 40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ullocator.instance.reallocate(p, 8 * int.sizeof);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(p.length == 32);
 | 
				
			||||||
 | 
					        assert((cast(int[]) p)[7] == 123);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ullocator.instance.reallocate(p, 20 * int.sizeof);
 | 
				
			||||||
 | 
					        (cast(int[]) p)[15] = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(p.length == 80);
 | 
				
			||||||
 | 
					        assert((cast(int[]) p)[15] == 8);
 | 
				
			||||||
 | 
					        assert((cast(int[]) p)[7] == 123);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ullocator.instance.reallocate(p, 8 * int.sizeof);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(p.length == 32);
 | 
				
			||||||
 | 
					        assert((cast(int[]) p)[7] == 123);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ullocator.instance.deallocate(p);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
     * Static allocator instance and initializer.
 | 
					     * Static allocator instance and initializer.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Returns: The global $(D_PSYMBOL Allocator) instance.
 | 
					     * Returns: Global $(D_PSYMBOL Ullocator) instance.
 | 
				
			||||||
	 */
 | 
					     */
 | 
				
			||||||
	static @property Ullocator instance() @trusted nothrow
 | 
					    static @property ref shared(Ullocator) instance() @nogc @trusted nothrow
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (instance_ is null)
 | 
					        if (instance_ is null)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			immutable instanceSize = addAlignment(__traits(classInstanceSize, Ullocator));
 | 
					            immutable instanceSize = addAlignment(__traits(classInstanceSize, Ullocator));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			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);
 | 
				
			||||||
 | 
					            if (data !is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                data[0..instanceSize] = typeid(Ullocator).initializer[];
 | 
				
			||||||
 | 
					                instance_ = cast(shared Ullocator) data;
 | 
				
			||||||
 | 
					                instance_.head = head;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return instance_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (data is null)
 | 
					    ///
 | 
				
			||||||
			{
 | 
					    @nogc @safe nothrow unittest
 | 
				
			||||||
				return null;
 | 
					    {
 | 
				
			||||||
			}
 | 
					        assert(instance is instance);
 | 
				
			||||||
			data[0..instanceSize] = typeid(Ullocator).initializer[];
 | 
					    }
 | 
				
			||||||
			instance_ = cast(Ullocator) data;
 | 
					 | 
				
			||||||
			instance_.head = head;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return instance_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
					    /**
 | 
				
			||||||
	unittest
 | 
					     * Initializes a region for one element.
 | 
				
			||||||
	{
 | 
					     *
 | 
				
			||||||
		assert(instance is instance);
 | 
					     * Params:
 | 
				
			||||||
	}
 | 
					     *     size = Aligned size of the first data block in the region.
 | 
				
			||||||
 | 
					     *     head = Region list head.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Returns: A pointer to the data.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    pragma(inline)
 | 
				
			||||||
 | 
					    private static void* initializeRegion(size_t size,
 | 
				
			||||||
 | 
					                                          ref Region head) @nogc nothrow
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        immutable regionSize = calculateRegionSize(size);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
	/**
 | 
					        version (Posix)
 | 
				
			||||||
	 * Initializes a region for one element.
 | 
					        {
 | 
				
			||||||
	 *
 | 
					            void* p = mmap(null,
 | 
				
			||||||
	 * Params:
 | 
					                           regionSize,
 | 
				
			||||||
	 * 	size = Aligned size of the first data block in the region.
 | 
					                           PROT_READ | PROT_WRITE,
 | 
				
			||||||
	 *  head = Region list head.
 | 
					                           MAP_PRIVATE | MAP_ANON,
 | 
				
			||||||
	 *
 | 
					                           -1,
 | 
				
			||||||
	 * Returns: A pointer to the data.
 | 
					                           0);
 | 
				
			||||||
	 */
 | 
					            if (p is MAP_FAILED)
 | 
				
			||||||
	pragma(inline)
 | 
					            {
 | 
				
			||||||
	private static void* initializeRegion(size_t size,
 | 
					                if (errno == ENOMEM)
 | 
				
			||||||
	                                      ref Region head) nothrow
 | 
					                {
 | 
				
			||||||
	{
 | 
					                    onOutOfMemoryError();
 | 
				
			||||||
		immutable regionSize = calculateRegionSize(size);
 | 
					                }
 | 
				
			||||||
		void* p = mmap(null,
 | 
					                return null;
 | 
				
			||||||
		               regionSize,
 | 
					            }
 | 
				
			||||||
		               PROT_READ | PROT_WRITE,
 | 
					        }
 | 
				
			||||||
		               MAP_PRIVATE | MAP_ANON,
 | 
					        else version (Windows)
 | 
				
			||||||
		               -1,
 | 
					        {
 | 
				
			||||||
		               0);
 | 
					            void* p = VirtualAlloc(null,
 | 
				
			||||||
		if (p is MAP_FAILED)
 | 
					                                   regionSize,
 | 
				
			||||||
		{
 | 
					                                   MEM_COMMIT,
 | 
				
			||||||
			return null;
 | 
					                                   PAGE_READWRITE);
 | 
				
			||||||
		}
 | 
					            if (p is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    onOutOfMemoryError();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Region region = cast(Region) p;
 | 
					        Region region = cast(Region) p;
 | 
				
			||||||
		region.blocks = 1;
 | 
					        region.blocks = 1;
 | 
				
			||||||
		region.size = regionSize;
 | 
					        region.size = regionSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Set the pointer to the head of the region list
 | 
					        // Set the pointer to the head of the region list
 | 
				
			||||||
		if (head !is null)
 | 
					        if (head !is null)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			head.prev = region;
 | 
					            head.prev = region;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
		region.next = head;
 | 
					        region.next = head;
 | 
				
			||||||
		region.prev = null;
 | 
					        region.prev = null;
 | 
				
			||||||
		head = region;
 | 
					        head = region;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Initialize the data block
 | 
					        // Initialize the data block
 | 
				
			||||||
		void* memoryPointer = p + regionEntrySize;
 | 
					        void* memoryPointer = p + regionEntrySize;
 | 
				
			||||||
		Block block1 = cast(Block) memoryPointer;
 | 
					        Block block1 = cast(Block) memoryPointer;
 | 
				
			||||||
		block1.size = size;
 | 
					        block1.size = size;
 | 
				
			||||||
		block1.free = false;
 | 
					        block1.free = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// It is what we want to return
 | 
					        // It is what we want to return
 | 
				
			||||||
		void* data = memoryPointer + blockEntrySize;
 | 
					        void* data = memoryPointer + blockEntrySize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Free block after data
 | 
					        // Free block after data
 | 
				
			||||||
		memoryPointer = data + size;
 | 
					        memoryPointer = data + size;
 | 
				
			||||||
		Block block2 = cast(Block) memoryPointer;
 | 
					        Block block2 = cast(Block) memoryPointer;
 | 
				
			||||||
		block1.prev = block2.next = null;
 | 
					        block1.prev = block2.next = null;
 | 
				
			||||||
		block1.next = block2;
 | 
					        block1.next = block2;
 | 
				
			||||||
		block2.prev = block1;
 | 
					        block2.prev = block1;
 | 
				
			||||||
		block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
 | 
					        block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
 | 
				
			||||||
		block2.free = true;
 | 
					        block2.free = true;
 | 
				
			||||||
		block1.region = block2.region = region;
 | 
					        block1.region = block2.region = region;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return data;
 | 
					        return data;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Ditto.
 | 
					    /// Ditto.
 | 
				
			||||||
	private void* initializeRegion(size_t size) nothrow
 | 
					    private void* initializeRegion(size_t size) shared @nogc nothrow
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		return initializeRegion(size, head);
 | 
					        return initializeRegion(size, head);
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					    /**
 | 
				
			||||||
	 * Params:
 | 
					     * Params:
 | 
				
			||||||
	 * 	x = Space to be aligned.
 | 
					     *     x = Space to be aligned.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Returns: Aligned size of $(D_PARAM x).
 | 
					     * Returns: Aligned size of $(D_PARAM x).
 | 
				
			||||||
	 */
 | 
					     */
 | 
				
			||||||
	pragma(inline)
 | 
					    pragma(inline)
 | 
				
			||||||
	private static immutable(size_t) addAlignment(size_t x) @safe pure nothrow
 | 
					    private static immutable(size_t) addAlignment(size_t x)
 | 
				
			||||||
	out (result)
 | 
					    @nogc @safe pure nothrow
 | 
				
			||||||
	{
 | 
					    out (result)
 | 
				
			||||||
		assert(result > 0);
 | 
					    {
 | 
				
			||||||
	}
 | 
					        assert(result > 0);
 | 
				
			||||||
	body
 | 
					    }
 | 
				
			||||||
	{
 | 
					    body
 | 
				
			||||||
		return (x - 1) / alignment * alignment + alignment;
 | 
					    {
 | 
				
			||||||
	}
 | 
					        return (x - 1) / alignment_ * alignment_ + alignment_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					    /**
 | 
				
			||||||
	 * Params:
 | 
					     * Params:
 | 
				
			||||||
	 * 	x = Required space.
 | 
					     *     x = Required space.
 | 
				
			||||||
	 *
 | 
					     *
 | 
				
			||||||
	 * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
 | 
					     * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
 | 
				
			||||||
	 */
 | 
					     */
 | 
				
			||||||
	pragma(inline)
 | 
					    pragma(inline)
 | 
				
			||||||
	private static immutable(size_t) calculateRegionSize(size_t x)
 | 
					    private static immutable(size_t) calculateRegionSize(size_t x)
 | 
				
			||||||
	@safe pure nothrow
 | 
					    @nogc @safe pure nothrow
 | 
				
			||||||
	out (result)
 | 
					    out (result)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		assert(result > 0);
 | 
					        assert(result > 0);
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
	body
 | 
					    body
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		x += regionEntrySize + blockEntrySize * 2;
 | 
					        x += regionEntrySize + blockEntrySize * 2;
 | 
				
			||||||
		return x / pageSize * pageSize + pageSize;
 | 
					        return x / pageSize * pageSize + pageSize;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum alignment = 8;
 | 
					    @property immutable(uint) alignment() shared const @nogc @safe pure nothrow
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return alignment_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private enum alignment_ = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static Ullocator instance_;
 | 
					    private shared static Ullocator instance_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private shared static immutable long pageSize;
 | 
					    private shared static immutable size_t pageSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private struct RegionEntry
 | 
					    private shared struct RegionEntry
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		Region prev;
 | 
					        Region prev;
 | 
				
			||||||
		Region next;
 | 
					        Region next;
 | 
				
			||||||
		uint blocks;
 | 
					        uint blocks;
 | 
				
			||||||
		ulong size;
 | 
					        size_t size;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
	private alias Region = RegionEntry*;
 | 
					    private alias Region = shared RegionEntry*;
 | 
				
			||||||
	private enum regionEntrySize = 32;
 | 
					    private enum regionEntrySize = 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Region head;
 | 
					    private shared Region head;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private struct BlockEntry
 | 
					    private shared struct BlockEntry
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		Block prev;
 | 
					        Block prev;
 | 
				
			||||||
		Block next;
 | 
					        Block next;
 | 
				
			||||||
		bool free;
 | 
					        bool free;
 | 
				
			||||||
		ulong size;
 | 
					        size_t size;
 | 
				
			||||||
		Region region;
 | 
					        Region region;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
	private alias Block = BlockEntry*;
 | 
					    private alias Block = shared BlockEntry*;
 | 
				
			||||||
	private enum blockEntrySize = 40;
 | 
					    private enum blockEntrySize = 40;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,6 @@ import tanya.memory;
 | 
				
			|||||||
import std.digest.sha;
 | 
					import std.digest.sha;
 | 
				
			||||||
import std.typecons;
 | 
					import std.typecons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Block size of entropy accumulator (SHA-512).
 | 
					/// Block size of entropy accumulator (SHA-512).
 | 
				
			||||||
enum blockSize = 64;
 | 
					enum blockSize = 64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,7 +25,6 @@ enum maxGather = 128;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class EntropyException : Exception
 | 
					class EntropyException : Exception
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Params:
 | 
						 * Params:
 | 
				
			||||||
	 * 	msg  = Message to output.
 | 
						 * 	msg  = Message to output.
 | 
				
			||||||
@@ -38,7 +35,7 @@ class EntropyException : Exception
 | 
				
			|||||||
	this(string msg,
 | 
						this(string msg,
 | 
				
			||||||
	     string file = __FILE__,
 | 
						     string file = __FILE__,
 | 
				
			||||||
	     size_t line = __LINE__,
 | 
						     size_t line = __LINE__,
 | 
				
			||||||
	     Throwable next = null) pure @safe nothrow const
 | 
						     Throwable next = null) pure @safe nothrow const @nogc
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		super(msg, file, line, next);
 | 
							super(msg, file, line, next);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -49,7 +46,6 @@ class EntropyException : Exception
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
abstract class EntropySource
 | 
					abstract class EntropySource
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// Amount of already generated entropy.
 | 
						/// Amount of already generated entropy.
 | 
				
			||||||
	protected ushort size_;
 | 
						protected ushort size_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,7 +99,6 @@ version (linux)
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	class PlatformEntropySource : EntropySource
 | 
						class PlatformEntropySource : EntropySource
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	@nogc:
 | 
					 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * Returns: Minimum bytes required from the entropy source.
 | 
							 * Returns: Minimum bytes required from the entropy source.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
@@ -164,13 +159,12 @@ version (linux)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class Entropy
 | 
					class Entropy
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@nogc:
 | 
					 | 
				
			||||||
	/// Entropy sources.
 | 
						/// Entropy sources.
 | 
				
			||||||
	protected EntropySource[] sources;
 | 
						protected EntropySource[] sources;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private ubyte sourceCount_;
 | 
						private ubyte sourceCount_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Allocator allocator;
 | 
						private shared Allocator allocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Entropy accumulator.
 | 
						/// Entropy accumulator.
 | 
				
			||||||
	protected SHA!(maxGather * 8, 512) accumulator;
 | 
						protected SHA!(maxGather * 8, 512) accumulator;
 | 
				
			||||||
@@ -181,7 +175,7 @@ class Entropy
 | 
				
			|||||||
	 * 	allocator  = Allocator to allocate entropy sources available on the
 | 
						 * 	allocator  = Allocator to allocate entropy sources available on the
 | 
				
			||||||
	 * 	             system.
 | 
						 * 	             system.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	this(size_t maxSources = 20, Allocator allocator = defaultAllocator)
 | 
						this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
 | 
				
			||||||
	in
 | 
						in
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		assert(maxSources > 0 && maxSources <= ubyte.max);
 | 
							assert(maxSources > 0 && maxSources <= ubyte.max);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user