14 Commits

23 changed files with 2854 additions and 884 deletions

4
README.md Normal file
View 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.

View File

@ -107,7 +107,7 @@ class EpollLoop : SelectorLoop
{
if (errno != EINTR)
{
throw defaultAllocator.make!BadLoopException();
throw theAllocator.make!BadLoopException();
}
return;
}

View File

@ -101,7 +101,7 @@ class IOCPLoop : Loop
completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
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)
{
MmapPool.instance.dispose(overlapped);
defaultAllocator.dispose(e);
theAllocator.dispose(e);
return false;
}
}
@ -173,7 +173,7 @@ class IOCPLoop : Loop
catch (SocketException e)
{
MmapPool.instance.dispose(overlapped);
defaultAllocator.dispose(e);
theAllocator.dispose(e);
return false;
}
}

View File

@ -127,13 +127,13 @@ else version (DragonFlyBSD)
version (MacBSD):
import dlib.async.event.selector;
import dlib.async.loop;
import dlib.async.transport;
import dlib.async.watcher;
import dlib.memory;
import dlib.memory.mmappool;
import dlib.network.socket;
import tanya.async.event.selector;
import tanya.async.loop;
import tanya.async.transport;
import tanya.async.watcher;
import tanya.memory;
import tanya.memory.mmappool;
import tanya.network.socket;
import core.stdc.errno;
import core.sys.posix.unistd;
import core.sys.posix.sys.time;
@ -250,7 +250,7 @@ class KqueueLoop : SelectorLoop
{
if (errno != EINTR)
{
throw defaultAllocator.make!BadLoopException();
throw theAllocator.make!BadLoopException();
}
return;
}

View File

@ -224,7 +224,7 @@ abstract class SelectorLoop : Loop
}
catch (SocketException e)
{
defaultAllocator.dispose(e);
theAllocator.dispose(e);
break;
}
if (client is null)
@ -235,7 +235,7 @@ abstract class SelectorLoop : Loop
IOWatcher io;
auto transport = MmapPool.instance.make!SelectorStreamTransport(this, client);
if (connections.length >= client.handle)
if (connections.length > client.handle)
{
io = cast(IOWatcher) connections[client.handle];
}

View File

@ -26,7 +26,7 @@
* this.transport = transport;
* }
*
* void disconnected(SocketException exception = null)
* void disconnected(SocketException e = null)
* {
* }
* }
@ -34,6 +34,7 @@
* void main()
* {
* auto address = new InternetAddress("127.0.0.1", cast(ushort) 8192);
*
* version (Windows)
* {
* auto sock = new OverlappedStreamSocket(AddressFamily.INET);
@ -119,17 +120,6 @@ enum Event : uint
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.
*/
@ -274,7 +264,7 @@ abstract class Loop
protected void kill(IOWatcher watcher, SocketException exception)
{
watcher.socket.shutdown();
defaultAllocator.dispose(watcher.socket);
theAllocator.dispose(watcher.socket);
MmapPool.instance.dispose(watcher.transport);
watcher.exception = exception;
swapPendings.insertBack(watcher);

View File

@ -10,10 +10,7 @@
*/
module tanya.async;
public
{
import tanya.async.loop;
import tanya.async.protocol;
import tanya.async.transport;
import tanya.async.watcher;
}
public import tanya.async.loop;
public import tanya.async.protocol;
public import tanya.async.transport;
public import tanya.async.watcher;

View File

@ -174,7 +174,7 @@ class IOWatcher : ConnectionWatcher
*
* Returns: $(D_KEYWORD this).
*/
IOWatcher opCall(StreamTransport transport, Protocol protocol) pure nothrow @safe @nogc
IOWatcher opCall(StreamTransport transport, Protocol protocol) pure nothrow @nogc
in
{
assert(transport !is null);

View File

@ -6,7 +6,7 @@
* 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)
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
*/
module tanya.container.buffer;
@ -131,7 +131,7 @@ class ReadBuffer : Buffer
{
this.minAvailable = minAvailable;
this.blockSize = size;
defaultAllocator.resizeArray!ubyte(buffer_, size);
theAllocator.resizeArray!ubyte(buffer_, size);
}
/**
@ -139,17 +139,17 @@ class ReadBuffer : Buffer
*/
~this()
{
defaultAllocator.dispose(buffer_);
theAllocator.dispose(buffer_);
}
///
unittest
{
auto b = defaultAllocator.make!ReadBuffer;
auto b = theAllocator.make!ReadBuffer;
assert(b.capacity == 8192);
assert(b.length == 0);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**
@ -190,7 +190,7 @@ class ReadBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!ReadBuffer;
auto b = theAllocator.make!ReadBuffer;
size_t numberRead;
// Fills the buffer with values 0..10
@ -202,7 +202,7 @@ class ReadBuffer : Buffer
b.clear();
assert(b.free == b.blockSize);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**
@ -224,7 +224,7 @@ class ReadBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!ReadBuffer;
auto b = theAllocator.make!ReadBuffer;
size_t numberRead;
ubyte[] result;
@ -252,7 +252,7 @@ class ReadBuffer : Buffer
assert(result[10] == 20);
assert(result[14] == 24);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**
@ -294,7 +294,7 @@ class ReadBuffer : Buffer
{
if (capacity - length < minAvailable)
{
defaultAllocator.resizeArray!ubyte(buffer_, capacity + blockSize);
theAllocator.resizeArray!ubyte(buffer_, capacity + blockSize);
}
ring = length_;
return buffer_[length_..$];
@ -304,7 +304,7 @@ class ReadBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!ReadBuffer;
auto b = theAllocator.make!ReadBuffer;
size_t numberRead;
ubyte[] result;
@ -319,7 +319,7 @@ class ReadBuffer : Buffer
b.clear();
assert(b.length == 0);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
}
@ -365,7 +365,7 @@ class WriteBuffer : Buffer
{
blockSize = size;
ring = size - 1;
defaultAllocator.resizeArray!ubyte(buffer_, size);
theAllocator.resizeArray!ubyte(buffer_, size);
}
/**
@ -373,7 +373,7 @@ class WriteBuffer : Buffer
*/
~this()
{
defaultAllocator.dispose(buffer_);
theAllocator.dispose(buffer_);
}
/**
@ -415,7 +415,7 @@ class WriteBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!WriteBuffer(4);
auto b = theAllocator.make!WriteBuffer(4);
ubyte[3] buf = [48, 23, 255];
b ~= buf;
@ -433,7 +433,7 @@ class WriteBuffer : Buffer
b += b.length;
assert(b.length == 0);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**
@ -498,7 +498,7 @@ class WriteBuffer : Buffer
{
auto newSize = end / blockSize * blockSize + blockSize;
defaultAllocator.resizeArray!ubyte(buffer_, newSize);
theAllocator.resizeArray!ubyte(buffer_, newSize);
}
buffer_[position..end] = buffer[start..$];
position = end;
@ -514,7 +514,7 @@ class WriteBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!WriteBuffer(4);
auto b = theAllocator.make!WriteBuffer(4);
ubyte[3] buf = [48, 23, 255];
b ~= buf;
@ -533,9 +533,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);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
b = make!WriteBuffer(defaultAllocator, 2);
b = make!WriteBuffer(theAllocator, 2);
b ~= buf;
assert(b.start == 0);
@ -543,7 +543,7 @@ class WriteBuffer : Buffer
assert(b.ring == 3);
assert(b.position == 3);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**
@ -620,7 +620,7 @@ class WriteBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!WriteBuffer;
auto b = theAllocator.make!WriteBuffer;
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
b ~= buf;
@ -630,7 +630,7 @@ class WriteBuffer : Buffer
b += 4;
assert(b.length == 0);
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**
@ -663,7 +663,7 @@ class WriteBuffer : Buffer
///
unittest
{
auto b = defaultAllocator.make!WriteBuffer(6);
auto b = theAllocator.make!WriteBuffer(6);
ubyte[6] buf = [23, 23, 255, 128, 127, 9];
b ~= buf;
@ -679,7 +679,7 @@ class WriteBuffer : Buffer
assert(b[0..$] == buf[0..6]);
b += b.length;
defaultAllocator.dispose(b);
theAllocator.dispose(b);
}
/**

View File

@ -27,31 +27,47 @@ class SList(T)
* allocator = The allocator should be used for the element
* allocations.
*/
this(shared Allocator allocator = defaultAllocator)
this(IAllocator allocator = theAllocator)
{
this.allocator = allocator;
reset();
}
/**
* Removes all elements from the list.
*/
~this()
{
clear();
}
/**
* Remove all contents from the $(D_PSYMBOL SList).
*/
void clear()
{
while (!empty)
{
static if (isFinalizable!T)
{
dispose(allocator, front);
}
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.
*/
@property ref T front()
@property ref inout(T) front() inout
in
{
assert(!empty);
@ -67,7 +83,7 @@ class SList(T)
* Params:
* x = New element.
*/
@property void front(T x)
void insertFront(T x)
{
Entry* temp = make!Entry(allocator);
@ -76,55 +92,26 @@ class SList(T)
first.next = temp;
}
///
unittest
{
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;
}
/// Ditto.
alias insert = insertFront;
///
unittest
{
auto l = make!(SList!int)(defaultAllocator);
int value = 5;
auto l = make!(SList!int)(theAllocator);
assert(l.empty);
l.insertFront(8);
assert(l.front == 8);
l.insertFront(9);
assert(l.front == 9);
l ~= value;
assert(l.front == value);
assert(!l.empty);
dispose(defaultAllocator, l);
dispose(theAllocator, l);
}
/**
* 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;
}
@ -153,85 +140,56 @@ class SList(T)
///
unittest
{
auto l = make!(SList!int)(defaultAllocator);
int[2] values = [8, 9];
auto l = make!(SList!int)(theAllocator);
l.front = values[0];
l.front = values[1];
assert(l.front == values[1]);
l.insertFront(8);
l.insertFront(9);
assert(l.front == 9);
l.popFront();
assert(l.front == values[0]);
assert(l.front == 8);
dispose(defaultAllocator, l);
dispose(theAllocator, l);
}
/**
* Returns the current item from the list and removes from the list.
* Removes $(D_PARAM howMany) elements from the list.
*
* Unlike $(D_PSYMBOL popFront()), this method doesn't fail, if it could not
* remove $(D_PARAM howMany) elements. Instead, if $(D_PARAM howMany) is
* greater than the list length, all elements are removed.
*
* Params:
* x = The item should be removed.
* howMany = How many elements should be removed.
*
* Returns: Removed item.
* Returns: The number of elements removed.
*/
T remove()
in
size_t removeFront(in size_t howMany = 1)
{
assert(!empty);
}
body
size_t i;
for (; i < howMany && !empty; ++i)
{
auto temp = position.next.next;
auto content = position.next.content;
dispose(allocator, position.next);
position.next = temp;
return content;
popFront();
}
return i;
}
/// Ditto.
alias remove = removeFront;
///
unittest
{
auto l = make!(SList!int)(defaultAllocator);
int[3] values = [8, 5, 4];
auto l = make!(SList!int)(theAllocator);
l.front = values[0];
l.front = values[1];
assert(l.remove() == 5);
l.front = values[2];
assert(l.remove() == 4);
assert(l.remove() == 8);
assert(l.empty);
l.insertFront(8);
l.insertFront(5);
l.insertFront(4);
assert(l.removeFront(0) == 0);
assert(l.removeFront(2) == 2);
assert(l.removeFront(3) == 1);
assert(l.removeFront(3) == 0);
dispose(defaultAllocator, l);
}
/**
* Resets the current position.
*
* Returns: $(D_KEYWORD this).
*/
typeof(this) reset()
{
position = &first;
return this;
}
///
unittest
{
auto l = make!(SList!int)(defaultAllocator);
int[2] values = [8, 5];
l.current = values[0];
l.current = values[1];
assert(l.current == 5);
l.advance();
assert(l.current == 8);
l.reset();
assert(l.current == 5);
dispose(defaultAllocator, l);
dispose(theAllocator, l);
}
/**
@ -240,134 +198,55 @@ class SList(T)
* Params:
* 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;
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)
{
return result;
}
}
reset();
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.
int opApply(int delegate(ref T) dg)
int opApply(scope int delegate(ref T) dg)
{
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)
{
return result;
}
}
reset();
return result;
}
///
unittest
{
auto l = make!(SList!int)(defaultAllocator);
int[3] values = [5, 4, 9];
size_t i;
auto l = make!(SList!int)(theAllocator);
l.front = values[0];
l.front = values[1];
l.front = values[2];
foreach (e; l)
l.insertFront(5);
l.insertFront(4);
l.insertFront(9);
foreach (i, e; l)
{
assert(i != 0 || e == values[2]);
assert(i != 1 || e == values[1]);
assert(i != 2 || e == values[0]);
++i;
assert(i != 0 || e == 9);
assert(i != 1 || e == 4);
assert(i != 2 || e == 5);
}
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;
dispose(theAllocator, l);
}
/**
@ -385,20 +264,38 @@ class SList(T)
/// 0th element of the list.
protected Entry first;
/// Current position in the list.
protected Entry* position;
private shared Allocator allocator;
}
interface Stuff
{
/// Allocator.
protected IAllocator allocator;
}
///
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);
}

View File

@ -10,6 +10,7 @@
*/
module tanya.container;
public import tanya.container.bit;
public import tanya.container.buffer;
public import tanya.container.list;
public import tanya.container.vector;

View File

@ -6,7 +6,7 @@
* 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)
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
*/
module tanya.container.queue;
@ -27,7 +27,7 @@ class Queue(T)
* allocator = The allocator should be used for the element
* allocations.
*/
this(shared Allocator allocator = defaultAllocator)
this(IAllocator allocator = theAllocator)
{
this.allocator = allocator;
}
@ -37,19 +37,38 @@ class Queue(T)
*/
~this()
{
foreach (e; this)
clear();
}
/**
* Removes all elements from the queue.
*/
void clear()
{
static if (isFinalizable!T)
while (!empty)
{
dispose(allocator, e);
popFront();
}
}
///
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.
*/
@property ref T front()
@property ref inout(T) front() inout
in
{
assert(!empty);
@ -64,10 +83,8 @@ class Queue(T)
*
* Params:
* x = New element.
*
* Returns: $(D_KEYWORD this).
*/
typeof(this) insertBack(T x)
void insertBack(T x)
{
Entry* temp = make!Entry(allocator);
@ -82,60 +99,29 @@ class Queue(T)
rear.next = temp;
rear = rear.next;
}
return this;
}
/// Ditto.
alias insert = insertBack;
///
unittest
{
auto q = make!(Queue!int)(defaultAllocator);
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;
auto q = make!(Queue!int)(theAllocator);
assert(q.empty);
q.insertBack(8);
assert(q.front == 8);
q.insertBack(9);
assert(q.front == 8);
q ~= value;
assert(q.front == value);
assert(!q.empty);
dispose(defaultAllocator, q);
dispose(theAllocator, q);
}
/**
* 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;
}
@ -143,22 +129,20 @@ class Queue(T)
///
unittest
{
auto q = make!(Queue!int)(defaultAllocator);
auto q = make!(Queue!int)(theAllocator);
int value = 7;
assert(q.empty);
q.insertBack(value);
assert(!q.empty);
dispose(defaultAllocator, q);
dispose(theAllocator, q);
}
/**
* Move position to the next element.
*
* Returns: $(D_KEYWORD this).
* Move the position to the next element.
*/
typeof(this) popFront()
void popFront()
in
{
assert(!empty);
@ -169,23 +153,93 @@ class Queue(T)
dispose(allocator, first.next);
first.next = n;
return this;
}
///
unittest
{
auto q = make!(Queue!int)(defaultAllocator);
int[2] values = [8, 9];
auto q = make!(Queue!int)(theAllocator);
q.insertBack(values[0]);
q.insertBack(values[1]);
assert(q.front is values[0]);
q.insertBack(8);
q.insertBack(9);
assert(q.front == 8);
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.
protected Entry* rear;
private shared Allocator allocator;
/// The allocator.
protected IAllocator allocator;
}
///
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);
}

View File

@ -10,22 +10,12 @@
*/
module tanya.container.vector;
import std.algorithm.comparison;
import std.traits;
import tanya.memory;
/**
* One dimensional array. It allocates automatically if needed.
*
* If you assign a value:
* ---
* auto v = make!(Vector!int)(defaultAllocator);
* int value = 5;
*
* v[1000] = value;
*
* dispose(defaultAllocator, v);
* ---
* it will allocate not only for one, but for 1000 elements. So this
* implementation is more suitable for sequential data with random access.
* One dimensional array.
*
* Params:
* T = Content type.
@ -33,48 +23,262 @@ import tanya.memory;
class Vector(T)
{
/**
* Creates a new $(D_PSYMBOL Vector).
*
* Params:
* length = Initial length.
* allocator = The allocator should be used for the element
* allocations.
* Defines the container's primary range.
*/
this(size_t length, shared Allocator allocator = defaultAllocator)
struct Range(V)
{
this.allocator = allocator;
vector = makeArray!T(allocator, length);
private V[1] data;
private @property ref inout(V) outer() inout
{
return data[0];
}
/// Ditto.
this(shared Allocator allocator = defaultAllocator)
private size_t start, end;
invariant
{
this(0, allocator);
assert(start <= end);
}
private alias ElementType = typeof(data[0].vector[0]);
protected this(V data, in size_t a, in size_t b)
{
this.data = data;
start = a;
end = b;
}
@property Range save()
{
return this;
}
@property bool empty() inout const
{
return start >= end;
}
@property size_t length() inout const
{
return end - start;
}
alias opDollar = length;
@property ref inout(ElementType) front() inout
in
{
assert(!empty);
}
body
{
return outer[start];
}
@property ref inout(ElementType) back() inout
in
{
assert(!empty);
}
body
{
return outer[end - 1];
}
void popFront()
in
{
assert(!empty);
}
body
{
++start;
}
void popBack()
in
{
assert(!empty);
}
body
{
--end;
}
ref inout(ElementType) opIndex(in size_t i) inout
in
{
assert(start + i < end);
}
body
{
return outer[start + i];
}
Range opIndex()
{
return typeof(return)(outer, start, end);
}
Range opSlice(in size_t i, in size_t j)
in
{
assert(i <= j);
assert(start + j <= end);
}
body
{
return typeof(return)(outer, start + i, start + j);
}
Range!(const(V)) opIndex() const
{
return typeof(return)(outer, start, end);
}
Range!(const(V)) opSlice(in size_t i, in size_t j) const
in
{
assert(i <= j);
assert(start + j <= end);
}
body
{
return typeof(return)(outer, start + i, start + j);
}
static if (isMutable!V)
{
Range opIndexAssign(in ElementType value)
in
{
assert(end <= outer.length);
}
body
{
return outer[start .. end] = value;
}
Range opSliceAssign(in ElementType value, in size_t i, in size_t j)
in
{
assert(start + j <= end);
}
body
{
return outer[start + i .. start + j] = value;
}
Range opSliceAssign(in Range!Vector value, in size_t i, in size_t j)
in
{
assert(length == value.length);
}
body
{
return outer[start + i .. start + j] = value;
}
Range opSliceAssign(in T[] value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
}
body
{
return outer[start + i .. start + j] = value;
}
}
}
/**
* Removes all elements from the vector.
* Creates an empty $(D_PSYMBOL Vector).
*
* Params:
* allocator = The allocator should be used for the element
* allocations.
*/
this(IAllocator allocator = theAllocator)
{
this.allocator = allocator;
}
/**
* Creates a new $(D_PSYMBOL Vector).
*
* 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.
*/
this(U...)(U params)
{
static if (isImplicitlyConvertible!(typeof(params[$ - 1]), IAllocator))
{
allocator = params[$ - 1];
auto values = params[0 .. $ - 1];
}
else
{
allocator = theAllocator;
alias values = params;
}
resizeArray!T(allocator, vector, values.length);
foreach (i, v; values)
{
vector[i] = v;
}
}
/**
* Destroys this $(D_PSYMBOL Vector).
*/
~this()
{
dispose(allocator, vector);
}
/**
* Removes all elements.
*/
void clear()
{
resizeArray!T(allocator, vector, 0);
}
///
unittest
{
auto v = theAllocator.make!(Vector!int)(18, 20, 15);
v.clear();
assert(v.length == 0);
}
/**
* Returns: Vector length.
*/
@property size_t length() const
@property size_t length() inout const
{
return vector.length;
}
/// Ditto.
size_t opDollar() inout const
{
return length;
}
/**
* Expans/shrinks the vector.
* Expands/shrinks the vector.
*
* Params:
* length = New length.
*/
@property void length(size_t length)
@property void length(in size_t length)
{
resizeArray!T(allocator, vector, length);
}
@ -82,82 +286,114 @@ class Vector(T)
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator);
auto v = theAllocator.make!(Vector!int);
v.length = 5;
assert(v.length == 5);
// TODO
v.length = 7;
assert(v.length == 7);
v.length = 0;
assert(v.length == 0);
dispose(defaultAllocator, v);
}
/**
* Returns: $(D_KEYWORD true) if the vector is empty.
*/
@property bool empty() const
@property bool empty() inout const
{
return length == 0;
}
static if (isFinalizable!T)
{
/**
* Removes an elements from the vector.
*
* Params:
* pos = Element index.
*/
void remove(size_t pos)
{
auto el = vector[pos];
dispose(allocator, el);
}
return vector.length == 0;
}
/**
* Assigns a value. Allocates if needed.
* Removes $(D_PARAM howMany) elements from the vector.
*
* This method doesn't fail if it could not remove $(D_PARAM howMany)
* elements. Instead, if $(D_PARAM howMany) is greater than the vector
* length, all elements are removed.
*
* Params:
* value = Value.
* howMany = How many elements should be removed.
*
* Returns: Assigned value.
* Returns: The number of elements removed
*/
T opIndexAssign(T value, size_t pos)
size_t removeBack(in size_t howMany)
{
if (pos >= length)
immutable toRemove = min(howMany, length);
static if (hasElaborateDestructor!T)
{
resizeArray!T(allocator, vector, pos + 1);
foreach (ref e; vector[$ - toRemove ..$])
{
allocator.dispose(e);
}
return vector[pos] = value;
}
length = length - toRemove;
return toRemove;
}
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator);
int[2] values = [5, 15];
auto v = theAllocator.make!(Vector!int)(5, 18, 17);
assert(v.length == 0);
v[1] = values[0];
assert(v.length == 2);
v[3] = values[0];
assert(v.length == 4);
v[4] = values[1];
assert(v.length == 5);
assert(v.removeBack(0) == 0);
assert(v.removeBack(2) == 2);
assert(v.removeBack(3) == 1);
assert(v.removeBack(3) == 0);
dispose(defaultAllocator, v);
theAllocator.dispose(v);
}
/**
* Returns: The value on index $(D_PARAM pos).
* Assigns a value to the element with the index $(D_PARAM pos).
*
* Params:
* value = Value.
*
* Returns: Assigned value.
*
* Precondition: $(D_INLINECODE length > pos)
*/
ref T opIndex(in size_t pos)
T opIndexAssign(in T value, in size_t pos)
in
{
assert(length > pos);
}
body
{
return vector[pos] = value;
}
/// Ditto.
Range!Vector opIndexAssign(in T value)
{
vector[0..$] = value;
return opIndex();
}
///
unittest
{
auto v1 = theAllocator.make!(Vector!int)(12, 1, 7);
v1[] = 3;
assert(v1[0] == 3);
assert(v1[1] == 3);
assert(v1[2] == 3);
theAllocator.dispose(v1);
}
/**
* Returns: The value on index $(D_PARAM pos).
*
* Precondition: $(D_INLINECODE length > pos)
*/
ref inout(T) opIndex(in size_t pos) inout
in
{
assert(length > pos);
@ -170,19 +406,55 @@ class Vector(T)
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator);
int[2] values = [5, 15];
auto v = theAllocator.make!(Vector!int)(6, 123, 34, 5);
v[1] = values[0];
assert(v[1] is values[0]);
v[3] = values[0];
assert(v[3] is values[0]);
v[4] = values[1];
assert(v[4] is values[1]);
v[0] = values[1];
assert(v[0] is values[1]);
assert(v[0] == 6);
assert(v[1] == 123);
assert(v[2] == 34);
assert(v[3] == 5);
dispose(defaultAllocator, v);
theAllocator.dispose(v);
}
/**
* Comparison for equality.
*
* Params:
* o = The vector to compare with.
*
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise.
*/
override bool opEquals(Object o)
{
auto v = cast(Vector) o;
return v is null ? super.opEquals(o) : vector == v.vector;
}
///
unittest
{
auto v1 = theAllocator.make!(Vector!int);
auto v2 = theAllocator.make!(Vector!int);
assert(v1 == v2);
v1.length = 1;
v2.length = 2;
assert(v1 != v2);
v1.length = 2;
v1[0] = v2[0] = 2;
v1[1] = 3;
v2[1] = 4;
assert(v1 != v2);
v2[1] = 3;
assert(v1 == v2);
theAllocator.dispose(v1);
theAllocator.dispose(v2);
}
/**
@ -191,15 +463,13 @@ class Vector(T)
* Params:
* dg = $(D_KEYWORD foreach) body.
*/
int opApply(int delegate(ref T) dg)
int opApply(scope int delegate(ref T) dg)
{
int result;
foreach (e; vector)
{
result = dg(e);
if (result != 0)
if ((result = dg(e)) != 0)
{
return result;
}
@ -208,15 +478,13 @@ class Vector(T)
}
/// Ditto.
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;
foreach (i, e; vector)
{
result = dg(i, e);
if (result != 0)
if ((result = dg(i, e)) != 0)
{
return result;
}
@ -227,50 +495,89 @@ class Vector(T)
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator, 1);
int[3] values = [5, 15, 8];
auto v = theAllocator.make!(Vector!int)(5, 15, 8);
v[0] = values[0];
v[1] = values[1];
v[2] = values[2];
int i;
foreach (e; v)
size_t i;
foreach (j, ref e; v)
{
assert(i != 0 || e is values[0]);
assert(i != 1 || e is values[1]);
assert(i != 2 || e is values[2]);
++i;
i = j;
}
assert(i == 2);
foreach (j, e; v)
{
assert(j != 0 || e is values[0]);
assert(j != 1 || e is values[1]);
assert(j != 2 || e is values[2]);
assert(j != 0 || e == 5);
assert(j != 1 || e == 15);
assert(j != 2 || e == 8);
}
dispose(defaultAllocator, v);
theAllocator.dispose(v);
}
/**
* Sets the first element. Allocates if the vector is empty.
* $(D_KEYWORD foreach) iteration.
*
* Params:
* x = New element.
* dg = $(D_KEYWORD foreach) body.
*/
@property void front(ref T x)
int opApplyReverse(scope int delegate(ref T) dg)
{
this[0] = x;
int result;
foreach_reverse (e; vector)
{
if ((result = dg(e)) != 0)
{
return result;
}
}
return result;
}
/// Ditto.
int opApplyReverse(scope int delegate(ref size_t i, ref T) dg)
{
int result;
foreach_reverse (i, e; vector)
{
if ((result = dg(i, e)) != 0)
{
return result;
}
}
return result;
}
///
unittest
{
auto v = theAllocator.make!(Vector!int)(5, 15, 8);
size_t i;
foreach_reverse (j, ref e; v)
{
i = j;
}
assert(i == 0);
foreach_reverse (j, e; v)
{
assert(j != 2 || e == 8);
assert(j != 1 || e == 15);
assert(j != 0 || e == 5);
}
theAllocator.dispose(v);
}
/**
* Returns: The first element.
*
* Precondition: $(D_INLINECODE length > 0)
*/
@property ref inout(T) front() inout
in
{
assert(!empty);
assert(vector.length > 0);
}
body
{
@ -280,72 +587,26 @@ class Vector(T)
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator, 1);
int[2] values = [5, 15];
auto v = theAllocator.make!(Vector!int)(5);
v.front = values[0];
assert(v.front == 5);
v.front = values[1];
assert(v.front == 15);
v.length = 2;
v[1] = 15;
assert(v.front == 5);
dispose(defaultAllocator, v);
}
/**
* Move position to the next element.
*
* Returns: $(D_KEYWORD this).
*/
typeof(this) popFront()
in
{
assert(!empty);
}
body
{
vector[0 .. $ - 1] = vector[1..$];
resizeArray(allocator, vector, length - 1);
return this;
}
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator, 1);
int[2] values = [5, 15];
v[0] = values[0];
v[1] = values[1];
assert(v.front is values[0]);
assert(v.length == 2);
v.popFront();
assert(v.front is values[1]);
assert(v.length == 1);
v.popFront();
assert(v.empty);
dispose(defaultAllocator, v);
}
/**
* Sets the last element. Allocates if the vector is empty.
*
* Params:
* x = New element.
*/
@property void back(ref T x)
{
vector[empty ? 0 : $ - 1] = x;
theAllocator.dispose(v);
}
/**
* Returns: The last element.
*
* Precondition: $(D_INLINECODE length > 0)
*/
@property ref inout(T) back() inout
in
{
assert(!empty);
assert(vector.length > 0);
}
body
{
@ -355,63 +616,166 @@ class Vector(T)
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator, 1);
int[2] values = [5, 15];
auto v = theAllocator.make!(Vector!int)(5);
v.back = values[0];
assert(v.back == 5);
v.back = values[1];
v.length = 2;
v[1] = 15;
assert(v.back == 15);
dispose(defaultAllocator, v);
theAllocator.dispose(v);
}
/**
* Move position to the previous element.
*
* Returns: $(D_KEYWORD this).
* Returns: A range that iterates over elements of the container, in
* forward order.
*/
typeof(this) popBack()
Range!Vector opIndex()
{
return typeof(return)(this, 0, length);
}
/// Ditto.
Range!(const Vector) opIndex() const
{
return typeof(return)(this, 0, length);
}
/// Ditto.
Range!(immutable Vector) opIndex() immutable
{
return typeof(return)(this, 0, length);
}
/**
* Params:
* i = Slice start.
* j = Slice end.
*
* Returns: A range that iterates over elements of the container from
* index $(D_PARAM i) up to (excluding) index $(D_PARAM j).
*
* Precondition: $(D_INLINECODE i <= j && j <= length)
*/
Range!Vector opSlice(in size_t i, in size_t j)
in
{
assert(!empty);
assert(i <= j);
assert(j <= length);
}
body
{
resizeArray(allocator, vector, length - 1);
return this;
return typeof(return)(this, i, j);
}
/// Ditto.
Range!(const Vector) opSlice(in size_t i, in size_t j) const
in
{
assert(i <= j);
assert(j <= length);
}
body
{
return typeof(return)(this, i, j);
}
/// Ditto.
Range!(immutable Vector) opSlice(in size_t i, in size_t j) immutable
in
{
assert(i <= j);
assert(j <= length);
}
body
{
return typeof(return)(this, i, j);
}
/**
* Slicing assignment.
*
* Params:
* value = New value.
* i = Slice start.
* j = Slice end.
*
* Returns: Assigned value.
*
* Precondition: $(D_INLINECODE i <= j && j <= length);
* The lenghts of the ranges and slices match.
*/
Range!Vector opSliceAssign(in T value, in size_t i, in size_t j)
in
{
assert(i <= j);
assert(j <= length);
}
body
{
vector[i .. j] = value;
return opSlice(i, j);
}
/// Ditto.
Range!Vector opSliceAssign(in Range!Vector value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
}
body
{
vector[i .. j] = value.outer.vector[value.start .. value.end];
return opSlice(i, j);
}
/// Ditto.
Range!Vector opSliceAssign(in T[] value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
}
body
{
vector[i .. j] = value;
return opSlice(i, j);
}
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator, 1);
int[2] values = [5, 15];
auto v1 = theAllocator.make!(Vector!int)(3, 3, 3);
auto v2 = theAllocator.make!(Vector!int)(1, 2);
v[0] = values[0];
v[1] = values[1];
assert(v.back is values[1]);
assert(v.length == 2);
v.popBack();
assert(v.back is values[0]);
assert(v.length == 1);
v.popBack();
assert(v.empty);
v1[0..2] = 286;
assert(v1[0] == 286);
assert(v1[1] == 286);
assert(v1[2] == 3);
dispose(defaultAllocator, v);
v2[0..$] = v1[1..3];
assert(v2[0] == 286);
assert(v2[1] == 3);
theAllocator.dispose(v2);
theAllocator.dispose(v1);
}
/// Container.
/// Internal representation.
protected T[] vector;
private shared Allocator allocator;
/// The allocator.
protected IAllocator allocator;
}
///
unittest
{
auto v = make!(Vector!int)(defaultAllocator);
auto v = theAllocator.make!(Vector!int)(5, 15, 8);
dispose(defaultAllocator, v);
assert(v.front == 5);
assert(v[1] == 15);
assert(v.back == 8);
theAllocator.dispose(v);
}

View File

@ -44,7 +44,7 @@ enum PaddingMode
ubyte[] pad(ref ubyte[] input,
in PaddingMode mode,
in ushort blockSize,
shared Allocator allocator = defaultAllocator)
IAllocator allocator = theAllocator)
in
{
assert(blockSize > 0 && blockSize <= 256);
@ -86,7 +86,7 @@ body
unittest
{
{ // Zeros
auto input = defaultAllocator.makeArray!ubyte(50);
auto input = theAllocator.makeArray!ubyte(50);
pad(input, PaddingMode.zero, 64);
assert(input.length == 64);
@ -95,10 +95,10 @@ unittest
assert(input.length == 64);
assert(input[63] == 0);
defaultAllocator.dispose(input);
theAllocator.dispose(input);
}
{ // PKCS#7
auto input = defaultAllocator.makeArray!ubyte(50);
auto input = theAllocator.makeArray!ubyte(50);
for (ubyte i; i < 40; ++i)
{
input[i] = i;
@ -140,10 +140,10 @@ unittest
}
}
defaultAllocator.dispose(input);
theAllocator.dispose(input);
}
{ // ANSI X.923
auto input = defaultAllocator.makeArray!ubyte(50);
auto input = theAllocator.makeArray!ubyte(50);
for (ubyte i; i < 40; ++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,
in PaddingMode mode,
in ushort blockSize,
shared Allocator allocator = defaultAllocator)
IAllocator allocator = theAllocator)
in
{
assert(input.length != 0);
@ -231,8 +231,8 @@ body
unittest
{
{ // Zeros
auto input = defaultAllocator.makeArray!ubyte(50);
auto inputDup = defaultAllocator.makeArray!ubyte(50);
auto input = theAllocator.makeArray!ubyte(50);
auto inputDup = theAllocator.makeArray!ubyte(50);
pad(input, PaddingMode.zero, 64);
pad(inputDup, PaddingMode.zero, 64);
@ -240,13 +240,13 @@ unittest
unpad(input, PaddingMode.zero, 64);
assert(input == inputDup);
defaultAllocator.dispose(input);
defaultAllocator.dispose(inputDup);
theAllocator.dispose(input);
theAllocator.dispose(inputDup);
}
{ // PKCS#7
auto input = defaultAllocator.makeArray!ubyte(50);
auto inputDup = defaultAllocator.makeArray!ubyte(50);
auto input = theAllocator.makeArray!ubyte(50);
auto inputDup = theAllocator.makeArray!ubyte(50);
for (ubyte i; i < 40; ++i)
{
input[i] = i;
@ -257,12 +257,12 @@ unittest
unpad(input, PaddingMode.pkcs7, 64);
assert(input == inputDup);
defaultAllocator.dispose(input);
defaultAllocator.dispose(inputDup);
theAllocator.dispose(input);
theAllocator.dispose(inputDup);
}
{ // ANSI X.923
auto input = defaultAllocator.makeArray!ubyte(50);
auto inputDup = defaultAllocator.makeArray!ubyte(50);
auto input = theAllocator.makeArray!ubyte(50);
auto inputDup = theAllocator.makeArray!ubyte(50);
for (ubyte i; i < 40; ++i)
{
input[i] = i;
@ -273,7 +273,7 @@ unittest
unpad(input, PaddingMode.pkcs7, 64);
assert(input == inputDup);
defaultAllocator.dispose(input);
defaultAllocator.dispose(inputDup);
theAllocator.dispose(input);
theAllocator.dispose(inputDup);
}
}

566
source/tanya/math/mp.d Normal file
View 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]);
}
}

View File

@ -8,15 +8,15 @@
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
*/
module tanya.container.math;
module tanya.math;
public import tanya.math.mp;
version (unittest)
{
import std.algorithm.iteration;
}
@nogc:
/**
* 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)
* 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
{
assert(z > 0);
@ -94,7 +94,7 @@ unittest
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
* $(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;
}

View File

@ -12,52 +12,127 @@ module tanya.memory.allocator;
import std.experimental.allocator;
import std.traits;
import std.typecons;
version (unittest)
/**
* Abstract class implementing a basic allocator.
*/
abstract class Allocator : IAllocator
{
import tanya.memory : defaultAllocator;
/**
* Not supported.
*
* Returns: $(D_KEYWORD false).
*/
bool deallocateAll() const @nogc @safe pure nothrow
{
return false;
}
/**
* Allocator interface.
*/
interface Allocator
{
/**
* Allocates $(D_PARAM size) bytes of memory.
* 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:
* 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:
* p = A pointer to the memory block to be freed.
* b = Block to be expanded.
* s = New size.
*
* Returns: Whether the deallocation was successful.
* Returns: $(D_KEYWORD false).
*/
bool deallocate(void[] p) shared;
bool expand(ref void[] b, size_t s) const @nogc @safe pure nothrow
{
return false;
}
/**
* Increases or decreases the size of a memory block.
* Not supported.
*
* Params:
* p = A pointer to the memory block.
* size = Size of the reallocated block.
* n = Amount of memory to allocate.
* a = Alignment.
*
* Returns: Whether the reallocation was successful.
* Returns: $(D_KEYWORD null).
*/
bool reallocate(ref void[] p, size_t size) shared;
void[] alignedAllocate(size_t n, uint a) const @nogc @safe pure nothrow
{
return null;
}
/**
* Returns: The alignment offered.
* Not supported.
*
* Params:
* n = Amount of memory to allocate.
* a = Alignment.
*
* Returns: $(D_KEYWORD false).
*/
@property immutable(uint) alignment() shared const @safe pure nothrow;
bool alignedReallocate(ref void[] b, size_t size, uint alignment)
const @nogc @safe pure nothrow
{
return false;
}
}
/**
@ -70,7 +145,7 @@ interface Allocator
* Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
* not be reallocated. In the latter
*/
bool resizeArray(T)(shared Allocator allocator,
bool resizeArray(T)(IAllocator allocator,
ref T[] array,
in size_t length)
{
@ -90,16 +165,16 @@ unittest
{
int[] p;
defaultAllocator.resizeArray(p, 20);
theAllocator.resizeArray(p, 20);
assert(p.length == 20);
defaultAllocator.resizeArray(p, 30);
theAllocator.resizeArray(p, 30);
assert(p.length == 30);
defaultAllocator.resizeArray(p, 10);
theAllocator.resizeArray(p, 10);
assert(p.length == 10);
defaultAllocator.resizeArray(p, 0);
theAllocator.resizeArray(p, 0);
assert(p is null);
}

View File

@ -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_;
}

View File

@ -83,7 +83,7 @@ class MmapPool : Allocator
*
* 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)
{
@ -119,7 +119,7 @@ class MmapPool : Allocator
*
* 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;
RegionLoop: for (auto r = head; r !is null; r = r.next)
@ -177,7 +177,7 @@ class MmapPool : Allocator
*
* 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)
{
@ -233,7 +233,7 @@ class MmapPool : Allocator
*
* 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;
@ -268,7 +268,7 @@ class MmapPool : Allocator
}
///
@nogc @safe nothrow unittest
@nogc nothrow unittest
{
void[] p;
MmapPool.instance.reallocate(p, 10 * int.sizeof);
@ -301,7 +301,7 @@ class MmapPool : Allocator
*
* 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)
{
@ -312,7 +312,7 @@ class MmapPool : Allocator
if (data !is null)
{
data[0..instanceSize] = typeid(MmapPool).initializer[];
instance_ = cast(shared MmapPool) data;
instance_ = cast(MmapPool) data;
instance_.head = head;
}
}
@ -334,7 +334,6 @@ class MmapPool : Allocator
*
* Returns: A pointer to the data.
*/
pragma(inline)
private static void* initializeRegion(size_t size,
ref Region head) @nogc nothrow
{
@ -409,7 +408,7 @@ class MmapPool : Allocator
}
/// Ditto.
private void* initializeRegion(size_t size) shared @nogc nothrow
private void* initializeRegion(size_t size) @nogc nothrow
{
return initializeRegion(size, head);
}
@ -451,13 +450,13 @@ class MmapPool : Allocator
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_;
}
private enum alignment_ = 8;
private shared static MmapPool instance_;
private static MmapPool instance_;
private shared static immutable size_t pageSize;

View File

@ -10,20 +10,5 @@
*/
module tanya.memory;
public
{
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;
}
public import tanya.memory.allocator;
public import std.experimental.allocator;

View File

@ -252,7 +252,7 @@ else version (Windows)
if (result == SOCKET_ERROR && !wouldHaveBlocked)
{
throw defaultAllocator.make!SocketException("Unable to receive");
throw theAllocator.make!SocketException("Unable to receive");
}
return result == 0;
}
@ -282,7 +282,7 @@ else version (Windows)
if (result == FALSE && !wouldHaveBlocked)
{
disconnected_ = true;
throw defaultAllocator.make!SocketException("Unable to receive");
throw theAllocator.make!SocketException("Unable to receive");
}
if (lpNumber == 0)
{
@ -324,7 +324,7 @@ else version (Windows)
if (result == SOCKET_ERROR && !wouldHaveBlocked)
{
disconnected_ = true;
throw defaultAllocator.make!SocketException("Unable to send");
throw theAllocator.make!SocketException("Unable to send");
}
return result == 0;
}
@ -354,7 +354,7 @@ else version (Windows)
if (result == FALSE && !wouldHaveBlocked)
{
disconnected_ = true;
throw defaultAllocator.make!SocketException("Unable to receive");
throw theAllocator.make!SocketException("Unable to receive");
}
return lpNumber;
}
@ -396,7 +396,7 @@ else version (Windows)
NULL);
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);
if (socket == socket_t.init)
{
throw defaultAllocator.make!SocketException("Unable to create socket");
throw theAllocator.make!SocketException("Unable to create socket");
}
scope (failure)
{
@ -426,7 +426,7 @@ else version (Windows)
overlapped.handle = cast(HANDLE) socket;
overlapped.event = OverlappedSocketEvent.accept;
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
BOOL result = acceptExtension(handle_,
@ -439,7 +439,7 @@ else version (Windows)
&overlapped.overlapped);
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;
}
@ -459,13 +459,13 @@ else version (Windows)
{
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);
scope (failure)
{
defaultAllocator.dispose(socket);
theAllocator.dispose(socket);
}
socket.setOption(SocketOptionLevel.SOCKET,
cast(SocketOption) SO_UPDATE_ACCEPT_CONTEXT,
@ -737,7 +737,7 @@ abstract class Socket
result.ptr,
&length) == SOCKET_ERROR)
{
throw defaultAllocator.make!SocketException("Unable to get socket option");
throw theAllocator.make!SocketException("Unable to get socket option");
}
return length;
}
@ -797,7 +797,7 @@ abstract class Socket
value.ptr,
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)
{
throw defaultAllocator.make!SocketException("Unable to set socket blocking");
throw theAllocator.make!SocketException("Unable to set socket blocking");
}
}
else version (Windows)
@ -873,7 +873,7 @@ abstract class Socket
uint num = !yes;
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;
}
@ -942,7 +942,7 @@ abstract class Socket
{
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);
if (handle == socket_t.init)
{
throw defaultAllocator.make!SocketException("Unable to create socket");
throw theAllocator.make!SocketException("Unable to create socket");
}
super(handle, af);
}
@ -1009,7 +1009,7 @@ class StreamSocket : Socket, ConnectionOrientedSocket
{
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;
}
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)
{ // Blocking mode already set
@ -1066,7 +1066,7 @@ class StreamSocket : Socket, ConnectionOrientedSocket
}
catch (SocketException e)
{
defaultAllocator.dispose(newSocket);
theAllocator.dispose(newSocket);
throw e;
}
}
@ -1162,7 +1162,7 @@ class ConnectedSocket : Socket, ConnectionOrientedSocket
return 0;
}
disconnected_ = true;
throw defaultAllocator.make!SocketException("Unable to receive");
throw theAllocator.make!SocketException("Unable to receive");
}
return ret;
}
@ -1199,7 +1199,7 @@ class ConnectedSocket : Socket, ConnectionOrientedSocket
{
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)
{
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;
port_ = port;
// 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[$ - 1] = '\0';
scope (exit)
{
defaultAllocator.dispose(node);
theAllocator.dispose(node);
}
// Convert port to a C-string.
@ -1278,7 +1278,7 @@ class InternetAddress : Address
auto ret = getaddrinfoPointer(node.ptr, servicePointer, null, &ai_res);
if (ret)
{
throw defaultAllocator.make!AddressException("Address info lookup failed");
throw theAllocator.make!AddressException("Address info lookup failed");
}
scope (exit)
{
@ -1292,7 +1292,7 @@ class InternetAddress : Address
}
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

File diff suppressed because it is too large Load Diff

View File

@ -148,13 +148,13 @@ version (linux)
/**
* Pseudorandom number generator.
* ---
* auto entropy = defaultAllocator.make!Entropy;
* auto entropy = theAllocator.make!Entropy;
*
* ubyte[blockSize] output;
*
* output = entropy.random;
*
* defaultAllocator.finalize(entropy);
* theAllocator.finalize(entropy);
* ---
*/
class Entropy
@ -164,7 +164,7 @@ class Entropy
private ubyte sourceCount_;
private shared Allocator allocator;
private IAllocator allocator;
/// Entropy accumulator.
protected SHA!(maxGather * 8, 512) accumulator;
@ -175,7 +175,7 @@ class Entropy
* allocator = Allocator to allocate entropy sources available on the
* system.
*/
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
this(size_t maxSources = 20, IAllocator allocator = theAllocator)
in
{
assert(maxSources > 0 && maxSources <= ubyte.max);