Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
1123d01e6c | |||
c53d319337 | |||
7c36dbb8f0 | |||
dd3becf6b7 | |||
b78ecdf4c5 | |||
a4aa5bcb2e | |||
edd3ec4b32 | |||
9fdcef86e7 | |||
ed0eb4ac74 | |||
192ee20bf7 | |||
965ca0088e | |||
b752acdff7 | |||
cbeb0395f9 | |||
5e6f8446d8 |
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# tanya
|
||||||
|
|
||||||
|
tanya's mission is to provide a GC-free, general purpose library for D
|
||||||
|
programming language for developing servers.
|
@ -107,7 +107,7 @@ class EpollLoop : SelectorLoop
|
|||||||
{
|
{
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!BadLoopException();
|
throw theAllocator.make!BadLoopException();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ class IOCPLoop : Loop
|
|||||||
completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||||
if (!completionPort)
|
if (!completionPort)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!BadLoopException("Creating completion port failed");
|
throw theAllocator.make!BadLoopException("Creating completion port failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ class IOCPLoop : Loop
|
|||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
MmapPool.instance.dispose(overlapped);
|
MmapPool.instance.dispose(overlapped);
|
||||||
defaultAllocator.dispose(e);
|
theAllocator.dispose(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ class IOCPLoop : Loop
|
|||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
MmapPool.instance.dispose(overlapped);
|
MmapPool.instance.dispose(overlapped);
|
||||||
defaultAllocator.dispose(e);
|
theAllocator.dispose(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,13 +127,13 @@ else version (DragonFlyBSD)
|
|||||||
|
|
||||||
version (MacBSD):
|
version (MacBSD):
|
||||||
|
|
||||||
import dlib.async.event.selector;
|
import tanya.async.event.selector;
|
||||||
import dlib.async.loop;
|
import tanya.async.loop;
|
||||||
import dlib.async.transport;
|
import tanya.async.transport;
|
||||||
import dlib.async.watcher;
|
import tanya.async.watcher;
|
||||||
import dlib.memory;
|
import tanya.memory;
|
||||||
import dlib.memory.mmappool;
|
import tanya.memory.mmappool;
|
||||||
import dlib.network.socket;
|
import tanya.network.socket;
|
||||||
import core.stdc.errno;
|
import core.stdc.errno;
|
||||||
import core.sys.posix.unistd;
|
import core.sys.posix.unistd;
|
||||||
import core.sys.posix.sys.time;
|
import core.sys.posix.sys.time;
|
||||||
@ -250,7 +250,7 @@ class KqueueLoop : SelectorLoop
|
|||||||
{
|
{
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!BadLoopException();
|
throw theAllocator.make!BadLoopException();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ abstract class SelectorLoop : Loop
|
|||||||
}
|
}
|
||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(e);
|
theAllocator.dispose(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (client is null)
|
if (client is null)
|
||||||
@ -235,7 +235,7 @@ abstract class SelectorLoop : Loop
|
|||||||
IOWatcher io;
|
IOWatcher io;
|
||||||
auto transport = MmapPool.instance.make!SelectorStreamTransport(this, client);
|
auto transport = MmapPool.instance.make!SelectorStreamTransport(this, client);
|
||||||
|
|
||||||
if (connections.length >= client.handle)
|
if (connections.length > client.handle)
|
||||||
{
|
{
|
||||||
io = cast(IOWatcher) connections[client.handle];
|
io = cast(IOWatcher) connections[client.handle];
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* this.transport = transport;
|
* this.transport = transport;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* void disconnected(SocketException exception = null)
|
* void disconnected(SocketException e = null)
|
||||||
* {
|
* {
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
@ -34,6 +34,7 @@
|
|||||||
* void main()
|
* void main()
|
||||||
* {
|
* {
|
||||||
* auto address = new InternetAddress("127.0.0.1", cast(ushort) 8192);
|
* auto address = new InternetAddress("127.0.0.1", cast(ushort) 8192);
|
||||||
|
*
|
||||||
* version (Windows)
|
* version (Windows)
|
||||||
* {
|
* {
|
||||||
* auto sock = new OverlappedStreamSocket(AddressFamily.INET);
|
* auto sock = new OverlappedStreamSocket(AddressFamily.INET);
|
||||||
@ -119,17 +120,6 @@ enum Event : uint
|
|||||||
|
|
||||||
alias EventMask = BitFlags!Event;
|
alias EventMask = BitFlags!Event;
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to set $(D_PSYMBOL MmapPool) to the default allocator.
|
|
||||||
*/
|
|
||||||
shared static this()
|
|
||||||
{
|
|
||||||
if (allocator is null)
|
|
||||||
{
|
|
||||||
allocator = MmapPool.instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event loop.
|
* Event loop.
|
||||||
*/
|
*/
|
||||||
@ -274,7 +264,7 @@ abstract class Loop
|
|||||||
protected void kill(IOWatcher watcher, SocketException exception)
|
protected void kill(IOWatcher watcher, SocketException exception)
|
||||||
{
|
{
|
||||||
watcher.socket.shutdown();
|
watcher.socket.shutdown();
|
||||||
defaultAllocator.dispose(watcher.socket);
|
theAllocator.dispose(watcher.socket);
|
||||||
MmapPool.instance.dispose(watcher.transport);
|
MmapPool.instance.dispose(watcher.transport);
|
||||||
watcher.exception = exception;
|
watcher.exception = exception;
|
||||||
swapPendings.insertBack(watcher);
|
swapPendings.insertBack(watcher);
|
||||||
|
@ -10,10 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.async;
|
module tanya.async;
|
||||||
|
|
||||||
public
|
public import tanya.async.loop;
|
||||||
{
|
public import tanya.async.protocol;
|
||||||
import tanya.async.loop;
|
public import tanya.async.transport;
|
||||||
import tanya.async.protocol;
|
public import tanya.async.watcher;
|
||||||
import tanya.async.transport;
|
|
||||||
import tanya.async.watcher;
|
|
||||||
}
|
|
||||||
|
@ -174,7 +174,7 @@ class IOWatcher : ConnectionWatcher
|
|||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
IOWatcher opCall(StreamTransport transport, Protocol protocol) pure nothrow @safe @nogc
|
IOWatcher opCall(StreamTransport transport, Protocol protocol) pure nothrow @nogc
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(transport !is null);
|
assert(transport !is null);
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
* Copyright: Eugene Wissner 2016.
|
* Copyright: Eugene Wissner 2016.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
*/
|
*/
|
||||||
module tanya.container.buffer;
|
module tanya.container.buffer;
|
||||||
|
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
@ -131,7 +131,7 @@ class ReadBuffer : Buffer
|
|||||||
{
|
{
|
||||||
this.minAvailable = minAvailable;
|
this.minAvailable = minAvailable;
|
||||||
this.blockSize = size;
|
this.blockSize = size;
|
||||||
defaultAllocator.resizeArray!ubyte(buffer_, size);
|
theAllocator.resizeArray!ubyte(buffer_, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,17 +139,17 @@ class ReadBuffer : Buffer
|
|||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(buffer_);
|
theAllocator.dispose(buffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!ReadBuffer;
|
auto b = theAllocator.make!ReadBuffer;
|
||||||
assert(b.capacity == 8192);
|
assert(b.capacity == 8192);
|
||||||
assert(b.length == 0);
|
assert(b.length == 0);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,7 +190,7 @@ class ReadBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!ReadBuffer;
|
auto b = theAllocator.make!ReadBuffer;
|
||||||
size_t numberRead;
|
size_t numberRead;
|
||||||
|
|
||||||
// Fills the buffer with values 0..10
|
// Fills the buffer with values 0..10
|
||||||
@ -202,7 +202,7 @@ class ReadBuffer : Buffer
|
|||||||
b.clear();
|
b.clear();
|
||||||
assert(b.free == b.blockSize);
|
assert(b.free == b.blockSize);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,7 +224,7 @@ class ReadBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!ReadBuffer;
|
auto b = theAllocator.make!ReadBuffer;
|
||||||
size_t numberRead;
|
size_t numberRead;
|
||||||
ubyte[] result;
|
ubyte[] result;
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ class ReadBuffer : Buffer
|
|||||||
assert(result[10] == 20);
|
assert(result[10] == 20);
|
||||||
assert(result[14] == 24);
|
assert(result[14] == 24);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -294,7 +294,7 @@ class ReadBuffer : Buffer
|
|||||||
{
|
{
|
||||||
if (capacity - length < minAvailable)
|
if (capacity - length < minAvailable)
|
||||||
{
|
{
|
||||||
defaultAllocator.resizeArray!ubyte(buffer_, capacity + blockSize);
|
theAllocator.resizeArray!ubyte(buffer_, capacity + blockSize);
|
||||||
}
|
}
|
||||||
ring = length_;
|
ring = length_;
|
||||||
return buffer_[length_..$];
|
return buffer_[length_..$];
|
||||||
@ -304,7 +304,7 @@ class ReadBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!ReadBuffer;
|
auto b = theAllocator.make!ReadBuffer;
|
||||||
size_t numberRead;
|
size_t numberRead;
|
||||||
ubyte[] result;
|
ubyte[] result;
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ class ReadBuffer : Buffer
|
|||||||
b.clear();
|
b.clear();
|
||||||
assert(b.length == 0);
|
assert(b.length == 0);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +365,7 @@ class WriteBuffer : Buffer
|
|||||||
{
|
{
|
||||||
blockSize = size;
|
blockSize = size;
|
||||||
ring = size - 1;
|
ring = size - 1;
|
||||||
defaultAllocator.resizeArray!ubyte(buffer_, size);
|
theAllocator.resizeArray!ubyte(buffer_, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -373,7 +373,7 @@ class WriteBuffer : Buffer
|
|||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(buffer_);
|
theAllocator.dispose(buffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -415,7 +415,7 @@ class WriteBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!WriteBuffer(4);
|
auto b = theAllocator.make!WriteBuffer(4);
|
||||||
ubyte[3] buf = [48, 23, 255];
|
ubyte[3] buf = [48, 23, 255];
|
||||||
|
|
||||||
b ~= buf;
|
b ~= buf;
|
||||||
@ -433,7 +433,7 @@ class WriteBuffer : Buffer
|
|||||||
b += b.length;
|
b += b.length;
|
||||||
assert(b.length == 0);
|
assert(b.length == 0);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -498,7 +498,7 @@ class WriteBuffer : Buffer
|
|||||||
{
|
{
|
||||||
auto newSize = end / blockSize * blockSize + blockSize;
|
auto newSize = end / blockSize * blockSize + blockSize;
|
||||||
|
|
||||||
defaultAllocator.resizeArray!ubyte(buffer_, newSize);
|
theAllocator.resizeArray!ubyte(buffer_, newSize);
|
||||||
}
|
}
|
||||||
buffer_[position..end] = buffer[start..$];
|
buffer_[position..end] = buffer[start..$];
|
||||||
position = end;
|
position = end;
|
||||||
@ -514,7 +514,7 @@ class WriteBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!WriteBuffer(4);
|
auto b = theAllocator.make!WriteBuffer(4);
|
||||||
ubyte[3] buf = [48, 23, 255];
|
ubyte[3] buf = [48, 23, 255];
|
||||||
|
|
||||||
b ~= buf;
|
b ~= buf;
|
||||||
@ -533,9 +533,9 @@ class WriteBuffer : Buffer
|
|||||||
assert(b.buffer_[0] == 23 && b.buffer_[1] == 255
|
assert(b.buffer_[0] == 23 && b.buffer_[1] == 255
|
||||||
&& b.buffer_[2] == 48 && b.buffer_[3] == 23 && b.buffer_[4] == 255);
|
&& b.buffer_[2] == 48 && b.buffer_[3] == 23 && b.buffer_[4] == 255);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
|
|
||||||
b = make!WriteBuffer(defaultAllocator, 2);
|
b = make!WriteBuffer(theAllocator, 2);
|
||||||
|
|
||||||
b ~= buf;
|
b ~= buf;
|
||||||
assert(b.start == 0);
|
assert(b.start == 0);
|
||||||
@ -543,7 +543,7 @@ class WriteBuffer : Buffer
|
|||||||
assert(b.ring == 3);
|
assert(b.ring == 3);
|
||||||
assert(b.position == 3);
|
assert(b.position == 3);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -620,7 +620,7 @@ class WriteBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!WriteBuffer;
|
auto b = theAllocator.make!WriteBuffer;
|
||||||
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
|
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
|
||||||
|
|
||||||
b ~= buf;
|
b ~= buf;
|
||||||
@ -630,7 +630,7 @@ class WriteBuffer : Buffer
|
|||||||
b += 4;
|
b += 4;
|
||||||
assert(b.length == 0);
|
assert(b.length == 0);
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -663,7 +663,7 @@ class WriteBuffer : Buffer
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto b = defaultAllocator.make!WriteBuffer(6);
|
auto b = theAllocator.make!WriteBuffer(6);
|
||||||
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
|
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
|
||||||
|
|
||||||
b ~= buf;
|
b ~= buf;
|
||||||
@ -679,7 +679,7 @@ class WriteBuffer : Buffer
|
|||||||
assert(b[0..$] == buf[0..6]);
|
assert(b[0..$] == buf[0..6]);
|
||||||
b += b.length;
|
b += b.length;
|
||||||
|
|
||||||
defaultAllocator.dispose(b);
|
theAllocator.dispose(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,31 +27,47 @@ class SList(T)
|
|||||||
* allocator = The allocator should be used for the element
|
* allocator = The allocator should be used for the element
|
||||||
* allocations.
|
* allocations.
|
||||||
*/
|
*/
|
||||||
this(shared Allocator allocator = defaultAllocator)
|
this(IAllocator allocator = theAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all elements from the list.
|
* Removes all elements from the list.
|
||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all contents from the $(D_PSYMBOL SList).
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
{
|
{
|
||||||
while (!empty)
|
while (!empty)
|
||||||
{
|
{
|
||||||
static if (isFinalizable!T)
|
|
||||||
{
|
|
||||||
dispose(allocator, front);
|
|
||||||
}
|
|
||||||
popFront();
|
popFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto l = make!(SList!int)(theAllocator);
|
||||||
|
|
||||||
|
l.insertFront(8);
|
||||||
|
l.insertFront(5);
|
||||||
|
l.clear();
|
||||||
|
assert(l.empty);
|
||||||
|
|
||||||
|
dispose(theAllocator, l);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: First element.
|
* Returns: First element.
|
||||||
*/
|
*/
|
||||||
@property ref T front()
|
@property ref inout(T) front() inout
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -67,7 +83,7 @@ class SList(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* x = New element.
|
* x = New element.
|
||||||
*/
|
*/
|
||||||
@property void front(T x)
|
void insertFront(T x)
|
||||||
{
|
{
|
||||||
Entry* temp = make!Entry(allocator);
|
Entry* temp = make!Entry(allocator);
|
||||||
|
|
||||||
@ -76,55 +92,26 @@ class SList(T)
|
|||||||
first.next = temp;
|
first.next = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
/// Ditto.
|
||||||
unittest
|
alias insert = insertFront;
|
||||||
{
|
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
|
||||||
int[2] values = [8, 9];
|
|
||||||
|
|
||||||
l.front = values[0];
|
|
||||||
assert(l.front == values[0]);
|
|
||||||
l.front = values[1];
|
|
||||||
assert(l.front == values[1]);
|
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a new element at the beginning.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* x = New element.
|
|
||||||
*
|
|
||||||
* Returns: $(D_KEYWORD this).
|
|
||||||
*/
|
|
||||||
typeof(this) opOpAssign(string Op)(ref T x)
|
|
||||||
if (Op == "~")
|
|
||||||
{
|
|
||||||
front = x;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
auto l = make!(SList!int)(theAllocator);
|
||||||
int value = 5;
|
|
||||||
|
|
||||||
assert(l.empty);
|
l.insertFront(8);
|
||||||
|
assert(l.front == 8);
|
||||||
|
l.insertFront(9);
|
||||||
|
assert(l.front == 9);
|
||||||
|
|
||||||
l ~= value;
|
dispose(theAllocator, l);
|
||||||
|
|
||||||
assert(l.front == value);
|
|
||||||
assert(!l.empty);
|
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: $(D_KEYWORD true) if the list is empty.
|
* Returns: $(D_KEYWORD true) if the list is empty.
|
||||||
*/
|
*/
|
||||||
@property bool empty() const @safe pure nothrow
|
@property bool empty() inout const
|
||||||
{
|
{
|
||||||
return first.next is null;
|
return first.next is null;
|
||||||
}
|
}
|
||||||
@ -147,91 +134,62 @@ class SList(T)
|
|||||||
dispose(allocator, first.next);
|
dispose(allocator, first.next);
|
||||||
first.next = n;
|
first.next = n;
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
|
||||||
int[2] values = [8, 9];
|
|
||||||
|
|
||||||
l.front = values[0];
|
|
||||||
l.front = values[1];
|
|
||||||
assert(l.front == values[1]);
|
|
||||||
l.popFront();
|
|
||||||
assert(l.front == values[0]);
|
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current item from the list and removes from the list.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* x = The item should be removed.
|
|
||||||
*
|
|
||||||
* Returns: Removed item.
|
|
||||||
*/
|
|
||||||
T remove()
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
auto temp = position.next.next;
|
|
||||||
auto content = position.next.content;
|
|
||||||
|
|
||||||
dispose(allocator, position.next);
|
|
||||||
position.next = temp;
|
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
auto l = make!(SList!int)(theAllocator);
|
||||||
int[3] values = [8, 5, 4];
|
|
||||||
|
|
||||||
l.front = values[0];
|
l.insertFront(8);
|
||||||
l.front = values[1];
|
l.insertFront(9);
|
||||||
assert(l.remove() == 5);
|
assert(l.front == 9);
|
||||||
l.front = values[2];
|
l.popFront();
|
||||||
assert(l.remove() == 4);
|
assert(l.front == 8);
|
||||||
assert(l.remove() == 8);
|
|
||||||
assert(l.empty);
|
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
dispose(theAllocator, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the current position.
|
* Removes $(D_PARAM howMany) elements from the list.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD this).
|
* Unlike $(D_PSYMBOL popFront()), this method doesn't fail, if it could not
|
||||||
*/
|
* remove $(D_PARAM howMany) elements. Instead, if $(D_PARAM howMany) is
|
||||||
typeof(this) reset()
|
* greater than the list length, all elements are removed.
|
||||||
{
|
*
|
||||||
position = &first;
|
* Params:
|
||||||
return this;
|
* howMany = How many elements should be removed.
|
||||||
}
|
*
|
||||||
|
* Returns: The number of elements removed.
|
||||||
|
*/
|
||||||
|
size_t removeFront(in size_t howMany = 1)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (; i < howMany && !empty; ++i)
|
||||||
|
{
|
||||||
|
popFront();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
alias remove = removeFront;
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
auto l = make!(SList!int)(theAllocator);
|
||||||
int[2] values = [8, 5];
|
|
||||||
|
|
||||||
l.current = values[0];
|
l.insertFront(8);
|
||||||
l.current = values[1];
|
l.insertFront(5);
|
||||||
assert(l.current == 5);
|
l.insertFront(4);
|
||||||
l.advance();
|
assert(l.removeFront(0) == 0);
|
||||||
assert(l.current == 8);
|
assert(l.removeFront(2) == 2);
|
||||||
l.reset();
|
assert(l.removeFront(3) == 1);
|
||||||
assert(l.current == 5);
|
assert(l.removeFront(3) == 0);
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
dispose(theAllocator, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,134 +198,55 @@ class SList(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* dg = $(D_KEYWORD foreach) body.
|
* dg = $(D_KEYWORD foreach) body.
|
||||||
*/
|
*/
|
||||||
int opApply(int delegate(ref size_t i, ref T) dg)
|
int opApply(scope int delegate(ref size_t i, ref T) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (position = first.next; position; position = position.next, ++i)
|
for (auto pos = first.next; pos; pos = pos.next, ++i)
|
||||||
{
|
{
|
||||||
result = dg(i, position.content);
|
result = dg(i, pos.content);
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reset();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
|
||||||
int[3] values = [5, 4, 9];
|
|
||||||
|
|
||||||
l.front = values[0];
|
|
||||||
l.front = values[1];
|
|
||||||
l.front = values[2];
|
|
||||||
foreach (i, e; l)
|
|
||||||
{
|
|
||||||
assert(i != 0 || e == values[2]);
|
|
||||||
assert(i != 1 || e == values[1]);
|
|
||||||
assert(i != 2 || e == values[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
int opApply(int delegate(ref T) dg)
|
int opApply(scope int delegate(ref T) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
for (position = first.next; position; position = position.next)
|
for (auto pos = first.next; pos; pos = pos.next)
|
||||||
{
|
{
|
||||||
result = dg(position.content);
|
result = dg(pos.content);
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reset();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto l = make!(SList!int)(defaultAllocator);
|
auto l = make!(SList!int)(theAllocator);
|
||||||
int[3] values = [5, 4, 9];
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
l.front = values[0];
|
l.insertFront(5);
|
||||||
l.front = values[1];
|
l.insertFront(4);
|
||||||
l.front = values[2];
|
l.insertFront(9);
|
||||||
foreach (e; l)
|
foreach (i, e; l)
|
||||||
{
|
{
|
||||||
assert(i != 0 || e == values[2]);
|
assert(i != 0 || e == 9);
|
||||||
assert(i != 1 || e == values[1]);
|
assert(i != 1 || e == 4);
|
||||||
assert(i != 2 || e == values[0]);
|
assert(i != 2 || e == 5);
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
|
dispose(theAllocator, l);
|
||||||
dispose(defaultAllocator, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: $(D_KEYWORD true) if the current position is the end position.
|
|
||||||
*/
|
|
||||||
@property bool end() const
|
|
||||||
{
|
|
||||||
return empty || position.next.next is null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves to the next element and returns it.
|
|
||||||
*
|
|
||||||
* Returns: The element on the next position.
|
|
||||||
*/
|
|
||||||
T advance()
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(!end);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
position = position.next;
|
|
||||||
return position.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: Element on the current position.
|
|
||||||
*/
|
|
||||||
@property ref T current()
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
return position.next.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a new element at the current position.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* x = New element.
|
|
||||||
*/
|
|
||||||
@property void current(T x)
|
|
||||||
{
|
|
||||||
Entry* temp = make!Entry(allocator);
|
|
||||||
|
|
||||||
temp.content = x;
|
|
||||||
temp.next = position.next;
|
|
||||||
position.next = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -385,20 +264,38 @@ class SList(T)
|
|||||||
/// 0th element of the list.
|
/// 0th element of the list.
|
||||||
protected Entry first;
|
protected Entry first;
|
||||||
|
|
||||||
/// Current position in the list.
|
/// Allocator.
|
||||||
protected Entry* position;
|
protected IAllocator allocator;
|
||||||
|
|
||||||
private shared Allocator allocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Stuff
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto l = make!(SList!Stuff)(defaultAllocator);
|
auto l = make!(SList!int)(theAllocator);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
dispose(defaultAllocator, l);
|
l.insertFront(5);
|
||||||
|
l.insertFront(4);
|
||||||
|
l.insertFront(9);
|
||||||
|
foreach (e; l)
|
||||||
|
{
|
||||||
|
assert(i != 0 || e == 9);
|
||||||
|
assert(i != 1 || e == 4);
|
||||||
|
assert(i != 2 || e == 5);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
assert(i == 3);
|
||||||
|
|
||||||
|
dispose(theAllocator, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
private unittest
|
||||||
|
{
|
||||||
|
interface Stuff
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
auto l = make!(SList!Stuff)(theAllocator);
|
||||||
|
|
||||||
|
dispose(theAllocator, l);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container;
|
module tanya.container;
|
||||||
|
|
||||||
|
public import tanya.container.bit;
|
||||||
public import tanya.container.buffer;
|
public import tanya.container.buffer;
|
||||||
public import tanya.container.list;
|
public import tanya.container.list;
|
||||||
public import tanya.container.vector;
|
public import tanya.container.vector;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Copyright: Eugene Wissner 2016.
|
* Copyright: Eugene Wissner 2016.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
||||||
*/
|
*/
|
||||||
module tanya.container.queue;
|
module tanya.container.queue;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ class Queue(T)
|
|||||||
* allocator = The allocator should be used for the element
|
* allocator = The allocator should be used for the element
|
||||||
* allocations.
|
* allocations.
|
||||||
*/
|
*/
|
||||||
this(shared Allocator allocator = defaultAllocator)
|
this(IAllocator allocator = theAllocator)
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
}
|
}
|
||||||
@ -37,19 +37,38 @@ class Queue(T)
|
|||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
foreach (e; this)
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements from the queue.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
while (!empty)
|
||||||
{
|
{
|
||||||
static if (isFinalizable!T)
|
popFront();
|
||||||
{
|
|
||||||
dispose(allocator, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto q = theAllocator.make!(Queue!int);
|
||||||
|
|
||||||
|
assert(q.empty);
|
||||||
|
q.insertBack(8);
|
||||||
|
q.insertBack(9);
|
||||||
|
q.clear();
|
||||||
|
assert(q.empty);
|
||||||
|
|
||||||
|
theAllocator.dispose(q);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: First element.
|
* Returns: First element.
|
||||||
*/
|
*/
|
||||||
@property ref T front()
|
@property ref inout(T) front() inout
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -64,10 +83,8 @@ class Queue(T)
|
|||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* x = New element.
|
* x = New element.
|
||||||
*
|
|
||||||
* Returns: $(D_KEYWORD this).
|
|
||||||
*/
|
*/
|
||||||
typeof(this) insertBack(T x)
|
void insertBack(T x)
|
||||||
{
|
{
|
||||||
Entry* temp = make!Entry(allocator);
|
Entry* temp = make!Entry(allocator);
|
||||||
|
|
||||||
@ -82,60 +99,29 @@ class Queue(T)
|
|||||||
rear.next = temp;
|
rear.next = temp;
|
||||||
rear = rear.next;
|
rear = rear.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
alias insert = insertBack;
|
alias insert = insertBack;
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto q = make!(Queue!int)(defaultAllocator);
|
auto q = make!(Queue!int)(theAllocator);
|
||||||
int[2] values = [8, 9];
|
|
||||||
|
|
||||||
q.insertBack(values[0]);
|
|
||||||
assert(q.front is values[0]);
|
|
||||||
q.insertBack(values[1]);
|
|
||||||
assert(q.front is values[0]);
|
|
||||||
|
|
||||||
dispose(defaultAllocator, q);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a new element.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* x = New element.
|
|
||||||
*
|
|
||||||
* Returns: $(D_KEYWORD this).
|
|
||||||
*/
|
|
||||||
typeof(this) opOpAssign(string Op)(ref T x)
|
|
||||||
if (Op == "~")
|
|
||||||
{
|
|
||||||
return insertBack(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
auto q = make!(Queue!int)(defaultAllocator);
|
|
||||||
int value = 5;
|
|
||||||
|
|
||||||
assert(q.empty);
|
assert(q.empty);
|
||||||
|
q.insertBack(8);
|
||||||
|
assert(q.front == 8);
|
||||||
|
q.insertBack(9);
|
||||||
|
assert(q.front == 8);
|
||||||
|
|
||||||
q ~= value;
|
dispose(theAllocator, q);
|
||||||
|
|
||||||
assert(q.front == value);
|
|
||||||
assert(!q.empty);
|
|
||||||
|
|
||||||
dispose(defaultAllocator, q);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: $(D_KEYWORD true) if the queue is empty.
|
* Returns: $(D_KEYWORD true) if the queue is empty.
|
||||||
*/
|
*/
|
||||||
@property bool empty() const @safe pure nothrow
|
@property bool empty() inout const
|
||||||
{
|
{
|
||||||
return first.next is null;
|
return first.next is null;
|
||||||
}
|
}
|
||||||
@ -143,22 +129,20 @@ class Queue(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto q = make!(Queue!int)(defaultAllocator);
|
auto q = make!(Queue!int)(theAllocator);
|
||||||
int value = 7;
|
int value = 7;
|
||||||
|
|
||||||
assert(q.empty);
|
assert(q.empty);
|
||||||
q.insertBack(value);
|
q.insertBack(value);
|
||||||
assert(!q.empty);
|
assert(!q.empty);
|
||||||
|
|
||||||
dispose(defaultAllocator, q);
|
dispose(theAllocator, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move position to the next element.
|
* Move the position to the next element.
|
||||||
*
|
|
||||||
* Returns: $(D_KEYWORD this).
|
|
||||||
*/
|
*/
|
||||||
typeof(this) popFront()
|
void popFront()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -169,23 +153,93 @@ class Queue(T)
|
|||||||
|
|
||||||
dispose(allocator, first.next);
|
dispose(allocator, first.next);
|
||||||
first.next = n;
|
first.next = n;
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto q = make!(Queue!int)(defaultAllocator);
|
auto q = make!(Queue!int)(theAllocator);
|
||||||
int[2] values = [8, 9];
|
|
||||||
|
|
||||||
q.insertBack(values[0]);
|
q.insertBack(8);
|
||||||
q.insertBack(values[1]);
|
q.insertBack(9);
|
||||||
assert(q.front is values[0]);
|
assert(q.front == 8);
|
||||||
q.popFront();
|
q.popFront();
|
||||||
assert(q.front is values[1]);
|
assert(q.front == 9);
|
||||||
|
|
||||||
dispose(defaultAllocator, q);
|
dispose(theAllocator, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $(D_KEYWORD foreach) iteration.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* dg = $(D_KEYWORD foreach) body.
|
||||||
|
*/
|
||||||
|
int opApply(scope int delegate(ref size_t i, ref T) dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
for (size_t i = 0; !empty; ++i)
|
||||||
|
{
|
||||||
|
if ((result = dg(i, front)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
popFront();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
int opApply(scope int delegate(ref T) dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
while (!empty)
|
||||||
|
{
|
||||||
|
if ((result = dg(front)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
popFront();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto q = theAllocator.make!(Queue!int);
|
||||||
|
|
||||||
|
size_t j;
|
||||||
|
q.insertBack(5);
|
||||||
|
q.insertBack(4);
|
||||||
|
q.insertBack(9);
|
||||||
|
foreach (i, e; q)
|
||||||
|
{
|
||||||
|
assert(i != 2 || e == 9);
|
||||||
|
assert(i != 1 || e == 4);
|
||||||
|
assert(i != 0 || e == 5);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
assert(j == 3);
|
||||||
|
assert(q.empty);
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
q.insertBack(5);
|
||||||
|
q.insertBack(4);
|
||||||
|
q.insertBack(9);
|
||||||
|
foreach (e; q)
|
||||||
|
{
|
||||||
|
assert(j != 2 || e == 9);
|
||||||
|
assert(j != 1 || e == 4);
|
||||||
|
assert(j != 0 || e == 5);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
assert(j == 3);
|
||||||
|
assert(q.empty);
|
||||||
|
|
||||||
|
dispose(theAllocator, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,13 +260,33 @@ class Queue(T)
|
|||||||
/// The last element of the list.
|
/// The last element of the list.
|
||||||
protected Entry* rear;
|
protected Entry* rear;
|
||||||
|
|
||||||
private shared Allocator allocator;
|
/// The allocator.
|
||||||
|
protected IAllocator allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto q = make!(Queue!int)(defaultAllocator);
|
auto q = theAllocator.make!(Queue!int);
|
||||||
|
|
||||||
dispose(defaultAllocator, q);
|
q.insertBack(5);
|
||||||
|
assert(!q.empty);
|
||||||
|
|
||||||
|
q.insertBack(4);
|
||||||
|
assert(q.front == 5);
|
||||||
|
|
||||||
|
q.insertBack(9);
|
||||||
|
assert(q.front == 5);
|
||||||
|
|
||||||
|
q.popFront();
|
||||||
|
assert(q.front == 4);
|
||||||
|
|
||||||
|
foreach (i, ref e; q)
|
||||||
|
{
|
||||||
|
assert(i != 0 || e == 4);
|
||||||
|
assert(i != 1 || e == 9);
|
||||||
|
}
|
||||||
|
assert(q.empty);
|
||||||
|
|
||||||
|
theAllocator.dispose(q);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,7 @@ enum PaddingMode
|
|||||||
ubyte[] pad(ref ubyte[] input,
|
ubyte[] pad(ref ubyte[] input,
|
||||||
in PaddingMode mode,
|
in PaddingMode mode,
|
||||||
in ushort blockSize,
|
in ushort blockSize,
|
||||||
shared Allocator allocator = defaultAllocator)
|
IAllocator allocator = theAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(blockSize > 0 && blockSize <= 256);
|
assert(blockSize > 0 && blockSize <= 256);
|
||||||
@ -86,7 +86,7 @@ body
|
|||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
{ // Zeros
|
{ // Zeros
|
||||||
auto input = defaultAllocator.makeArray!ubyte(50);
|
auto input = theAllocator.makeArray!ubyte(50);
|
||||||
|
|
||||||
pad(input, PaddingMode.zero, 64);
|
pad(input, PaddingMode.zero, 64);
|
||||||
assert(input.length == 64);
|
assert(input.length == 64);
|
||||||
@ -95,10 +95,10 @@ unittest
|
|||||||
assert(input.length == 64);
|
assert(input.length == 64);
|
||||||
assert(input[63] == 0);
|
assert(input[63] == 0);
|
||||||
|
|
||||||
defaultAllocator.dispose(input);
|
theAllocator.dispose(input);
|
||||||
}
|
}
|
||||||
{ // PKCS#7
|
{ // PKCS#7
|
||||||
auto input = defaultAllocator.makeArray!ubyte(50);
|
auto input = theAllocator.makeArray!ubyte(50);
|
||||||
for (ubyte i; i < 40; ++i)
|
for (ubyte i; i < 40; ++i)
|
||||||
{
|
{
|
||||||
input[i] = i;
|
input[i] = i;
|
||||||
@ -140,10 +140,10 @@ unittest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultAllocator.dispose(input);
|
theAllocator.dispose(input);
|
||||||
}
|
}
|
||||||
{ // ANSI X.923
|
{ // ANSI X.923
|
||||||
auto input = defaultAllocator.makeArray!ubyte(50);
|
auto input = theAllocator.makeArray!ubyte(50);
|
||||||
for (ubyte i; i < 40; ++i)
|
for (ubyte i; i < 40; ++i)
|
||||||
{
|
{
|
||||||
input[i] = i;
|
input[i] = i;
|
||||||
@ -185,7 +185,7 @@ unittest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultAllocator.dispose(input);
|
theAllocator.dispose(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ unittest
|
|||||||
ref ubyte[] unpad(ref ubyte[] input,
|
ref ubyte[] unpad(ref ubyte[] input,
|
||||||
in PaddingMode mode,
|
in PaddingMode mode,
|
||||||
in ushort blockSize,
|
in ushort blockSize,
|
||||||
shared Allocator allocator = defaultAllocator)
|
IAllocator allocator = theAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(input.length != 0);
|
assert(input.length != 0);
|
||||||
@ -231,8 +231,8 @@ body
|
|||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
{ // Zeros
|
{ // Zeros
|
||||||
auto input = defaultAllocator.makeArray!ubyte(50);
|
auto input = theAllocator.makeArray!ubyte(50);
|
||||||
auto inputDup = defaultAllocator.makeArray!ubyte(50);
|
auto inputDup = theAllocator.makeArray!ubyte(50);
|
||||||
|
|
||||||
pad(input, PaddingMode.zero, 64);
|
pad(input, PaddingMode.zero, 64);
|
||||||
pad(inputDup, PaddingMode.zero, 64);
|
pad(inputDup, PaddingMode.zero, 64);
|
||||||
@ -240,13 +240,13 @@ unittest
|
|||||||
unpad(input, PaddingMode.zero, 64);
|
unpad(input, PaddingMode.zero, 64);
|
||||||
assert(input == inputDup);
|
assert(input == inputDup);
|
||||||
|
|
||||||
defaultAllocator.dispose(input);
|
theAllocator.dispose(input);
|
||||||
defaultAllocator.dispose(inputDup);
|
theAllocator.dispose(inputDup);
|
||||||
|
|
||||||
}
|
}
|
||||||
{ // PKCS#7
|
{ // PKCS#7
|
||||||
auto input = defaultAllocator.makeArray!ubyte(50);
|
auto input = theAllocator.makeArray!ubyte(50);
|
||||||
auto inputDup = defaultAllocator.makeArray!ubyte(50);
|
auto inputDup = theAllocator.makeArray!ubyte(50);
|
||||||
for (ubyte i; i < 40; ++i)
|
for (ubyte i; i < 40; ++i)
|
||||||
{
|
{
|
||||||
input[i] = i;
|
input[i] = i;
|
||||||
@ -257,12 +257,12 @@ unittest
|
|||||||
unpad(input, PaddingMode.pkcs7, 64);
|
unpad(input, PaddingMode.pkcs7, 64);
|
||||||
assert(input == inputDup);
|
assert(input == inputDup);
|
||||||
|
|
||||||
defaultAllocator.dispose(input);
|
theAllocator.dispose(input);
|
||||||
defaultAllocator.dispose(inputDup);
|
theAllocator.dispose(inputDup);
|
||||||
}
|
}
|
||||||
{ // ANSI X.923
|
{ // ANSI X.923
|
||||||
auto input = defaultAllocator.makeArray!ubyte(50);
|
auto input = theAllocator.makeArray!ubyte(50);
|
||||||
auto inputDup = defaultAllocator.makeArray!ubyte(50);
|
auto inputDup = theAllocator.makeArray!ubyte(50);
|
||||||
for (ubyte i; i < 40; ++i)
|
for (ubyte i; i < 40; ++i)
|
||||||
{
|
{
|
||||||
input[i] = i;
|
input[i] = i;
|
||||||
@ -273,7 +273,7 @@ unittest
|
|||||||
unpad(input, PaddingMode.pkcs7, 64);
|
unpad(input, PaddingMode.pkcs7, 64);
|
||||||
assert(input == inputDup);
|
assert(input == inputDup);
|
||||||
|
|
||||||
defaultAllocator.dispose(input);
|
theAllocator.dispose(input);
|
||||||
defaultAllocator.dispose(inputDup);
|
theAllocator.dispose(inputDup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
566
source/tanya/math/mp.d
Normal file
566
source/tanya/math/mp.d
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright: Eugene Wissner 2016.
|
||||||
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
|
* Mozilla Public License, v. 2.0).
|
||||||
|
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
||||||
|
*/
|
||||||
|
module tanya.math.mp;
|
||||||
|
|
||||||
|
import std.algorithm.comparison;
|
||||||
|
import std.algorithm.mutation;
|
||||||
|
import std.algorithm.searching;
|
||||||
|
|
||||||
|
struct Integer
|
||||||
|
{
|
||||||
|
private ubyte[] rep;
|
||||||
|
private bool sign;
|
||||||
|
|
||||||
|
this(in uint value)
|
||||||
|
{
|
||||||
|
opAssign(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h = Integer(79);
|
||||||
|
assert(h.length == 1);
|
||||||
|
assert(h.rep[0] == 79);
|
||||||
|
}
|
||||||
|
|
||||||
|
this(in Integer value)
|
||||||
|
{
|
||||||
|
opAssign(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
~this()
|
||||||
|
{
|
||||||
|
destroy(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer opAssign(in uint value)
|
||||||
|
{
|
||||||
|
uint mask, shift;
|
||||||
|
ushort size = 4;
|
||||||
|
|
||||||
|
// Figure out the minimum amount of space this value will take
|
||||||
|
// up in bytes (leave at least one byte, though, if the value is 0).
|
||||||
|
for (mask = 0xff000000; mask > 0x000000ff; mask >>= 8)
|
||||||
|
{
|
||||||
|
if (value & mask)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
rep.length = size;
|
||||||
|
|
||||||
|
// Work backward through the int, masking off each byte
|
||||||
|
// (up to the first 0 byte) and copy it into the internal
|
||||||
|
// representation in big-endian format.
|
||||||
|
mask = 0x00000000ff;
|
||||||
|
shift = 0;
|
||||||
|
for (auto i = size; i; --i)
|
||||||
|
{
|
||||||
|
rep[i - 1] = cast(ubyte) ((value & mask) >> shift);
|
||||||
|
mask <<= 8;
|
||||||
|
shift += 8;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer opAssign(in Integer value)
|
||||||
|
{
|
||||||
|
rep.length = value.length;
|
||||||
|
value.rep.copy(rep);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h = Integer(1019);
|
||||||
|
assert(h.length == 2);
|
||||||
|
assert(h.rep[0] == 0b00000011 && h.rep[1] == 0b11111011);
|
||||||
|
|
||||||
|
h = 3337;
|
||||||
|
assert(h.length == 2);
|
||||||
|
assert(h.rep[0] == 0b00001101 && h.rep[1] == 0b00001001);
|
||||||
|
|
||||||
|
h = 688;
|
||||||
|
assert(h.length == 2);
|
||||||
|
assert(h.rep[0] == 0b00000010 && h.rep[1] == 0b10110000);
|
||||||
|
|
||||||
|
h = 0;
|
||||||
|
assert(h.length == 1);
|
||||||
|
assert(h.rep[0] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property size_t length() const pure nothrow @safe @nogc
|
||||||
|
{
|
||||||
|
return rep.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(in Integer h)
|
||||||
|
{
|
||||||
|
return rep == h.rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare h1 to h2. Return:
|
||||||
|
* a positive number if h1 > h2
|
||||||
|
* a negative number if h1 < h2
|
||||||
|
*/
|
||||||
|
int opCmp(in Integer h)
|
||||||
|
{
|
||||||
|
if (length > h.length)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (length < h.length)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, keep searching through the representational integers
|
||||||
|
// until one is bigger than another - once we've found one, it's
|
||||||
|
// safe to stop, since the lower order bytes can't affect the
|
||||||
|
// comparison
|
||||||
|
int i = 0, j = 0;
|
||||||
|
while (i < length && j < h.length)
|
||||||
|
{
|
||||||
|
if (rep[i] < h.rep[j])
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (rep[i] > h.rep[j])
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
// if we got all the way to the end without a comparison, the
|
||||||
|
// two are equal
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(1019);
|
||||||
|
auto h2 = Integer(1019);
|
||||||
|
assert(h1 == h2);
|
||||||
|
|
||||||
|
h2 = 3337;
|
||||||
|
assert(h1 < h2);
|
||||||
|
|
||||||
|
h2 = 688;
|
||||||
|
assert(h1 > h2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two huges - overwrite h1 with the result.
|
||||||
|
*/
|
||||||
|
Integer opOpAssign(string op)(Integer h)
|
||||||
|
if (op == "+")
|
||||||
|
{
|
||||||
|
uint sum;
|
||||||
|
uint carry = 0;
|
||||||
|
|
||||||
|
// Adding h2 to h1. If h2 is > h1 to begin with, resize h1
|
||||||
|
|
||||||
|
if (h.length > length)
|
||||||
|
{
|
||||||
|
auto tmp = new ubyte[h.length];
|
||||||
|
tmp[h.length - length ..$] = rep[0..length];
|
||||||
|
destroy(rep);
|
||||||
|
rep = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto i = length;
|
||||||
|
auto j = h.length;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
if (j)
|
||||||
|
{
|
||||||
|
--j;
|
||||||
|
sum = rep[i] + h.rep[j] + carry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum = rep[i] + carry;
|
||||||
|
}
|
||||||
|
carry = sum > 0xff;
|
||||||
|
rep[i] = cast(ubyte) sum;
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
|
||||||
|
if (carry)
|
||||||
|
{
|
||||||
|
// Still overflowed; allocate more space
|
||||||
|
ubyte[] tmp = new ubyte[length + 1];
|
||||||
|
tmp[1..$] = rep[0..length];
|
||||||
|
tmp[0] = 0x01;
|
||||||
|
destroy(rep);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer opOpAssign(string op)(Integer h)
|
||||||
|
if (op == "-")
|
||||||
|
{
|
||||||
|
auto i = rep.length;
|
||||||
|
auto j = h.rep.length;
|
||||||
|
uint borrow = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int difference;
|
||||||
|
--i;
|
||||||
|
|
||||||
|
if (j)
|
||||||
|
{
|
||||||
|
--j;
|
||||||
|
difference = rep[i] - h.rep[j] - borrow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
difference = rep[i] - borrow;
|
||||||
|
}
|
||||||
|
borrow = difference < 0;
|
||||||
|
rep[i] = cast(ubyte) difference;
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
|
||||||
|
if (borrow && i)
|
||||||
|
{
|
||||||
|
if (!(rep[i - 1])) // Don't borrow i
|
||||||
|
{
|
||||||
|
throw new Exception("Error, subtraction result is negative\n");
|
||||||
|
}
|
||||||
|
--rep[i - 1];
|
||||||
|
}
|
||||||
|
// Go through the representation array and see how many of the
|
||||||
|
// left-most bytes are unused. Remove them and resize the array.
|
||||||
|
immutable offset = rep.countUntil!(a => a != 0);
|
||||||
|
if (offset > 0)
|
||||||
|
{
|
||||||
|
ubyte[] tmp = rep;
|
||||||
|
rep = new ubyte[rep.length - offset];
|
||||||
|
tmp[offset..$].copy(rep);
|
||||||
|
destroy(tmp);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(4294967295);
|
||||||
|
auto h2 = Integer(4294967295);
|
||||||
|
h1 += h2;
|
||||||
|
|
||||||
|
h2 = 2147483647;
|
||||||
|
h1 -= h2;
|
||||||
|
assert(h1.rep == [0x01, 0x7f, 0xff, 0xff, 0xff]);
|
||||||
|
|
||||||
|
h2 = 4294967294;
|
||||||
|
h1 -= h2;
|
||||||
|
assert(h1.rep == [0x80, 0x00, 0x00, 0x01]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer opOpAssign(string op)(in size_t n)
|
||||||
|
if (op == "<<")
|
||||||
|
{
|
||||||
|
ubyte carry;
|
||||||
|
auto i = rep.length;
|
||||||
|
size_t j;
|
||||||
|
immutable bit = n % 8;
|
||||||
|
immutable delta = 8 - bit;
|
||||||
|
|
||||||
|
if (cast(ubyte) (rep[0] >> delta))
|
||||||
|
{
|
||||||
|
rep.length = rep.length + n / 8 + 1;
|
||||||
|
j = i + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rep.length = rep.length + n / 8;
|
||||||
|
j = i;
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
--j;
|
||||||
|
immutable oldCarry = carry;
|
||||||
|
carry = rep[i] >> delta;
|
||||||
|
rep[j] = cast(ubyte) ((rep[i] << bit) | oldCarry);
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
if (carry)
|
||||||
|
{
|
||||||
|
rep[0] = carry;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(4294967295);
|
||||||
|
h1 <<= 1;
|
||||||
|
assert(h1.rep == [0x01, 0xff, 0xff, 0xff, 0xfe]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer opOpAssign(string op)(in size_t n)
|
||||||
|
if (op == ">>")
|
||||||
|
{
|
||||||
|
immutable step = n / 8;
|
||||||
|
if (step >= rep.length)
|
||||||
|
{
|
||||||
|
rep.length = 1;
|
||||||
|
rep[0] = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i, j;
|
||||||
|
ubyte carry;
|
||||||
|
immutable bit = n % 8;
|
||||||
|
immutable delta = 8 - bit;
|
||||||
|
|
||||||
|
carry = cast(ubyte) (rep[0] << delta);
|
||||||
|
rep[0] = (rep[0] >> bit);
|
||||||
|
if (rep[0])
|
||||||
|
{
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
for (i = 1; i < rep.length; ++i)
|
||||||
|
{
|
||||||
|
immutable oldCarry = carry;
|
||||||
|
carry = cast(ubyte) (rep[i] << delta);
|
||||||
|
rep[j] = (rep[i] >> bit | oldCarry);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
rep.length = max(1, rep.length - n / 8 - (i == j ? 0 : 1));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(4294967294);
|
||||||
|
h1 >>= 10;
|
||||||
|
assert(h1.rep == [0x3f, 0xff, 0xff]);
|
||||||
|
|
||||||
|
h1 = 27336704;
|
||||||
|
h1 >>= 1;
|
||||||
|
assert(h1.rep == [0xd0, 0x90, 0x00]);
|
||||||
|
|
||||||
|
h1 = 4294967294;
|
||||||
|
h1 >>= 20;
|
||||||
|
assert(h1.rep == [0x0f, 0xff]);
|
||||||
|
|
||||||
|
h1 >>= 0;
|
||||||
|
assert(h1.rep == [0x0f, 0xff]);
|
||||||
|
|
||||||
|
h1 >>= 20;
|
||||||
|
assert(h1.rep == [0x00]);
|
||||||
|
|
||||||
|
h1 >>= 2;
|
||||||
|
assert(h1.rep == [0x00]);
|
||||||
|
|
||||||
|
h1 = 1431655765;
|
||||||
|
h1 >>= 16;
|
||||||
|
assert(h1.rep == [0x55, 0x55]);
|
||||||
|
|
||||||
|
h1 >>= 16;
|
||||||
|
assert(h1.rep == [0x00]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply h1 by h2, overwriting the value of h1.
|
||||||
|
*/
|
||||||
|
Integer opOpAssign(string op)(in Integer h)
|
||||||
|
if (op == "*")
|
||||||
|
{
|
||||||
|
ubyte mask;
|
||||||
|
auto i = h.rep.length;
|
||||||
|
auto temp = Integer(this);
|
||||||
|
|
||||||
|
opAssign(0);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
for (mask = 0x01; mask; mask <<= 1)
|
||||||
|
{
|
||||||
|
if (mask & h.rep[i])
|
||||||
|
{
|
||||||
|
opOpAssign!"+"(temp);
|
||||||
|
}
|
||||||
|
temp <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(123);
|
||||||
|
auto h2 = Integer(456);
|
||||||
|
h1 *= h2;
|
||||||
|
assert(h1.rep == [0xdb, 0x18]); // 56088
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* divident = numerator, divisor = denominator
|
||||||
|
*
|
||||||
|
* Note that this process destroys divisor (and, of couse,
|
||||||
|
* overwrites quotient). The divident is the remainder of the
|
||||||
|
* division (if that's important to the caller). The divisor will
|
||||||
|
* be modified by this routine, but it will end up back where it
|
||||||
|
* "started".
|
||||||
|
*/
|
||||||
|
Integer opOpAssign(string op)(in Integer h)
|
||||||
|
if ((op == "/") || (op == "%"))
|
||||||
|
{
|
||||||
|
auto divisor = Integer(h);
|
||||||
|
// "bit_position" keeps track of which bit, of the quotient,
|
||||||
|
// is being set or cleared on the current operation.
|
||||||
|
size_t bit_size;
|
||||||
|
|
||||||
|
// First, left-shift divisor until it's >= than the divident
|
||||||
|
while (opCmp(divisor) > 0)
|
||||||
|
{
|
||||||
|
divisor <<= 1;
|
||||||
|
++bit_size;
|
||||||
|
}
|
||||||
|
static if (op == "/")
|
||||||
|
{
|
||||||
|
auto quotient = new ubyte[bit_size / 8 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bit_position = 8 - (bit_size % 8) - 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (opCmp(divisor) >= 0)
|
||||||
|
{
|
||||||
|
opOpAssign!"-"(divisor);
|
||||||
|
static if (op == "/")
|
||||||
|
{
|
||||||
|
quotient[bit_position / 8] |= (0x80 >> (bit_position % 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit_size)
|
||||||
|
{
|
||||||
|
divisor >>= 1;
|
||||||
|
}
|
||||||
|
++bit_position;
|
||||||
|
}
|
||||||
|
while (bit_size--);
|
||||||
|
|
||||||
|
static if (op == "/")
|
||||||
|
{
|
||||||
|
destroy(rep);
|
||||||
|
rep = quotient;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(18);
|
||||||
|
auto h2 = Integer(4);
|
||||||
|
h1 %= h2;
|
||||||
|
assert(h1.rep == [0x02]);
|
||||||
|
|
||||||
|
h1 = 8;
|
||||||
|
h1 %= h2;
|
||||||
|
assert(h1.rep == [0x00]);
|
||||||
|
|
||||||
|
h1 = 7;
|
||||||
|
h1 %= h2;
|
||||||
|
assert(h1.rep == [0x03]);
|
||||||
|
|
||||||
|
h1 = 56088;
|
||||||
|
h2 = 456;
|
||||||
|
h1 /= h2;
|
||||||
|
assert(h1.rep == [0x7b]); // 123
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer opOpAssign(string op)(in Integer exp)
|
||||||
|
if (op == "^^")
|
||||||
|
{
|
||||||
|
auto i = exp.rep.length;
|
||||||
|
auto tmp1 = Integer(this);
|
||||||
|
Integer tmp2;
|
||||||
|
|
||||||
|
opAssign(1);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
for (ubyte mask = 0x01; mask; mask <<= 1)
|
||||||
|
{
|
||||||
|
if (exp.rep[i] & mask)
|
||||||
|
{
|
||||||
|
opOpAssign!"*"(tmp1);
|
||||||
|
}
|
||||||
|
// Square tmp1
|
||||||
|
tmp2 = tmp1;
|
||||||
|
tmp1 *= tmp2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto h1 = Integer(2);
|
||||||
|
auto h2 = Integer(4);
|
||||||
|
|
||||||
|
h1 ^^= h2;
|
||||||
|
assert(h1.rep == [0x10]);
|
||||||
|
|
||||||
|
h1 = Integer(2342);
|
||||||
|
h1 ^^= h2;
|
||||||
|
assert(h1.rep == [0x1b, 0x5c, 0xab, 0x9c, 0x31, 0x10]);
|
||||||
|
}
|
||||||
|
}
|
@ -8,15 +8,15 @@
|
|||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
||||||
*/
|
*/
|
||||||
module tanya.container.math;
|
module tanya.math;
|
||||||
|
|
||||||
|
public import tanya.math.mp;
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
import std.algorithm.iteration;
|
import std.algorithm.iteration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes $(D_PARAM x) to the power $(D_PARAM y) modulo $(D_PARAM z).
|
* Computes $(D_PARAM x) to the power $(D_PARAM y) modulo $(D_PARAM z).
|
||||||
*
|
*
|
||||||
@ -28,7 +28,7 @@ version (unittest)
|
|||||||
* Returns: Reminder of the division of $(D_PARAM x) to the power $(D_PARAM y)
|
* Returns: Reminder of the division of $(D_PARAM x) to the power $(D_PARAM y)
|
||||||
* by $(D_PARAM z).
|
* by $(D_PARAM z).
|
||||||
*/
|
*/
|
||||||
ulong pow(ulong x, ulong y, ulong z) @safe nothrow pure
|
ulong pow(ulong x, ulong y, ulong z) nothrow pure @safe @nogc
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(z > 0);
|
assert(z > 0);
|
||||||
@ -94,7 +94,7 @@ unittest
|
|||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
*/
|
*/
|
||||||
bool isPseudoprime(ulong x) @safe nothrow pure
|
bool isPseudoprime(ulong x) nothrow pure @safe @nogc
|
||||||
{
|
{
|
||||||
return pow(2, x - 1, x) == 1;
|
return pow(2, x - 1, x) == 1;
|
||||||
}
|
}
|
@ -12,52 +12,127 @@ module tanya.memory.allocator;
|
|||||||
|
|
||||||
import std.experimental.allocator;
|
import std.experimental.allocator;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
import std.typecons;
|
||||||
version (unittest)
|
|
||||||
{
|
|
||||||
import tanya.memory : defaultAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocator interface.
|
* Abstract class implementing a basic allocator.
|
||||||
*/
|
*/
|
||||||
interface Allocator
|
abstract class Allocator : IAllocator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Allocates $(D_PARAM size) bytes of memory.
|
* Not supported.
|
||||||
*
|
*
|
||||||
|
* Returns: $(D_KEYWORD false).
|
||||||
|
*/
|
||||||
|
bool deallocateAll() const @nogc @safe pure nothrow
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported.
|
||||||
|
*
|
||||||
|
* Returns $(D_PSYMBOL Ternary.unknown).
|
||||||
|
*/
|
||||||
|
Ternary empty() const @nogc @safe pure nothrow
|
||||||
|
{
|
||||||
|
return Ternary.unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* b = Memory block.
|
||||||
|
*
|
||||||
|
* Returns: $(D_PSYMBOL Ternary.unknown).
|
||||||
|
*/
|
||||||
|
Ternary owns(void[] b) const @nogc @safe pure nothrow
|
||||||
|
{
|
||||||
|
return Ternary.unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
* Params:
|
||||||
* size = Amount of memory to allocate.
|
* size = Amount of memory to allocate.
|
||||||
*
|
*
|
||||||
* Returns: The pointer to the new allocated memory.
|
* Returns: The good allocation size that guarantees zero internal
|
||||||
|
* fragmentation.
|
||||||
*/
|
*/
|
||||||
void[] allocate(size_t size) shared;
|
size_t goodAllocSize(size_t s)
|
||||||
|
{
|
||||||
|
auto rem = s % alignment;
|
||||||
|
return rem ? s + alignment - rem : s;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocates a memory block.
|
* 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:
|
* Params:
|
||||||
* p = A pointer to the memory block to be freed.
|
* n = Amount of memory to allocate.
|
||||||
|
* a = Alignment.
|
||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* Returns: $(D_KEYWORD null).
|
||||||
*/
|
*/
|
||||||
bool deallocate(void[] p) shared;
|
void[] alignedAllocate(size_t n, uint a) const @nogc @safe pure nothrow
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases or decreases the size of a memory block.
|
* Not supported.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* p = A pointer to the memory block.
|
* n = Amount of memory to allocate.
|
||||||
* size = Size of the reallocated block.
|
* a = Alignment.
|
||||||
*
|
*
|
||||||
* Returns: Whether the reallocation was successful.
|
* Returns: $(D_KEYWORD false).
|
||||||
*/
|
*/
|
||||||
bool reallocate(ref void[] p, size_t size) shared;
|
bool alignedReallocate(ref void[] b, size_t size, uint alignment)
|
||||||
|
const @nogc @safe pure nothrow
|
||||||
/**
|
{
|
||||||
* Returns: The alignment offered.
|
return false;
|
||||||
*/
|
}
|
||||||
@property immutable(uint) alignment() shared const @safe pure nothrow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +145,7 @@ interface Allocator
|
|||||||
* Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
|
* Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
|
||||||
* not be reallocated. In the latter
|
* not be reallocated. In the latter
|
||||||
*/
|
*/
|
||||||
bool resizeArray(T)(shared Allocator allocator,
|
bool resizeArray(T)(IAllocator allocator,
|
||||||
ref T[] array,
|
ref T[] array,
|
||||||
in size_t length)
|
in size_t length)
|
||||||
{
|
{
|
||||||
@ -90,16 +165,16 @@ unittest
|
|||||||
{
|
{
|
||||||
int[] p;
|
int[] p;
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 20);
|
theAllocator.resizeArray(p, 20);
|
||||||
assert(p.length == 20);
|
assert(p.length == 20);
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 30);
|
theAllocator.resizeArray(p, 30);
|
||||||
assert(p.length == 30);
|
assert(p.length == 30);
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 10);
|
theAllocator.resizeArray(p, 10);
|
||||||
assert(p.length == 10);
|
assert(p.length == 10);
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 0);
|
theAllocator.resizeArray(p, 0);
|
||||||
assert(p is null);
|
assert(p is null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,173 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copyright: Eugene Wissner 2016.
|
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
|
||||||
* Mozilla Public License, v. 2.0).
|
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
|
||||||
*/
|
|
||||||
module tanya.memory.mallocator;
|
|
||||||
|
|
||||||
import tanya.memory.allocator;
|
|
||||||
import core.exception;
|
|
||||||
import core.stdc.stdlib;
|
|
||||||
import std.algorithm.comparison;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for malloc/realloc/free from the C standard library.
|
|
||||||
*/
|
|
||||||
class Mallocator : Allocator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 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) shared @nogc nothrow
|
|
||||||
{
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
auto p = malloc(size + psize);
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
{
|
|
||||||
onOutOfMemoryError();
|
|
||||||
}
|
|
||||||
return p[psize.. psize + size];
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@nogc nothrow unittest
|
|
||||||
{
|
|
||||||
auto p = Mallocator.instance.allocate(20);
|
|
||||||
|
|
||||||
assert(p.length == 20);
|
|
||||||
|
|
||||||
Mallocator.instance.deallocate(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deallocates a memory block.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* p = A pointer to the memory block to be freed.
|
|
||||||
*
|
|
||||||
* Returns: Whether the deallocation was successful.
|
|
||||||
*/
|
|
||||||
bool deallocate(void[] p) shared @nogc nothrow
|
|
||||||
{
|
|
||||||
if (p !is null)
|
|
||||||
{
|
|
||||||
free(p.ptr - psize);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@nogc nothrow unittest
|
|
||||||
{
|
|
||||||
void[] p;
|
|
||||||
assert(Mallocator.instance.deallocate(p));
|
|
||||||
|
|
||||||
p = Mallocator.instance.allocate(10);
|
|
||||||
assert(Mallocator.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 @nogc nothrow
|
|
||||||
{
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
deallocate(p);
|
|
||||||
p = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (p is null)
|
|
||||||
{
|
|
||||||
p = allocate(size);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto r = realloc(p.ptr - psize, size + psize);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
{
|
|
||||||
onOutOfMemoryError();
|
|
||||||
}
|
|
||||||
p = r[psize.. psize + size];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@nogc nothrow unittest
|
|
||||||
{
|
|
||||||
void[] p;
|
|
||||||
|
|
||||||
Mallocator.instance.reallocate(p, 20);
|
|
||||||
assert(p.length == 20);
|
|
||||||
|
|
||||||
Mallocator.instance.reallocate(p, 30);
|
|
||||||
assert(p.length == 30);
|
|
||||||
|
|
||||||
Mallocator.instance.reallocate(p, 10);
|
|
||||||
assert(p.length == 10);
|
|
||||||
|
|
||||||
Mallocator.instance.reallocate(p, 0);
|
|
||||||
assert(p is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: The alignment offered.
|
|
||||||
*/
|
|
||||||
@property immutable(uint) alignment() shared const @safe pure nothrow
|
|
||||||
{
|
|
||||||
return cast(uint) max(double.alignof, real.alignof);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static allocator instance and initializer.
|
|
||||||
*
|
|
||||||
* Returns: The global $(D_PSYMBOL Allocator) instance.
|
|
||||||
*/
|
|
||||||
static @property ref shared(Mallocator) instance() @nogc nothrow
|
|
||||||
{
|
|
||||||
if (instance_ is null)
|
|
||||||
{
|
|
||||||
immutable size = __traits(classInstanceSize, Mallocator) + psize;
|
|
||||||
void* p = malloc(size);
|
|
||||||
|
|
||||||
if (p is null)
|
|
||||||
{
|
|
||||||
onOutOfMemoryError();
|
|
||||||
}
|
|
||||||
p[psize..size] = typeid(Mallocator).initializer[];
|
|
||||||
instance_ = cast(shared Mallocator) p[psize..size].ptr;
|
|
||||||
}
|
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@nogc nothrow unittest
|
|
||||||
{
|
|
||||||
assert(instance is instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum psize = 8;
|
|
||||||
|
|
||||||
private shared static Mallocator instance_;
|
|
||||||
}
|
|
@ -83,7 +83,7 @@ class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: The pointer to the new allocated memory.
|
* Returns: The pointer to the new allocated memory.
|
||||||
*/
|
*/
|
||||||
void[] allocate(size_t size) shared @nogc @trusted nothrow
|
void[] allocate(size_t size, TypeInfo ti = null) @nogc @trusted nothrow
|
||||||
{
|
{
|
||||||
if (!size)
|
if (!size)
|
||||||
{
|
{
|
||||||
@ -119,7 +119,7 @@ class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Data the block points to or $(D_KEYWORD null).
|
* Returns: Data the block points to or $(D_KEYWORD null).
|
||||||
*/
|
*/
|
||||||
private void* findBlock(size_t size) shared @nogc nothrow
|
private void* findBlock(size_t size) @nogc nothrow
|
||||||
{
|
{
|
||||||
Block block1;
|
Block block1;
|
||||||
RegionLoop: for (auto r = head; r !is null; r = r.next)
|
RegionLoop: for (auto r = head; r !is null; r = r.next)
|
||||||
@ -177,7 +177,7 @@ class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* Returns: Whether the deallocation was successful.
|
||||||
*/
|
*/
|
||||||
bool deallocate(void[] p) shared @nogc @trusted nothrow
|
bool deallocate(void[] p) @nogc @trusted nothrow
|
||||||
{
|
{
|
||||||
if (p is null)
|
if (p is null)
|
||||||
{
|
{
|
||||||
@ -233,7 +233,7 @@ class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Whether the reallocation was successful.
|
* Returns: Whether the reallocation was successful.
|
||||||
*/
|
*/
|
||||||
bool reallocate(ref void[] p, size_t size) shared @nogc @trusted nothrow
|
bool reallocate(ref void[] p, size_t size) @nogc @trusted nothrow
|
||||||
{
|
{
|
||||||
void[] reallocP;
|
void[] reallocP;
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@nogc @safe nothrow unittest
|
@nogc nothrow unittest
|
||||||
{
|
{
|
||||||
void[] p;
|
void[] p;
|
||||||
MmapPool.instance.reallocate(p, 10 * int.sizeof);
|
MmapPool.instance.reallocate(p, 10 * int.sizeof);
|
||||||
@ -301,7 +301,7 @@ class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Global $(D_PSYMBOL MmapPool) instance.
|
* Returns: Global $(D_PSYMBOL MmapPool) instance.
|
||||||
*/
|
*/
|
||||||
static @property ref shared(MmapPool) instance() @nogc @trusted nothrow
|
static @property ref MmapPool instance() @nogc @trusted nothrow
|
||||||
{
|
{
|
||||||
if (instance_ is null)
|
if (instance_ is null)
|
||||||
{
|
{
|
||||||
@ -312,7 +312,7 @@ class MmapPool : Allocator
|
|||||||
if (data !is null)
|
if (data !is null)
|
||||||
{
|
{
|
||||||
data[0..instanceSize] = typeid(MmapPool).initializer[];
|
data[0..instanceSize] = typeid(MmapPool).initializer[];
|
||||||
instance_ = cast(shared MmapPool) data;
|
instance_ = cast(MmapPool) data;
|
||||||
instance_.head = head;
|
instance_.head = head;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,7 +334,6 @@ class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: A pointer to the data.
|
* Returns: A pointer to the data.
|
||||||
*/
|
*/
|
||||||
pragma(inline)
|
|
||||||
private static void* initializeRegion(size_t size,
|
private static void* initializeRegion(size_t size,
|
||||||
ref Region head) @nogc nothrow
|
ref Region head) @nogc nothrow
|
||||||
{
|
{
|
||||||
@ -409,7 +408,7 @@ class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
private void* initializeRegion(size_t size) shared @nogc nothrow
|
private void* initializeRegion(size_t size) @nogc nothrow
|
||||||
{
|
{
|
||||||
return initializeRegion(size, head);
|
return initializeRegion(size, head);
|
||||||
}
|
}
|
||||||
@ -451,13 +450,13 @@ class MmapPool : Allocator
|
|||||||
return x / pageSize * pageSize + pageSize;
|
return x / pageSize * pageSize + pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property immutable(uint) alignment() shared const @nogc @safe pure nothrow
|
@property uint alignment() const @nogc @safe pure nothrow
|
||||||
{
|
{
|
||||||
return alignment_;
|
return alignment_;
|
||||||
}
|
}
|
||||||
private enum alignment_ = 8;
|
private enum alignment_ = 8;
|
||||||
|
|
||||||
private shared static MmapPool instance_;
|
private static MmapPool instance_;
|
||||||
|
|
||||||
private shared static immutable size_t pageSize;
|
private shared static immutable size_t pageSize;
|
||||||
|
|
||||||
|
@ -10,20 +10,5 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.memory;
|
module tanya.memory;
|
||||||
|
|
||||||
public
|
public import tanya.memory.allocator;
|
||||||
{
|
public import std.experimental.allocator;
|
||||||
import tanya.memory.allocator;
|
|
||||||
import std.experimental.allocator : make, dispose, shrinkArray, expandArray, makeArray, dispose;
|
|
||||||
}
|
|
||||||
|
|
||||||
shared Allocator allocator;
|
|
||||||
|
|
||||||
@property ref shared(Allocator) defaultAllocator()
|
|
||||||
{
|
|
||||||
import tanya.memory.mallocator;
|
|
||||||
if (allocator is null)
|
|
||||||
{
|
|
||||||
allocator = Mallocator.instance;
|
|
||||||
}
|
|
||||||
return allocator;
|
|
||||||
}
|
|
||||||
|
@ -252,7 +252,7 @@ else version (Windows)
|
|||||||
|
|
||||||
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to receive");
|
throw theAllocator.make!SocketException("Unable to receive");
|
||||||
}
|
}
|
||||||
return result == 0;
|
return result == 0;
|
||||||
}
|
}
|
||||||
@ -282,7 +282,7 @@ else version (Windows)
|
|||||||
if (result == FALSE && !wouldHaveBlocked)
|
if (result == FALSE && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
disconnected_ = true;
|
disconnected_ = true;
|
||||||
throw defaultAllocator.make!SocketException("Unable to receive");
|
throw theAllocator.make!SocketException("Unable to receive");
|
||||||
}
|
}
|
||||||
if (lpNumber == 0)
|
if (lpNumber == 0)
|
||||||
{
|
{
|
||||||
@ -324,7 +324,7 @@ else version (Windows)
|
|||||||
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
if (result == SOCKET_ERROR && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
disconnected_ = true;
|
disconnected_ = true;
|
||||||
throw defaultAllocator.make!SocketException("Unable to send");
|
throw theAllocator.make!SocketException("Unable to send");
|
||||||
}
|
}
|
||||||
return result == 0;
|
return result == 0;
|
||||||
}
|
}
|
||||||
@ -354,7 +354,7 @@ else version (Windows)
|
|||||||
if (result == FALSE && !wouldHaveBlocked)
|
if (result == FALSE && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
disconnected_ = true;
|
disconnected_ = true;
|
||||||
throw defaultAllocator.make!SocketException("Unable to receive");
|
throw theAllocator.make!SocketException("Unable to receive");
|
||||||
}
|
}
|
||||||
return lpNumber;
|
return lpNumber;
|
||||||
}
|
}
|
||||||
@ -396,7 +396,7 @@ else version (Windows)
|
|||||||
NULL);
|
NULL);
|
||||||
if (!result == SOCKET_ERROR)
|
if (!result == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to retrieve an accept extension function pointer");
|
throw theAllocator.make!SocketException("Unable to retrieve an accept extension function pointer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +416,7 @@ else version (Windows)
|
|||||||
auto socket = cast(socket_t) socket(addressFamily, SOCK_STREAM, 0);
|
auto socket = cast(socket_t) socket(addressFamily, SOCK_STREAM, 0);
|
||||||
if (socket == socket_t.init)
|
if (socket == socket_t.init)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to create socket");
|
throw theAllocator.make!SocketException("Unable to create socket");
|
||||||
}
|
}
|
||||||
scope (failure)
|
scope (failure)
|
||||||
{
|
{
|
||||||
@ -426,7 +426,7 @@ else version (Windows)
|
|||||||
overlapped.handle = cast(HANDLE) socket;
|
overlapped.handle = cast(HANDLE) socket;
|
||||||
overlapped.event = OverlappedSocketEvent.accept;
|
overlapped.event = OverlappedSocketEvent.accept;
|
||||||
overlapped.buffer.len = (sockaddr_in.sizeof + 16) * 2;
|
overlapped.buffer.len = (sockaddr_in.sizeof + 16) * 2;
|
||||||
overlapped.buffer.buf = defaultAllocator.makeArray!char(overlapped.buffer.len).ptr;
|
overlapped.buffer.buf = theAllocator.makeArray!char(overlapped.buffer.len).ptr;
|
||||||
|
|
||||||
// We don't want to get any data now, but only start to accept the connections
|
// We don't want to get any data now, but only start to accept the connections
|
||||||
BOOL result = acceptExtension(handle_,
|
BOOL result = acceptExtension(handle_,
|
||||||
@ -439,7 +439,7 @@ else version (Windows)
|
|||||||
&overlapped.overlapped);
|
&overlapped.overlapped);
|
||||||
if (result == FALSE && !wouldHaveBlocked)
|
if (result == FALSE && !wouldHaveBlocked)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to accept socket connection");
|
throw theAllocator.make!SocketException("Unable to accept socket connection");
|
||||||
}
|
}
|
||||||
return result == TRUE;
|
return result == TRUE;
|
||||||
}
|
}
|
||||||
@ -459,13 +459,13 @@ else version (Windows)
|
|||||||
{
|
{
|
||||||
scope (exit)
|
scope (exit)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(overlapped.buffer.buf[0..overlapped.buffer.len]);
|
theAllocator.dispose(overlapped.buffer.buf[0..overlapped.buffer.len]);
|
||||||
}
|
}
|
||||||
auto socket = defaultAllocator.make!OverlappedConnectedSocket(cast(socket_t) overlapped.handle,
|
auto socket = theAllocator.make!OverlappedConnectedSocket(cast(socket_t) overlapped.handle,
|
||||||
addressFamily);
|
addressFamily);
|
||||||
scope (failure)
|
scope (failure)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(socket);
|
theAllocator.dispose(socket);
|
||||||
}
|
}
|
||||||
socket.setOption(SocketOptionLevel.SOCKET,
|
socket.setOption(SocketOptionLevel.SOCKET,
|
||||||
cast(SocketOption) SO_UPDATE_ACCEPT_CONTEXT,
|
cast(SocketOption) SO_UPDATE_ACCEPT_CONTEXT,
|
||||||
@ -737,7 +737,7 @@ abstract class Socket
|
|||||||
result.ptr,
|
result.ptr,
|
||||||
&length) == SOCKET_ERROR)
|
&length) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to get socket option");
|
throw theAllocator.make!SocketException("Unable to get socket option");
|
||||||
}
|
}
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -797,7 +797,7 @@ abstract class Socket
|
|||||||
value.ptr,
|
value.ptr,
|
||||||
cast(uint) value.length) == SOCKET_ERROR)
|
cast(uint) value.length) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to set socket option");
|
throw theAllocator.make!SocketException("Unable to set socket option");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -865,7 +865,7 @@ abstract class Socket
|
|||||||
}
|
}
|
||||||
if (fl == SOCKET_ERROR)
|
if (fl == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to set socket blocking");
|
throw theAllocator.make!SocketException("Unable to set socket blocking");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else version (Windows)
|
else version (Windows)
|
||||||
@ -873,7 +873,7 @@ abstract class Socket
|
|||||||
uint num = !yes;
|
uint num = !yes;
|
||||||
if (ioctlsocket(handle_, FIONBIO, &num) == SOCKET_ERROR)
|
if (ioctlsocket(handle_, FIONBIO, &num) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to set socket blocking");
|
throw theAllocator.make!SocketException("Unable to set socket blocking");
|
||||||
}
|
}
|
||||||
blocking_ = yes;
|
blocking_ = yes;
|
||||||
}
|
}
|
||||||
@ -942,7 +942,7 @@ abstract class Socket
|
|||||||
{
|
{
|
||||||
if (.listen(handle_, backlog) == SOCKET_ERROR)
|
if (.listen(handle_, backlog) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to listen on socket");
|
throw theAllocator.make!SocketException("Unable to listen on socket");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,7 +992,7 @@ class StreamSocket : Socket, ConnectionOrientedSocket
|
|||||||
auto handle = cast(socket_t) socket(af, SOCK_STREAM, 0);
|
auto handle = cast(socket_t) socket(af, SOCK_STREAM, 0);
|
||||||
if (handle == socket_t.init)
|
if (handle == socket_t.init)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to create socket");
|
throw theAllocator.make!SocketException("Unable to create socket");
|
||||||
}
|
}
|
||||||
super(handle, af);
|
super(handle, af);
|
||||||
}
|
}
|
||||||
@ -1009,7 +1009,7 @@ class StreamSocket : Socket, ConnectionOrientedSocket
|
|||||||
{
|
{
|
||||||
if (.bind(handle_, address.name, address.length) == SOCKET_ERROR)
|
if (.bind(handle_, address.name, address.length) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!SocketException("Unable to bind socket");
|
throw theAllocator.make!SocketException("Unable to bind socket");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,10 +1048,10 @@ class StreamSocket : Socket, ConnectionOrientedSocket
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
throw defaultAllocator.make!SocketException("Unable to accept socket connection");
|
throw theAllocator.make!SocketException("Unable to accept socket connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newSocket = defaultAllocator.make!ConnectedSocket(sock, addressFamily);
|
auto newSocket = theAllocator.make!ConnectedSocket(sock, addressFamily);
|
||||||
|
|
||||||
version (linux)
|
version (linux)
|
||||||
{ // Blocking mode already set
|
{ // Blocking mode already set
|
||||||
@ -1066,7 +1066,7 @@ class StreamSocket : Socket, ConnectionOrientedSocket
|
|||||||
}
|
}
|
||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(newSocket);
|
theAllocator.dispose(newSocket);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1162,7 +1162,7 @@ class ConnectedSocket : Socket, ConnectionOrientedSocket
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
disconnected_ = true;
|
disconnected_ = true;
|
||||||
throw defaultAllocator.make!SocketException("Unable to receive");
|
throw theAllocator.make!SocketException("Unable to receive");
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1199,7 +1199,7 @@ class ConnectedSocket : Socket, ConnectionOrientedSocket
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
throw defaultAllocator.make!SocketException("Unable to send");
|
throw theAllocator.make!SocketException("Unable to send");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1242,18 +1242,18 @@ class InternetAddress : Address
|
|||||||
{
|
{
|
||||||
if (getaddrinfoPointer is null || freeaddrinfoPointer is null)
|
if (getaddrinfoPointer is null || freeaddrinfoPointer is null)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!AddressException("Address info lookup is not available on this system");
|
throw theAllocator.make!AddressException("Address info lookup is not available on this system");
|
||||||
}
|
}
|
||||||
addrinfo* ai_res;
|
addrinfo* ai_res;
|
||||||
port_ = port;
|
port_ = port;
|
||||||
|
|
||||||
// Make C-string from host.
|
// Make C-string from host.
|
||||||
char[] node = defaultAllocator.makeArray!char(host.length + 1);
|
char[] node = theAllocator.makeArray!char(host.length + 1);
|
||||||
node[0.. $ - 1] = host;
|
node[0.. $ - 1] = host;
|
||||||
node[$ - 1] = '\0';
|
node[$ - 1] = '\0';
|
||||||
scope (exit)
|
scope (exit)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(node);
|
theAllocator.dispose(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert port to a C-string.
|
// Convert port to a C-string.
|
||||||
@ -1278,7 +1278,7 @@ class InternetAddress : Address
|
|||||||
auto ret = getaddrinfoPointer(node.ptr, servicePointer, null, &ai_res);
|
auto ret = getaddrinfoPointer(node.ptr, servicePointer, null, &ai_res);
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!AddressException("Address info lookup failed");
|
throw theAllocator.make!AddressException("Address info lookup failed");
|
||||||
}
|
}
|
||||||
scope (exit)
|
scope (exit)
|
||||||
{
|
{
|
||||||
@ -1292,7 +1292,7 @@ class InternetAddress : Address
|
|||||||
}
|
}
|
||||||
if (ai_res.ai_family != AddressFamily.INET && ai_res.ai_family != AddressFamily.INET6)
|
if (ai_res.ai_family != AddressFamily.INET && ai_res.ai_family != AddressFamily.INET6)
|
||||||
{
|
{
|
||||||
throw defaultAllocator.make!AddressException("Wrong address family");
|
throw theAllocator.make!AddressException("Wrong address family");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1191
source/tanya/network/url.d
Normal file
1191
source/tanya/network/url.d
Normal file
File diff suppressed because it is too large
Load Diff
@ -148,13 +148,13 @@ version (linux)
|
|||||||
/**
|
/**
|
||||||
* Pseudorandom number generator.
|
* Pseudorandom number generator.
|
||||||
* ---
|
* ---
|
||||||
* auto entropy = defaultAllocator.make!Entropy;
|
* auto entropy = theAllocator.make!Entropy;
|
||||||
*
|
*
|
||||||
* ubyte[blockSize] output;
|
* ubyte[blockSize] output;
|
||||||
*
|
*
|
||||||
* output = entropy.random;
|
* output = entropy.random;
|
||||||
*
|
*
|
||||||
* defaultAllocator.finalize(entropy);
|
* theAllocator.finalize(entropy);
|
||||||
* ---
|
* ---
|
||||||
*/
|
*/
|
||||||
class Entropy
|
class Entropy
|
||||||
@ -164,7 +164,7 @@ class Entropy
|
|||||||
|
|
||||||
private ubyte sourceCount_;
|
private ubyte sourceCount_;
|
||||||
|
|
||||||
private shared Allocator allocator;
|
private IAllocator allocator;
|
||||||
|
|
||||||
/// Entropy accumulator.
|
/// Entropy accumulator.
|
||||||
protected SHA!(maxGather * 8, 512) accumulator;
|
protected SHA!(maxGather * 8, 512) accumulator;
|
||||||
@ -175,7 +175,7 @@ class Entropy
|
|||||||
* allocator = Allocator to allocate entropy sources available on the
|
* allocator = Allocator to allocate entropy sources available on the
|
||||||
* system.
|
* system.
|
||||||
*/
|
*/
|
||||||
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
|
this(size_t maxSources = 20, IAllocator allocator = theAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(maxSources > 0 && maxSources <= ubyte.max);
|
assert(maxSources > 0 && maxSources <= ubyte.max);
|
||||||
|
Reference in New Issue
Block a user