Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
f51e9405c9 | |||
de15281ccb | |||
a86b6690f0 | |||
15f7994187 | |||
37b0afe290 | |||
cd9960db2a | |||
7357503c5a | |||
173ae115ee | |||
7561b964d3 | |||
c663703221 |
@ -7,7 +7,7 @@ os:
|
|||||||
language: d
|
language: d
|
||||||
|
|
||||||
d:
|
d:
|
||||||
- dmd-2.080.0
|
- dmd-2.080.1
|
||||||
- dmd-2.079.1
|
- dmd-2.079.1
|
||||||
- dmd-2.078.3
|
- dmd-2.078.3
|
||||||
- dmd-2.077.1
|
- dmd-2.077.1
|
||||||
@ -23,7 +23,7 @@ addons:
|
|||||||
- gcc-multilib
|
- gcc-multilib
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- if [ "`$DC --version | head -n 1 | grep 'v2.080.0'`" ]; then
|
- if [ "`$DC --version | head -n 1 | grep 'v2.080.1'`" ]; then
|
||||||
export UNITTEST="unittest-cov";
|
export UNITTEST="unittest-cov";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ parameter is used)
|
|||||||
|
|
||||||
| DMD | GCC |
|
| DMD | GCC |
|
||||||
|:-------:|:---------:|
|
|:-------:|:---------:|
|
||||||
| 2.080.0 | *master* |
|
| 2.080.1 | *master* |
|
||||||
| 2.079.1 | |
|
| 2.079.1 | |
|
||||||
| 2.078.3 | |
|
| 2.078.3 | |
|
||||||
| 2.077.1 | |
|
| 2.077.1 | |
|
||||||
|
@ -4,10 +4,10 @@ os: Visual Studio 2015
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.080.0
|
DVersion: 2.080.1
|
||||||
arch: x64
|
arch: x64
|
||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.080.0
|
DVersion: 2.080.1
|
||||||
arch: x86
|
arch: x86
|
||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.079.1
|
DVersion: 2.079.1
|
||||||
|
@ -47,6 +47,7 @@ _D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi:
|
|||||||
|
|
||||||
aligned_1: // Compare the remaining bytes
|
aligned_1: // Compare the remaining bytes
|
||||||
mov %rdx, %rcx
|
mov %rdx, %rcx
|
||||||
|
cmp $0x0, %rcx
|
||||||
|
|
||||||
repe cmpsb
|
repe cmpsb
|
||||||
jl less
|
jl less
|
||||||
|
@ -16,6 +16,7 @@ module tanya.algorithm.comparison;
|
|||||||
|
|
||||||
import tanya.algorithm.mutation;
|
import tanya.algorithm.mutation;
|
||||||
import tanya.math : isNaN;
|
import tanya.math : isNaN;
|
||||||
|
import tanya.memory.op;
|
||||||
import tanya.meta.metafunction;
|
import tanya.meta.metafunction;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
@ -270,3 +271,63 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
|||||||
assert(max(s2, s3).s == 3);
|
assert(max(s2, s3).s == 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares element-wise two ranges for equality.
|
||||||
|
*
|
||||||
|
* If the ranges have different lengths, they aren't equal.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R1 = First range type.
|
||||||
|
* R2 = Second range type.
|
||||||
|
* r1 = First range.
|
||||||
|
* r2 = Second range.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if both ranges are equal, $(D_KEYWORD false)
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool equal(R1, R2)(R1 r1, R2 r2)
|
||||||
|
if (allSatisfy!(isInputRange, R1, R2) && is(typeof(r1.front == r2.front)))
|
||||||
|
{
|
||||||
|
static if (isDynamicArray!R1
|
||||||
|
&& is(R1 == R2)
|
||||||
|
&& __traits(isPOD, ElementType!R1))
|
||||||
|
{
|
||||||
|
return cmp(r1, r2) == 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static if (hasLength!R1 && hasLength!R2)
|
||||||
|
{
|
||||||
|
if (r1.length != r2.length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront())
|
||||||
|
{
|
||||||
|
if (r1.front != r2.front)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static if (hasLength!R1 && hasLength!R2)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return r1.empty && r2.empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
int[2] range1 = [1, 2];
|
||||||
|
assert(equal(range1[], range1[]));
|
||||||
|
|
||||||
|
int[3] range2 = [1, 2, 3];
|
||||||
|
assert(!equal(range1[], range2[]));
|
||||||
|
}
|
||||||
|
@ -13,50 +13,52 @@
|
|||||||
*
|
*
|
||||||
* class EchoProtocol : TransmissionControlProtocol
|
* class EchoProtocol : TransmissionControlProtocol
|
||||||
* {
|
* {
|
||||||
* private DuplexTransport transport;
|
* private DuplexTransport transport;
|
||||||
*
|
*
|
||||||
* void received(in ubyte[] data) @nogc
|
* void received(in ubyte[] data) @nogc
|
||||||
* {
|
* {
|
||||||
* transport.write(data);
|
* ubyte[512] buffer;
|
||||||
* }
|
* buffer[0 .. data.length] = data;
|
||||||
|
* transport.write(buffer[]);
|
||||||
|
* }
|
||||||
*
|
*
|
||||||
* void connected(DuplexTransport transport) @nogc
|
* void connected(DuplexTransport transport) @nogc
|
||||||
* {
|
* {
|
||||||
* this.transport = transport;
|
* this.transport = transport;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* void disconnected(SocketException e) @nogc
|
* void disconnected(SocketException e) @nogc
|
||||||
* {
|
* {
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* void main()
|
* void main()
|
||||||
* {
|
* {
|
||||||
* auto address = defaultAllocator.make!InternetAddress("127.0.0.1", cast(ushort) 8192);
|
* auto address = defaultAllocator.make!InternetAddress("127.0.0.1", cast(ushort) 8192);
|
||||||
*
|
*
|
||||||
* version (Windows)
|
* version (Windows)
|
||||||
* {
|
* {
|
||||||
* auto sock = defaultAllocator.make!OverlappedStreamSocket(AddressFamily.inet);
|
* auto sock = defaultAllocator.make!OverlappedStreamSocket(AddressFamily.inet);
|
||||||
* }
|
* }
|
||||||
* else
|
* else
|
||||||
* {
|
* {
|
||||||
* auto sock = defaultAllocator.make!StreamSocket(AddressFamily.inet);
|
* auto sock = defaultAllocator.make!StreamSocket(AddressFamily.inet);
|
||||||
* sock.blocking = false;
|
* sock.blocking = false;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* sock.bind(address);
|
* sock.bind(address);
|
||||||
* sock.listen(5);
|
* sock.listen(5);
|
||||||
*
|
*
|
||||||
* auto io = defaultAllocator.make!ConnectionWatcher(sock);
|
* auto io = defaultAllocator.make!ConnectionWatcher(sock);
|
||||||
* io.setProtocol!EchoProtocol;
|
* io.setProtocol!EchoProtocol;
|
||||||
*
|
*
|
||||||
* defaultLoop.start(io);
|
* defaultLoop.start(io);
|
||||||
* defaultLoop.run();
|
* defaultLoop.run();
|
||||||
*
|
*
|
||||||
* sock.shutdown();
|
* sock.shutdown();
|
||||||
* defaultAllocator.dispose(io);
|
* defaultAllocator.dispose(io);
|
||||||
* defaultAllocator.dispose(sock);
|
* defaultAllocator.dispose(sock);
|
||||||
* defaultAllocator.dispose(address);
|
* defaultAllocator.dispose(address);
|
||||||
* }
|
* }
|
||||||
* ---
|
* ---
|
||||||
*
|
*
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
module tanya.container.array;
|
module tanya.container.array;
|
||||||
|
|
||||||
import core.checkedint;
|
import core.checkedint;
|
||||||
import std.algorithm.comparison : equal;
|
|
||||||
import std.algorithm.mutation : bringToFront,
|
import std.algorithm.mutation : bringToFront,
|
||||||
copy,
|
copy,
|
||||||
fill,
|
fill,
|
||||||
|
@ -51,7 +51,7 @@ version (unittest)
|
|||||||
* T = Buffer type.
|
* T = Buffer type.
|
||||||
*/
|
*/
|
||||||
struct ReadBuffer(T = ubyte)
|
struct ReadBuffer(T = ubyte)
|
||||||
if (isScalarType!T)
|
if (isScalarType!T)
|
||||||
{
|
{
|
||||||
/// Internal buffer.
|
/// Internal buffer.
|
||||||
private T[] buffer_;
|
private T[] buffer_;
|
||||||
@ -66,16 +66,16 @@ struct ReadBuffer(T = ubyte)
|
|||||||
private size_t ring;
|
private size_t ring;
|
||||||
|
|
||||||
/// Available space.
|
/// Available space.
|
||||||
private immutable size_t minAvailable = 1024;
|
private size_t minAvailable = 1024;
|
||||||
|
|
||||||
/// Size by which the buffer will grow.
|
/// Size by which the buffer will grow.
|
||||||
private immutable size_t blockSize = 8192;
|
private size_t blockSize = 8192;
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
{
|
{
|
||||||
assert(length_ <= buffer_.length);
|
assert(this.length_ <= this.buffer_.length);
|
||||||
assert(blockSize > 0);
|
assert(this.blockSize > 0);
|
||||||
assert(minAvailable > 0);
|
assert(this.minAvailable > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,14 +89,14 @@ struct ReadBuffer(T = ubyte)
|
|||||||
* $(D_PSYMBOL free) < $(D_PARAM minAvailable)).
|
* $(D_PSYMBOL free) < $(D_PARAM minAvailable)).
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(in size_t size,
|
this(size_t size,
|
||||||
in size_t minAvailable = 1024,
|
size_t minAvailable = 1024,
|
||||||
shared Allocator allocator = defaultAllocator) @trusted
|
shared Allocator allocator = defaultAllocator) @trusted
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
this.minAvailable = minAvailable;
|
this.minAvailable = minAvailable;
|
||||||
this.blockSize = size;
|
this.blockSize = size;
|
||||||
buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof);
|
this.buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
@ -115,7 +115,7 @@ struct ReadBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
~this() @trusted
|
~this() @trusted
|
||||||
{
|
{
|
||||||
allocator.deallocate(buffer_);
|
allocator.deallocate(this.buffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -131,7 +131,7 @@ struct ReadBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
@property size_t capacity() const
|
@property size_t capacity() const
|
||||||
{
|
{
|
||||||
return buffer_.length;
|
return this.buffer_.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,7 +139,7 @@ struct ReadBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
@property size_t length() const
|
@property size_t length() const
|
||||||
{
|
{
|
||||||
return length_ - start;
|
return this.length_ - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
@ -152,7 +152,7 @@ struct ReadBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
start = length_ = ring;
|
start = this.length_ = ring;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,10 +187,10 @@ struct ReadBuffer(T = ubyte)
|
|||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref ReadBuffer opOpAssign(string op)(in size_t length)
|
ref ReadBuffer opOpAssign(string op)(size_t length)
|
||||||
if (op == "+")
|
if (op == "+")
|
||||||
{
|
{
|
||||||
length_ += length;
|
this.length_ += length;
|
||||||
ring = start;
|
ring = start;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -234,9 +234,9 @@ struct ReadBuffer(T = ubyte)
|
|||||||
*
|
*
|
||||||
* Returns: Array between $(D_PARAM start) and $(D_PARAM end).
|
* Returns: Array between $(D_PARAM start) and $(D_PARAM end).
|
||||||
*/
|
*/
|
||||||
T[] opSlice(in size_t start, in size_t end)
|
T[] opSlice(size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return buffer_[this.start + start .. this.start + end];
|
return this.buffer_[this.start + start .. this.start + end];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,23 +250,24 @@ struct ReadBuffer(T = ubyte)
|
|||||||
{
|
{
|
||||||
if (start > 0)
|
if (start > 0)
|
||||||
{
|
{
|
||||||
auto ret = buffer_[0 .. start];
|
auto ret = this.buffer_[0 .. start];
|
||||||
ring = 0;
|
ring = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (capacity - length < minAvailable)
|
if (capacity - length < this.minAvailable)
|
||||||
{
|
{
|
||||||
void[] buf = buffer_;
|
void[] buf = this.buffer_;
|
||||||
immutable cap = capacity;
|
const cap = capacity;
|
||||||
() @trusted {
|
() @trusted {
|
||||||
allocator.reallocate(buf, (cap + blockSize) * T.sizeof);
|
allocator.reallocate(buf,
|
||||||
buffer_ = cast(T[]) buf;
|
(cap + this.blockSize) * T.sizeof);
|
||||||
|
this.buffer_ = cast(T[]) buf;
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
ring = length_;
|
ring = this.length_;
|
||||||
return buffer_[length_ .. $];
|
return this.buffer_[this.length_ .. $];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +311,7 @@ struct ReadBuffer(T = ubyte)
|
|||||||
* T = Buffer type.
|
* T = Buffer type.
|
||||||
*/
|
*/
|
||||||
struct WriteBuffer(T = ubyte)
|
struct WriteBuffer(T = ubyte)
|
||||||
if (isScalarType!T)
|
if (isScalarType!T)
|
||||||
{
|
{
|
||||||
/// Internal buffer.
|
/// Internal buffer.
|
||||||
private T[] buffer_;
|
private T[] buffer_;
|
||||||
@ -322,16 +323,16 @@ struct WriteBuffer(T = ubyte)
|
|||||||
private size_t ring;
|
private size_t ring;
|
||||||
|
|
||||||
/// Size by which the buffer will grow.
|
/// Size by which the buffer will grow.
|
||||||
private immutable size_t blockSize;
|
private const size_t blockSize;
|
||||||
|
|
||||||
/// The position of the free area in the buffer.
|
/// The position of the free area in the buffer.
|
||||||
private size_t position;
|
private size_t position;
|
||||||
|
|
||||||
invariant
|
invariant
|
||||||
{
|
{
|
||||||
assert(blockSize > 0);
|
assert(this.blockSize > 0);
|
||||||
// Position can refer to an element outside the buffer if the buffer is full.
|
// Position can refer to an element outside the buffer if the buffer is full.
|
||||||
assert(position <= buffer_.length);
|
assert(this.position <= this.buffer_.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -342,7 +343,7 @@ struct WriteBuffer(T = ubyte)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE size > 0 && allocator !is null)
|
* Precondition: $(D_INLINECODE size > 0 && allocator !is null)
|
||||||
*/
|
*/
|
||||||
this(in size_t size, shared Allocator allocator = defaultAllocator) @trusted
|
this(size_t size, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
@ -350,10 +351,10 @@ struct WriteBuffer(T = ubyte)
|
|||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
blockSize = size;
|
this.blockSize = size;
|
||||||
ring = size - 1;
|
ring = size - 1;
|
||||||
allocator_ = allocator;
|
allocator_ = allocator;
|
||||||
buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof);
|
this.buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof);
|
||||||
}
|
}
|
||||||
|
|
||||||
@disable this();
|
@disable this();
|
||||||
@ -363,7 +364,7 @@ struct WriteBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
allocator.deallocate(buffer_);
|
allocator.deallocate(this.buffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -371,7 +372,7 @@ struct WriteBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
@property size_t capacity() const
|
@property size_t capacity() const
|
||||||
{
|
{
|
||||||
return buffer_.length;
|
return this.buffer_.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -384,13 +385,13 @@ struct WriteBuffer(T = ubyte)
|
|||||||
*/
|
*/
|
||||||
@property size_t length() const
|
@property size_t length() const
|
||||||
{
|
{
|
||||||
if (position > ring || position < start) // Buffer overflowed
|
if (this.position > ring || this.position < start) // Buffer overflowed
|
||||||
{
|
{
|
||||||
return ring - start + 1;
|
return ring - start + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return position - start;
|
return this.position - start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,61 +434,62 @@ struct WriteBuffer(T = ubyte)
|
|||||||
* Params:
|
* Params:
|
||||||
* buffer = Buffer chunk got with $(D_PSYMBOL opIndex).
|
* buffer = Buffer chunk got with $(D_PSYMBOL opIndex).
|
||||||
*/
|
*/
|
||||||
ref WriteBuffer opOpAssign(string op)(in T[] buffer)
|
ref WriteBuffer opOpAssign(string op)(const T[] buffer)
|
||||||
if (op == "~")
|
if (op == "~")
|
||||||
{
|
{
|
||||||
size_t end, start;
|
size_t end, start;
|
||||||
|
|
||||||
if (position >= this.start && position <= ring)
|
if (this.position >= this.start && this.position <= ring)
|
||||||
{
|
{
|
||||||
auto afterRing = ring + 1;
|
auto afterRing = ring + 1;
|
||||||
|
|
||||||
end = position + buffer.length;
|
end = this.position + buffer.length;
|
||||||
if (end > afterRing)
|
if (end > afterRing)
|
||||||
{
|
{
|
||||||
end = afterRing;
|
end = afterRing;
|
||||||
}
|
}
|
||||||
start = end - position;
|
start = end - this.position;
|
||||||
buffer_[position .. end] = buffer[0 .. start];
|
this.buffer_[this.position .. end] = buffer[0 .. start];
|
||||||
if (end == afterRing)
|
if (end == afterRing)
|
||||||
{
|
{
|
||||||
position = this.start == 0 ? afterRing : 0;
|
this.position = this.start == 0 ? afterRing : 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
position = end;
|
this.position = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have some free space at the beginning
|
// Check if we have some free space at the beginning
|
||||||
if (start < buffer.length && position < this.start)
|
if (start < buffer.length && this.position < this.start)
|
||||||
{
|
{
|
||||||
end = position + buffer.length - start;
|
end = this.position + buffer.length - start;
|
||||||
if (end > this.start)
|
if (end > this.start)
|
||||||
{
|
{
|
||||||
end = this.start;
|
end = this.start;
|
||||||
}
|
}
|
||||||
auto areaEnd = end - position + start;
|
auto areaEnd = end - this.position + start;
|
||||||
buffer_[position .. end] = buffer[start .. areaEnd];
|
this.buffer_[this.position .. end] = buffer[start .. areaEnd];
|
||||||
position = end == this.start ? ring + 1 : end - position;
|
this.position = end == this.start ? ring + 1 : end - this.position;
|
||||||
start = areaEnd;
|
start = areaEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// And if we still haven't found any place, save the rest in the overflow area
|
// And if we still haven't found any place, save the rest in the overflow area
|
||||||
if (start < buffer.length)
|
if (start < buffer.length)
|
||||||
{
|
{
|
||||||
end = position + buffer.length - start;
|
end = this.position + buffer.length - start;
|
||||||
if (end > capacity)
|
if (end > capacity)
|
||||||
{
|
{
|
||||||
auto newSize = (end / blockSize * blockSize + blockSize) * T.sizeof;
|
const newSize = end / this.blockSize * this.blockSize
|
||||||
|
+ this.blockSize;
|
||||||
() @trusted {
|
() @trusted {
|
||||||
void[] buf = buffer_;
|
void[] buf = this.buffer_;
|
||||||
allocator.reallocate(buf, newSize);
|
allocator.reallocate(buf, newSize * T.sizeof);
|
||||||
buffer_ = cast(T[]) buf;
|
this.buffer_ = cast(T[]) buf;
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
buffer_[position .. end] = buffer[start .. $];
|
this.buffer_[this.position .. end] = buffer[start .. $];
|
||||||
position = end;
|
this.position = end;
|
||||||
if (this.start == 0)
|
if (this.start == 0)
|
||||||
{
|
{
|
||||||
ring = capacity - 1;
|
ring = capacity - 1;
|
||||||
@ -506,7 +508,7 @@ struct WriteBuffer(T = ubyte)
|
|||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref WriteBuffer opOpAssign(string op)(in size_t length)
|
ref WriteBuffer opOpAssign(string op)(size_t length)
|
||||||
if (op == "+")
|
if (op == "+")
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -521,42 +523,42 @@ struct WriteBuffer(T = ubyte)
|
|||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
else if (position <= afterRing)
|
else if (this.position <= afterRing)
|
||||||
{
|
{
|
||||||
start += length;
|
start += length;
|
||||||
if (start > 0 && position == afterRing)
|
if (start > 0 && this.position == afterRing)
|
||||||
{
|
{
|
||||||
position = oldStart;
|
this.position = oldStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto overflow = position - afterRing;
|
auto overflow = this.position - afterRing;
|
||||||
|
|
||||||
if (overflow > length)
|
if (overflow > length)
|
||||||
{
|
{
|
||||||
immutable afterLength = afterRing + length;
|
const afterLength = afterRing + length;
|
||||||
buffer_[start .. start + length] = buffer_[afterRing .. afterLength];
|
this.buffer_[start .. start + length] = this.buffer_[afterRing .. afterLength];
|
||||||
buffer_[afterRing .. afterLength] = buffer_[afterLength .. position];
|
this.buffer_[afterRing .. afterLength] = this.buffer_[afterLength .. this.position];
|
||||||
position -= length;
|
this.position -= length;
|
||||||
}
|
}
|
||||||
else if (overflow == length)
|
else if (overflow == length)
|
||||||
{
|
{
|
||||||
buffer_[start .. start + overflow] = buffer_[afterRing .. position];
|
this.buffer_[start .. start + overflow] = this.buffer_[afterRing .. this.position];
|
||||||
position -= overflow;
|
this.position -= overflow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer_[start .. start + overflow] = buffer_[afterRing .. position];
|
this.buffer_[start .. start + overflow] = this.buffer_[afterRing .. this.position];
|
||||||
position = overflow;
|
this.position = overflow;
|
||||||
}
|
}
|
||||||
start += length;
|
start += length;
|
||||||
|
|
||||||
if (start == position)
|
if (start == this.position)
|
||||||
{
|
{
|
||||||
if (position != afterRing)
|
if (this.position != afterRing)
|
||||||
{
|
{
|
||||||
position = 0;
|
this.position = 0;
|
||||||
}
|
}
|
||||||
start = 0;
|
start = 0;
|
||||||
ring = capacity - 1;
|
ring = capacity - 1;
|
||||||
@ -596,15 +598,15 @@ struct WriteBuffer(T = ubyte)
|
|||||||
*
|
*
|
||||||
* Returns: A chunk of data buffer.
|
* Returns: A chunk of data buffer.
|
||||||
*/
|
*/
|
||||||
T[] opSlice(in size_t start, in size_t end)
|
T[] opSlice(size_t start, size_t end)
|
||||||
{
|
{
|
||||||
if (position > ring || position < start) // Buffer overflowed
|
if (this.position > ring || this.position < start) // Buffer overflowed
|
||||||
{
|
{
|
||||||
return buffer_[this.start .. ring + 1 - length + end];
|
return this.buffer_[this.start .. ring + 1 - length + end];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return buffer_[this.start .. this.start + end];
|
return this.buffer_[this.start .. this.start + end];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.list;
|
module tanya.container.list;
|
||||||
|
|
||||||
import std.algorithm.comparison : equal;
|
|
||||||
import std.algorithm.searching;
|
import std.algorithm.searching;
|
||||||
import tanya.algorithm.comparison;
|
import tanya.algorithm.comparison;
|
||||||
import tanya.algorithm.mutation;
|
import tanya.algorithm.mutation;
|
||||||
@ -178,7 +177,6 @@ struct SList(T)
|
|||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto l = SList!int(2, 3);
|
auto l = SList!int(2, 3);
|
||||||
assert(l.length == 2);
|
|
||||||
assert(l.front == 3);
|
assert(l.front == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +190,6 @@ struct SList(T)
|
|||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto l = SList!int(2);
|
auto l = SList!int(2);
|
||||||
assert(l.length == 2);
|
|
||||||
assert(l.front == 0);
|
assert(l.front == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +429,6 @@ struct SList(T)
|
|||||||
assert(l2.front == 25);
|
assert(l2.front == 25);
|
||||||
|
|
||||||
l2.insertFront(l1[]);
|
l2.insertFront(l1[]);
|
||||||
assert(l2.length == 5);
|
|
||||||
assert(l2.front == 9);
|
assert(l2.front == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,12 +562,6 @@ struct SList(T)
|
|||||||
assert(l1 == l2);
|
assert(l1 == l2);
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated
|
|
||||||
@property size_t length() const
|
|
||||||
{
|
|
||||||
return count(this[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparison for equality.
|
* Comparison for equality.
|
||||||
*
|
*
|
||||||
@ -583,7 +573,7 @@ struct SList(T)
|
|||||||
*/
|
*/
|
||||||
bool opEquals()(auto ref typeof(this) that) inout
|
bool opEquals()(auto ref typeof(this) that) inout
|
||||||
{
|
{
|
||||||
return equal(this[], that[]);
|
return equal(opIndex(), that[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -1154,7 +1144,6 @@ struct DList(T)
|
|||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto l = DList!int(2, 3);
|
auto l = DList!int(2, 3);
|
||||||
assert(l.length == 2);
|
|
||||||
assert(l.front == 3);
|
assert(l.front == 3);
|
||||||
assert(l.back == 3);
|
assert(l.back == 3);
|
||||||
}
|
}
|
||||||
@ -1169,7 +1158,6 @@ struct DList(T)
|
|||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto l = DList!int(2);
|
auto l = DList!int(2);
|
||||||
assert(l.length == 2);
|
|
||||||
assert(l.front == 0);
|
assert(l.front == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1480,7 +1468,6 @@ struct DList(T)
|
|||||||
assert(l2.back == 15);
|
assert(l2.back == 15);
|
||||||
|
|
||||||
l2.insertFront(l1[]);
|
l2.insertFront(l1[]);
|
||||||
assert(l2.length == 5);
|
|
||||||
assert(l2.front == 9);
|
assert(l2.front == 9);
|
||||||
assert(l2.back == 15);
|
assert(l2.back == 15);
|
||||||
}
|
}
|
||||||
@ -1600,7 +1587,6 @@ struct DList(T)
|
|||||||
assert(l2.back == 15);
|
assert(l2.back == 15);
|
||||||
|
|
||||||
l2.insertBack(l1[]);
|
l2.insertBack(l1[]);
|
||||||
assert(l2.length == 5);
|
|
||||||
assert(l2.back == 9);
|
assert(l2.back == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1855,12 +1841,6 @@ struct DList(T)
|
|||||||
return insertAfter!(T[])(r, el[]);
|
return insertAfter!(T[])(r, el[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated
|
|
||||||
@property size_t length() const
|
|
||||||
{
|
|
||||||
return count(this[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparison for equality.
|
* Comparison for equality.
|
||||||
*
|
*
|
||||||
@ -2354,7 +2334,6 @@ struct DList(T)
|
|||||||
l.insertAfter(l[], 234);
|
l.insertAfter(l[], 234);
|
||||||
assert(l.front == 234);
|
assert(l.front == 234);
|
||||||
assert(l.back == 234);
|
assert(l.back == 234);
|
||||||
assert(l.length == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.string;
|
module tanya.container.string;
|
||||||
|
|
||||||
import std.algorithm.comparison : cmp, equal;
|
import std.algorithm.comparison : cmp;
|
||||||
import std.algorithm.mutation : bringToFront, copy;
|
import std.algorithm.mutation : bringToFront, copy;
|
||||||
import std.algorithm.searching;
|
import std.algorithm.searching;
|
||||||
import tanya.algorithm.comparison;
|
import tanya.algorithm.comparison;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* This module provides functions for converting between different types.
|
* This module provides functions for converting between different types.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -20,6 +20,8 @@ import tanya.memory;
|
|||||||
import tanya.memory.op;
|
import tanya.memory.op;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
|
import tanya.range.array;
|
||||||
|
import tanya.range.primitive;
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
@ -264,28 +266,148 @@ final class ConvException : Exception
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
package bool stringToInt(R)(R range, ref ushort n)
|
/*
|
||||||
|
* Converts a string $(D_PARAM range) into an integral value of type
|
||||||
|
* $(D_PARAM T) in $(D_PARAM base).
|
||||||
|
*
|
||||||
|
* The convertion stops when $(D_PARAM range) is empty of if the next character
|
||||||
|
* cannot be converted because it is not a digit (with respect to the
|
||||||
|
* $(D_PARAM base)) or if the reading the next character would cause integer
|
||||||
|
* overflow. The function returns the value converted so far then. The front
|
||||||
|
* element of the $(D_PARAM range) points to the first character cannot be
|
||||||
|
* converted or $(D_PARAM range) is empty if the whole string could be
|
||||||
|
* converted.
|
||||||
|
*
|
||||||
|
* Base must be between 2 and 36 inclursive. Default base is 10.
|
||||||
|
*
|
||||||
|
* The function doesn't handle the sign (+ or -) or number prefixes (like 0x).
|
||||||
|
*/
|
||||||
|
package T readIntegral(T, R)(ref R range, ubyte base = 10)
|
||||||
|
if (isForwardRange!R
|
||||||
|
&& isSomeChar!(ElementType!R)
|
||||||
|
&& isIntegral!T
|
||||||
|
&& isUnsigned!T)
|
||||||
|
in
|
||||||
{
|
{
|
||||||
import tanya.encoding.ascii;
|
assert(base >= 2);
|
||||||
import tanya.range.array;
|
assert(base <= 36);
|
||||||
|
}
|
||||||
size_t i = 1;
|
do
|
||||||
uint lPort;
|
{
|
||||||
|
T boundary = cast(T) (T.max / base);
|
||||||
for (; !range.empty && range.front.isDigit() && i <= 6; ++i, range.popFront())
|
if (range.empty)
|
||||||
{
|
{
|
||||||
lPort = lPort * 10 + (range.front - '0');
|
return T.init;
|
||||||
}
|
}
|
||||||
if (i != 1 && (range.empty || range.front == '/'))
|
|
||||||
|
T n;
|
||||||
|
while (n <= boundary)
|
||||||
{
|
{
|
||||||
if (lPort > ushort.max)
|
int digit;
|
||||||
|
if (range.front >= 'a')
|
||||||
{
|
{
|
||||||
return false;
|
digit = range.front - 'W';
|
||||||
|
}
|
||||||
|
else if (range.front >= 'A')
|
||||||
|
{
|
||||||
|
digit = range.front - '7';
|
||||||
|
}
|
||||||
|
else if (range.front >= '0')
|
||||||
|
{
|
||||||
|
digit = range.front - '0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
if (digit >= base)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
n = cast(T) (n * base + digit);
|
||||||
|
range.popFront();
|
||||||
|
|
||||||
|
if (range.empty)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
n = cast(ushort) lPort;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
if (range.length > 1)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int digit = range.front - '0';
|
||||||
|
if (n > cast(T) ((T.max - digit) / base))
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
n = cast(T) (n * base + digit);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads ubyte.max
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "255";
|
||||||
|
assert(readIntegral!ubyte(number) == 255);
|
||||||
|
assert(number.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// detects integer overflow
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "500";
|
||||||
|
readIntegral!ubyte(number);
|
||||||
|
assert(number.front == '0');
|
||||||
|
assert(number.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stops on a non-digit
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "10-";
|
||||||
|
readIntegral!ubyte(number);
|
||||||
|
assert(number.front == '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns false if the number string is empty
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "";
|
||||||
|
readIntegral!ubyte(number);
|
||||||
|
assert(number.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "29";
|
||||||
|
assert(readIntegral!ubyte(number) == 29);
|
||||||
|
assert(number.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "25467";
|
||||||
|
readIntegral!ubyte(number);
|
||||||
|
assert(number.front == '6');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts lower case hexadecimals
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "a";
|
||||||
|
assert(readIntegral!ubyte(number, 16) == 10);
|
||||||
|
assert(number.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts upper case hexadecimals
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
string number = "FF";
|
||||||
|
assert(readIntegral!ubyte(number, 16) == 255);
|
||||||
|
assert(number.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Common exceptions and errors.
|
* Common exceptions and errors.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This package contains formatting and conversion functions.
|
* This package doesn't yet contain public symbols. Refer to
|
||||||
|
* $(D_PSYMBOL tanya.conv) for basic formatting and conversion functionality.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.math.mp;
|
module tanya.math.mp;
|
||||||
|
|
||||||
import std.algorithm.comparison : cmp, equal;
|
import std.algorithm.comparison : cmp;
|
||||||
import std.algorithm.mutation : copy, fill, reverse;
|
import std.algorithm.mutation : copy, fill, reverse;
|
||||||
import std.range;
|
import std.range;
|
||||||
import tanya.algorithm.comparison;
|
import tanya.algorithm.comparison;
|
||||||
|
@ -38,7 +38,7 @@ enum IEEEPrecision : ubyte
|
|||||||
/**
|
/**
|
||||||
* Tests the precision of floating-point type $(D_PARAM F).
|
* Tests the precision of floating-point type $(D_PARAM F).
|
||||||
*
|
*
|
||||||
* For $(D_KEYWORD float), $(D_PSYMBOL ieeePrecision) always evaluates to
|
* For $(D_KEYWORD float) $(D_PSYMBOL ieeePrecision) always evaluates to
|
||||||
* $(D_INLINECODE IEEEPrecision.single); for $(D_KEYWORD double) - to
|
* $(D_INLINECODE IEEEPrecision.single); for $(D_KEYWORD double) - to
|
||||||
* $(D_INLINECODE IEEEPrecision.double). It returns different values only
|
* $(D_INLINECODE IEEEPrecision.double). It returns different values only
|
||||||
* for $(D_KEYWORD real), since $(D_KEYWORD real) is a platform-dependent type.
|
* for $(D_KEYWORD real), since $(D_KEYWORD real) is a platform-dependent type.
|
||||||
@ -396,7 +396,7 @@ if (isFloatingPoint!F)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether $(D_PARAM x) is a denormilized number or not.
|
* Determines whether $(D_PARAM x) is a denormilized number or not.
|
||||||
|
*
|
||||||
* Denormalized number is a number between `0` and `1` that cannot be
|
* Denormalized number is a number between `0` and `1` that cannot be
|
||||||
* represented as
|
* represented as
|
||||||
*
|
*
|
||||||
@ -459,7 +459,7 @@ if (isFloatingPoint!F)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether $(D_PARAM x) is a normilized number or not.
|
* Determines whether $(D_PARAM x) is a normilized number or not.
|
||||||
|
*
|
||||||
* Normalized number is a number that can be represented as
|
* Normalized number is a number that can be represented as
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -40,6 +40,11 @@ version (TanyaNative)
|
|||||||
fillMemory(buffer[1 .. $], 0);
|
fillMemory(buffer[1 .. $], 0);
|
||||||
assert(buffer[0] == 1 && buffer[1] == 0);
|
assert(buffer[0] == 1 && buffer[1] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(cmp(null, null) == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum alignMask = size_t.sizeof - 1;
|
private enum alignMask = size_t.sizeof - 1;
|
||||||
|
@ -305,7 +305,14 @@ struct URL
|
|||||||
*/
|
*/
|
||||||
private bool parsePort(const(char)[] port) @nogc nothrow pure @safe
|
private bool parsePort(const(char)[] port) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
return stringToInt(port[1 .. $], this.port);
|
auto unparsed = port[1 .. $];
|
||||||
|
auto parsed = readIntegral!ushort(unparsed);
|
||||||
|
if (unparsed.length == 0 || unparsed[0] == '/')
|
||||||
|
{
|
||||||
|
this.port = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Network programming.
|
* Network programming.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2016-2017.
|
* Copyright: Eugene Wissner 2016-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -5,7 +5,43 @@
|
|||||||
/**
|
/**
|
||||||
* Low-level socket programming.
|
* Low-level socket programming.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2016-2017.
|
* Current API supports only server-side TCP communication.
|
||||||
|
*
|
||||||
|
* Here is an example of a cross-platform blocking server:
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
* import std.stdio;
|
||||||
|
* import tanya.memory;
|
||||||
|
* import tanya.network;
|
||||||
|
*
|
||||||
|
* void main()
|
||||||
|
* {
|
||||||
|
* auto socket = defaultAllocator.make!StreamSocket(AddressFamily.inet);
|
||||||
|
* auto address = defaultAllocator.make!InternetAddress("127.0.0.1",
|
||||||
|
* cast(ushort) 8192);
|
||||||
|
*
|
||||||
|
* socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
|
||||||
|
* socket.blocking = true;
|
||||||
|
* socket.bind(address);
|
||||||
|
* socket.listen(5);
|
||||||
|
*
|
||||||
|
* auto client = socket.accept();
|
||||||
|
* client.send(cast(const(ubyte)[]) "Test\n");
|
||||||
|
*
|
||||||
|
* ubyte[100] buf;
|
||||||
|
* auto response = client.receive(buf[]);
|
||||||
|
*
|
||||||
|
* writeln(cast(const(char)[]) buf[0 .. response]);
|
||||||
|
*
|
||||||
|
* defaultAllocator.dispose(client);
|
||||||
|
* defaultAllocator.dispose(socket);
|
||||||
|
* }
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* For an example of an asynchronous server refer to the documentation of the
|
||||||
|
* $(D_PSYMBOL tanya.async.loop) module.
|
||||||
|
*
|
||||||
|
* Copyright: Eugene Wissner 2016-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* This package provides platform-independent interfaces to operating system
|
* This package provides platform-independent interfaces to operating system
|
||||||
* functionality.
|
* functionality.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
375
source/tanya/range/adapter.d
Normal file
375
source/tanya/range/adapter.d
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Range adapters.
|
||||||
|
*
|
||||||
|
* A range adapter wraps another range and modifies the way, how the original
|
||||||
|
* range is iterated, or the order in which its elements are accessed.
|
||||||
|
*
|
||||||
|
* All adapters are lazy algorithms, they request the next element of the
|
||||||
|
* adapted range on demand.
|
||||||
|
*
|
||||||
|
* Copyright: Eugene Wissner 2018.
|
||||||
|
* 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)
|
||||||
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/range/adapter.d,
|
||||||
|
* tanya/range/adapter.d)
|
||||||
|
*/
|
||||||
|
module tanya.range.adapter;
|
||||||
|
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
|
import tanya.math;
|
||||||
|
import tanya.range.primitive;
|
||||||
|
|
||||||
|
private mixin template Take(R, bool exactly)
|
||||||
|
{
|
||||||
|
private R source;
|
||||||
|
size_t length_;
|
||||||
|
|
||||||
|
@disable this();
|
||||||
|
|
||||||
|
private this(R source, size_t length)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
static if (!exactly && hasLength!R)
|
||||||
|
{
|
||||||
|
this.length_ = min(source.length, length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.length_ = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property auto ref front()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return this.source.front;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source.popFront();
|
||||||
|
--this.length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property bool empty()
|
||||||
|
{
|
||||||
|
static if (exactly || isInfinite!R)
|
||||||
|
{
|
||||||
|
return length == 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return length == 0 || this.source.empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property size_t length()
|
||||||
|
{
|
||||||
|
return this.length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (hasAssignableElements!R)
|
||||||
|
{
|
||||||
|
@property void front(ref ElementType!R value)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source.front = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property void front(ElementType!R value)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source.front = move(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (isForwardRange!R)
|
||||||
|
{
|
||||||
|
typeof(this) save()
|
||||||
|
{
|
||||||
|
return typeof(this)(this.source.save(), length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static if (isRandomAccessRange!R)
|
||||||
|
{
|
||||||
|
@property auto ref back()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return this.source[this.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void popBack()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
--this.length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ref opIndex(size_t i)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i < length);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return this.source[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (hasAssignableElements!R)
|
||||||
|
{
|
||||||
|
@property void back(ref ElementType!R value)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source[length - 1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property void back(ElementType!R value)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source[length - 1] = move(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void opIndexAssign(ref ElementType!R value, size_t i)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i < length);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source[i] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opIndexAssign(ElementType!R value, size_t i)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i < length);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.source[i] = move(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static if (hasSlicing!R)
|
||||||
|
{
|
||||||
|
auto opSlice(size_t i, size_t j)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i <= j);
|
||||||
|
assert(j <= length);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return take(this.source[i .. j], length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes $(D_PARAM n) elements from $(D_PARAM range).
|
||||||
|
*
|
||||||
|
* If $(D_PARAM range) doesn't have $(D_PARAM n) elements, the resulting range
|
||||||
|
* spans all elements of $(D_PARAM range).
|
||||||
|
*
|
||||||
|
* $(D_PSYMBOL take) is particulary useful with infinite ranges. You can take
|
||||||
|
` $(B n) elements from such range and pass the result to an algorithm which
|
||||||
|
* expects a finit range.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Type of the adapted range.
|
||||||
|
* range = The range to take the elements from.
|
||||||
|
* n = The number of elements to take.
|
||||||
|
*
|
||||||
|
* Returns: A range containing maximum $(D_PARAM n) first elements of
|
||||||
|
* $(D_PARAM range).
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL takeExactly).
|
||||||
|
*/
|
||||||
|
auto take(R)(R range, size_t n)
|
||||||
|
if (isInputRange!R)
|
||||||
|
{
|
||||||
|
struct Take
|
||||||
|
{
|
||||||
|
mixin .Take!(R, false);
|
||||||
|
}
|
||||||
|
return Take(range, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct InfiniteRange
|
||||||
|
{
|
||||||
|
private size_t front_ = 1;
|
||||||
|
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
@property size_t front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this.front_;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property void front(size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
this.front_ = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
++this.front_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t opIndex(size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this.front_ + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opIndexAssign(size_t value, size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
this.front = i + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfiniteRange save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto t = InfiniteRange().take(3);
|
||||||
|
assert(t.length == 3);
|
||||||
|
assert(t.front == 1);
|
||||||
|
assert(t.back == 3);
|
||||||
|
|
||||||
|
t.popFront();
|
||||||
|
assert(t.front == 2);
|
||||||
|
assert(t.back == 3);
|
||||||
|
|
||||||
|
t.popBack();
|
||||||
|
assert(t.front == 2);
|
||||||
|
assert(t.back == 2);
|
||||||
|
|
||||||
|
t.popFront();
|
||||||
|
assert(t.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes exactly $(D_PARAM n) elements from $(D_PARAM range).
|
||||||
|
*
|
||||||
|
* $(D_PARAM range) must have at least $(D_PARAM n) elements.
|
||||||
|
*
|
||||||
|
* $(D_PSYMBOL takeExactly) is particulary useful with infinite ranges. You can
|
||||||
|
` take $(B n) elements from such range and pass the result to an algorithm
|
||||||
|
* which expects a finit range.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Type of the adapted range.
|
||||||
|
* range = The range to take the elements from.
|
||||||
|
* n = The number of elements to take.
|
||||||
|
*
|
||||||
|
* Returns: A range containing $(D_PARAM n) first elements of $(D_PARAM range).
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL take).
|
||||||
|
*/
|
||||||
|
auto takeExactly(R)(R range, size_t n)
|
||||||
|
if (isInputRange!R)
|
||||||
|
{
|
||||||
|
struct TakeExactly
|
||||||
|
{
|
||||||
|
mixin Take!(R, true);
|
||||||
|
}
|
||||||
|
return TakeExactly(range, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct InfiniteRange
|
||||||
|
{
|
||||||
|
private size_t front_ = 1;
|
||||||
|
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
@property size_t front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this.front_;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property void front(size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
this.front_ = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
++this.front_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t opIndex(size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this.front_ + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opIndexAssign(size_t value, size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
this.front = i + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfiniteRange save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto t = InfiniteRange().takeExactly(3);
|
||||||
|
assert(t.length == 3);
|
||||||
|
assert(t.front == 1);
|
||||||
|
assert(t.back == 3);
|
||||||
|
|
||||||
|
t.popFront();
|
||||||
|
assert(t.front == 2);
|
||||||
|
assert(t.back == 3);
|
||||||
|
|
||||||
|
t.popBack();
|
||||||
|
assert(t.front == 2);
|
||||||
|
assert(t.back == 2);
|
||||||
|
|
||||||
|
t.popFront();
|
||||||
|
assert(t.empty);
|
||||||
|
}
|
@ -15,5 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.range;
|
module tanya.range;
|
||||||
|
|
||||||
|
public import tanya.range.adapter;
|
||||||
public import tanya.range.array;
|
public import tanya.range.array;
|
||||||
public import tanya.range.primitive;
|
public import tanya.range.primitive;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* defined here.
|
* defined here.
|
||||||
* Also aliases for specific types like $(D_PSYMBOL SOCKET) are defined here.
|
* Also aliases for specific types like $(D_PSYMBOL SOCKET) are defined here.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -58,4 +58,4 @@ align(1) struct GUID
|
|||||||
ushort Data2;
|
ushort Data2;
|
||||||
ushort Data3;
|
ushort Data3;
|
||||||
char[8] Data4;
|
char[8] Data4;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -17,4 +17,4 @@ version (Windows):
|
|||||||
public import tanya.sys.windows.def;
|
public import tanya.sys.windows.def;
|
||||||
public import tanya.sys.windows.error;
|
public import tanya.sys.windows.error;
|
||||||
public import tanya.sys.windows.winbase;
|
public import tanya.sys.windows.winbase;
|
||||||
public import tanya.sys.windows.winsock2;
|
public import tanya.sys.windows.winsock2;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Definitions from winbase.h.
|
* Definitions from winbase.h.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -52,4 +52,4 @@ extern(Windows)
|
|||||||
BOOL GetOverlappedResult(HANDLE hFile,
|
BOOL GetOverlappedResult(HANDLE hFile,
|
||||||
OVERLAPPED* lpOverlapped,
|
OVERLAPPED* lpOverlapped,
|
||||||
DWORD* lpNumberOfBytesTransferred,
|
DWORD* lpNumberOfBytesTransferred,
|
||||||
BOOL bWait) nothrow @system @nogc;
|
BOOL bWait) nothrow @system @nogc;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Definitions from winsock2.h, ws2def.h and MSWSock.h.
|
* Definitions from winsock2.h, ws2def.h and MSWSock.h.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -216,4 +216,4 @@ enum
|
|||||||
SO_UPDATE_ACCEPT_CONTEXT = 0x700B,
|
SO_UPDATE_ACCEPT_CONTEXT = 0x700B,
|
||||||
SO_CONNECT_TIME = 0x700C,
|
SO_CONNECT_TIME = 0x700C,
|
||||||
SO_UPDATE_CONNECT_CONTEXT = 0x7010,
|
SO_UPDATE_CONNECT_CONTEXT = 0x7010,
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* The functions can cause segmentation fault if the module is compiled
|
* The functions can cause segmentation fault if the module is compiled
|
||||||
* in production mode and the condition fails.
|
* in production mode and the condition fails.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Test suite for $(D_KEYWORD unittest)-blocks.
|
* Test suite for $(D_KEYWORD unittest)-blocks.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017.
|
* Copyright: Eugene Wissner 2017-2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.typecons;
|
module tanya.typecons;
|
||||||
|
|
||||||
|
import tanya.format;
|
||||||
import tanya.meta.metafunction : AliasSeq, AliasTuple = Tuple, Map;
|
import tanya.meta.metafunction : AliasSeq, AliasTuple = Tuple, Map;
|
||||||
|
|
||||||
deprecated("Use tanya.typecons.Tuple instead")
|
deprecated("Use tanya.typecons.Tuple instead")
|
||||||
@ -77,11 +78,10 @@ template Pair(Specs...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $(D_PSYMBOL Tuple) can store two heterogeneous objects.
|
* $(D_PSYMBOL Tuple) can store two or more heterogeneous objects.
|
||||||
*
|
*
|
||||||
* The objects can by accessed by index as $(D_INLINECODE obj[0]) and
|
* The objects can by accessed by index as `obj[0]` and `obj[1]` or by optional
|
||||||
* $(D_INLINECODE obj[1]) or by optional names (e.g.
|
* names (e.g. `obj.first`).
|
||||||
* $(D_INLINECODE obj.first)).
|
|
||||||
*
|
*
|
||||||
* $(D_PARAM Specs) contains a list of object types and names. First
|
* $(D_PARAM Specs) contains a list of object types and names. First
|
||||||
* comes the object type, then an optional string containing the name.
|
* comes the object type, then an optional string containing the name.
|
||||||
@ -123,7 +123,26 @@ template Tuple(Specs...)
|
|||||||
alias ChooseType(alias T) = T.Seq[0];
|
alias ChooseType(alias T) = T.Seq[0];
|
||||||
alias ParsedSpecs = parseSpecs!(0, Specs);
|
alias ParsedSpecs = parseSpecs!(0, Specs);
|
||||||
|
|
||||||
static assert(ParsedSpecs.length == 2, "Invalid argument count");
|
static assert(ParsedSpecs.length > 1, "Invalid argument count");
|
||||||
|
|
||||||
|
private string formatAliases(size_t n, Specs...)()
|
||||||
|
{
|
||||||
|
static if (Specs.length == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string fieldAlias;
|
||||||
|
static if (Specs[0].length == 2)
|
||||||
|
{
|
||||||
|
char[21] buffer;
|
||||||
|
fieldAlias = "alias " ~ Specs[0][1] ~ " = expand["
|
||||||
|
~ integral2String(n, buffer).idup ~ "];";
|
||||||
|
}
|
||||||
|
return fieldAlias ~ formatAliases!(n + 1, Specs[1 .. $])();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Tuple
|
struct Tuple
|
||||||
{
|
{
|
||||||
@ -131,14 +150,7 @@ template Tuple(Specs...)
|
|||||||
alias Types = Map!(ChooseType, ParsedSpecs);
|
alias Types = Map!(ChooseType, ParsedSpecs);
|
||||||
|
|
||||||
// Create field aliases.
|
// Create field aliases.
|
||||||
static if (ParsedSpecs[0].length == 2)
|
mixin(formatAliases!(0, ParsedSpecs[0 .. $])());
|
||||||
{
|
|
||||||
mixin("alias " ~ ParsedSpecs[0][1] ~ " = expand[0];");
|
|
||||||
}
|
|
||||||
static if (ParsedSpecs[1].length == 2)
|
|
||||||
{
|
|
||||||
mixin("alias " ~ ParsedSpecs[1][1] ~ " = expand[1];");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the values of the $(D_PSYMBOL Tuple) as a list of values.
|
/// Represents the values of the $(D_PSYMBOL Tuple) as a list of values.
|
||||||
Types expand;
|
Types expand;
|
||||||
@ -171,4 +183,7 @@ template Tuple(Specs...)
|
|||||||
static assert(!is(Tuple!(int, int, int)));
|
static assert(!is(Tuple!(int, int, int)));
|
||||||
|
|
||||||
static assert(!is(Tuple!(int, "first")));
|
static assert(!is(Tuple!(int, "first")));
|
||||||
|
|
||||||
|
static assert(!is(Tuple!(int, double, char)));
|
||||||
|
static assert(!is(Tuple!(int, "first", double, "second", char, "third")));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user