Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
ab930657b6 | |||
291920b479 | |||
999c9bdb0f | |||
405b6d9f9f | |||
87b74b2542 | |||
d6514cb515 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@
|
||||
.dub
|
||||
__test__*__
|
||||
__test__*__.core
|
||||
|
||||
/docs/
|
||||
/docs.json
|
||||
|
@ -5,8 +5,7 @@
|
||||
[](https://code.dlang.org/packages/tanya)
|
||||
[](https://raw.githubusercontent.com/caraus-ecms/tanya/master/LICENSE)
|
||||
|
||||
Tanya is a general purpose library for D programming language that doesn't
|
||||
rely on the Garbage Collector.
|
||||
Tanya is a general purpose library for D programming language.
|
||||
|
||||
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
|
||||
@ -36,12 +35,12 @@ helper functions).
|
||||
The library is currently under development, but some parts of it can already be
|
||||
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
|
||||
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
|
||||
a stable API (that mostly consists of operator overloads), but still needs
|
||||
testing and work on its performance.
|
||||
|
@ -159,7 +159,7 @@ class EpollLoop : SelectorLoop
|
||||
}
|
||||
else if (io.output.length)
|
||||
{
|
||||
swapPendings.insertBack(io);
|
||||
swapPendings.enqueue(io);
|
||||
}
|
||||
}
|
||||
else if (events[i].events & EPOLLOUT)
|
||||
|
@ -218,11 +218,11 @@ class IOCPLoop : Loop
|
||||
auto transport = MmapPool.instance.make!IOCPStreamTransport(socket);
|
||||
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));
|
||||
|
||||
swapPendings.insertBack(connection);
|
||||
swapPendings.enqueue(connection);
|
||||
listener.beginAccept(overlapped);
|
||||
break;
|
||||
case OverlappedSocketEvent.read:
|
||||
@ -264,7 +264,7 @@ class IOCPLoop : Loop
|
||||
{
|
||||
transport.socket.beginReceive(io.output[], overlapped);
|
||||
}
|
||||
swapPendings.insertBack(io);
|
||||
swapPendings.enqueue(io);
|
||||
}
|
||||
break;
|
||||
case OverlappedSocketEvent.write:
|
||||
|
@ -271,7 +271,7 @@ class KqueueLoop : SelectorLoop
|
||||
}
|
||||
else if (io.output.length)
|
||||
{
|
||||
swapPendings.insertBack(io);
|
||||
swapPendings.enqueue(io);
|
||||
}
|
||||
}
|
||||
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));
|
||||
connection.incoming.insertBack(io);
|
||||
connection.incoming.enqueue(io);
|
||||
}
|
||||
|
||||
if (!connection.incoming.empty)
|
||||
{
|
||||
swapPendings.insertBack(connection);
|
||||
swapPendings.enqueue(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,8 +184,10 @@ abstract class Loop
|
||||
poll();
|
||||
|
||||
// Invoke pendings
|
||||
swapPendings.each!((ref p) @nogc => p.invoke());
|
||||
|
||||
foreach (ref w; *swapPendings)
|
||||
{
|
||||
w.invoke();
|
||||
}
|
||||
swap(pendings, swapPendings);
|
||||
}
|
||||
while (!done_);
|
||||
@ -283,7 +285,7 @@ abstract class Loop
|
||||
defaultAllocator.dispose(watcher.socket);
|
||||
MmapPool.instance.dispose(watcher.transport);
|
||||
watcher.exception = exception;
|
||||
swapPendings.insertBack(watcher);
|
||||
swapPendings.enqueue(watcher);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,7 +632,7 @@ struct WriteBuffer(T = ubyte)
|
||||
* written.
|
||||
*
|
||||
* $(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,
|
||||
* maximally 3 calls are required.
|
||||
*
|
||||
@ -677,7 +677,7 @@ struct WriteBuffer(T = ubyte)
|
||||
* written.
|
||||
*
|
||||
* $(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,
|
||||
* maximally 3 calls are required.
|
||||
*
|
||||
|
@ -10,8 +10,9 @@
|
||||
*/
|
||||
module tanya.container.queue;
|
||||
|
||||
import tanya.container.entry;
|
||||
import std.traits;
|
||||
import std.algorithm.mutation;
|
||||
import tanya.container.entry;
|
||||
import tanya.memory;
|
||||
|
||||
/**
|
||||
@ -27,32 +28,24 @@ struct Queue(T)
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
clear();
|
||||
while (!empty)
|
||||
{
|
||||
dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from the queue.
|
||||
*/
|
||||
deprecated
|
||||
void clear()
|
||||
{
|
||||
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
|
||||
* to count the elements.
|
||||
@ -75,18 +68,18 @@ struct Queue(T)
|
||||
Queue!int q;
|
||||
|
||||
assert(q.length == 0);
|
||||
q.insertBack(5);
|
||||
q.enqueue(5);
|
||||
assert(q.length == 1);
|
||||
q.insertBack(4);
|
||||
q.enqueue(4);
|
||||
assert(q.length == 2);
|
||||
q.insertBack(9);
|
||||
q.enqueue(9);
|
||||
assert(q.length == 3);
|
||||
|
||||
q.popFront();
|
||||
q.dequeue();
|
||||
assert(q.length == 2);
|
||||
q.popFront();
|
||||
q.dequeue();
|
||||
assert(q.length == 1);
|
||||
q.popFront();
|
||||
q.dequeue();
|
||||
assert(q.length == 0);
|
||||
}
|
||||
|
||||
@ -97,14 +90,17 @@ struct Queue(T)
|
||||
*
|
||||
* Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal.
|
||||
*/
|
||||
deprecated
|
||||
int opEquals(ref typeof(this) that);
|
||||
|
||||
/// Ditto.
|
||||
deprecated
|
||||
int opEquals(typeof(this) that);
|
||||
}
|
||||
else static if (!hasMember!(T, "opEquals")
|
||||
|| (functionAttributes!(T.opEquals) & FunctionAttribute.const_))
|
||||
{
|
||||
deprecated
|
||||
bool opEquals(in ref typeof(this) that) const
|
||||
{
|
||||
const(Entry!T)* i = first.next;
|
||||
@ -121,7 +117,7 @@ struct Queue(T)
|
||||
return i is null && j is null;
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
deprecated
|
||||
bool opEquals(in typeof(this) that) const
|
||||
{
|
||||
return opEquals(that);
|
||||
@ -129,11 +125,7 @@ struct Queue(T)
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Compares two queues. Checks if all elements of the both queues are equal.
|
||||
*
|
||||
* Returns: How many elements are in the queue.
|
||||
*/
|
||||
deprecated
|
||||
bool opEquals(ref typeof(this) that)
|
||||
{
|
||||
Entry!T* i = first.next;
|
||||
@ -150,46 +142,17 @@ struct Queue(T)
|
||||
return i is null && j is null;
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
deprecated
|
||||
bool opEquals(typeof(this) 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.
|
||||
*/
|
||||
deprecated("Use dequeue instead.")
|
||||
@property ref inout(T) front() inout
|
||||
in
|
||||
{
|
||||
@ -205,13 +168,12 @@ struct Queue(T)
|
||||
*
|
||||
* Params:
|
||||
* 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);
|
||||
|
||||
temp.content = x;
|
||||
|
||||
auto temp = allocator.make!(Entry!T)(x);
|
||||
if (empty)
|
||||
{
|
||||
first.next = rear = temp;
|
||||
@ -221,16 +183,20 @@ struct Queue(T)
|
||||
rear.next = temp;
|
||||
rear = rear.next;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
void insertBack(T x)
|
||||
ref typeof(this) enqueue(T x)
|
||||
{
|
||||
insertBack(x);
|
||||
return enqueue(x);
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
alias insert = insertBack;
|
||||
deprecated("Use enqueue instead.")
|
||||
alias insert = enqueue;
|
||||
|
||||
deprecated("Use enqueue instead.")
|
||||
alias insertBack = enqueue;
|
||||
|
||||
///
|
||||
unittest
|
||||
@ -238,10 +204,9 @@ struct Queue(T)
|
||||
Queue!int q;
|
||||
|
||||
assert(q.empty);
|
||||
q.insertBack(8);
|
||||
assert(q.front == 8);
|
||||
q.insertBack(9);
|
||||
assert(q.front == 8);
|
||||
q.enqueue(8).enqueue(9);
|
||||
assert(q.dequeue() == 8);
|
||||
assert(q.dequeue() == 9);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,14 +224,16 @@ struct Queue(T)
|
||||
int value = 7;
|
||||
|
||||
assert(q.empty);
|
||||
q.insertBack(value);
|
||||
q.enqueue(value);
|
||||
assert(!q.empty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the position to the next element.
|
||||
*
|
||||
* Returns: Dequeued element.
|
||||
*/
|
||||
void popFront()
|
||||
T dequeue()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
@ -275,21 +242,24 @@ struct Queue(T)
|
||||
body
|
||||
{
|
||||
auto n = first.next.next;
|
||||
T ret = move(first.next.content);
|
||||
|
||||
dispose(allocator, first.next);
|
||||
first.next = n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
deprecated("Use dequeue instead.")
|
||||
alias popFront = dequeue;
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
Queue!int q;
|
||||
|
||||
q.insertBack(8);
|
||||
q.insertBack(9);
|
||||
assert(q.front == 8);
|
||||
q.popFront();
|
||||
assert(q.front == 9);
|
||||
q.enqueue(8).enqueue(9);
|
||||
assert(q.dequeue() == 8);
|
||||
assert(q.dequeue() == 9);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,11 +275,11 @@ struct Queue(T)
|
||||
|
||||
for (size_t i = 0; !empty; ++i)
|
||||
{
|
||||
if ((result = dg(i, front)) != 0)
|
||||
auto e = dequeue();
|
||||
if ((result = dg(i, e)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
popFront();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -321,11 +291,11 @@ struct Queue(T)
|
||||
|
||||
while (!empty)
|
||||
{
|
||||
if ((result = dg(front)) != 0)
|
||||
auto e = dequeue();
|
||||
if ((result = dg(e)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
popFront();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -336,9 +306,7 @@ struct Queue(T)
|
||||
Queue!int q;
|
||||
|
||||
size_t j;
|
||||
q.insertBack(5);
|
||||
q.insertBack(4);
|
||||
q.insertBack(9);
|
||||
q.enqueue(5).enqueue(4).enqueue(9);
|
||||
foreach (i, e; q)
|
||||
{
|
||||
assert(i != 2 || e == 9);
|
||||
@ -350,9 +318,7 @@ struct Queue(T)
|
||||
assert(q.empty);
|
||||
|
||||
j = 0;
|
||||
q.insertBack(5);
|
||||
q.insertBack(4);
|
||||
q.insertBack(9);
|
||||
q.enqueue(5).enqueue(4).enqueue(9);
|
||||
foreach (e; q)
|
||||
{
|
||||
assert(j != 2 || e == 9);
|
||||
@ -378,17 +344,12 @@ unittest
|
||||
{
|
||||
Queue!int q;
|
||||
|
||||
q.insertBack(5);
|
||||
q.enqueue(5);
|
||||
assert(!q.empty);
|
||||
|
||||
q.insertBack(4);
|
||||
assert(q.front == 5);
|
||||
q.enqueue(4).enqueue(9);
|
||||
|
||||
q.insertBack(9);
|
||||
assert(q.front == 5);
|
||||
|
||||
q.popFront();
|
||||
assert(q.front == 4);
|
||||
assert(q.dequeue() == 5);
|
||||
|
||||
foreach (i, ref e; q)
|
||||
{
|
||||
|
@ -10,9 +10,10 @@
|
||||
*/
|
||||
module tanya.container.vector;
|
||||
|
||||
import core.stdc.string;
|
||||
import core.checkedint;
|
||||
import core.exception;
|
||||
import std.algorithm.comparison;
|
||||
import std.algorithm.mutation;
|
||||
import std.conv;
|
||||
import std.range.primitives;
|
||||
import std.meta;
|
||||
@ -271,8 +272,7 @@ private struct Range(E)
|
||||
}
|
||||
|
||||
Range opSliceAssign(R)(R value, in size_t i, in size_t j)
|
||||
if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
|| is(R == Vector))
|
||||
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
{
|
||||
return opSliceAssign(value[], i, j);
|
||||
}
|
||||
@ -297,30 +297,6 @@ struct Vector(T)
|
||||
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).
|
||||
*
|
||||
@ -330,16 +306,15 @@ struct Vector(T)
|
||||
* to generate a list.
|
||||
* allocator = Allocator.
|
||||
*/
|
||||
this(R)(auto ref R init, shared Allocator allocator = defaultAllocator)
|
||||
if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
|| is(R == Vector))
|
||||
this(R)(auto in ref R init, shared Allocator allocator = defaultAllocator)
|
||||
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
{
|
||||
this(allocator);
|
||||
insertBack(init[]);
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
this(R)(R init, shared Allocator allocator = defaultAllocator)
|
||||
this(R)(auto in ref R init, shared Allocator allocator = defaultAllocator)
|
||||
if (!isInfinite!R
|
||||
&& isInputRange!R
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
@ -348,12 +323,78 @@ struct Vector(T)
|
||||
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).
|
||||
*
|
||||
* Params:
|
||||
* len = Initial length of the vector.
|
||||
* init = Initial value to fill the vector with.
|
||||
* allocator = Allocator.
|
||||
*/
|
||||
this(size_t len, shared Allocator allocator = defaultAllocator) @trusted
|
||||
@ -365,11 +406,19 @@ struct Vector(T)
|
||||
{
|
||||
return;
|
||||
}
|
||||
initialize(len);
|
||||
capacity_ = length_ = len;
|
||||
reserve(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(allocator);
|
||||
@ -379,9 +428,9 @@ struct Vector(T)
|
||||
{
|
||||
return;
|
||||
}
|
||||
initialize(len);
|
||||
capacity_ = length_ = len;
|
||||
opSliceAssign(init, 0, length_);
|
||||
reserve(len);
|
||||
uninitializedFill(vector[0 .. len], init);
|
||||
length_ = len;
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
@ -415,6 +464,11 @@ struct Vector(T)
|
||||
assert(v[0] == 5 && v[1] == 5 && v[2] == 5);
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
auto v1 = Vector!int(defaultAllocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this $(D_PSYMBOL Vector).
|
||||
*/
|
||||
@ -497,7 +551,8 @@ struct Vector(T)
|
||||
}
|
||||
else if (len > length_)
|
||||
{
|
||||
initialize(len);
|
||||
reserve(len);
|
||||
initializeAll(vector[length_ .. len]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -543,13 +598,39 @@ struct Vector(T)
|
||||
*/
|
||||
void reserve(in size_t size) @trusted
|
||||
{
|
||||
if (capacity_ < size)
|
||||
if (capacity_ >= size)
|
||||
{
|
||||
void[] buf = vector[0 .. capacity_];
|
||||
allocator.reallocate(buf, size * T.sizeof);
|
||||
vector = cast(T*) buf;
|
||||
capacity_ = size;
|
||||
return;
|
||||
}
|
||||
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))
|
||||
{
|
||||
reserve(length_ + el.length);
|
||||
if (capacity_ <= length_)
|
||||
{
|
||||
onOutOfMemoryError();
|
||||
}
|
||||
foreach (i; el)
|
||||
{
|
||||
emplace(vector + length_, i);
|
||||
@ -732,11 +809,11 @@ struct Vector(T)
|
||||
{
|
||||
immutable rLen = walkLength(el);
|
||||
|
||||
initialize(length_ + rLen);
|
||||
reserve(length_ + rLen);
|
||||
T* pos = vector + length_;
|
||||
foreach (e; el)
|
||||
{
|
||||
*pos = e;
|
||||
emplace(pos, e);
|
||||
++length_, ++pos;
|
||||
}
|
||||
return rLen;
|
||||
@ -892,7 +969,6 @@ struct Vector(T)
|
||||
* 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)
|
||||
@ -952,7 +1028,16 @@ struct Vector(T)
|
||||
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
|
||||
if (is(Unqual!R == T))
|
||||
{
|
||||
@ -1239,14 +1324,14 @@ struct Vector(T)
|
||||
* Slicing assignment.
|
||||
*
|
||||
* Params:
|
||||
* value = New value.
|
||||
* value = New value (single value or input range).
|
||||
* i = Slice start.
|
||||
* j = Slice end.
|
||||
*
|
||||
* Returns: Slice with the assigned part of the vector.
|
||||
*
|
||||
* 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
|
||||
in
|
||||
@ -1256,11 +1341,7 @@ struct Vector(T)
|
||||
}
|
||||
body
|
||||
{
|
||||
const T* end = vector + j;
|
||||
for (T* v = vector + i; v != end; ++v)
|
||||
{
|
||||
*v = value;
|
||||
}
|
||||
vector[i .. j].fill(value);
|
||||
return opSlice(i, j);
|
||||
}
|
||||
|
||||
@ -1277,6 +1358,8 @@ struct Vector(T)
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
assert(j - i == walkLength(value));
|
||||
}
|
||||
body
|
||||
@ -1291,8 +1374,7 @@ struct Vector(T)
|
||||
|
||||
/// Ditto.
|
||||
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
|
||||
if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
|| is(R == Vector))
|
||||
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
{
|
||||
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
|
||||
* region is deallocated.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
* | | | | | || | | |
|
||||
* | |prev <----------- | || | | |
|
||||
* | R | B | | B | || R | B | |
|
||||
@ -46,7 +46,7 @@ else version (Windows)
|
||||
* | O | K | | K | prev O | K | |
|
||||
* | N | -----------> next| || N | | |
|
||||
* | | | | | || | | |
|
||||
* --------------------------------------------------- ------------------------
|
||||
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
final class MmapPool : Allocator
|
||||
{
|
||||
|
@ -374,9 +374,10 @@ private unittest
|
||||
* object).
|
||||
*
|
||||
* Params:
|
||||
* T = Type of the constructed object.
|
||||
* A = Types of the arguments to the constructor of $(D_PARAM T).
|
||||
* args = Constructor arguments of $(D_PARAM T).
|
||||
* T = Type of the constructed object.
|
||||
* A = Types of the arguments to the constructor of $(D_PARAM T).
|
||||
* allocator = Allocator.
|
||||
* args = Constructor arguments of $(D_PARAM T).
|
||||
*
|
||||
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
|
||||
*/
|
||||
|
@ -812,7 +812,7 @@ abstract class Socket
|
||||
* Params:
|
||||
* level = Protocol level at that the option exists.
|
||||
* option = Option.
|
||||
* result = Option value.
|
||||
* value = Option value.
|
||||
*
|
||||
* Throws: $(D_PSYMBOL SocketException) on error.
|
||||
*/
|
||||
|
@ -630,32 +630,31 @@ static this()
|
||||
/**
|
||||
* A Unique Resource Locator.
|
||||
*/
|
||||
struct URL(U = string)
|
||||
if (isSomeString!U)
|
||||
struct URL
|
||||
{
|
||||
/** The URL scheme. */
|
||||
U scheme;
|
||||
const(char)[] scheme;
|
||||
|
||||
/** The username. */
|
||||
U user;
|
||||
const(char)[] user;
|
||||
|
||||
/** The password. */
|
||||
U pass;
|
||||
const(char)[] pass;
|
||||
|
||||
/** The hostname. */
|
||||
U host;
|
||||
const(char)[] host;
|
||||
|
||||
/** The port number. */
|
||||
ushort port;
|
||||
|
||||
/** The path. */
|
||||
U path;
|
||||
const(char)[] path;
|
||||
|
||||
/** The query string. */
|
||||
U query;
|
||||
const(char)[] query;
|
||||
|
||||
/** The anchor. */
|
||||
U fragment;
|
||||
const(char)[] fragment;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
this(U source)
|
||||
this(in char[] source)
|
||||
{
|
||||
auto value = source;
|
||||
ptrdiff_t pos = -1, endPos = value.length, start;
|
||||
@ -954,7 +953,7 @@ struct URL(U = string)
|
||||
*
|
||||
* 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;
|
||||
float lPort = 0;
|
||||
@ -984,14 +983,14 @@ struct URL(U = string)
|
||||
///
|
||||
unittest
|
||||
{
|
||||
auto u = URL!()("example.org");
|
||||
auto u = URL("example.org");
|
||||
assert(u.path == "example.org");
|
||||
|
||||
u = URL!()("relative/path");
|
||||
u = URL("relative/path");
|
||||
assert(u.path == "relative/path");
|
||||
|
||||
// Host and scheme
|
||||
u = URL!()("https://example.org");
|
||||
u = URL("https://example.org");
|
||||
assert(u.scheme == "https");
|
||||
assert(u.host == "example.org");
|
||||
assert(u.path is null);
|
||||
@ -999,7 +998,7 @@ unittest
|
||||
assert(u.fragment is null);
|
||||
|
||||
// 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.host == "example.org");
|
||||
assert(u.path == "/foo/bar");
|
||||
@ -1009,7 +1008,7 @@ unittest
|
||||
assert(u.fragment is null);
|
||||
|
||||
// With query string
|
||||
u = URL!()("https://example.org/?login=true");
|
||||
u = URL("https://example.org/?login=true");
|
||||
assert(u.scheme == "https");
|
||||
assert(u.host == "example.org");
|
||||
assert(u.path == "/");
|
||||
@ -1017,14 +1016,14 @@ unittest
|
||||
assert(u.fragment is null);
|
||||
|
||||
// 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.host == "example.org");
|
||||
assert(u.path == "/");
|
||||
assert(u.query == "login=false");
|
||||
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.user == "root");
|
||||
assert(u.pass == "password");
|
||||
@ -1043,7 +1042,7 @@ private unittest
|
||||
{
|
||||
try
|
||||
{
|
||||
URL!()(t[0]);
|
||||
URL(t[0]);
|
||||
assert(0);
|
||||
}
|
||||
catch (URIException e)
|
||||
@ -1053,7 +1052,7 @@ private unittest
|
||||
}
|
||||
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,
|
||||
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.
|
||||
*/
|
||||
URL parseURL(U)(in U source)
|
||||
if (isSomeString!U)
|
||||
URL parseURL(typeof(null) T)(in char[] source)
|
||||
{
|
||||
return URL!U(source);
|
||||
return URL(source);
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
string parseURL(string T, U)(in U source)
|
||||
if ((T == "scheme"
|
||||
const(char)[] parseURL(immutable(char)[] T)(in char[] source)
|
||||
if (T == "scheme"
|
||||
|| T =="host"
|
||||
|| T == "user"
|
||||
|| T == "pass"
|
||||
|| T == "path"
|
||||
|| T == "query"
|
||||
|| T == "fragment") && isSomeString!U)
|
||||
|| T == "fragment")
|
||||
{
|
||||
auto ret = URL!U(source);
|
||||
auto ret = URL(source);
|
||||
return mixin("ret." ~ T);
|
||||
}
|
||||
|
||||
/// Ditto.
|
||||
ushort parseURL(string T, U)(in U source)
|
||||
if (T == "port" && isSomeString!U)
|
||||
ushort parseURL(immutable(char)[] T)(in char[] source)
|
||||
if (T == "port")
|
||||
{
|
||||
auto ret = URL!U(source);
|
||||
auto ret = URL(source);
|
||||
return ret.port;
|
||||
}
|
||||
|
||||
@ -1158,7 +1156,7 @@ private unittest
|
||||
else
|
||||
{
|
||||
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,
|
||||
t[0]);
|
||||
component = parseURL!(Component.user)(t[0]);
|
||||
|
Reference in New Issue
Block a user