Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
ab930657b6 | |||
291920b479 | |||
999c9bdb0f | |||
405b6d9f9f | |||
87b74b2542 | |||
d6514cb515 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@
|
|||||||
.dub
|
.dub
|
||||||
__test__*__
|
__test__*__
|
||||||
__test__*__.core
|
__test__*__.core
|
||||||
|
|
||||||
|
/docs/
|
||||||
|
/docs.json
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
[](https://code.dlang.org/packages/tanya)
|
[](https://code.dlang.org/packages/tanya)
|
||||||
[](https://raw.githubusercontent.com/caraus-ecms/tanya/master/LICENSE)
|
[](https://raw.githubusercontent.com/caraus-ecms/tanya/master/LICENSE)
|
||||||
|
|
||||||
Tanya is a general purpose library for D programming language that doesn't
|
Tanya is a general purpose library for D programming language.
|
||||||
rely on the Garbage Collector.
|
|
||||||
|
|
||||||
Its aim is to simplify the manual memory management in D and to provide a
|
Its aim is to simplify the manual memory management in D and to provide a
|
||||||
guarantee with @nogc attribute that there are no hidden allocations on the
|
guarantee with @nogc attribute that there are no hidden allocations on the
|
||||||
@ -36,12 +35,12 @@ helper functions).
|
|||||||
The library is currently under development, but some parts of it can already be
|
The library is currently under development, but some parts of it can already be
|
||||||
used.
|
used.
|
||||||
|
|
||||||
|
`network` and `async` exist for quite some time and could be better tested than
|
||||||
|
other components.
|
||||||
|
|
||||||
Containers were newly reworked and the API won't change significantly, but will
|
Containers were newly reworked and the API won't change significantly, but will
|
||||||
be only extended. The same is true for the `memory` package.
|
be only extended. The same is true for the `memory` package.
|
||||||
|
|
||||||
`network` and `async` packages should be reviewed in the future and the API may
|
|
||||||
change.
|
|
||||||
|
|
||||||
`math` package contains an arbitrary precision integer implementation that has
|
`math` package contains an arbitrary precision integer implementation that has
|
||||||
a stable API (that mostly consists of operator overloads), but still needs
|
a stable API (that mostly consists of operator overloads), but still needs
|
||||||
testing and work on its performance.
|
testing and work on its performance.
|
||||||
|
@ -159,7 +159,7 @@ class EpollLoop : SelectorLoop
|
|||||||
}
|
}
|
||||||
else if (io.output.length)
|
else if (io.output.length)
|
||||||
{
|
{
|
||||||
swapPendings.insertBack(io);
|
swapPendings.enqueue(io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (events[i].events & EPOLLOUT)
|
else if (events[i].events & EPOLLOUT)
|
||||||
|
@ -218,11 +218,11 @@ class IOCPLoop : Loop
|
|||||||
auto transport = MmapPool.instance.make!IOCPStreamTransport(socket);
|
auto transport = MmapPool.instance.make!IOCPStreamTransport(socket);
|
||||||
auto io = MmapPool.instance.make!IOWatcher(transport, connection.protocol);
|
auto io = MmapPool.instance.make!IOWatcher(transport, connection.protocol);
|
||||||
|
|
||||||
connection.incoming.insertBack(io);
|
connection.incoming.enqueue(io);
|
||||||
|
|
||||||
reify(io, EventMask(Event.none), EventMask(Event.read, Event.write));
|
reify(io, EventMask(Event.none), EventMask(Event.read, Event.write));
|
||||||
|
|
||||||
swapPendings.insertBack(connection);
|
swapPendings.enqueue(connection);
|
||||||
listener.beginAccept(overlapped);
|
listener.beginAccept(overlapped);
|
||||||
break;
|
break;
|
||||||
case OverlappedSocketEvent.read:
|
case OverlappedSocketEvent.read:
|
||||||
@ -264,7 +264,7 @@ class IOCPLoop : Loop
|
|||||||
{
|
{
|
||||||
transport.socket.beginReceive(io.output[], overlapped);
|
transport.socket.beginReceive(io.output[], overlapped);
|
||||||
}
|
}
|
||||||
swapPendings.insertBack(io);
|
swapPendings.enqueue(io);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OverlappedSocketEvent.write:
|
case OverlappedSocketEvent.write:
|
||||||
|
@ -271,7 +271,7 @@ class KqueueLoop : SelectorLoop
|
|||||||
}
|
}
|
||||||
else if (io.output.length)
|
else if (io.output.length)
|
||||||
{
|
{
|
||||||
swapPendings.insertBack(io);
|
swapPendings.enqueue(io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (events[i].filter == EVFILT_WRITE)
|
else if (events[i].filter == EVFILT_WRITE)
|
||||||
|
@ -248,12 +248,12 @@ abstract class SelectorLoop : Loop
|
|||||||
}
|
}
|
||||||
|
|
||||||
reify(io, EventMask(Event.none), EventMask(Event.read, Event.write));
|
reify(io, EventMask(Event.none), EventMask(Event.read, Event.write));
|
||||||
connection.incoming.insertBack(io);
|
connection.incoming.enqueue(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connection.incoming.empty)
|
if (!connection.incoming.empty)
|
||||||
{
|
{
|
||||||
swapPendings.insertBack(connection);
|
swapPendings.enqueue(connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,8 +184,10 @@ abstract class Loop
|
|||||||
poll();
|
poll();
|
||||||
|
|
||||||
// Invoke pendings
|
// Invoke pendings
|
||||||
swapPendings.each!((ref p) @nogc => p.invoke());
|
foreach (ref w; *swapPendings)
|
||||||
|
{
|
||||||
|
w.invoke();
|
||||||
|
}
|
||||||
swap(pendings, swapPendings);
|
swap(pendings, swapPendings);
|
||||||
}
|
}
|
||||||
while (!done_);
|
while (!done_);
|
||||||
@ -283,7 +285,7 @@ abstract class Loop
|
|||||||
defaultAllocator.dispose(watcher.socket);
|
defaultAllocator.dispose(watcher.socket);
|
||||||
MmapPool.instance.dispose(watcher.transport);
|
MmapPool.instance.dispose(watcher.transport);
|
||||||
watcher.exception = exception;
|
watcher.exception = exception;
|
||||||
swapPendings.insertBack(watcher);
|
swapPendings.enqueue(watcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -632,7 +632,7 @@ struct WriteBuffer(T = ubyte)
|
|||||||
* written.
|
* written.
|
||||||
*
|
*
|
||||||
* $(D_PSYMBOL opIndex) may return only part of the data. You may need
|
* $(D_PSYMBOL opIndex) may return only part of the data. You may need
|
||||||
* to call it (and set $(D_KEYWORD +=) several times until
|
* to call it and set $(D_KEYWORD +=) several times until
|
||||||
* $(D_PSYMBOL length) is 0. If all the data can be written,
|
* $(D_PSYMBOL length) is 0. If all the data can be written,
|
||||||
* maximally 3 calls are required.
|
* maximally 3 calls are required.
|
||||||
*
|
*
|
||||||
@ -677,7 +677,7 @@ struct WriteBuffer(T = ubyte)
|
|||||||
* written.
|
* written.
|
||||||
*
|
*
|
||||||
* $(D_PSYMBOL opIndex) may return only part of the data. You may need
|
* $(D_PSYMBOL opIndex) may return only part of the data. You may need
|
||||||
* to call it (and set $(D_KEYWORD +=) several times until
|
* to call it and set $(D_KEYWORD +=) several times until
|
||||||
* $(D_PSYMBOL length) is 0. If all the data can be written,
|
* $(D_PSYMBOL length) is 0. If all the data can be written,
|
||||||
* maximally 3 calls are required.
|
* maximally 3 calls are required.
|
||||||
*
|
*
|
||||||
|
@ -10,8 +10,9 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.queue;
|
module tanya.container.queue;
|
||||||
|
|
||||||
import tanya.container.entry;
|
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
import std.algorithm.mutation;
|
||||||
|
import tanya.container.entry;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,32 +28,24 @@ struct Queue(T)
|
|||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
clear();
|
while (!empty)
|
||||||
|
{
|
||||||
|
dequeue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all elements from the queue.
|
* Removes all elements from the queue.
|
||||||
*/
|
*/
|
||||||
|
deprecated
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
while (!empty)
|
while (!empty)
|
||||||
{
|
{
|
||||||
popFront();
|
dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
Queue!int q;
|
|
||||||
|
|
||||||
assert(q.empty);
|
|
||||||
q.insertBack(8);
|
|
||||||
q.insertBack(9);
|
|
||||||
q.clear();
|
|
||||||
assert(q.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns how many elements are in the queue. It iterates through the queue
|
* Returns how many elements are in the queue. It iterates through the queue
|
||||||
* to count the elements.
|
* to count the elements.
|
||||||
@ -75,18 +68,18 @@ struct Queue(T)
|
|||||||
Queue!int q;
|
Queue!int q;
|
||||||
|
|
||||||
assert(q.length == 0);
|
assert(q.length == 0);
|
||||||
q.insertBack(5);
|
q.enqueue(5);
|
||||||
assert(q.length == 1);
|
assert(q.length == 1);
|
||||||
q.insertBack(4);
|
q.enqueue(4);
|
||||||
assert(q.length == 2);
|
assert(q.length == 2);
|
||||||
q.insertBack(9);
|
q.enqueue(9);
|
||||||
assert(q.length == 3);
|
assert(q.length == 3);
|
||||||
|
|
||||||
q.popFront();
|
q.dequeue();
|
||||||
assert(q.length == 2);
|
assert(q.length == 2);
|
||||||
q.popFront();
|
q.dequeue();
|
||||||
assert(q.length == 1);
|
assert(q.length == 1);
|
||||||
q.popFront();
|
q.dequeue();
|
||||||
assert(q.length == 0);
|
assert(q.length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,14 +90,17 @@ struct Queue(T)
|
|||||||
*
|
*
|
||||||
* Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal.
|
* Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal.
|
||||||
*/
|
*/
|
||||||
|
deprecated
|
||||||
int opEquals(ref typeof(this) that);
|
int opEquals(ref typeof(this) that);
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
|
deprecated
|
||||||
int opEquals(typeof(this) that);
|
int opEquals(typeof(this) that);
|
||||||
}
|
}
|
||||||
else static if (!hasMember!(T, "opEquals")
|
else static if (!hasMember!(T, "opEquals")
|
||||||
|| (functionAttributes!(T.opEquals) & FunctionAttribute.const_))
|
|| (functionAttributes!(T.opEquals) & FunctionAttribute.const_))
|
||||||
{
|
{
|
||||||
|
deprecated
|
||||||
bool opEquals(in ref typeof(this) that) const
|
bool opEquals(in ref typeof(this) that) const
|
||||||
{
|
{
|
||||||
const(Entry!T)* i = first.next;
|
const(Entry!T)* i = first.next;
|
||||||
@ -121,7 +117,7 @@ struct Queue(T)
|
|||||||
return i is null && j is null;
|
return i is null && j is null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
deprecated
|
||||||
bool opEquals(in typeof(this) that) const
|
bool opEquals(in typeof(this) that) const
|
||||||
{
|
{
|
||||||
return opEquals(that);
|
return opEquals(that);
|
||||||
@ -129,11 +125,7 @@ struct Queue(T)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/**
|
deprecated
|
||||||
* Compares two queues. Checks if all elements of the both queues are equal.
|
|
||||||
*
|
|
||||||
* Returns: How many elements are in the queue.
|
|
||||||
*/
|
|
||||||
bool opEquals(ref typeof(this) that)
|
bool opEquals(ref typeof(this) that)
|
||||||
{
|
{
|
||||||
Entry!T* i = first.next;
|
Entry!T* i = first.next;
|
||||||
@ -150,46 +142,17 @@ struct Queue(T)
|
|||||||
return i is null && j is null;
|
return i is null && j is null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
deprecated
|
||||||
bool opEquals(typeof(this) that)
|
bool opEquals(typeof(this) that)
|
||||||
{
|
{
|
||||||
return opEquals(that);
|
return opEquals(that);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
Queue!int q1, q2;
|
|
||||||
|
|
||||||
q1.insertBack(5);
|
|
||||||
q1.insertBack(4);
|
|
||||||
q2.insertBack(5);
|
|
||||||
assert(q1 != q2);
|
|
||||||
q2.insertBack(4);
|
|
||||||
assert(q1 == q2);
|
|
||||||
|
|
||||||
q2.popFront();
|
|
||||||
assert(q1 != q2);
|
|
||||||
|
|
||||||
q1.popFront();
|
|
||||||
assert(q1 == q2);
|
|
||||||
|
|
||||||
q1.popFront();
|
|
||||||
q2.popFront();
|
|
||||||
assert(q1 == q2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unittest
|
|
||||||
{
|
|
||||||
static assert(is(Queue!ConstEqualsStruct));
|
|
||||||
static assert(is(Queue!MutableEqualsStruct));
|
|
||||||
static assert(is(Queue!NoEqualsStruct));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: First element.
|
* Returns: First element.
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use dequeue instead.")
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(T) front() inout
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -205,13 +168,12 @@ struct Queue(T)
|
|||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* x = New element.
|
* x = New element.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
void insertBack(ref T x)
|
ref typeof(this) enqueue(ref T x)
|
||||||
{
|
{
|
||||||
auto temp = allocator.make!(Entry!T);
|
auto temp = allocator.make!(Entry!T)(x);
|
||||||
|
|
||||||
temp.content = x;
|
|
||||||
|
|
||||||
if (empty)
|
if (empty)
|
||||||
{
|
{
|
||||||
first.next = rear = temp;
|
first.next = rear = temp;
|
||||||
@ -221,16 +183,20 @@ struct Queue(T)
|
|||||||
rear.next = temp;
|
rear.next = temp;
|
||||||
rear = rear.next;
|
rear = rear.next;
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
void insertBack(T x)
|
ref typeof(this) enqueue(T x)
|
||||||
{
|
{
|
||||||
insertBack(x);
|
return enqueue(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
deprecated("Use enqueue instead.")
|
||||||
alias insert = insertBack;
|
alias insert = enqueue;
|
||||||
|
|
||||||
|
deprecated("Use enqueue instead.")
|
||||||
|
alias insertBack = enqueue;
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
@ -238,10 +204,9 @@ struct Queue(T)
|
|||||||
Queue!int q;
|
Queue!int q;
|
||||||
|
|
||||||
assert(q.empty);
|
assert(q.empty);
|
||||||
q.insertBack(8);
|
q.enqueue(8).enqueue(9);
|
||||||
assert(q.front == 8);
|
assert(q.dequeue() == 8);
|
||||||
q.insertBack(9);
|
assert(q.dequeue() == 9);
|
||||||
assert(q.front == 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -259,14 +224,16 @@ struct Queue(T)
|
|||||||
int value = 7;
|
int value = 7;
|
||||||
|
|
||||||
assert(q.empty);
|
assert(q.empty);
|
||||||
q.insertBack(value);
|
q.enqueue(value);
|
||||||
assert(!q.empty);
|
assert(!q.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the position to the next element.
|
* Move the position to the next element.
|
||||||
|
*
|
||||||
|
* Returns: Dequeued element.
|
||||||
*/
|
*/
|
||||||
void popFront()
|
T dequeue()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -275,21 +242,24 @@ struct Queue(T)
|
|||||||
body
|
body
|
||||||
{
|
{
|
||||||
auto n = first.next.next;
|
auto n = first.next.next;
|
||||||
|
T ret = move(first.next.content);
|
||||||
|
|
||||||
dispose(allocator, first.next);
|
dispose(allocator, first.next);
|
||||||
first.next = n;
|
first.next = n;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deprecated("Use dequeue instead.")
|
||||||
|
alias popFront = dequeue;
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
Queue!int q;
|
Queue!int q;
|
||||||
|
|
||||||
q.insertBack(8);
|
q.enqueue(8).enqueue(9);
|
||||||
q.insertBack(9);
|
assert(q.dequeue() == 8);
|
||||||
assert(q.front == 8);
|
assert(q.dequeue() == 9);
|
||||||
q.popFront();
|
|
||||||
assert(q.front == 9);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,11 +275,11 @@ struct Queue(T)
|
|||||||
|
|
||||||
for (size_t i = 0; !empty; ++i)
|
for (size_t i = 0; !empty; ++i)
|
||||||
{
|
{
|
||||||
if ((result = dg(i, front)) != 0)
|
auto e = dequeue();
|
||||||
|
if ((result = dg(i, e)) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
popFront();
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -321,11 +291,11 @@ struct Queue(T)
|
|||||||
|
|
||||||
while (!empty)
|
while (!empty)
|
||||||
{
|
{
|
||||||
if ((result = dg(front)) != 0)
|
auto e = dequeue();
|
||||||
|
if ((result = dg(e)) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
popFront();
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -336,9 +306,7 @@ struct Queue(T)
|
|||||||
Queue!int q;
|
Queue!int q;
|
||||||
|
|
||||||
size_t j;
|
size_t j;
|
||||||
q.insertBack(5);
|
q.enqueue(5).enqueue(4).enqueue(9);
|
||||||
q.insertBack(4);
|
|
||||||
q.insertBack(9);
|
|
||||||
foreach (i, e; q)
|
foreach (i, e; q)
|
||||||
{
|
{
|
||||||
assert(i != 2 || e == 9);
|
assert(i != 2 || e == 9);
|
||||||
@ -350,9 +318,7 @@ struct Queue(T)
|
|||||||
assert(q.empty);
|
assert(q.empty);
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
q.insertBack(5);
|
q.enqueue(5).enqueue(4).enqueue(9);
|
||||||
q.insertBack(4);
|
|
||||||
q.insertBack(9);
|
|
||||||
foreach (e; q)
|
foreach (e; q)
|
||||||
{
|
{
|
||||||
assert(j != 2 || e == 9);
|
assert(j != 2 || e == 9);
|
||||||
@ -378,17 +344,12 @@ unittest
|
|||||||
{
|
{
|
||||||
Queue!int q;
|
Queue!int q;
|
||||||
|
|
||||||
q.insertBack(5);
|
q.enqueue(5);
|
||||||
assert(!q.empty);
|
assert(!q.empty);
|
||||||
|
|
||||||
q.insertBack(4);
|
q.enqueue(4).enqueue(9);
|
||||||
assert(q.front == 5);
|
|
||||||
|
|
||||||
q.insertBack(9);
|
assert(q.dequeue() == 5);
|
||||||
assert(q.front == 5);
|
|
||||||
|
|
||||||
q.popFront();
|
|
||||||
assert(q.front == 4);
|
|
||||||
|
|
||||||
foreach (i, ref e; q)
|
foreach (i, ref e; q)
|
||||||
{
|
{
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.vector;
|
module tanya.container.vector;
|
||||||
|
|
||||||
import core.stdc.string;
|
import core.checkedint;
|
||||||
import core.exception;
|
import core.exception;
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
|
import std.algorithm.mutation;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
import std.range.primitives;
|
import std.range.primitives;
|
||||||
import std.meta;
|
import std.meta;
|
||||||
@ -271,8 +272,7 @@ private struct Range(E)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Range opSliceAssign(R)(R value, in size_t i, in size_t j)
|
Range opSliceAssign(R)(R value, in size_t i, in size_t j)
|
||||||
if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||||
|| is(R == Vector))
|
|
||||||
{
|
{
|
||||||
return opSliceAssign(value[], i, j);
|
return opSliceAssign(value[], i, j);
|
||||||
}
|
}
|
||||||
@ -297,30 +297,6 @@ struct Vector(T)
|
|||||||
assert(capacity_ == 0 || vector !is null);
|
assert(capacity_ == 0 || vector !is null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserves memory to store len objects and initializes it.
|
|
||||||
// Doesn't change the length.
|
|
||||||
private void initialize(in size_t len)
|
|
||||||
{
|
|
||||||
reserve(len);
|
|
||||||
if (capacity_ < len)
|
|
||||||
{
|
|
||||||
onOutOfMemoryError();
|
|
||||||
}
|
|
||||||
const init = typeid(T).initializer();
|
|
||||||
if (init.ptr)
|
|
||||||
{
|
|
||||||
const T* end = vector + len;
|
|
||||||
for (void* v = vector + length_; v != end; v += init.length)
|
|
||||||
{
|
|
||||||
memcpy(v, init.ptr, init.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(vector + length_, 0, (len - length_) * T.sizeof);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL Vector).
|
* Creates a new $(D_PSYMBOL Vector).
|
||||||
*
|
*
|
||||||
@ -330,16 +306,15 @@ struct Vector(T)
|
|||||||
* to generate a list.
|
* to generate a list.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(R)(auto ref R init, shared Allocator allocator = defaultAllocator)
|
this(R)(auto in ref R init, shared Allocator allocator = defaultAllocator)
|
||||||
if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||||
|| is(R == Vector))
|
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
insertBack(init[]);
|
insertBack(init[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(R)(R init, shared Allocator allocator = defaultAllocator)
|
this(R)(auto in ref R init, shared Allocator allocator = defaultAllocator)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
@ -348,12 +323,78 @@ struct Vector(T)
|
|||||||
insertBack(init);
|
insertBack(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this vector from another one.
|
||||||
|
*
|
||||||
|
* If $(D_PARAM init) is passed by value, it won't be copied, but moved
|
||||||
|
* If the allocator of ($D_PARAM init) matches $(D_PARAM allocator),
|
||||||
|
* $(D_KEYWORD this) will just take the ownership over $(D_PARAM init)'s
|
||||||
|
* storage, otherwise, the storage will be allocated with
|
||||||
|
* $(D_PARAM allocator) and all elements will be moved;
|
||||||
|
* $(D_PARAM init) will be destroyed at the end.
|
||||||
|
*
|
||||||
|
* If $(D_PARAM init) is passed by reference, it will be copied.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* init = Source vector.
|
||||||
|
* allocator = Allocator.
|
||||||
|
*/
|
||||||
|
this(ref Vector init, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
|
{
|
||||||
|
this(allocator);
|
||||||
|
insertBack(init[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
this(Vector init, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
|
{
|
||||||
|
if (allocator is init.allocator)
|
||||||
|
{
|
||||||
|
// Just steal all references and the allocator.
|
||||||
|
this(init.allocator);
|
||||||
|
vector = init.vector;
|
||||||
|
length_ = init.length_;
|
||||||
|
capacity_ = init.capacity_;
|
||||||
|
|
||||||
|
// Reset the source vector, so it can't destroy the moved storage.
|
||||||
|
init.length_ = init.capacity_ = 0;
|
||||||
|
init.vector = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Move each element.
|
||||||
|
this(allocator);
|
||||||
|
reserve(init.length);
|
||||||
|
|
||||||
|
const T* end = vector + init.length;
|
||||||
|
for (T* src = init.vector, dest = vector; dest != end; ++src, ++dest)
|
||||||
|
{
|
||||||
|
moveEmplace(*src, *dest);
|
||||||
|
}
|
||||||
|
length_ = init.length;
|
||||||
|
// Destructor of init should destroy it here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc @safe unittest
|
||||||
|
{
|
||||||
|
auto v1 = Vector!int(IL(1, 2, 3));
|
||||||
|
auto v2 = Vector!int(v1);
|
||||||
|
assert(v1.vector !is v2.vector);
|
||||||
|
assert(v1 == v2);
|
||||||
|
|
||||||
|
auto v3 = Vector!int(Vector!int(IL(1, 2, 3)));
|
||||||
|
assert(v1 == v3);
|
||||||
|
assert(v3.length == 3);
|
||||||
|
assert(v3.capacity == 3);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL Vector).
|
* Creates a new $(D_PSYMBOL Vector).
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* len = Initial length of the vector.
|
* len = Initial length of the vector.
|
||||||
* init = Initial value to fill the vector with.
|
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(size_t len, shared Allocator allocator = defaultAllocator) @trusted
|
this(size_t len, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
@ -365,11 +406,19 @@ struct Vector(T)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initialize(len);
|
reserve(len);
|
||||||
capacity_ = length_ = len;
|
initializeAll(vector[0 .. len]);
|
||||||
|
length_ = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/**
|
||||||
|
* Creates a new $(D_PSYMBOL Vector).
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* len = Initial length of the vector.
|
||||||
|
* init = Initial value to fill the vector with.
|
||||||
|
* allocator = Allocator.
|
||||||
|
*/
|
||||||
this(size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
|
this(size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
@ -379,9 +428,9 @@ struct Vector(T)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initialize(len);
|
reserve(len);
|
||||||
capacity_ = length_ = len;
|
uninitializedFill(vector[0 .. len], init);
|
||||||
opSliceAssign(init, 0, length_);
|
length_ = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
@ -415,6 +464,11 @@ struct Vector(T)
|
|||||||
assert(v[0] == 5 && v[1] == 5 && v[2] == 5);
|
assert(v[0] == 5 && v[1] == 5 && v[2] == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@safe unittest
|
||||||
|
{
|
||||||
|
auto v1 = Vector!int(defaultAllocator);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys this $(D_PSYMBOL Vector).
|
* Destroys this $(D_PSYMBOL Vector).
|
||||||
*/
|
*/
|
||||||
@ -497,7 +551,8 @@ struct Vector(T)
|
|||||||
}
|
}
|
||||||
else if (len > length_)
|
else if (len > length_)
|
||||||
{
|
{
|
||||||
initialize(len);
|
reserve(len);
|
||||||
|
initializeAll(vector[length_ .. len]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -543,13 +598,39 @@ struct Vector(T)
|
|||||||
*/
|
*/
|
||||||
void reserve(in size_t size) @trusted
|
void reserve(in size_t size) @trusted
|
||||||
{
|
{
|
||||||
if (capacity_ < size)
|
if (capacity_ >= size)
|
||||||
{
|
{
|
||||||
void[] buf = vector[0 .. capacity_];
|
return;
|
||||||
allocator.reallocate(buf, size * T.sizeof);
|
|
||||||
vector = cast(T*) buf;
|
|
||||||
capacity_ = size;
|
|
||||||
}
|
}
|
||||||
|
bool overflow;
|
||||||
|
immutable byteSize = mulu(size, T.sizeof, overflow);
|
||||||
|
assert(!overflow);
|
||||||
|
|
||||||
|
void[] buf = vector[0 .. capacity_];
|
||||||
|
if (!allocator.expand(buf, byteSize))
|
||||||
|
{
|
||||||
|
buf = allocator.allocate(byteSize);
|
||||||
|
if (buf is null)
|
||||||
|
{
|
||||||
|
onOutOfMemoryErrorNoGC();
|
||||||
|
}
|
||||||
|
scope (failure)
|
||||||
|
{
|
||||||
|
allocator.deallocate(buf);
|
||||||
|
}
|
||||||
|
const T* end = vector + length_;
|
||||||
|
for (T* src = vector, dest = cast(T*) buf; src != end; ++src, ++dest)
|
||||||
|
{
|
||||||
|
moveEmplace(*src, *dest);
|
||||||
|
static if (hasElaborateDestructor!T)
|
||||||
|
{
|
||||||
|
destroy(*src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allocator.deallocate(vector[0 .. capacity_]);
|
||||||
|
vector = cast(T*) buf;
|
||||||
|
}
|
||||||
|
capacity_ = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -712,10 +793,6 @@ struct Vector(T)
|
|||||||
if (allSatisfy!(ApplyRight!(isImplicitlyConvertible, T), R))
|
if (allSatisfy!(ApplyRight!(isImplicitlyConvertible, T), R))
|
||||||
{
|
{
|
||||||
reserve(length_ + el.length);
|
reserve(length_ + el.length);
|
||||||
if (capacity_ <= length_)
|
|
||||||
{
|
|
||||||
onOutOfMemoryError();
|
|
||||||
}
|
|
||||||
foreach (i; el)
|
foreach (i; el)
|
||||||
{
|
{
|
||||||
emplace(vector + length_, i);
|
emplace(vector + length_, i);
|
||||||
@ -732,11 +809,11 @@ struct Vector(T)
|
|||||||
{
|
{
|
||||||
immutable rLen = walkLength(el);
|
immutable rLen = walkLength(el);
|
||||||
|
|
||||||
initialize(length_ + rLen);
|
reserve(length_ + rLen);
|
||||||
T* pos = vector + length_;
|
T* pos = vector + length_;
|
||||||
foreach (e; el)
|
foreach (e; el)
|
||||||
{
|
{
|
||||||
*pos = e;
|
emplace(pos, e);
|
||||||
++length_, ++pos;
|
++length_, ++pos;
|
||||||
}
|
}
|
||||||
return rLen;
|
return rLen;
|
||||||
@ -892,7 +969,6 @@ struct Vector(T)
|
|||||||
* Comparison for equality.
|
* Comparison for equality.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* R = Right hand side type.
|
|
||||||
* v = The vector to compare with.
|
* v = The vector to compare with.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
|
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
|
||||||
@ -952,7 +1028,16 @@ struct Vector(T)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/**
|
||||||
|
* Comparison for equality.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Right hand side type.
|
||||||
|
* v = The vector to compare with.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
bool opEquals(R)(Range!R v) const @trusted
|
bool opEquals(R)(Range!R v) const @trusted
|
||||||
if (is(Unqual!R == T))
|
if (is(Unqual!R == T))
|
||||||
{
|
{
|
||||||
@ -1239,14 +1324,14 @@ struct Vector(T)
|
|||||||
* Slicing assignment.
|
* Slicing assignment.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* value = New value.
|
* value = New value (single value or input range).
|
||||||
* i = Slice start.
|
* i = Slice start.
|
||||||
* j = Slice end.
|
* j = Slice end.
|
||||||
*
|
*
|
||||||
* Returns: Slice with the assigned part of the vector.
|
* Returns: Slice with the assigned part of the vector.
|
||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE i <= j && j <= length);
|
* Precondition: $(D_INLINECODE i <= j && j <= length);
|
||||||
* The lenghts of the ranges and slices match.
|
* The lenghts of the range and slice match.
|
||||||
*/
|
*/
|
||||||
Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted
|
Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted
|
||||||
in
|
in
|
||||||
@ -1256,11 +1341,7 @@ struct Vector(T)
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
const T* end = vector + j;
|
vector[i .. j].fill(value);
|
||||||
for (T* v = vector + i; v != end; ++v)
|
|
||||||
{
|
|
||||||
*v = value;
|
|
||||||
}
|
|
||||||
return opSlice(i, j);
|
return opSlice(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1277,6 +1358,8 @@ struct Vector(T)
|
|||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
assert(i <= j);
|
||||||
|
assert(j <= length);
|
||||||
assert(j - i == walkLength(value));
|
assert(j - i == walkLength(value));
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
@ -1291,8 +1374,7 @@ struct Vector(T)
|
|||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
|
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
|
||||||
if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||||
|| is(R == Vector))
|
|
||||||
{
|
{
|
||||||
return opSliceAssign(value[], i, j);
|
return opSliceAssign(value[], i, j);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ else version (Windows)
|
|||||||
* block as free and only if all blocks in the region are free, the complete
|
* block as free and only if all blocks in the region are free, the complete
|
||||||
* region is deallocated.
|
* region is deallocated.
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
* | | | | | || | | |
|
* | | | | | || | | |
|
||||||
* | |prev <----------- | || | | |
|
* | |prev <----------- | || | | |
|
||||||
* | R | B | | B | || R | B | |
|
* | R | B | | B | || R | B | |
|
||||||
@ -46,7 +46,7 @@ else version (Windows)
|
|||||||
* | O | K | | K | prev O | K | |
|
* | O | K | | K | prev O | K | |
|
||||||
* | N | -----------> next| || N | | |
|
* | N | -----------> next| || N | | |
|
||||||
* | | | | | || | | |
|
* | | | | | || | | |
|
||||||
* --------------------------------------------------- ------------------------
|
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
*/
|
*/
|
||||||
final class MmapPool : Allocator
|
final class MmapPool : Allocator
|
||||||
{
|
{
|
||||||
|
@ -374,9 +374,10 @@ private unittest
|
|||||||
* object).
|
* object).
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Type of the constructed object.
|
* T = Type of the constructed object.
|
||||||
* A = Types of the arguments to the constructor of $(D_PARAM T).
|
* A = Types of the arguments to the constructor of $(D_PARAM T).
|
||||||
* args = Constructor arguments of $(D_PARAM T).
|
* allocator = Allocator.
|
||||||
|
* args = Constructor arguments of $(D_PARAM T).
|
||||||
*
|
*
|
||||||
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
||||||
*/
|
*/
|
||||||
|
@ -812,7 +812,7 @@ abstract class Socket
|
|||||||
* Params:
|
* Params:
|
||||||
* level = Protocol level at that the option exists.
|
* level = Protocol level at that the option exists.
|
||||||
* option = Option.
|
* option = Option.
|
||||||
* result = Option value.
|
* value = Option value.
|
||||||
*
|
*
|
||||||
* Throws: $(D_PSYMBOL SocketException) on error.
|
* Throws: $(D_PSYMBOL SocketException) on error.
|
||||||
*/
|
*/
|
||||||
|
@ -630,32 +630,31 @@ static this()
|
|||||||
/**
|
/**
|
||||||
* A Unique Resource Locator.
|
* A Unique Resource Locator.
|
||||||
*/
|
*/
|
||||||
struct URL(U = string)
|
struct URL
|
||||||
if (isSomeString!U)
|
|
||||||
{
|
{
|
||||||
/** The URL scheme. */
|
/** The URL scheme. */
|
||||||
U scheme;
|
const(char)[] scheme;
|
||||||
|
|
||||||
/** The username. */
|
/** The username. */
|
||||||
U user;
|
const(char)[] user;
|
||||||
|
|
||||||
/** The password. */
|
/** The password. */
|
||||||
U pass;
|
const(char)[] pass;
|
||||||
|
|
||||||
/** The hostname. */
|
/** The hostname. */
|
||||||
U host;
|
const(char)[] host;
|
||||||
|
|
||||||
/** The port number. */
|
/** The port number. */
|
||||||
ushort port;
|
ushort port;
|
||||||
|
|
||||||
/** The path. */
|
/** The path. */
|
||||||
U path;
|
const(char)[] path;
|
||||||
|
|
||||||
/** The query string. */
|
/** The query string. */
|
||||||
U query;
|
const(char)[] query;
|
||||||
|
|
||||||
/** The anchor. */
|
/** The anchor. */
|
||||||
U fragment;
|
const(char)[] fragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to parse an URL from a string.
|
* Attempts to parse an URL from a string.
|
||||||
@ -666,7 +665,7 @@ struct URL(U = string)
|
|||||||
*
|
*
|
||||||
* Throws: $(D_PSYMBOL URIException) if the URL is malformed.
|
* Throws: $(D_PSYMBOL URIException) if the URL is malformed.
|
||||||
*/
|
*/
|
||||||
this(U source)
|
this(in char[] source)
|
||||||
{
|
{
|
||||||
auto value = source;
|
auto value = source;
|
||||||
ptrdiff_t pos = -1, endPos = value.length, start;
|
ptrdiff_t pos = -1, endPos = value.length, start;
|
||||||
@ -954,7 +953,7 @@ struct URL(U = string)
|
|||||||
*
|
*
|
||||||
* Returns: Whether the port could be found.
|
* Returns: Whether the port could be found.
|
||||||
*/
|
*/
|
||||||
private bool parsePort(U port) pure nothrow @safe @nogc
|
private bool parsePort(in char[] port) pure nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
ptrdiff_t i = 1;
|
ptrdiff_t i = 1;
|
||||||
float lPort = 0;
|
float lPort = 0;
|
||||||
@ -984,14 +983,14 @@ struct URL(U = string)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto u = URL!()("example.org");
|
auto u = URL("example.org");
|
||||||
assert(u.path == "example.org");
|
assert(u.path == "example.org");
|
||||||
|
|
||||||
u = URL!()("relative/path");
|
u = URL("relative/path");
|
||||||
assert(u.path == "relative/path");
|
assert(u.path == "relative/path");
|
||||||
|
|
||||||
// Host and scheme
|
// Host and scheme
|
||||||
u = URL!()("https://example.org");
|
u = URL("https://example.org");
|
||||||
assert(u.scheme == "https");
|
assert(u.scheme == "https");
|
||||||
assert(u.host == "example.org");
|
assert(u.host == "example.org");
|
||||||
assert(u.path is null);
|
assert(u.path is null);
|
||||||
@ -999,7 +998,7 @@ unittest
|
|||||||
assert(u.fragment is null);
|
assert(u.fragment is null);
|
||||||
|
|
||||||
// With user and port and path
|
// With user and port and path
|
||||||
u = URL!()("https://hilary:putnam@example.org:443/foo/bar");
|
u = URL("https://hilary:putnam@example.org:443/foo/bar");
|
||||||
assert(u.scheme == "https");
|
assert(u.scheme == "https");
|
||||||
assert(u.host == "example.org");
|
assert(u.host == "example.org");
|
||||||
assert(u.path == "/foo/bar");
|
assert(u.path == "/foo/bar");
|
||||||
@ -1009,7 +1008,7 @@ unittest
|
|||||||
assert(u.fragment is null);
|
assert(u.fragment is null);
|
||||||
|
|
||||||
// With query string
|
// With query string
|
||||||
u = URL!()("https://example.org/?login=true");
|
u = URL("https://example.org/?login=true");
|
||||||
assert(u.scheme == "https");
|
assert(u.scheme == "https");
|
||||||
assert(u.host == "example.org");
|
assert(u.host == "example.org");
|
||||||
assert(u.path == "/");
|
assert(u.path == "/");
|
||||||
@ -1017,14 +1016,14 @@ unittest
|
|||||||
assert(u.fragment is null);
|
assert(u.fragment is null);
|
||||||
|
|
||||||
// With query string and fragment
|
// With query string and fragment
|
||||||
u = URL!()("https://example.org/?login=false#label");
|
u = URL("https://example.org/?login=false#label");
|
||||||
assert(u.scheme == "https");
|
assert(u.scheme == "https");
|
||||||
assert(u.host == "example.org");
|
assert(u.host == "example.org");
|
||||||
assert(u.path == "/");
|
assert(u.path == "/");
|
||||||
assert(u.query == "login=false");
|
assert(u.query == "login=false");
|
||||||
assert(u.fragment == "label");
|
assert(u.fragment == "label");
|
||||||
|
|
||||||
u = URL!()("redis://root:password@localhost:2201/path?query=value#fragment");
|
u = URL("redis://root:password@localhost:2201/path?query=value#fragment");
|
||||||
assert(u.scheme == "redis");
|
assert(u.scheme == "redis");
|
||||||
assert(u.user == "root");
|
assert(u.user == "root");
|
||||||
assert(u.pass == "password");
|
assert(u.pass == "password");
|
||||||
@ -1043,7 +1042,7 @@ private unittest
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
URL!()(t[0]);
|
URL(t[0]);
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
catch (URIException e)
|
catch (URIException e)
|
||||||
@ -1053,7 +1052,7 @@ private unittest
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto u = URL!()(t[0]);
|
auto u = URL(t[0]);
|
||||||
assert("scheme" in t[1] ? u.scheme == t[1]["scheme"] : u.scheme is null,
|
assert("scheme" in t[1] ? u.scheme == t[1]["scheme"] : u.scheme is null,
|
||||||
t[0]);
|
t[0]);
|
||||||
assert("user" in t[1] ? u.user == t[1]["user"] : u.user is null, t[0]);
|
assert("user" in t[1] ? u.user == t[1]["user"] : u.user is null, t[0]);
|
||||||
@ -1100,31 +1099,30 @@ enum Component : string
|
|||||||
*
|
*
|
||||||
* Returns: Requested URL components.
|
* Returns: Requested URL components.
|
||||||
*/
|
*/
|
||||||
URL parseURL(U)(in U source)
|
URL parseURL(typeof(null) T)(in char[] source)
|
||||||
if (isSomeString!U)
|
|
||||||
{
|
{
|
||||||
return URL!U(source);
|
return URL(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
string parseURL(string T, U)(in U source)
|
const(char)[] parseURL(immutable(char)[] T)(in char[] source)
|
||||||
if ((T == "scheme"
|
if (T == "scheme"
|
||||||
|| T =="host"
|
|| T =="host"
|
||||||
|| T == "user"
|
|| T == "user"
|
||||||
|| T == "pass"
|
|| T == "pass"
|
||||||
|| T == "path"
|
|| T == "path"
|
||||||
|| T == "query"
|
|| T == "query"
|
||||||
|| T == "fragment") && isSomeString!U)
|
|| T == "fragment")
|
||||||
{
|
{
|
||||||
auto ret = URL!U(source);
|
auto ret = URL(source);
|
||||||
return mixin("ret." ~ T);
|
return mixin("ret." ~ T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
ushort parseURL(string T, U)(in U source)
|
ushort parseURL(immutable(char)[] T)(in char[] source)
|
||||||
if (T == "port" && isSomeString!U)
|
if (T == "port")
|
||||||
{
|
{
|
||||||
auto ret = URL!U(source);
|
auto ret = URL(source);
|
||||||
return ret.port;
|
return ret.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1158,7 +1156,7 @@ private unittest
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ushort port = parseURL!(Component.port)(t[0]);
|
ushort port = parseURL!(Component.port)(t[0]);
|
||||||
string component = parseURL!(Component.scheme)(t[0]);
|
auto component = parseURL!(Component.scheme)(t[0]);
|
||||||
assert("scheme" in t[1] ? component == t[1]["scheme"] : component is null,
|
assert("scheme" in t[1] ? component == t[1]["scheme"] : component is null,
|
||||||
t[0]);
|
t[0]);
|
||||||
component = parseURL!(Component.user)(t[0]);
|
component = parseURL!(Component.user)(t[0]);
|
||||||
|
Reference in New Issue
Block a user