Make allocator shared and fix some RefCounted bugs
This commit is contained in:
		@@ -107,7 +107,7 @@ class EpollLoop : SelectorLoop
 | 
			
		||||
		{
 | 
			
		||||
			if (errno != EINTR)
 | 
			
		||||
			{
 | 
			
		||||
				throw theAllocator.make!BadLoopException();
 | 
			
		||||
				throw defaultAllocator.make!BadLoopException();
 | 
			
		||||
			}
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ class IOCPStreamTransport : StreamTransport
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		socket_ = socket;
 | 
			
		||||
		input = MmapPool.instance.make!WriteBuffer();
 | 
			
		||||
		input = MmapPool.instance.make!WriteBuffer(8192, MmapPool.instance);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~this()
 | 
			
		||||
@@ -101,7 +101,8 @@ class IOCPStreamTransport : StreamTransport
 | 
			
		||||
		completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
 | 
			
		||||
		if (!completionPort)
 | 
			
		||||
		{
 | 
			
		||||
			throw theAllocator.make!BadLoopException("Creating completion port failed");
 | 
			
		||||
			throw make!BadLoopException(defaultAllocator,
 | 
			
		||||
			                            "Creating completion port failed");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -141,7 +142,7 @@ class IOCPStreamTransport : StreamTransport
 | 
			
		||||
			catch (SocketException e)
 | 
			
		||||
			{
 | 
			
		||||
				MmapPool.instance.dispose(overlapped);
 | 
			
		||||
				theAllocator.dispose(e);
 | 
			
		||||
				defaultAllocator.dispose(e);
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -173,7 +174,7 @@ class IOCPStreamTransport : StreamTransport
 | 
			
		||||
				catch (SocketException e)
 | 
			
		||||
				{
 | 
			
		||||
					MmapPool.instance.dispose(overlapped);
 | 
			
		||||
					theAllocator.dispose(e);
 | 
			
		||||
					defaultAllocator.dispose(e);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -250,7 +250,7 @@ class KqueueLoop : SelectorLoop
 | 
			
		||||
		{
 | 
			
		||||
			if (errno != EINTR)
 | 
			
		||||
			{
 | 
			
		||||
				throw theAllocator.make!BadLoopException();
 | 
			
		||||
				throw defaultAllocatorAllocator.make!BadLoopException();
 | 
			
		||||
			}
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ class SelectorStreamTransport : StreamTransport
 | 
			
		||||
	{
 | 
			
		||||
		socket_ = socket;
 | 
			
		||||
		this.loop = loop;
 | 
			
		||||
		input = MmapPool.instance.make!WriteBuffer();
 | 
			
		||||
		input = MmapPool.instance.make!WriteBuffer(8192, MmapPool.instance);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -224,7 +224,7 @@ abstract class SelectorLoop : Loop
 | 
			
		||||
			}
 | 
			
		||||
			catch (SocketException e)
 | 
			
		||||
			{
 | 
			
		||||
				theAllocator.dispose(e);
 | 
			
		||||
				defaultAllocator.dispose(e);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			if (client is null)
 | 
			
		||||
 
 | 
			
		||||
@@ -34,31 +34,31 @@
 | 
			
		||||
 *
 | 
			
		||||
 * void main()
 | 
			
		||||
 * {
 | 
			
		||||
 * 	auto address = theAllocator.make!InternetAddress("127.0.0.1", cast(ushort) 8192);
 | 
			
		||||
 * 	auto address = defaultAllocator.make!InternetAddress("127.0.0.1", cast(ushort) 8192);
 | 
			
		||||
 *
 | 
			
		||||
 * 	version (Windows)
 | 
			
		||||
 * 	{
 | 
			
		||||
 * 		auto sock = theAllocator.make!OverlappedStreamSocket(AddressFamily.INET);
 | 
			
		||||
 * 		auto sock = defaultAllocator.make!OverlappedStreamSocket(AddressFamily.INET);
 | 
			
		||||
 * 	}
 | 
			
		||||
 * 	else
 | 
			
		||||
 * 	{
 | 
			
		||||
 * 		auto sock = theAllocator.make!StreamSocket(AddressFamily.INET);
 | 
			
		||||
 * 		auto sock = defaultAllocator.make!StreamSocket(AddressFamily.INET);
 | 
			
		||||
 * 		sock.blocking = false;
 | 
			
		||||
 * 	}
 | 
			
		||||
 *
 | 
			
		||||
 * 	sock.bind(address);
 | 
			
		||||
 * 	sock.listen(5);
 | 
			
		||||
 *
 | 
			
		||||
 * 	auto io = theAllocator.make!ConnectionWatcher(sock);
 | 
			
		||||
 * 	auto io = defaultAllocator.make!ConnectionWatcher(sock);
 | 
			
		||||
 * 	io.setProtocol!EchoProtocol;
 | 
			
		||||
 *
 | 
			
		||||
 * 	defaultLoop.start(io);
 | 
			
		||||
 * 	defaultLoop.run();
 | 
			
		||||
 *
 | 
			
		||||
 * 	sock.shutdown();
 | 
			
		||||
 * 	theAllocator.dispose(io);
 | 
			
		||||
 * 	theAllocator.dispose(sock);
 | 
			
		||||
 * 	theAllocator.dispose(address);
 | 
			
		||||
 * 	defaultAllocator.dispose(io);
 | 
			
		||||
 * 	defaultAllocator.dispose(sock);
 | 
			
		||||
 * 	defaultAllocator.dispose(address);
 | 
			
		||||
 * }
 | 
			
		||||
 * ---
 | 
			
		||||
 */
 | 
			
		||||
@@ -278,7 +278,7 @@ abstract class Loop
 | 
			
		||||
	protected void kill(IOWatcher watcher, SocketException exception)
 | 
			
		||||
	{
 | 
			
		||||
		watcher.socket.shutdown();
 | 
			
		||||
		theAllocator.dispose(watcher.socket);
 | 
			
		||||
		defaultAllocator.dispose(watcher.socket);
 | 
			
		||||
		MmapPool.instance.dispose(watcher.transport);
 | 
			
		||||
		watcher.exception = exception;
 | 
			
		||||
		swapPendings.insertBack(watcher);
 | 
			
		||||
 
 | 
			
		||||
@@ -157,7 +157,7 @@ class IOWatcher : ConnectionWatcher
 | 
			
		||||
		super();
 | 
			
		||||
		transport_ = transport;
 | 
			
		||||
		protocol_ = protocol;
 | 
			
		||||
		output = MmapPool.instance.make!ReadBuffer();
 | 
			
		||||
		output = MmapPool.instance.make!ReadBuffer(8192, 1024, MmapPool.instance);
 | 
			
		||||
		active = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -108,30 +108,36 @@ class ReadBuffer : Buffer
 | 
			
		||||
    /// Size by which the buffer will grow.
 | 
			
		||||
    protected immutable size_t blockSize;
 | 
			
		||||
 | 
			
		||||
	/// Allocator.
 | 
			
		||||
	protected shared Allocator allocator;
 | 
			
		||||
 | 
			
		||||
    invariant
 | 
			
		||||
    {
 | 
			
		||||
        assert(length_ <= buffer_.length);
 | 
			
		||||
        assert(blockSize > 0);
 | 
			
		||||
        assert(minAvailable > 0);
 | 
			
		||||
		assert(allocator !is null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new read buffer.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     size         = Initial buffer size and the size by which the buffer
 | 
			
		||||
     *                    will grow.
 | 
			
		||||
     *     minAvailable = minimal size should be always  available to fill.
 | 
			
		||||
     *                    So it will reallocate if $(D_INLINECODE 
 | 
			
		||||
     *                    $(D_PSYMBOL free) < $(D_PARAM minAvailable)
 | 
			
		||||
     *                    ).
 | 
			
		||||
     * 	size         = Initial buffer size and the size by which the buffer
 | 
			
		||||
     * 	               will grow.
 | 
			
		||||
     * 	minAvailable = minimal size should be always  available to fill.
 | 
			
		||||
     * 	               So it will reallocate if $(D_INLINECODE 
 | 
			
		||||
     * 	               $(D_PSYMBOL free) < $(D_PARAM minAvailable)).
 | 
			
		||||
	 * 	allocator    = Allocator.
 | 
			
		||||
     */
 | 
			
		||||
    this(size_t size = 8192,
 | 
			
		||||
         size_t minAvailable = 1024)
 | 
			
		||||
         size_t minAvailable = 1024,
 | 
			
		||||
	     shared Allocator allocator = defaultAllocator)
 | 
			
		||||
    {
 | 
			
		||||
        this.minAvailable = minAvailable;
 | 
			
		||||
        this.blockSize = size;
 | 
			
		||||
        theAllocator.resizeArray!ubyte(buffer_, size);
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
        allocator.resizeArray!ubyte(buffer_, size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -139,17 +145,17 @@ class ReadBuffer : Buffer
 | 
			
		||||
     */
 | 
			
		||||
    ~this()
 | 
			
		||||
    {
 | 
			
		||||
        theAllocator.dispose(buffer_);
 | 
			
		||||
        allocator.dispose(buffer_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!ReadBuffer;
 | 
			
		||||
        auto b = defaultAllocator.make!ReadBuffer;
 | 
			
		||||
        assert(b.capacity == 8192);
 | 
			
		||||
        assert(b.length == 0);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -190,7 +196,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!ReadBuffer;
 | 
			
		||||
        auto b = defaultAllocator.make!ReadBuffer;
 | 
			
		||||
        size_t numberRead;
 | 
			
		||||
 | 
			
		||||
        // Fills the buffer with values 0..10
 | 
			
		||||
@@ -202,7 +208,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
        b.clear();
 | 
			
		||||
        assert(b.free == b.blockSize);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -224,7 +230,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!ReadBuffer;
 | 
			
		||||
        auto b = defaultAllocator.make!ReadBuffer;
 | 
			
		||||
        size_t numberRead;
 | 
			
		||||
        ubyte[] result;
 | 
			
		||||
 | 
			
		||||
@@ -252,7 +258,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
        assert(result[10] == 20);
 | 
			
		||||
        assert(result[14] == 24);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -294,7 +300,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
        {
 | 
			
		||||
            if (capacity - length < minAvailable)
 | 
			
		||||
            {
 | 
			
		||||
                theAllocator.resizeArray!ubyte(buffer_, capacity + blockSize);
 | 
			
		||||
                allocator.resizeArray!ubyte(buffer_, capacity + blockSize);
 | 
			
		||||
            }
 | 
			
		||||
            ring = length_;
 | 
			
		||||
            return buffer_[length_..$];
 | 
			
		||||
@@ -304,7 +310,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!ReadBuffer;
 | 
			
		||||
        auto b = defaultAllocator.make!ReadBuffer;
 | 
			
		||||
        size_t numberRead;
 | 
			
		||||
        ubyte[] result;
 | 
			
		||||
 | 
			
		||||
@@ -319,7 +325,7 @@ class ReadBuffer : Buffer
 | 
			
		||||
        b.clear();
 | 
			
		||||
        assert(b.length == 0);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -349,23 +355,29 @@ class WriteBuffer : Buffer
 | 
			
		||||
    /// The position of the free area in the buffer.
 | 
			
		||||
    protected size_t position;
 | 
			
		||||
 | 
			
		||||
	/// Allocator.
 | 
			
		||||
	protected shared Allocator allocator;
 | 
			
		||||
 | 
			
		||||
    invariant
 | 
			
		||||
    {
 | 
			
		||||
        assert(blockSize > 0);
 | 
			
		||||
        // position can refer to an element outside the buffer if the buffer is full.
 | 
			
		||||
        assert(position <= buffer_.length);
 | 
			
		||||
		assert(allocator !is null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Params:
 | 
			
		||||
     *  size = Initial buffer size and the size by which the buffer
 | 
			
		||||
     *            will grow.
 | 
			
		||||
     *  size      = Initial buffer size and the size by which the buffer will
 | 
			
		||||
     * 	            grow.
 | 
			
		||||
	 * 	allocator = Allocator.
 | 
			
		||||
     */
 | 
			
		||||
    this(size_t size = 8192)
 | 
			
		||||
    this(size_t size = 8192, shared Allocator allocator = defaultAllocator)
 | 
			
		||||
    {
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
        blockSize = size;
 | 
			
		||||
        ring = size - 1;
 | 
			
		||||
        theAllocator.resizeArray!ubyte(buffer_, size);
 | 
			
		||||
        allocator.resizeArray!ubyte(buffer_, size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -373,7 +385,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
     */
 | 
			
		||||
    ~this()
 | 
			
		||||
    {
 | 
			
		||||
        theAllocator.dispose(buffer_);
 | 
			
		||||
        allocator.dispose(buffer_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -415,7 +427,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!WriteBuffer(4);
 | 
			
		||||
        auto b = defaultAllocator.make!WriteBuffer(4);
 | 
			
		||||
        ubyte[3] buf = [48, 23, 255];
 | 
			
		||||
 | 
			
		||||
        b ~= buf;
 | 
			
		||||
@@ -433,7 +445,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
        b += b.length;
 | 
			
		||||
        assert(b.length == 0);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -498,7 +510,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
            {
 | 
			
		||||
                auto newSize = end / blockSize * blockSize + blockSize;
 | 
			
		||||
 | 
			
		||||
                theAllocator.resizeArray!ubyte(buffer_, newSize);
 | 
			
		||||
                allocator.resizeArray!ubyte(buffer_, newSize);
 | 
			
		||||
            }
 | 
			
		||||
            buffer_[position..end] = buffer[start..$];
 | 
			
		||||
            position = end;
 | 
			
		||||
@@ -514,7 +526,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!WriteBuffer(4);
 | 
			
		||||
        auto b = defaultAllocator.make!WriteBuffer(4);
 | 
			
		||||
        ubyte[3] buf = [48, 23, 255];
 | 
			
		||||
 | 
			
		||||
        b ~= buf;
 | 
			
		||||
@@ -533,9 +545,9 @@ class WriteBuffer : Buffer
 | 
			
		||||
        assert(b.buffer_[0] == 23 && b.buffer_[1] == 255
 | 
			
		||||
            && b.buffer_[2] == 48 && b.buffer_[3] == 23 && b.buffer_[4] == 255);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
 | 
			
		||||
        b = make!WriteBuffer(theAllocator, 2);
 | 
			
		||||
        b = make!WriteBuffer(defaultAllocator, 2);
 | 
			
		||||
 | 
			
		||||
        b ~= buf;
 | 
			
		||||
        assert(b.start == 0);
 | 
			
		||||
@@ -543,7 +555,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
        assert(b.ring == 3);
 | 
			
		||||
        assert(b.position == 3);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -620,7 +632,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!WriteBuffer;
 | 
			
		||||
        auto b = defaultAllocator.make!WriteBuffer;
 | 
			
		||||
        ubyte[6] buf = [23, 23, 255, 128, 127, 9];
 | 
			
		||||
 | 
			
		||||
        b ~= buf;
 | 
			
		||||
@@ -630,7 +642,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
        b += 4;
 | 
			
		||||
        assert(b.length == 0);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -663,7 +675,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
    ///
 | 
			
		||||
    unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto b = theAllocator.make!WriteBuffer(6);
 | 
			
		||||
        auto b = defaultAllocator.make!WriteBuffer(6);
 | 
			
		||||
        ubyte[6] buf = [23, 23, 255, 128, 127, 9];
 | 
			
		||||
 | 
			
		||||
        b ~= buf;
 | 
			
		||||
@@ -679,7 +691,7 @@ class WriteBuffer : Buffer
 | 
			
		||||
        assert(b[0..$] == buf[0..6]);
 | 
			
		||||
        b += b.length;
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(b);
 | 
			
		||||
        defaultAllocator.dispose(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ class SList(T)
 | 
			
		||||
	 * 	allocator = The allocator should be used for the element
 | 
			
		||||
	 * 	            allocations.
 | 
			
		||||
	 */
 | 
			
		||||
	this(IAllocator allocator = theAllocator)
 | 
			
		||||
	this(shared Allocator allocator = defaultAllocator)
 | 
			
		||||
	{
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
	}
 | 
			
		||||
@@ -54,14 +54,14 @@ class SList(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto l = make!(SList!int)(theAllocator);
 | 
			
		||||
		auto l = make!(SList!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		l.insertFront(8);
 | 
			
		||||
		l.insertFront(5);
 | 
			
		||||
		l.clear();
 | 
			
		||||
		assert(l.empty);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, l);
 | 
			
		||||
		dispose(defaultAllocator, l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -98,14 +98,14 @@ class SList(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto l = make!(SList!int)(theAllocator);
 | 
			
		||||
		auto l = make!(SList!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		l.insertFront(8);
 | 
			
		||||
		assert(l.front == 8);
 | 
			
		||||
		l.insertFront(9);
 | 
			
		||||
		assert(l.front == 9);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, l);
 | 
			
		||||
		dispose(defaultAllocator, l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -140,7 +140,7 @@ class SList(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto l = make!(SList!int)(theAllocator);
 | 
			
		||||
		auto l = make!(SList!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		l.insertFront(8);
 | 
			
		||||
		l.insertFront(9);
 | 
			
		||||
@@ -148,7 +148,7 @@ class SList(T)
 | 
			
		||||
		l.popFront();
 | 
			
		||||
		assert(l.front == 8);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, l);
 | 
			
		||||
		dispose(defaultAllocator, l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -179,7 +179,7 @@ class SList(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto l = make!(SList!int)(theAllocator);
 | 
			
		||||
		auto l = make!(SList!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		l.insertFront(8);
 | 
			
		||||
		l.insertFront(5);
 | 
			
		||||
@@ -189,7 +189,7 @@ class SList(T)
 | 
			
		||||
		assert(l.removeFront(3) == 1);
 | 
			
		||||
		assert(l.removeFront(3) == 0);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, l);
 | 
			
		||||
		dispose(defaultAllocator, l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -235,7 +235,7 @@ class SList(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto l = make!(SList!int)(theAllocator);
 | 
			
		||||
		auto l = make!(SList!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		l.insertFront(5);
 | 
			
		||||
		l.insertFront(4);
 | 
			
		||||
@@ -246,7 +246,7 @@ class SList(T)
 | 
			
		||||
			assert(i != 1 || e == 4);
 | 
			
		||||
			assert(i != 2 || e == 5);
 | 
			
		||||
		}
 | 
			
		||||
		dispose(theAllocator, l);
 | 
			
		||||
		dispose(defaultAllocator, l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -265,13 +265,13 @@ class SList(T)
 | 
			
		||||
	protected Entry first;
 | 
			
		||||
 | 
			
		||||
	/// Allocator.
 | 
			
		||||
	protected IAllocator allocator;
 | 
			
		||||
	protected shared Allocator allocator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
	auto l = make!(SList!int)(theAllocator);
 | 
			
		||||
	auto l = make!(SList!int)(defaultAllocator);
 | 
			
		||||
	size_t i;
 | 
			
		||||
 | 
			
		||||
	l.insertFront(5);
 | 
			
		||||
@@ -286,7 +286,7 @@ unittest
 | 
			
		||||
	}
 | 
			
		||||
	assert(i == 3);
 | 
			
		||||
 | 
			
		||||
	dispose(theAllocator, l);
 | 
			
		||||
	dispose(defaultAllocator, l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private unittest
 | 
			
		||||
@@ -295,7 +295,7 @@ private unittest
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto l = make!(SList!Stuff)(theAllocator);
 | 
			
		||||
	auto l = make!(SList!Stuff)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
	dispose(theAllocator, l);
 | 
			
		||||
	dispose(defaultAllocator, l);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ class Queue(T)
 | 
			
		||||
	 * 	allocator = The allocator should be used for the element
 | 
			
		||||
	 * 	            allocations.
 | 
			
		||||
	 */
 | 
			
		||||
	this(IAllocator allocator = theAllocator)
 | 
			
		||||
	this(shared Allocator allocator = defaultAllocator)
 | 
			
		||||
	{
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
	}
 | 
			
		||||
@@ -54,7 +54,7 @@ class Queue(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto q = theAllocator.make!(Queue!int);
 | 
			
		||||
		auto q = defaultAllocator.make!(Queue!int);
 | 
			
		||||
 | 
			
		||||
		assert(q.empty);
 | 
			
		||||
		q.insertBack(8);
 | 
			
		||||
@@ -62,7 +62,7 @@ class Queue(T)
 | 
			
		||||
		q.clear();
 | 
			
		||||
		assert(q.empty);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(q);
 | 
			
		||||
		defaultAllocator.dispose(q);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -107,7 +107,7 @@ class Queue(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto q = make!(Queue!int)(theAllocator);
 | 
			
		||||
		auto q = make!(Queue!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		assert(q.empty);
 | 
			
		||||
		q.insertBack(8);
 | 
			
		||||
@@ -115,7 +115,7 @@ class Queue(T)
 | 
			
		||||
		q.insertBack(9);
 | 
			
		||||
		assert(q.front == 8);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, q);
 | 
			
		||||
		dispose(defaultAllocator, q);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -129,14 +129,14 @@ class Queue(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto q = make!(Queue!int)(theAllocator);
 | 
			
		||||
		auto q = make!(Queue!int)(defaultAllocator);
 | 
			
		||||
		int value = 7;
 | 
			
		||||
 | 
			
		||||
		assert(q.empty);
 | 
			
		||||
		q.insertBack(value);
 | 
			
		||||
		assert(!q.empty);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, q);
 | 
			
		||||
		dispose(defaultAllocator, q);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -158,7 +158,7 @@ class Queue(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto q = make!(Queue!int)(theAllocator);
 | 
			
		||||
		auto q = make!(Queue!int)(defaultAllocator);
 | 
			
		||||
 | 
			
		||||
		q.insertBack(8);
 | 
			
		||||
		q.insertBack(9);
 | 
			
		||||
@@ -166,7 +166,7 @@ class Queue(T)
 | 
			
		||||
		q.popFront();
 | 
			
		||||
		assert(q.front == 9);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, q);
 | 
			
		||||
		dispose(defaultAllocator, q);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -210,7 +210,7 @@ class Queue(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto q = theAllocator.make!(Queue!int);
 | 
			
		||||
		auto q = defaultAllocator.make!(Queue!int);
 | 
			
		||||
 | 
			
		||||
		size_t j;
 | 
			
		||||
		q.insertBack(5);
 | 
			
		||||
@@ -240,7 +240,7 @@ class Queue(T)
 | 
			
		||||
		assert(j == 3);
 | 
			
		||||
		assert(q.empty);
 | 
			
		||||
 | 
			
		||||
		dispose(theAllocator, q);
 | 
			
		||||
		dispose(defaultAllocator, q);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -262,13 +262,13 @@ class Queue(T)
 | 
			
		||||
	protected Entry* rear;
 | 
			
		||||
 | 
			
		||||
	/// The allocator.
 | 
			
		||||
	protected IAllocator allocator;
 | 
			
		||||
	protected shared Allocator allocator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
	auto q = theAllocator.make!(Queue!int);
 | 
			
		||||
	auto q = defaultAllocator.make!(Queue!int);
 | 
			
		||||
 | 
			
		||||
	q.insertBack(5);
 | 
			
		||||
	assert(!q.empty);
 | 
			
		||||
@@ -289,5 +289,5 @@ unittest
 | 
			
		||||
	}
 | 
			
		||||
	assert(q.empty);
 | 
			
		||||
 | 
			
		||||
	theAllocator.dispose(q);
 | 
			
		||||
	defaultAllocator.dispose(q);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -200,7 +200,7 @@ class Vector(T)
 | 
			
		||||
	 * 	allocator = The allocator should be used for the element
 | 
			
		||||
	 * 	            allocations.
 | 
			
		||||
	 */
 | 
			
		||||
	this(IAllocator allocator = theAllocator)
 | 
			
		||||
	this(shared Allocator allocator = defaultAllocator)
 | 
			
		||||
	{
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
	}
 | 
			
		||||
@@ -211,18 +211,18 @@ class Vector(T)
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 *  U      = Variadic template for the constructor parameters.
 | 
			
		||||
	 * 	params = Values to initialize the array with. The last parameter can
 | 
			
		||||
	 * 	         be an allocator, if not, $(D_PSYMBOL theAllocator) is used.
 | 
			
		||||
	 * 	         be an allocator, if not, $(D_PSYMBOL defaultAllocator) is used.
 | 
			
		||||
	 */
 | 
			
		||||
	this(U...)(U params)
 | 
			
		||||
	{
 | 
			
		||||
		static if (isImplicitlyConvertible!(typeof(params[$ - 1]), IAllocator))
 | 
			
		||||
		static if (isImplicitlyConvertible!(typeof(params[$ - 1]), Allocator))
 | 
			
		||||
		{
 | 
			
		||||
			allocator = params[$ - 1];
 | 
			
		||||
			auto values = params[0 .. $ - 1];
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			allocator = theAllocator;
 | 
			
		||||
			allocator = defaultAllocator;
 | 
			
		||||
			alias values = params;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -252,7 +252,7 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(18, 20, 15);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(18, 20, 15);
 | 
			
		||||
 | 
			
		||||
		v.clear();
 | 
			
		||||
		assert(v.length == 0);
 | 
			
		||||
@@ -286,7 +286,7 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int);
 | 
			
		||||
 | 
			
		||||
		v.length = 5;
 | 
			
		||||
		assert(v.length == 5);
 | 
			
		||||
@@ -337,14 +337,14 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(5, 18, 17);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(5, 18, 17);
 | 
			
		||||
 | 
			
		||||
		assert(v.removeBack(0) == 0);
 | 
			
		||||
		assert(v.removeBack(2) == 2);
 | 
			
		||||
		assert(v.removeBack(3) == 1);
 | 
			
		||||
		assert(v.removeBack(3) == 0);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v);
 | 
			
		||||
		defaultAllocator.dispose(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -377,14 +377,14 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v1 = theAllocator.make!(Vector!int)(12, 1, 7);
 | 
			
		||||
		auto v1 = defaultAllocator.make!(Vector!int)(12, 1, 7);
 | 
			
		||||
 | 
			
		||||
		v1[] = 3;
 | 
			
		||||
		assert(v1[0] == 3);
 | 
			
		||||
		assert(v1[1] == 3);
 | 
			
		||||
		assert(v1[2] == 3);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v1);
 | 
			
		||||
		defaultAllocator.dispose(v1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -406,14 +406,14 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(6, 123, 34, 5);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(6, 123, 34, 5);
 | 
			
		||||
 | 
			
		||||
		assert(v[0] == 6);
 | 
			
		||||
		assert(v[1] == 123);
 | 
			
		||||
		assert(v[2] == 34);
 | 
			
		||||
		assert(v[3] == 5);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v);
 | 
			
		||||
		defaultAllocator.dispose(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -435,8 +435,8 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v1 = theAllocator.make!(Vector!int);
 | 
			
		||||
		auto v2 = theAllocator.make!(Vector!int);
 | 
			
		||||
		auto v1 = defaultAllocator.make!(Vector!int);
 | 
			
		||||
		auto v2 = defaultAllocator.make!(Vector!int);
 | 
			
		||||
 | 
			
		||||
		assert(v1 == v2);
 | 
			
		||||
 | 
			
		||||
@@ -453,8 +453,8 @@ class Vector(T)
 | 
			
		||||
		v2[1] = 3;
 | 
			
		||||
		assert(v1 == v2);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v1);
 | 
			
		||||
		theAllocator.dispose(v2);
 | 
			
		||||
		defaultAllocator.dispose(v1);
 | 
			
		||||
		defaultAllocator.dispose(v2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -495,7 +495,7 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(5, 15, 8);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(5, 15, 8);
 | 
			
		||||
 | 
			
		||||
		size_t i;
 | 
			
		||||
		foreach (j, ref e; v)
 | 
			
		||||
@@ -510,7 +510,7 @@ class Vector(T)
 | 
			
		||||
			assert(j != 1 || e == 15);
 | 
			
		||||
			assert(j != 2 || e == 8);
 | 
			
		||||
		}
 | 
			
		||||
		theAllocator.dispose(v);
 | 
			
		||||
		defaultAllocator.dispose(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -551,7 +551,7 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(5, 15, 8);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(5, 15, 8);
 | 
			
		||||
		size_t i;
 | 
			
		||||
 | 
			
		||||
		foreach_reverse (j, ref e; v)
 | 
			
		||||
@@ -566,7 +566,7 @@ class Vector(T)
 | 
			
		||||
			assert(j != 1 || e == 15);
 | 
			
		||||
			assert(j != 0 || e == 5);
 | 
			
		||||
		}
 | 
			
		||||
		theAllocator.dispose(v);
 | 
			
		||||
		defaultAllocator.dispose(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -587,7 +587,7 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(5);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(5);
 | 
			
		||||
 | 
			
		||||
		assert(v.front == 5);
 | 
			
		||||
 | 
			
		||||
@@ -595,7 +595,7 @@ class Vector(T)
 | 
			
		||||
		v[1] = 15;
 | 
			
		||||
		assert(v.front == 5);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v);
 | 
			
		||||
		defaultAllocator.dispose(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -616,7 +616,7 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v = theAllocator.make!(Vector!int)(5);
 | 
			
		||||
		auto v = defaultAllocator.make!(Vector!int)(5);
 | 
			
		||||
 | 
			
		||||
		assert(v.back == 5);
 | 
			
		||||
 | 
			
		||||
@@ -624,7 +624,7 @@ class Vector(T)
 | 
			
		||||
		v[1] = 15;
 | 
			
		||||
		assert(v.back == 15);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v);
 | 
			
		||||
		defaultAllocator.dispose(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -745,8 +745,8 @@ class Vector(T)
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto v1 = theAllocator.make!(Vector!int)(3, 3, 3);
 | 
			
		||||
		auto v2 = theAllocator.make!(Vector!int)(1, 2);
 | 
			
		||||
		auto v1 = defaultAllocator.make!(Vector!int)(3, 3, 3);
 | 
			
		||||
		auto v2 = defaultAllocator.make!(Vector!int)(1, 2);
 | 
			
		||||
 | 
			
		||||
		v1[0..2] = 286;
 | 
			
		||||
		assert(v1[0] == 286);
 | 
			
		||||
@@ -757,25 +757,25 @@ class Vector(T)
 | 
			
		||||
		assert(v2[0] == 286);
 | 
			
		||||
		assert(v2[1] == 3);
 | 
			
		||||
 | 
			
		||||
		theAllocator.dispose(v2);
 | 
			
		||||
		theAllocator.dispose(v1);
 | 
			
		||||
		defaultAllocator.dispose(v2);
 | 
			
		||||
		defaultAllocator.dispose(v1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Internal representation.
 | 
			
		||||
	protected T[] vector;
 | 
			
		||||
 | 
			
		||||
	/// The allocator.
 | 
			
		||||
	protected IAllocator allocator;
 | 
			
		||||
	protected shared Allocator allocator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
	auto v = theAllocator.make!(Vector!int)(5, 15, 8);
 | 
			
		||||
	auto v = defaultAllocator.make!(Vector!int)(5, 15, 8);
 | 
			
		||||
 | 
			
		||||
	assert(v.front == 5);
 | 
			
		||||
	assert(v[1] == 15);
 | 
			
		||||
	assert(v.back == 8);
 | 
			
		||||
 | 
			
		||||
	theAllocator.dispose(v);
 | 
			
		||||
	defaultAllocator.dispose(v);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,260 +20,260 @@ import std.typecons;
 | 
			
		||||
 * Supported padding mode.
 | 
			
		||||
 *
 | 
			
		||||
 * See_Also:
 | 
			
		||||
 *     $(D_PSYMBOL pad)
 | 
			
		||||
 * 	$(D_PSYMBOL pad)
 | 
			
		||||
 */
 | 
			
		||||
enum PaddingMode
 | 
			
		||||
{
 | 
			
		||||
    zero,
 | 
			
		||||
    pkcs7,
 | 
			
		||||
    ansiX923,
 | 
			
		||||
	zero,
 | 
			
		||||
	pkcs7,
 | 
			
		||||
	ansiX923,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params:
 | 
			
		||||
 *     input     = Sequence that should be padded.
 | 
			
		||||
 *     mode      = Padding mode.
 | 
			
		||||
 *     blockSize = Block size.
 | 
			
		||||
 *  allocator = Allocator was used to allocate $(D_PARAM input).
 | 
			
		||||
 * 	input     = Sequence that should be padded.
 | 
			
		||||
 * 	mode      = Padding mode.
 | 
			
		||||
 * 	blockSize = Block size.
 | 
			
		||||
 * 	allocator = Allocator was used to allocate $(D_PARAM input).
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: The function modifies the initial array and returns it.
 | 
			
		||||
 *
 | 
			
		||||
 * See_Also:
 | 
			
		||||
 *     $(D_PSYMBOL PaddingMode)
 | 
			
		||||
 * 	$(D_PSYMBOL PaddingMode)
 | 
			
		||||
 */
 | 
			
		||||
ubyte[] pad(ref ubyte[] input,
 | 
			
		||||
            in PaddingMode mode,
 | 
			
		||||
            in ushort blockSize,
 | 
			
		||||
            IAllocator allocator = theAllocator)
 | 
			
		||||
            shared Allocator allocator = defaultAllocator)
 | 
			
		||||
in
 | 
			
		||||
{
 | 
			
		||||
    assert(blockSize > 0 && blockSize <= 256);
 | 
			
		||||
    assert(blockSize % 64 == 0);
 | 
			
		||||
    assert(input.length > 0);
 | 
			
		||||
	assert(blockSize > 0 && blockSize <= 256);
 | 
			
		||||
	assert(blockSize % 64 == 0);
 | 
			
		||||
	assert(input.length > 0);
 | 
			
		||||
}
 | 
			
		||||
body
 | 
			
		||||
{
 | 
			
		||||
    immutable rest = cast(ubyte) input.length % blockSize;
 | 
			
		||||
    immutable size_t lastBlock = input.length - (rest > 0 ? rest : blockSize);
 | 
			
		||||
    immutable needed = cast(ubyte) (rest > 0 ? blockSize - rest : 0);
 | 
			
		||||
	immutable rest = cast(ubyte) input.length % blockSize;
 | 
			
		||||
	immutable size_t lastBlock = input.length - (rest > 0 ? rest : blockSize);
 | 
			
		||||
	immutable needed = cast(ubyte) (rest > 0 ? blockSize - rest : 0);
 | 
			
		||||
 | 
			
		||||
    final switch (mode) with (PaddingMode)
 | 
			
		||||
    {
 | 
			
		||||
        case zero:
 | 
			
		||||
            allocator.expandArray(input, needed);
 | 
			
		||||
            break;
 | 
			
		||||
        case pkcs7:
 | 
			
		||||
            if (needed)
 | 
			
		||||
            {
 | 
			
		||||
                allocator.expandArray(input, needed);
 | 
			
		||||
                input[input.length - needed ..$].each!((ref e) => e = needed);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                allocator.expandArray(input, blockSize);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case ansiX923:
 | 
			
		||||
            allocator.expandArray(input, needed ? needed : blockSize);
 | 
			
		||||
            input[$ - 1] = needed;
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
	final switch (mode) with (PaddingMode)
 | 
			
		||||
	{
 | 
			
		||||
		case zero:
 | 
			
		||||
			allocator.expandArray(input, needed);
 | 
			
		||||
			break;
 | 
			
		||||
		case pkcs7:
 | 
			
		||||
			if (needed)
 | 
			
		||||
			{
 | 
			
		||||
				allocator.expandArray(input, needed);
 | 
			
		||||
				input[input.length - needed ..$].each!((ref e) => e = needed);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				allocator.expandArray(input, blockSize);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case ansiX923:
 | 
			
		||||
			allocator.expandArray(input, needed ? needed : blockSize);
 | 
			
		||||
			input[$ - 1] = needed;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    return input;
 | 
			
		||||
	return input;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
    { // Zeros
 | 
			
		||||
        auto input = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
	{ // Zeros
 | 
			
		||||
		auto input = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.zero, 64);
 | 
			
		||||
        assert(input.length == 64);
 | 
			
		||||
		pad(input, PaddingMode.zero, 64);
 | 
			
		||||
		assert(input.length == 64);
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.zero, 64);
 | 
			
		||||
        assert(input.length == 64);
 | 
			
		||||
        assert(input[63] == 0);
 | 
			
		||||
		pad(input, PaddingMode.zero, 64);
 | 
			
		||||
		assert(input.length == 64);
 | 
			
		||||
		assert(input[63] == 0);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(input);
 | 
			
		||||
    }
 | 
			
		||||
    { // PKCS#7
 | 
			
		||||
        auto input = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        for (ubyte i; i < 40; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            input[i] = i;
 | 
			
		||||
        }
 | 
			
		||||
		defaultAllocator.dispose(input);
 | 
			
		||||
	}
 | 
			
		||||
	{ // PKCS#7
 | 
			
		||||
		auto input = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		for (ubyte i; i < 40; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			input[i] = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        assert(input.length == 64);
 | 
			
		||||
        for (ubyte i; i < 64; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (i >= 40 && i < 50)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 0);
 | 
			
		||||
            }
 | 
			
		||||
            else if (i >= 50)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 14);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		assert(input.length == 64);
 | 
			
		||||
		for (ubyte i; i < 64; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			if (i >= 40 && i < 50)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 0);
 | 
			
		||||
			}
 | 
			
		||||
			else if (i >= 50)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 14);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == i);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        assert(input.length == 128);
 | 
			
		||||
        for (ubyte i; i < 128; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (i >= 64 || (i >= 40 && i < 50))
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 0);
 | 
			
		||||
            }
 | 
			
		||||
            else if (i >= 50 && i < 64)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 14);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		assert(input.length == 128);
 | 
			
		||||
		for (ubyte i; i < 128; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			if (i >= 64 || (i >= 40 && i < 50))
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 0);
 | 
			
		||||
			}
 | 
			
		||||
			else if (i >= 50 && i < 64)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 14);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == i);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(input);
 | 
			
		||||
    }
 | 
			
		||||
    { // ANSI X.923
 | 
			
		||||
        auto input = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        for (ubyte i; i < 40; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            input[i] = i;
 | 
			
		||||
        }
 | 
			
		||||
		defaultAllocator.dispose(input);
 | 
			
		||||
	}
 | 
			
		||||
	{ // ANSI X.923
 | 
			
		||||
		auto input = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		for (ubyte i; i < 40; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			input[i] = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.ansiX923, 64);
 | 
			
		||||
        assert(input.length == 64);
 | 
			
		||||
        for (ubyte i; i < 64; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (i < 40)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == i);
 | 
			
		||||
            }
 | 
			
		||||
            else if (i == 63)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 14);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		pad(input, PaddingMode.ansiX923, 64);
 | 
			
		||||
		assert(input.length == 64);
 | 
			
		||||
		for (ubyte i; i < 64; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			if (i < 40)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == i);
 | 
			
		||||
			}
 | 
			
		||||
			else if (i == 63)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 14);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 0);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        assert(input.length == 128);
 | 
			
		||||
        for (ubyte i = 0; i < 128; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (i < 40)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == i);
 | 
			
		||||
            }
 | 
			
		||||
            else if (i == 63)
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 14);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                assert(input[i] == 0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		assert(input.length == 128);
 | 
			
		||||
		for (ubyte i = 0; i < 128; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			if (i < 40)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == i);
 | 
			
		||||
			}
 | 
			
		||||
			else if (i == 63)
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 14);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				assert(input[i] == 0);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(input);
 | 
			
		||||
    }
 | 
			
		||||
		defaultAllocator.dispose(input);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params:
 | 
			
		||||
 *     input     = Sequence that should be padded.
 | 
			
		||||
 *     mode      = Padding mode.
 | 
			
		||||
 *     blockSize = Block size.
 | 
			
		||||
 *  allocator = Allocator was used to allocate $(D_PARAM input).
 | 
			
		||||
 * 	input     = Sequence that should be padded.
 | 
			
		||||
 * 	mode      = Padding mode.
 | 
			
		||||
 * 	blockSize = Block size.
 | 
			
		||||
 * 	allocator = Allocator was used to allocate $(D_PARAM input).
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: The function modifies the initial array and returns it.
 | 
			
		||||
 *
 | 
			
		||||
 * See_Also:
 | 
			
		||||
 *     $(D_PSYMBOL pad)
 | 
			
		||||
 * 	$(D_PSYMBOL pad)
 | 
			
		||||
 */
 | 
			
		||||
ref ubyte[] unpad(ref ubyte[] input,
 | 
			
		||||
                  in PaddingMode mode,
 | 
			
		||||
                  in ushort blockSize,
 | 
			
		||||
                  IAllocator allocator = theAllocator)
 | 
			
		||||
                  shared Allocator allocator = defaultAllocator)
 | 
			
		||||
in
 | 
			
		||||
{
 | 
			
		||||
    assert(input.length != 0);
 | 
			
		||||
    assert(input.length % 64 == 0);
 | 
			
		||||
	assert(input.length != 0);
 | 
			
		||||
	assert(input.length % 64 == 0);
 | 
			
		||||
}
 | 
			
		||||
body
 | 
			
		||||
{
 | 
			
		||||
    final switch (mode) with (PaddingMode)
 | 
			
		||||
    {
 | 
			
		||||
        case zero:
 | 
			
		||||
            break;
 | 
			
		||||
        case pkcs7:
 | 
			
		||||
        case ansiX923:
 | 
			
		||||
            immutable last = input[$ - 1];
 | 
			
		||||
	final switch (mode) with (PaddingMode)
 | 
			
		||||
	{
 | 
			
		||||
		case zero:
 | 
			
		||||
			break;
 | 
			
		||||
		case pkcs7:
 | 
			
		||||
		case ansiX923:
 | 
			
		||||
			immutable last = input[$ - 1];
 | 
			
		||||
 | 
			
		||||
            allocator.shrinkArray(input, last ? last : blockSize);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
			allocator.shrinkArray(input, last ? last : blockSize);
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    return input;
 | 
			
		||||
	return input;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
    { // Zeros
 | 
			
		||||
        auto input = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        auto inputDup = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
	{ // Zeros
 | 
			
		||||
		auto input = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		auto inputDup = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.zero, 64);
 | 
			
		||||
        pad(inputDup, PaddingMode.zero, 64);
 | 
			
		||||
		pad(input, PaddingMode.zero, 64);
 | 
			
		||||
		pad(inputDup, PaddingMode.zero, 64);
 | 
			
		||||
 | 
			
		||||
        unpad(input, PaddingMode.zero, 64);
 | 
			
		||||
        assert(input == inputDup);
 | 
			
		||||
		unpad(input, PaddingMode.zero, 64);
 | 
			
		||||
		assert(input == inputDup);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(input);
 | 
			
		||||
        theAllocator.dispose(inputDup);
 | 
			
		||||
		defaultAllocator.dispose(input);
 | 
			
		||||
		defaultAllocator.dispose(inputDup);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    { // PKCS#7
 | 
			
		||||
        auto input = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        auto inputDup = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        for (ubyte i; i < 40; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            input[i] = i;
 | 
			
		||||
            inputDup[i] = i;
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
	{ // PKCS#7
 | 
			
		||||
		auto input = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		auto inputDup = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		for (ubyte i; i < 40; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			input[i] = i;
 | 
			
		||||
			inputDup[i] = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        unpad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        assert(input == inputDup);
 | 
			
		||||
		pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		unpad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		assert(input == inputDup);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(input);
 | 
			
		||||
        theAllocator.dispose(inputDup);
 | 
			
		||||
    }
 | 
			
		||||
    { // ANSI X.923
 | 
			
		||||
        auto input = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        auto inputDup = theAllocator.makeArray!ubyte(50);
 | 
			
		||||
        for (ubyte i; i < 40; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            input[i] = i;
 | 
			
		||||
            inputDup[i] = i;
 | 
			
		||||
        }
 | 
			
		||||
		defaultAllocator.dispose(input);
 | 
			
		||||
		defaultAllocator.dispose(inputDup);
 | 
			
		||||
	}
 | 
			
		||||
	{ // ANSI X.923
 | 
			
		||||
		auto input = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		auto inputDup = defaultAllocator.makeArray!ubyte(50);
 | 
			
		||||
		for (ubyte i; i < 40; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			input[i] = i;
 | 
			
		||||
			inputDup[i] = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        unpad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
        assert(input == inputDup);
 | 
			
		||||
		pad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		unpad(input, PaddingMode.pkcs7, 64);
 | 
			
		||||
		assert(input == inputDup);
 | 
			
		||||
 | 
			
		||||
        theAllocator.dispose(input);
 | 
			
		||||
        theAllocator.dispose(inputDup);
 | 
			
		||||
    }
 | 
			
		||||
		defaultAllocator.dispose(input);
 | 
			
		||||
		defaultAllocator.dispose(inputDup);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,17 +13,16 @@ module tanya.math.mp;
 | 
			
		||||
import std.algorithm.iteration;
 | 
			
		||||
import std.algorithm.searching;
 | 
			
		||||
import std.algorithm.mutation;
 | 
			
		||||
import std.experimental.allocator;
 | 
			
		||||
import std.math;
 | 
			
		||||
import std.range;
 | 
			
		||||
import std.traits;
 | 
			
		||||
import tanya.memory.allocator;
 | 
			
		||||
import tanya.memory.types;
 | 
			
		||||
import tanya.memory;
 | 
			
		||||
 | 
			
		||||
struct Integer
 | 
			
		||||
{
 | 
			
		||||
    private RefCounted!(ubyte[]) rep;
 | 
			
		||||
	private bool sign;
 | 
			
		||||
	private shared Allocator allocator;
 | 
			
		||||
 | 
			
		||||
	invariant
 | 
			
		||||
	{
 | 
			
		||||
@@ -34,10 +33,11 @@ struct Integer
 | 
			
		||||
	 * Creates a multiple precision integer.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	T         = Value type.
 | 
			
		||||
	 * 	value     = Initial value.
 | 
			
		||||
	 *	allocator = Allocator.
 | 
			
		||||
	 */
 | 
			
		||||
	this(T)(in T value, IAllocator allocator = theAllocator)
 | 
			
		||||
	this(T)(in T value, shared Allocator allocator = defaultAllocator)
 | 
			
		||||
		if (isIntegral!T)
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
@@ -47,21 +47,30 @@ struct Integer
 | 
			
		||||
	{
 | 
			
		||||
		this(allocator);
 | 
			
		||||
 | 
			
		||||
		immutable size = calculateSizeFromInt(value);
 | 
			
		||||
		T absolute = value;
 | 
			
		||||
		immutable size = calculateSizeFromInt(absolute);
 | 
			
		||||
		allocator.resizeArray(rep, size);
 | 
			
		||||
		assignInt(value);
 | 
			
		||||
		assignInt(absolute);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto h = Integer(79);
 | 
			
		||||
		assert(h.length == 1);
 | 
			
		||||
		assert(h.rep[0] == 79);
 | 
			
		||||
		{
 | 
			
		||||
			auto h = Integer(79);
 | 
			
		||||
			assert(h.length == 1);
 | 
			
		||||
			assert(h.rep[0] == 79);
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			auto h = Integer(-2);
 | 
			
		||||
			assert(h.length == 1);
 | 
			
		||||
			assert(h.rep[0] == 2);
 | 
			
		||||
			assert(h.sign);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	this(in Integer value, IAllocator allocator = theAllocator)
 | 
			
		||||
	this(in Integer value, shared Allocator allocator = defaultAllocator)
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		assert(allocator !is null);
 | 
			
		||||
@@ -76,21 +85,35 @@ struct Integer
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	this(IAllocator allocator)
 | 
			
		||||
	this(shared Allocator allocator)
 | 
			
		||||
	{
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
		rep = RefCounted!(ubyte[])(allocator);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Figure out the minimum amount of space this value will take
 | 
			
		||||
	 * up in bytes.
 | 
			
		||||
	 * Figures out the minimum amount of space this value will take
 | 
			
		||||
	 * up in bytes. Set the sign.
 | 
			
		||||
	 */
 | 
			
		||||
	pragma(inline, true)
 | 
			
		||||
	private ubyte calculateSizeFromInt(in ulong value)
 | 
			
		||||
	const pure nothrow @safe @nogc
 | 
			
		||||
	private ubyte calculateSizeFromInt(T)(ref T value)
 | 
			
		||||
	pure nothrow @safe @nogc
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		static assert(isIntegral!T);
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		ubyte size = ulong.sizeof;
 | 
			
		||||
 | 
			
		||||
		static if (isSigned!T)
 | 
			
		||||
		{
 | 
			
		||||
			sign = value < 0 ? true : false;
 | 
			
		||||
			value = abs(value);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			sign = false;
 | 
			
		||||
		}
 | 
			
		||||
		for (ulong mask = 0xff00000000000000; mask >= 0xff; mask >>= 8)
 | 
			
		||||
		{
 | 
			
		||||
			if (value & mask)
 | 
			
		||||
@@ -107,40 +130,42 @@ struct Integer
 | 
			
		||||
	 * (up to the first 0 byte) and copy it into the internal
 | 
			
		||||
	 * representation in big-endian format.
 | 
			
		||||
	 */
 | 
			
		||||
	pragma(inline, true)
 | 
			
		||||
	private void assignInt(T)(ref in T value)
 | 
			
		||||
	private void assignInt(in ulong value)
 | 
			
		||||
	pure nothrow @safe @nogc
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		static assert(isIntegral!T);
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		uint mask = 0xff, shift;
 | 
			
		||||
		immutable absolute = abs(value);
 | 
			
		||||
 | 
			
		||||
		sign = value < 0 ? true : false;
 | 
			
		||||
		for (auto i = length; i; --i)
 | 
			
		||||
		{
 | 
			
		||||
			rep[i - 1] = cast(ubyte) ((absolute & mask) >> shift);
 | 
			
		||||
			rep[i - 1] = cast(ubyte) ((value & mask) >> shift);
 | 
			
		||||
			mask <<= 8;
 | 
			
		||||
			shift += 8;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Assigns a new value.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	T     = Value type.
 | 
			
		||||
	 * 	value = Value.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: $(D_KEYWORD this).
 | 
			
		||||
	 */
 | 
			
		||||
	ref Integer opAssign(T)(in T value)
 | 
			
		||||
		if (isIntegral!T)
 | 
			
		||||
	{
 | 
			
		||||
		immutable size = calculateSizeFromInt(value);
 | 
			
		||||
		T absolute = value;
 | 
			
		||||
		immutable size = calculateSizeFromInt(absolute);
 | 
			
		||||
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
		allocator.resizeArray(rep.get, size);
 | 
			
		||||
		assignInt(value);
 | 
			
		||||
		assignInt(absolute);
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	ref Integer opAssign(in Integer value)
 | 
			
		||||
	{
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
@@ -251,23 +276,11 @@ struct Integer
 | 
			
		||||
		assert(h1 > h2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Assignment operators with another $(D_PSYMBOL Integer).
 | 
			
		||||
	 *
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	op = Operation.
 | 
			
		||||
	 * 	h  = The second integer.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: $(D_KEYWORD this).
 | 
			
		||||
	 */
 | 
			
		||||
	ref Integer opOpAssign(string op)(in Integer h)
 | 
			
		||||
		if (op == "+")
 | 
			
		||||
	private void add(in ref RefCounted!(ubyte[]) h)
 | 
			
		||||
	{
 | 
			
		||||
		uint sum;
 | 
			
		||||
		uint carry = 0;
 | 
			
		||||
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
 | 
			
		||||
		// Adding h2 to h1. If h2 is > h1 to begin with, resize h1
 | 
			
		||||
 | 
			
		||||
		if (h.length > length)
 | 
			
		||||
@@ -286,7 +299,7 @@ struct Integer
 | 
			
		||||
			if (j)
 | 
			
		||||
			{
 | 
			
		||||
				--j;
 | 
			
		||||
				sum = rep[i] + h.rep[j] + carry;
 | 
			
		||||
				sum = rep[i] + h[j] + carry;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
@@ -305,36 +318,15 @@ struct Integer
 | 
			
		||||
			tmp[0] = 0x01;
 | 
			
		||||
			rep = tmp;
 | 
			
		||||
		}
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto h1 = Integer(1019);
 | 
			
		||||
		
 | 
			
		||||
		auto h2 = Integer(3337);
 | 
			
		||||
		h1 += h2;
 | 
			
		||||
		assert(h1.rep == [0x11, 0x04]);
 | 
			
		||||
 | 
			
		||||
		h2 = 2_147_483_647;
 | 
			
		||||
		h1 += h2;
 | 
			
		||||
		assert(h1.rep == [0x80, 0x00, 0x11, 0x03]);
 | 
			
		||||
 | 
			
		||||
		h1 += h2;
 | 
			
		||||
		assert(h1.rep == [0x01, 0x00, 0x00, 0x11, 0x02]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	ref Integer opOpAssign(string op)(in Integer h)
 | 
			
		||||
		if (op == "-")
 | 
			
		||||
	private void subtract(in ref RefCounted!(ubyte[]) h)
 | 
			
		||||
	{
 | 
			
		||||
		auto i = rep.length;
 | 
			
		||||
		auto j = h.rep.length;
 | 
			
		||||
		auto j = h.length;
 | 
			
		||||
		uint borrow = 0;
 | 
			
		||||
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
 | 
			
		||||
		do
 | 
			
		||||
		{
 | 
			
		||||
			int difference;
 | 
			
		||||
@@ -343,7 +335,7 @@ struct Integer
 | 
			
		||||
			if (j)
 | 
			
		||||
			{
 | 
			
		||||
				--j;
 | 
			
		||||
				difference = rep[i] - h.rep[j] - borrow;
 | 
			
		||||
				difference = rep[i] - h[j] - borrow;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
@@ -371,11 +363,49 @@ struct Integer
 | 
			
		||||
		{
 | 
			
		||||
			allocator.resizeArray(rep, 0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Assignment operators with another $(D_PSYMBOL Integer).
 | 
			
		||||
	 *
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	op = Operation.
 | 
			
		||||
	 * 	h  = The second integer.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: $(D_KEYWORD this).
 | 
			
		||||
	 */
 | 
			
		||||
	ref Integer opOpAssign(string op)(in Integer h)
 | 
			
		||||
		if ((op == "+") || (op == "-"))
 | 
			
		||||
	{
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
		static if (op == "+")
 | 
			
		||||
		{
 | 
			
		||||
			add(h.rep);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			subtract(h.rep);
 | 
			
		||||
		}
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	unittest
 | 
			
		||||
	private unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto h1 = Integer(1019);
 | 
			
		||||
		
 | 
			
		||||
		auto h2 = Integer(3337);
 | 
			
		||||
		h1 += h2;
 | 
			
		||||
		assert(h1.rep == [0x11, 0x04]);
 | 
			
		||||
 | 
			
		||||
		h2 = 2_147_483_647;
 | 
			
		||||
		h1 += h2;
 | 
			
		||||
		assert(h1.rep == [0x80, 0x00, 0x11, 0x03]);
 | 
			
		||||
 | 
			
		||||
		h1 += h2;
 | 
			
		||||
		assert(h1.rep == [0x01, 0x00, 0x00, 0x11, 0x02]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto h1 = Integer(4294967295);
 | 
			
		||||
		auto h2 = Integer(4294967295);
 | 
			
		||||
@@ -417,8 +447,7 @@ struct Integer
 | 
			
		||||
		}
 | 
			
		||||
		do
 | 
			
		||||
		{
 | 
			
		||||
			--i;
 | 
			
		||||
			--j;
 | 
			
		||||
			--i, --j;
 | 
			
		||||
			immutable oldCarry = carry;
 | 
			
		||||
			carry = rep[i] >> delta;
 | 
			
		||||
			rep[j] = cast(ubyte) ((rep[i] << bit) | oldCarry);
 | 
			
		||||
@@ -546,6 +575,11 @@ struct Integer
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	ref Integer opOpAssign(string op)(in Integer h)
 | 
			
		||||
		if ((op == "/") || (op == "%"))
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		assert(h.length > 0, "Division by zero.");
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
 | 
			
		||||
@@ -715,6 +749,40 @@ struct Integer
 | 
			
		||||
		assert(h2.rep[0] == ~cast(ubyte) 79);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void decrement()
 | 
			
		||||
	{
 | 
			
		||||
		immutable size = rep.get.retro.countUntil!((const ref a) => a != 0);
 | 
			
		||||
		if (rep[0] == 1)
 | 
			
		||||
		{
 | 
			
		||||
			allocator.resizeArray(rep, rep.length - 1);
 | 
			
		||||
			rep[0 .. $] = typeof(rep[0]).max;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			--rep[$ - size - 1];
 | 
			
		||||
			rep[$ - size .. $] = typeof(rep[0]).max;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void increment()
 | 
			
		||||
	{
 | 
			
		||||
		auto size = rep
 | 
			
		||||
				   .get
 | 
			
		||||
				   .retro
 | 
			
		||||
				   .countUntil!((const ref a) => a != typeof(rep[0]).max);
 | 
			
		||||
		if (size == -1)
 | 
			
		||||
		{
 | 
			
		||||
			size = length;
 | 
			
		||||
			allocator.resizeArray(rep.get, rep.length + 1);
 | 
			
		||||
			rep[0] = 1;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			++rep[$ - size - 1];
 | 
			
		||||
		}
 | 
			
		||||
		rep[$ - size .. $] = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Increment/decrement.
 | 
			
		||||
	 *
 | 
			
		||||
@@ -728,45 +796,28 @@ struct Integer
 | 
			
		||||
	{
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
 | 
			
		||||
		if (op == "++" || sign || length == 0)
 | 
			
		||||
		static if (op == "++")
 | 
			
		||||
		{
 | 
			
		||||
			static if (op == "--")
 | 
			
		||||
			if (sign)
 | 
			
		||||
			{
 | 
			
		||||
				sign = true;
 | 
			
		||||
			}
 | 
			
		||||
			auto size = rep
 | 
			
		||||
			           .get
 | 
			
		||||
			           .retro
 | 
			
		||||
			           .countUntil!((const ref a) => a != typeof(rep[0]).max);
 | 
			
		||||
			if (size == -1)
 | 
			
		||||
			{
 | 
			
		||||
				size = length;
 | 
			
		||||
				allocator.resizeArray(rep.get, rep.length + 1);
 | 
			
		||||
				rep[0] = 1;
 | 
			
		||||
				decrement();
 | 
			
		||||
				if (length == 0)
 | 
			
		||||
				{
 | 
			
		||||
					sign = false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				++rep[$ - size - 1];
 | 
			
		||||
				increment();
 | 
			
		||||
			}
 | 
			
		||||
			rep[$ - size .. $] = 0;
 | 
			
		||||
		}
 | 
			
		||||
		else if (sign)
 | 
			
		||||
		{
 | 
			
		||||
			increment();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			immutable size = rep.get.retro.countUntil!((const ref a) => a != 0);
 | 
			
		||||
			if (rep[0] == 1)
 | 
			
		||||
			{
 | 
			
		||||
				allocator.resizeArray(rep, rep.length - 1);
 | 
			
		||||
				rep[0 .. $] = typeof(rep[0]).max;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				--rep[$ - size - 1];
 | 
			
		||||
				rep[$ - size .. $] = typeof(rep[0]).max;
 | 
			
		||||
			}
 | 
			
		||||
			if (rep.length == 0)
 | 
			
		||||
			{
 | 
			
		||||
				sign = false;
 | 
			
		||||
			}
 | 
			
		||||
			decrement();
 | 
			
		||||
		}
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
@@ -803,7 +854,17 @@ struct Integer
 | 
			
		||||
 | 
			
		||||
		--h;
 | 
			
		||||
		assert(h.rep == [0xff, 0xff]);
 | 
			
		||||
 | 
			
		||||
		h = -2;
 | 
			
		||||
		++h;
 | 
			
		||||
		assert(h.rep == [0x01]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mixin StructAllocator;
 | 
			
		||||
	private void checkAllocator() nothrow @safe @nogc
 | 
			
		||||
	{
 | 
			
		||||
		if (allocator is null)
 | 
			
		||||
		{
 | 
			
		||||
			allocator = defaultAllocator;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,214 +10,42 @@
 | 
			
		||||
 */
 | 
			
		||||
module tanya.memory.allocator;
 | 
			
		||||
 | 
			
		||||
import std.algorithm.mutation;
 | 
			
		||||
import std.experimental.allocator;
 | 
			
		||||
import std.typecons;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract class implementing a basic allocator.
 | 
			
		||||
 */
 | 
			
		||||
abstract class Allocator : IAllocator
 | 
			
		||||
interface Allocator
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: $(D_KEYWORD false).
 | 
			
		||||
     */
 | 
			
		||||
    bool deallocateAll() const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@nogc:
 | 
			
		||||
	@property uint alignment() const shared pure nothrow @safe;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns $(D_PSYMBOL Ternary.unknown).
 | 
			
		||||
     */
 | 
			
		||||
    Ternary empty() const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return Ternary.unknown;
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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, TypeInfo ti = null) shared nothrow @safe;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     b = Memory block.
 | 
			
		||||
     * 
 | 
			
		||||
     * Returns: $(D_PSYMBOL Ternary.unknown).
 | 
			
		||||
     */
 | 
			
		||||
    Ternary owns(void[] b) const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return Ternary.unknown;
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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 nothrow @safe;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     p      = Pointer to a memory block.
 | 
			
		||||
     *     result = Full block allocated.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: $(D_PSYMBOL Ternary.unknown).
 | 
			
		||||
     */
 | 
			
		||||
    Ternary resolveInternalPointer(void* p, ref void[] result)
 | 
			
		||||
    const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return Ternary.unknown;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     size = Amount of memory to allocate.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: The good allocation size that guarantees zero internal
 | 
			
		||||
     *          fragmentation.
 | 
			
		||||
     */
 | 
			
		||||
    size_t goodAllocSize(size_t s)
 | 
			
		||||
    {
 | 
			
		||||
        auto rem = s % alignment;
 | 
			
		||||
        return rem ? s + alignment - rem : s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     * 
 | 
			
		||||
     * Returns: $(D_KEYWORD null).
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    void[] allocateAll() const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     * 
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     b = Block to be expanded.
 | 
			
		||||
     *     s = New size.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: $(D_KEYWORD false).
 | 
			
		||||
     */
 | 
			
		||||
    bool expand(ref void[] b, size_t s) const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     n = Amount of memory to allocate.
 | 
			
		||||
     *     a = Alignment.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: $(D_KEYWORD null).
 | 
			
		||||
     */
 | 
			
		||||
    void[] alignedAllocate(size_t n, uint a) const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not supported.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     n = Amount of memory to allocate.
 | 
			
		||||
     *     a = Alignment.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: $(D_KEYWORD false).
 | 
			
		||||
     */
 | 
			
		||||
    bool alignedReallocate(ref void[] b, size_t size, uint alignment)
 | 
			
		||||
    const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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.
 | 
			
		||||
 * 	init      = The value to fill the new part of the array with if it becomes
 | 
			
		||||
 * 	            larger.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
 | 
			
		||||
 *          not be reallocated. In the latter
 | 
			
		||||
 */
 | 
			
		||||
bool resizeArray(T)(IAllocator allocator,
 | 
			
		||||
                    ref T[] array,
 | 
			
		||||
                    in size_t length,
 | 
			
		||||
					T init = T.init)
 | 
			
		||||
{
 | 
			
		||||
    void[] buf = array;
 | 
			
		||||
	immutable oldLength = array.length;
 | 
			
		||||
 | 
			
		||||
    if (!allocator.reallocate(buf, length * T.sizeof))
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    array = cast(T[]) buf;
 | 
			
		||||
	if (oldLength < length)
 | 
			
		||||
	{
 | 
			
		||||
		array[oldLength .. $].uninitializedFill(init);
 | 
			
		||||
	}
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
    int[] p;
 | 
			
		||||
 | 
			
		||||
    theAllocator.resizeArray(p, 20);
 | 
			
		||||
    assert(p.length == 20);
 | 
			
		||||
 | 
			
		||||
    theAllocator.resizeArray(p, 30);
 | 
			
		||||
    assert(p.length == 30);
 | 
			
		||||
 | 
			
		||||
    theAllocator.resizeArray(p, 10);
 | 
			
		||||
    assert(p.length == 10);
 | 
			
		||||
 | 
			
		||||
    theAllocator.resizeArray(p, 0);
 | 
			
		||||
    assert(p is null);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mixin to get around the impossibility to define a default constructor for
 | 
			
		||||
 * structs. It can be used for the structs that don't disable the default
 | 
			
		||||
 * constructor and don't wan't to force passing the allocator each time to
 | 
			
		||||
 * the constructor.
 | 
			
		||||
 *
 | 
			
		||||
 * It defines the private property `allocator`, a constructor that accepts only
 | 
			
		||||
 * an allocator instance and the method `checkAllocator` that checks if an
 | 
			
		||||
 * allocator is set and sets it to ` $(D_PSYMBOL theAllocator) if not.
 | 
			
		||||
 *
 | 
			
		||||
 * `checkAllocator` should be used at beginning of functions that
 | 
			
		||||
 * allocate/free memory.
 | 
			
		||||
 */
 | 
			
		||||
mixin template StructAllocator()
 | 
			
		||||
{
 | 
			
		||||
	private IAllocator allocator;
 | 
			
		||||
 | 
			
		||||
	this(IAllocator allocator) pure nothrow @safe @nogc
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		assert(allocator !is null);
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pragma(inline, true)
 | 
			
		||||
	private void checkAllocator() nothrow @safe @nogc
 | 
			
		||||
	{
 | 
			
		||||
		if (allocator is null)
 | 
			
		||||
		{
 | 
			
		||||
			allocator = theAllocator;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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) shared nothrow @safe;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,14 +16,14 @@ import core.exception;
 | 
			
		||||
 | 
			
		||||
version (Posix)
 | 
			
		||||
{
 | 
			
		||||
    import core.stdc.errno;
 | 
			
		||||
    import core.sys.posix.sys.mman;
 | 
			
		||||
    import core.sys.posix.unistd;
 | 
			
		||||
	import core.stdc.errno;
 | 
			
		||||
	import core.sys.posix.sys.mman;
 | 
			
		||||
	import core.sys.posix.unistd;
 | 
			
		||||
}
 | 
			
		||||
else version (Windows)
 | 
			
		||||
{
 | 
			
		||||
    import core.sys.windows.winbase;
 | 
			
		||||
    import core.sys.windows.windows;
 | 
			
		||||
	import core.sys.windows.winbase;
 | 
			
		||||
	import core.sys.windows.windows;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -49,437 +49,436 @@ else version (Windows)
 | 
			
		||||
 * --------------------------------------------------- ------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * 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)
 | 
			
		||||
 *     )
 | 
			
		||||
 * 	$(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 MmapPool : Allocator
 | 
			
		||||
{
 | 
			
		||||
    @disable this();
 | 
			
		||||
@nogc:
 | 
			
		||||
	shared static this()
 | 
			
		||||
	{
 | 
			
		||||
		version (Posix)
 | 
			
		||||
		{
 | 
			
		||||
			pageSize = sysconf(_SC_PAGE_SIZE);
 | 
			
		||||
		}
 | 
			
		||||
		else version (Windows)
 | 
			
		||||
		{
 | 
			
		||||
			SYSTEM_INFO si;
 | 
			
		||||
			GetSystemInfo(&si);
 | 
			
		||||
			pageSize = si.dwPageSize;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    shared static this()
 | 
			
		||||
    {
 | 
			
		||||
        version (Posix)
 | 
			
		||||
        {
 | 
			
		||||
            pageSize = sysconf(_SC_PAGE_SIZE);
 | 
			
		||||
        }
 | 
			
		||||
        else version (Windows)
 | 
			
		||||
        {
 | 
			
		||||
            SYSTEM_INFO si;
 | 
			
		||||
            GetSystemInfo(&si);
 | 
			
		||||
            pageSize = si.dwPageSize;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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, TypeInfo ti = null) shared nothrow @trusted
 | 
			
		||||
	{
 | 
			
		||||
		if (!size)
 | 
			
		||||
		{
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		immutable dataSize = addAlignment(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, TypeInfo ti = null) @nogc @trusted nothrow
 | 
			
		||||
    {
 | 
			
		||||
        if (!size)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        immutable dataSize = addAlignment(size);
 | 
			
		||||
		void* data = findBlock(dataSize);
 | 
			
		||||
		if (data is null)
 | 
			
		||||
		{
 | 
			
		||||
			data = initializeRegion(dataSize);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        void* data = findBlock(dataSize);
 | 
			
		||||
        if (data is null)
 | 
			
		||||
        {
 | 
			
		||||
            data = initializeRegion(dataSize);
 | 
			
		||||
        }
 | 
			
		||||
		return data is null ? null : data[0..size];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        return data is null ? null : data[0..size];
 | 
			
		||||
    }
 | 
			
		||||
	///
 | 
			
		||||
	@safe nothrow unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto p = MmapPool.instance.allocate(20);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    @nogc @safe nothrow unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto p = MmapPool.instance.allocate(20);
 | 
			
		||||
		assert(p);
 | 
			
		||||
 | 
			
		||||
        assert(p);
 | 
			
		||||
		MmapPool.instance.deallocate(p);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        MmapPool.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) shared 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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) @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;
 | 
			
		||||
			block1.free = false;
 | 
			
		||||
			block2.free = true;
 | 
			
		||||
 | 
			
		||||
            block1.free = false;
 | 
			
		||||
            block2.free = true;
 | 
			
		||||
			block2.size = block1.size - blockEntrySize - size;
 | 
			
		||||
			block1.size = size;
 | 
			
		||||
 | 
			
		||||
            block2.size = block1.size - blockEntrySize - size;
 | 
			
		||||
            block1.size = size;
 | 
			
		||||
			block2.region = block1.region;
 | 
			
		||||
			atomicOp!"+="(block1.region.blocks, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			block1.free = false;
 | 
			
		||||
			atomicOp!"+="(block1.region.blocks, 1);
 | 
			
		||||
		}
 | 
			
		||||
		return cast(void*) block1 + blockEntrySize;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
            block2.region = block1.region;
 | 
			
		||||
            atomicOp!"+="(block1.region.blocks, 1);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            block1.free = false;
 | 
			
		||||
            atomicOp!"+="(block1.region.blocks, 1);
 | 
			
		||||
        }
 | 
			
		||||
        return cast(void*) block1 + blockEntrySize;
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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 nothrow @trusted
 | 
			
		||||
	{
 | 
			
		||||
		if (p is null)
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deallocates a memory block.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     p = A pointer to the memory block to be freed.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: Whether the deallocation was successful.
 | 
			
		||||
     */
 | 
			
		||||
    bool deallocate(void[] p) @nogc @trusted nothrow
 | 
			
		||||
    {
 | 
			
		||||
        if (p is null)
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
		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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	///
 | 
			
		||||
	@safe nothrow unittest
 | 
			
		||||
	{
 | 
			
		||||
		auto p = MmapPool.instance.allocate(20);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    @nogc @safe nothrow unittest
 | 
			
		||||
    {
 | 
			
		||||
        auto p = MmapPool.instance.allocate(20);
 | 
			
		||||
		assert(MmapPool.instance.deallocate(p));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        assert(MmapPool.instance.deallocate(p));
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * Increases or decreases the size of a memory block.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	p    = A pointer to the memory block.
 | 
			
		||||
	 * 	size = Size of the reallocated block.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: Whether the reallocation was successful.
 | 
			
		||||
	 */
 | 
			
		||||
	bool reallocate(ref void[] p, size_t size) shared nothrow @trusted
 | 
			
		||||
	{
 | 
			
		||||
		void[] reallocP;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Increases or decreases the size of a memory block.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     p    = A pointer to the memory block.
 | 
			
		||||
     *     size = Size of the reallocated block.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: Whether the reallocation was successful.
 | 
			
		||||
     */
 | 
			
		||||
    bool reallocate(ref void[] p, size_t size) @nogc @trusted nothrow
 | 
			
		||||
    {
 | 
			
		||||
        void[] reallocP;
 | 
			
		||||
		if (size == p.length)
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		else if (size > 0)
 | 
			
		||||
		{
 | 
			
		||||
			reallocP = allocate(size);
 | 
			
		||||
			if (reallocP is null)
 | 
			
		||||
			{
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        if (size == p.length)
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (size > 0)
 | 
			
		||||
        {
 | 
			
		||||
            reallocP = allocate(size);
 | 
			
		||||
            if (reallocP is null)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		if (p !is null)
 | 
			
		||||
		{
 | 
			
		||||
			if (size > p.length)
 | 
			
		||||
			{
 | 
			
		||||
				reallocP[0..p.length] = p[0..$];
 | 
			
		||||
			}
 | 
			
		||||
			else if (size > 0)
 | 
			
		||||
			{
 | 
			
		||||
				reallocP[0..size] = p[0..size];
 | 
			
		||||
			}
 | 
			
		||||
			deallocate(p);
 | 
			
		||||
		}
 | 
			
		||||
		p = reallocP;
 | 
			
		||||
 | 
			
		||||
        if (p !is null)
 | 
			
		||||
        {
 | 
			
		||||
            if (size > p.length)
 | 
			
		||||
            {
 | 
			
		||||
                reallocP[0..p.length] = p[0..$];
 | 
			
		||||
            }
 | 
			
		||||
            else if (size > 0)
 | 
			
		||||
            {
 | 
			
		||||
                reallocP[0..size] = p[0..size];
 | 
			
		||||
            }
 | 
			
		||||
            deallocate(p);
 | 
			
		||||
        }
 | 
			
		||||
        p = reallocP;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
	///
 | 
			
		||||
	nothrow unittest
 | 
			
		||||
	{
 | 
			
		||||
		void[] p;
 | 
			
		||||
		MmapPool.instance.reallocate(p, 10 * int.sizeof);
 | 
			
		||||
		(cast(int[]) p)[7] = 123;
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    @nogc nothrow unittest
 | 
			
		||||
    {
 | 
			
		||||
        void[] p;
 | 
			
		||||
        MmapPool.instance.reallocate(p, 10 * int.sizeof);
 | 
			
		||||
        (cast(int[]) p)[7] = 123;
 | 
			
		||||
		assert(p.length == 40);
 | 
			
		||||
 | 
			
		||||
        assert(p.length == 40);
 | 
			
		||||
		MmapPool.instance.reallocate(p, 8 * int.sizeof);
 | 
			
		||||
 | 
			
		||||
        MmapPool.instance.reallocate(p, 8 * int.sizeof);
 | 
			
		||||
		assert(p.length == 32);
 | 
			
		||||
		assert((cast(int[]) p)[7] == 123);
 | 
			
		||||
 | 
			
		||||
        assert(p.length == 32);
 | 
			
		||||
        assert((cast(int[]) p)[7] == 123);
 | 
			
		||||
		MmapPool.instance.reallocate(p, 20 * int.sizeof);
 | 
			
		||||
		(cast(int[]) p)[15] = 8;
 | 
			
		||||
 | 
			
		||||
        MmapPool.instance.reallocate(p, 20 * int.sizeof);
 | 
			
		||||
        (cast(int[]) p)[15] = 8;
 | 
			
		||||
		assert(p.length == 80);
 | 
			
		||||
		assert((cast(int[]) p)[15] == 8);
 | 
			
		||||
		assert((cast(int[]) p)[7] == 123);
 | 
			
		||||
 | 
			
		||||
        assert(p.length == 80);
 | 
			
		||||
        assert((cast(int[]) p)[15] == 8);
 | 
			
		||||
        assert((cast(int[]) p)[7] == 123);
 | 
			
		||||
		MmapPool.instance.reallocate(p, 8 * int.sizeof);
 | 
			
		||||
 | 
			
		||||
        MmapPool.instance.reallocate(p, 8 * int.sizeof);
 | 
			
		||||
		assert(p.length == 32);
 | 
			
		||||
		assert((cast(int[]) p)[7] == 123);
 | 
			
		||||
 | 
			
		||||
        assert(p.length == 32);
 | 
			
		||||
        assert((cast(int[]) p)[7] == 123);
 | 
			
		||||
		MmapPool.instance.deallocate(p);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        MmapPool.instance.deallocate(p);
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * Static allocator instance and initializer.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: Global $(D_PSYMBOL MmapPool) instance.
 | 
			
		||||
	 */
 | 
			
		||||
	static @property ref shared(MmapPool) instance() nothrow @trusted
 | 
			
		||||
	{
 | 
			
		||||
		if (instance_ is null)
 | 
			
		||||
		{
 | 
			
		||||
			immutable instanceSize = addAlignment(__traits(classInstanceSize, MmapPool));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Static allocator instance and initializer.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: Global $(D_PSYMBOL MmapPool) instance.
 | 
			
		||||
     */
 | 
			
		||||
    static @property ref MmapPool instance() @nogc @trusted nothrow
 | 
			
		||||
    {
 | 
			
		||||
        if (instance_ is null)
 | 
			
		||||
        {
 | 
			
		||||
            immutable instanceSize = addAlignment(__traits(classInstanceSize, MmapPool));
 | 
			
		||||
			Region head; // Will become soon our region list head
 | 
			
		||||
			void* data = initializeRegion(instanceSize, head);
 | 
			
		||||
			if (data !is null)
 | 
			
		||||
			{
 | 
			
		||||
				data[0..instanceSize] = typeid(MmapPool).initializer[];
 | 
			
		||||
				instance_ = cast(shared MmapPool) data;
 | 
			
		||||
				instance_.head = head;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return instance_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
            Region head; // Will become soon our region list head
 | 
			
		||||
            void* data = initializeRegion(instanceSize, head);
 | 
			
		||||
            if (data !is null)
 | 
			
		||||
            {
 | 
			
		||||
                data[0..instanceSize] = typeid(MmapPool).initializer[];
 | 
			
		||||
                instance_ = cast(MmapPool) data;
 | 
			
		||||
                instance_.head = head;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return instance_;
 | 
			
		||||
    }
 | 
			
		||||
	///
 | 
			
		||||
	@safe nothrow unittest
 | 
			
		||||
	{
 | 
			
		||||
		assert(instance is instance);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    @nogc @safe nothrow unittest
 | 
			
		||||
    {
 | 
			
		||||
        assert(instance is instance);
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes a region for one element.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	size = Aligned size of the first data block in the region.
 | 
			
		||||
	 * 	head = Region list head.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: A pointer to the data.
 | 
			
		||||
	 */
 | 
			
		||||
	private static void* initializeRegion(size_t size,
 | 
			
		||||
										  ref Region head) nothrow
 | 
			
		||||
	{
 | 
			
		||||
		immutable regionSize = calculateRegionSize(size);
 | 
			
		||||
		
 | 
			
		||||
		version (Posix)
 | 
			
		||||
		{
 | 
			
		||||
			void* p = mmap(null,
 | 
			
		||||
						   regionSize,
 | 
			
		||||
						   PROT_READ | PROT_WRITE,
 | 
			
		||||
						   MAP_PRIVATE | MAP_ANON,
 | 
			
		||||
						   -1,
 | 
			
		||||
						   0);
 | 
			
		||||
			if (p is MAP_FAILED)
 | 
			
		||||
			{
 | 
			
		||||
				if (errno == ENOMEM)
 | 
			
		||||
				{
 | 
			
		||||
					onOutOfMemoryError();
 | 
			
		||||
				}
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else version (Windows)
 | 
			
		||||
		{
 | 
			
		||||
			void* p = VirtualAlloc(null,
 | 
			
		||||
								   regionSize,
 | 
			
		||||
								   MEM_COMMIT,
 | 
			
		||||
								   PAGE_READWRITE);
 | 
			
		||||
			if (p is null)
 | 
			
		||||
			{
 | 
			
		||||
				if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
 | 
			
		||||
				{
 | 
			
		||||
					onOutOfMemoryError();
 | 
			
		||||
				}
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes a region for one element.
 | 
			
		||||
     *
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     size = Aligned size of the first data block in the region.
 | 
			
		||||
     *     head = Region list head.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: A pointer to the data.
 | 
			
		||||
     */
 | 
			
		||||
    private static void* initializeRegion(size_t size,
 | 
			
		||||
                                          ref Region head) @nogc nothrow
 | 
			
		||||
    {
 | 
			
		||||
        immutable regionSize = calculateRegionSize(size);
 | 
			
		||||
        
 | 
			
		||||
        version (Posix)
 | 
			
		||||
        {
 | 
			
		||||
            void* p = mmap(null,
 | 
			
		||||
                           regionSize,
 | 
			
		||||
                           PROT_READ | PROT_WRITE,
 | 
			
		||||
                           MAP_PRIVATE | MAP_ANON,
 | 
			
		||||
                           -1,
 | 
			
		||||
                           0);
 | 
			
		||||
            if (p is MAP_FAILED)
 | 
			
		||||
            {
 | 
			
		||||
                if (errno == ENOMEM)
 | 
			
		||||
                {
 | 
			
		||||
                    onOutOfMemoryError();
 | 
			
		||||
                }
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else version (Windows)
 | 
			
		||||
        {
 | 
			
		||||
            void* p = VirtualAlloc(null,
 | 
			
		||||
                                   regionSize,
 | 
			
		||||
                                   MEM_COMMIT,
 | 
			
		||||
                                   PAGE_READWRITE);
 | 
			
		||||
            if (p is null)
 | 
			
		||||
            {
 | 
			
		||||
                if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
 | 
			
		||||
                {
 | 
			
		||||
                    onOutOfMemoryError();
 | 
			
		||||
                }
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		Region region = cast(Region) p;
 | 
			
		||||
		region.blocks = 1;
 | 
			
		||||
		region.size = regionSize;
 | 
			
		||||
 | 
			
		||||
        Region region = cast(Region) p;
 | 
			
		||||
        region.blocks = 1;
 | 
			
		||||
        region.size = regionSize;
 | 
			
		||||
		// Set the pointer to the head of the region list
 | 
			
		||||
		if (head !is null)
 | 
			
		||||
		{
 | 
			
		||||
			head.prev = region;
 | 
			
		||||
		}
 | 
			
		||||
		region.next = head;
 | 
			
		||||
		region.prev = null;
 | 
			
		||||
		head = region;
 | 
			
		||||
 | 
			
		||||
        // Set the pointer to the head of the region list
 | 
			
		||||
        if (head !is null)
 | 
			
		||||
        {
 | 
			
		||||
            head.prev = region;
 | 
			
		||||
        }
 | 
			
		||||
        region.next = head;
 | 
			
		||||
        region.prev = null;
 | 
			
		||||
        head = region;
 | 
			
		||||
		// Initialize the data block
 | 
			
		||||
		void* memoryPointer = p + regionEntrySize;
 | 
			
		||||
		Block block1 = cast(Block) memoryPointer;
 | 
			
		||||
		block1.size = size;
 | 
			
		||||
		block1.free = false;
 | 
			
		||||
 | 
			
		||||
        // Initialize the data block
 | 
			
		||||
        void* memoryPointer = p + regionEntrySize;
 | 
			
		||||
        Block block1 = cast(Block) memoryPointer;
 | 
			
		||||
        block1.size = size;
 | 
			
		||||
        block1.free = false;
 | 
			
		||||
		// It is what we want to return
 | 
			
		||||
		void* data = memoryPointer + blockEntrySize;
 | 
			
		||||
 | 
			
		||||
        // It is what we want to return
 | 
			
		||||
        void* data = memoryPointer + blockEntrySize;
 | 
			
		||||
		// Free block after data
 | 
			
		||||
		memoryPointer = data + size;
 | 
			
		||||
		Block block2 = cast(Block) memoryPointer;
 | 
			
		||||
		block1.prev = block2.next = null;
 | 
			
		||||
		block1.next = block2;
 | 
			
		||||
		block2.prev = block1;
 | 
			
		||||
		block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
 | 
			
		||||
		block2.free = true;
 | 
			
		||||
		block1.region = block2.region = region;
 | 
			
		||||
 | 
			
		||||
        // Free block after data
 | 
			
		||||
        memoryPointer = data + size;
 | 
			
		||||
        Block block2 = cast(Block) memoryPointer;
 | 
			
		||||
        block1.prev = block2.next = null;
 | 
			
		||||
        block1.next = block2;
 | 
			
		||||
        block2.prev = block1;
 | 
			
		||||
        block2.size = regionSize - size - regionEntrySize - blockEntrySize * 2;
 | 
			
		||||
        block2.free = true;
 | 
			
		||||
        block1.region = block2.region = region;
 | 
			
		||||
		return data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	private void* initializeRegion(size_t size) shared nothrow
 | 
			
		||||
	{
 | 
			
		||||
		return initializeRegion(size, head);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    /// Ditto.
 | 
			
		||||
    private void* initializeRegion(size_t size) @nogc nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return initializeRegion(size, head);
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	x = Space to be aligned.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: Aligned size of $(D_PARAM x).
 | 
			
		||||
	 */
 | 
			
		||||
	pragma(inline)
 | 
			
		||||
	private static immutable(size_t) addAlignment(size_t x)
 | 
			
		||||
	@safe pure nothrow
 | 
			
		||||
	out (result)
 | 
			
		||||
	{
 | 
			
		||||
		assert(result > 0);
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		return (x - 1) / alignment_ * alignment_ + alignment_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     x = Space to be aligned.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: Aligned size of $(D_PARAM x).
 | 
			
		||||
     */
 | 
			
		||||
    pragma(inline)
 | 
			
		||||
    private static immutable(size_t) addAlignment(size_t x)
 | 
			
		||||
    @nogc @safe pure nothrow
 | 
			
		||||
    out (result)
 | 
			
		||||
    {
 | 
			
		||||
        assert(result > 0);
 | 
			
		||||
    }
 | 
			
		||||
    body
 | 
			
		||||
    {
 | 
			
		||||
        return (x - 1) / alignment_ * alignment_ + alignment_;
 | 
			
		||||
    }
 | 
			
		||||
	/**
 | 
			
		||||
	 * Params:
 | 
			
		||||
	 * 	x = Required space.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
 | 
			
		||||
	 */
 | 
			
		||||
	pragma(inline)
 | 
			
		||||
	private static immutable(size_t) calculateRegionSize(size_t x)
 | 
			
		||||
	@safe pure nothrow
 | 
			
		||||
	out (result)
 | 
			
		||||
	{
 | 
			
		||||
		assert(result > 0);
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		x += regionEntrySize + blockEntrySize * 2;
 | 
			
		||||
		return x / pageSize * pageSize + pageSize;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Params:
 | 
			
		||||
     *     x = Required space.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
 | 
			
		||||
     */
 | 
			
		||||
    pragma(inline)
 | 
			
		||||
    private static immutable(size_t) calculateRegionSize(size_t x)
 | 
			
		||||
    @nogc @safe pure nothrow
 | 
			
		||||
    out (result)
 | 
			
		||||
    {
 | 
			
		||||
        assert(result > 0);
 | 
			
		||||
    }
 | 
			
		||||
    body
 | 
			
		||||
    {
 | 
			
		||||
        x += regionEntrySize + blockEntrySize * 2;
 | 
			
		||||
        return x / pageSize * pageSize + pageSize;
 | 
			
		||||
    }
 | 
			
		||||
	@property uint alignment() shared const pure nothrow @safe
 | 
			
		||||
	{
 | 
			
		||||
		return alignment_;
 | 
			
		||||
	}
 | 
			
		||||
	private enum alignment_ = 8;
 | 
			
		||||
 | 
			
		||||
    @property uint alignment() const @nogc @safe pure nothrow
 | 
			
		||||
    {
 | 
			
		||||
        return alignment_;
 | 
			
		||||
    }
 | 
			
		||||
    private enum alignment_ = 8;
 | 
			
		||||
	private static shared MmapPool instance_;
 | 
			
		||||
 | 
			
		||||
    private static MmapPool instance_;
 | 
			
		||||
	private shared static immutable size_t pageSize;
 | 
			
		||||
 | 
			
		||||
    private shared static immutable size_t pageSize;
 | 
			
		||||
	private shared struct RegionEntry
 | 
			
		||||
	{
 | 
			
		||||
		Region prev;
 | 
			
		||||
		Region next;
 | 
			
		||||
		uint blocks;
 | 
			
		||||
		size_t size;
 | 
			
		||||
	}
 | 
			
		||||
	private alias Region = shared RegionEntry*;
 | 
			
		||||
	private enum regionEntrySize = 32;
 | 
			
		||||
 | 
			
		||||
    private shared struct RegionEntry
 | 
			
		||||
    {
 | 
			
		||||
        Region prev;
 | 
			
		||||
        Region next;
 | 
			
		||||
        uint blocks;
 | 
			
		||||
        size_t size;
 | 
			
		||||
    }
 | 
			
		||||
    private alias Region = shared RegionEntry*;
 | 
			
		||||
    private enum regionEntrySize = 32;
 | 
			
		||||
	private shared Region head;
 | 
			
		||||
 | 
			
		||||
    private shared Region head;
 | 
			
		||||
 | 
			
		||||
    private shared struct BlockEntry
 | 
			
		||||
    {
 | 
			
		||||
        Block prev;
 | 
			
		||||
        Block next;
 | 
			
		||||
        bool free;
 | 
			
		||||
        size_t size;
 | 
			
		||||
        Region region;
 | 
			
		||||
    }
 | 
			
		||||
    private alias Block = shared BlockEntry*;
 | 
			
		||||
    private enum blockEntrySize = 40;
 | 
			
		||||
	private shared struct BlockEntry
 | 
			
		||||
	{
 | 
			
		||||
		Block prev;
 | 
			
		||||
		Block next;
 | 
			
		||||
		bool free;
 | 
			
		||||
		size_t size;
 | 
			
		||||
		Region region;
 | 
			
		||||
	}
 | 
			
		||||
	private alias Block = shared BlockEntry*;
 | 
			
		||||
	private enum blockEntrySize = 40;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,75 @@
 | 
			
		||||
 */
 | 
			
		||||
module tanya.memory;
 | 
			
		||||
 | 
			
		||||
import std.algorithm.mutation;
 | 
			
		||||
public import std.experimental.allocator;
 | 
			
		||||
public import tanya.memory.allocator;
 | 
			
		||||
public import tanya.memory.types;
 | 
			
		||||
 | 
			
		||||
shared Allocator allocator;
 | 
			
		||||
 | 
			
		||||
shared static this() nothrow @safe @nogc
 | 
			
		||||
{
 | 
			
		||||
	import tanya.memory.mmappool;
 | 
			
		||||
	allocator = MmapPool.instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc
 | 
			
		||||
{
 | 
			
		||||
	return allocator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@property void defaultAllocator(shared(Allocator) allocator) nothrow @safe @nogc
 | 
			
		||||
{
 | 
			
		||||
	.allocator = 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.
 | 
			
		||||
 * 	init      = The value to fill the new part of the array with if it becomes
 | 
			
		||||
 * 	            larger.
 | 
			
		||||
 *
 | 
			
		||||
 * 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,
 | 
			
		||||
                    T init = T.init)
 | 
			
		||||
{
 | 
			
		||||
	void[] buf = array;
 | 
			
		||||
	immutable oldLength = array.length;
 | 
			
		||||
 | 
			
		||||
	if (!allocator.reallocate(buf, length * T.sizeof))
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	array = cast(T[]) buf;
 | 
			
		||||
	if (oldLength < length)
 | 
			
		||||
	{
 | 
			
		||||
		array[oldLength .. $].uninitializedFill(init);
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
	int[] p;
 | 
			
		||||
 | 
			
		||||
	defaultAllocator.resizeArray(p, 20);
 | 
			
		||||
	assert(p.length == 20);
 | 
			
		||||
 | 
			
		||||
	defaultAllocator.resizeArray(p, 30);
 | 
			
		||||
	assert(p.length == 30);
 | 
			
		||||
 | 
			
		||||
	defaultAllocator.resizeArray(p, 10);
 | 
			
		||||
	assert(p.length == 10);
 | 
			
		||||
 | 
			
		||||
	defaultAllocator.resizeArray(p, 0);
 | 
			
		||||
	assert(p is null);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,13 +37,15 @@ struct RefCounted(T)
 | 
			
		||||
		private T* payload;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private uint *counter;
 | 
			
		||||
	private uint counter;
 | 
			
		||||
 | 
			
		||||
	invariant
 | 
			
		||||
	{
 | 
			
		||||
		assert(counter is null || allocator !is null);
 | 
			
		||||
		assert(counter == 0 || allocator !is null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private shared Allocator allocator;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Takes ownership over $(D_PARAM value), setting the counter to 1.
 | 
			
		||||
	 *
 | 
			
		||||
@@ -54,20 +56,29 @@ struct RefCounted(T)
 | 
			
		||||
 | 
			
		||||
	 * Precondition: $(D_INLINECODE allocator !is null)
 | 
			
		||||
	 */
 | 
			
		||||
	this(T value, IAllocator allocator = theAllocator)
 | 
			
		||||
	this(T value, shared Allocator allocator = defaultAllocator)
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		assert(allocator !is null);
 | 
			
		||||
	}
 | 
			
		||||
	body
 | 
			
		||||
	{
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
		initialize();
 | 
			
		||||
		move(value, get);
 | 
			
		||||
		this(allocator);
 | 
			
		||||
		static if (!isReference!T)
 | 
			
		||||
		{
 | 
			
		||||
			payload = cast(T*) allocator.allocate(stateSize!T).ptr;
 | 
			
		||||
			move(value, *payload);
 | 
			
		||||
			counter = 1;
 | 
			
		||||
		}
 | 
			
		||||
		else if (value !is null)
 | 
			
		||||
		{
 | 
			
		||||
			move(value, payload);
 | 
			
		||||
			counter = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Ditto.
 | 
			
		||||
	this(IAllocator allocator)
 | 
			
		||||
	this(shared Allocator allocator) pure nothrow @safe @nogc
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		assert(allocator !is null);
 | 
			
		||||
@@ -77,28 +88,6 @@ struct RefCounted(T)
 | 
			
		||||
		this.allocator = allocator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Allocates the internal storage.
 | 
			
		||||
	 */
 | 
			
		||||
	private void initialize()
 | 
			
		||||
	{
 | 
			
		||||
		static if (isReference!T)
 | 
			
		||||
		{
 | 
			
		||||
			counter = allocator.make!uint(1);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Allocate for the counter and the payload together.
 | 
			
		||||
			auto p = allocator.allocate(uint.sizeof + T.sizeof);
 | 
			
		||||
			if (p is null)
 | 
			
		||||
			{
 | 
			
		||||
				onOutOfMemoryError();
 | 
			
		||||
			}
 | 
			
		||||
			counter = emplace(cast(uint*) p.ptr, 1);
 | 
			
		||||
			payload = cast(T*) p[uint.sizeof .. $].ptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Increases the reference counter by one.
 | 
			
		||||
	 */
 | 
			
		||||
@@ -106,7 +95,7 @@ struct RefCounted(T)
 | 
			
		||||
	{
 | 
			
		||||
		if (isInitialized)
 | 
			
		||||
		{
 | 
			
		||||
			++(*counter);
 | 
			
		||||
			++counter;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -117,15 +106,14 @@ struct RefCounted(T)
 | 
			
		||||
	 */
 | 
			
		||||
	~this()
 | 
			
		||||
	{
 | 
			
		||||
		if (!isInitialized || (--(*counter)))
 | 
			
		||||
		if (isInitialized && !--counter)
 | 
			
		||||
		{
 | 
			
		||||
			return;
 | 
			
		||||
			static if (isReference!T)
 | 
			
		||||
			{
 | 
			
		||||
				allocator.dispose(payload);
 | 
			
		||||
				payload = null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		allocator.dispose(payload);
 | 
			
		||||
		payload = null;
 | 
			
		||||
 | 
			
		||||
		allocator.dispose(counter);
 | 
			
		||||
		counter = null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -135,7 +123,7 @@ struct RefCounted(T)
 | 
			
		||||
	 * If it is the last reference of the previously owned object,
 | 
			
		||||
	 * it will be destroyed.
 | 
			
		||||
	 *
 | 
			
		||||
	 * If the allocator wasn't set before, $(D_PSYMBOL theAllocator) will
 | 
			
		||||
	 * If the allocator wasn't set before, $(D_PSYMBOL defaultAllocator) will
 | 
			
		||||
	 * be used. If you need a different allocator, create a new
 | 
			
		||||
	 * $(D_PSYMBOL RefCounted).
 | 
			
		||||
	 *
 | 
			
		||||
@@ -144,21 +132,18 @@ struct RefCounted(T)
 | 
			
		||||
	 */
 | 
			
		||||
	ref T opAssign(T rhs)
 | 
			
		||||
	{
 | 
			
		||||
		checkAllocator();
 | 
			
		||||
		if (isInitialized)
 | 
			
		||||
		if (allocator is null)
 | 
			
		||||
		{
 | 
			
		||||
			static if (isReference!T)
 | 
			
		||||
			{
 | 
			
		||||
				if (!--(*counter))
 | 
			
		||||
				{
 | 
			
		||||
					allocator.dispose(payload);
 | 
			
		||||
					*counter = 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			allocator = defaultAllocator;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		static if (isReference!T)
 | 
			
		||||
		{
 | 
			
		||||
			initialize();
 | 
			
		||||
			counter == 1 ? allocator.dispose(payload) : --counter;
 | 
			
		||||
		}
 | 
			
		||||
		else if (!isInitialized)
 | 
			
		||||
		{
 | 
			
		||||
			payload = cast(T*) allocator.allocate(stateSize!T).ptr;
 | 
			
		||||
			counter = 1;
 | 
			
		||||
		}
 | 
			
		||||
		move(rhs, get);
 | 
			
		||||
		return get;
 | 
			
		||||
@@ -212,7 +197,7 @@ struct RefCounted(T)
 | 
			
		||||
	 */
 | 
			
		||||
	@property uint count() const pure nothrow @safe @nogc
 | 
			
		||||
	{
 | 
			
		||||
		return counter is null ? 0 : *counter;
 | 
			
		||||
		return counter;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -220,11 +205,9 @@ struct RefCounted(T)
 | 
			
		||||
	 */
 | 
			
		||||
	@property bool isInitialized() const pure nothrow @safe @nogc
 | 
			
		||||
	{
 | 
			
		||||
		return counter !is null;
 | 
			
		||||
		return counter != 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mixin StructAllocator;
 | 
			
		||||
 | 
			
		||||
	alias get this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -247,9 +230,11 @@ version (unittest)
 | 
			
		||||
 | 
			
		||||
	struct B
 | 
			
		||||
	{
 | 
			
		||||
		int prop;
 | 
			
		||||
		@disable this();
 | 
			
		||||
		this(int param1)
 | 
			
		||||
		{
 | 
			
		||||
			prop = param1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -269,7 +254,7 @@ unittest
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto arr = theAllocator.makeArray!ubyte(2);
 | 
			
		||||
	auto arr = defaultAllocator.makeArray!ubyte(2);
 | 
			
		||||
	{
 | 
			
		||||
		auto a = S(arr);
 | 
			
		||||
		assert(a.member.count == 1);
 | 
			
		||||
@@ -288,7 +273,7 @@ unittest
 | 
			
		||||
private unittest
 | 
			
		||||
{
 | 
			
		||||
	uint destroyed;
 | 
			
		||||
	auto a = theAllocator.make!A(destroyed);
 | 
			
		||||
	auto a = defaultAllocator.make!A(destroyed);
 | 
			
		||||
 | 
			
		||||
	assert(destroyed == 0);
 | 
			
		||||
	{
 | 
			
		||||
@@ -323,6 +308,7 @@ private unittest
 | 
			
		||||
	static assert(!is(typeof(cast(int) (RefCounted!A()))));
 | 
			
		||||
 | 
			
		||||
	static assert(is(RefCounted!B));
 | 
			
		||||
	static assert(is(RefCounted!A));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -341,40 +327,26 @@ private unittest
 | 
			
		||||
 * 
 | 
			
		||||
 * Returns: Newly created $(D_PSYMBOL RefCounted!T).
 | 
			
		||||
 */
 | 
			
		||||
RefCounted!T refCounted(T, A...)(IAllocator allocator, auto ref A args)
 | 
			
		||||
RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
 | 
			
		||||
	if (!is(T == interface) && !isAbstractClass!T)
 | 
			
		||||
{
 | 
			
		||||
	auto rc = typeof(return)(allocator);
 | 
			
		||||
 | 
			
		||||
	immutable toAllocate = max(stateSize!T, 1) + uint.sizeof;
 | 
			
		||||
	auto p = allocator.allocate(toAllocate);
 | 
			
		||||
	if (p is null)
 | 
			
		||||
	static if (isReference!T)
 | 
			
		||||
	{
 | 
			
		||||
		onOutOfMemoryError();
 | 
			
		||||
	}
 | 
			
		||||
	scope (failure)
 | 
			
		||||
	{
 | 
			
		||||
		allocator.deallocate(p);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc.counter = emplace(cast(uint*) p.ptr, 1);
 | 
			
		||||
 | 
			
		||||
	static if (is(T == class))
 | 
			
		||||
	{
 | 
			
		||||
		rc.payload = emplace!T(p[uint.sizeof .. $], args);
 | 
			
		||||
		return typeof(return)(allocator.make!T(args), allocator);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		rc.payload = emplace(cast(T*) p[uint.sizeof .. $].ptr, args);
 | 
			
		||||
		auto rc = typeof(return)(allocator);
 | 
			
		||||
		rc.counter = 1;
 | 
			
		||||
		rc.payload = allocator.make!T(args);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
unittest
 | 
			
		||||
{
 | 
			
		||||
	auto rc = theAllocator.refCounted!int(5);
 | 
			
		||||
	auto rc = defaultAllocator.refCounted!int(5);
 | 
			
		||||
	assert(rc.count == 1);
 | 
			
		||||
 | 
			
		||||
	void func(RefCounted!int param)
 | 
			
		||||
@@ -395,7 +367,21 @@ unittest
 | 
			
		||||
 | 
			
		||||
private unittest
 | 
			
		||||
{
 | 
			
		||||
	static assert(!is(theAllocator.refCounted!A));
 | 
			
		||||
	static assert(!is(typeof(theAllocator.refCounted!B())));
 | 
			
		||||
	static assert(is(typeof(theAllocator.refCounted!B(5))));
 | 
			
		||||
	struct E
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	static assert(is(typeof(defaultAllocator.refCounted!bool(false))));
 | 
			
		||||
	static assert(is(typeof(defaultAllocator.refCounted!B(5))));
 | 
			
		||||
	static assert(!is(typeof(defaultAllocator.refCounted!B())));
 | 
			
		||||
 | 
			
		||||
	static assert(is(typeof(defaultAllocator.refCounted!E())));
 | 
			
		||||
	static assert(!is(typeof(defaultAllocator.refCounted!E(5))));
 | 
			
		||||
	{
 | 
			
		||||
		auto rc = defaultAllocator.refCounted!B(3);
 | 
			
		||||
		assert(rc.get.prop == 3);
 | 
			
		||||
	}
 | 
			
		||||
	{
 | 
			
		||||
		auto rc = defaultAllocator.refCounted!E();
 | 
			
		||||
		assert(rc.isInitialized);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -10,9 +10,10 @@
 | 
			
		||||
 */  
 | 
			
		||||
module tanya.random;
 | 
			
		||||
 | 
			
		||||
import tanya.memory;
 | 
			
		||||
import std.experimental.allocator;
 | 
			
		||||
import std.digest.sha;
 | 
			
		||||
import std.typecons;
 | 
			
		||||
import tanya.memory;
 | 
			
		||||
 | 
			
		||||
/// Block size of entropy accumulator (SHA-512).
 | 
			
		||||
enum blockSize = 64;
 | 
			
		||||
@@ -148,13 +149,13 @@ version (linux)
 | 
			
		||||
/**
 | 
			
		||||
 * Pseudorandom number generator.
 | 
			
		||||
 * ---
 | 
			
		||||
 * auto entropy = theAllocator.make!Entropy;
 | 
			
		||||
 * auto entropy = defaultAllocator.make!Entropy();
 | 
			
		||||
 *
 | 
			
		||||
 * ubyte[blockSize] output;
 | 
			
		||||
 *
 | 
			
		||||
 * output = entropy.random;
 | 
			
		||||
 *
 | 
			
		||||
 * theAllocator.finalize(entropy);
 | 
			
		||||
 * defaultAllocator.finalize(entropy);
 | 
			
		||||
 * ---
 | 
			
		||||
 */
 | 
			
		||||
class Entropy
 | 
			
		||||
@@ -175,7 +176,7 @@ class Entropy
 | 
			
		||||
	 * 	allocator  = Allocator to allocate entropy sources available on the
 | 
			
		||||
	 * 	             system.
 | 
			
		||||
	 */
 | 
			
		||||
	this(size_t maxSources = 20, IAllocator allocator = theAllocator)
 | 
			
		||||
	this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
 | 
			
		||||
	in
 | 
			
		||||
	{
 | 
			
		||||
		assert(maxSources > 0 && maxSources <= ubyte.max);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user