210 lines
5.1 KiB
D
210 lines
5.1 KiB
D
module utility;
|
|
|
|
private import std.range : isInputRange, isInfinite, isForwardRange,
|
|
ElementType;
|
|
|
|
auto concat(T : E[n], E, size_t n)(in E[][] args...) @nogc
|
|
{
|
|
size_t offset = 0;
|
|
T result = void;
|
|
foreach (arr; args)
|
|
{
|
|
result[offset .. offset + arr.length] = arr;
|
|
offset += arr.length;
|
|
}
|
|
assert(offset == result.length);
|
|
return result;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
assert(concat!(int[0])() == []);
|
|
assert(concat!(int[0])([]) == []);
|
|
assert(concat!(int[0])([], []) == []);
|
|
assert(concat!(int[1])([1]) == [1]);
|
|
assert(concat!(int[1])([1], []) == [1]);
|
|
assert(concat!(int[1])([], [1]) == [1]);
|
|
assert(concat!(int[2])([1, 2]) == [1, 2]);
|
|
assert(concat!(int[2])([1], [2]) == [1, 2]);
|
|
assert(concat!(int[6])([1], [2, 3], [4, 5, 6]) == [1, 2, 3, 4, 5, 6]);
|
|
assert(concat!(char[12])("Hello", " ", "World!") == "Hello World!");
|
|
}
|
|
|
|
auto bufferedChunks(Source)(Source source, size_t chunkSize)
|
|
if (isInputRange!Source)
|
|
{
|
|
static struct BufferedChunks
|
|
{
|
|
this(Source source, size_t chunkSize)
|
|
{
|
|
assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
|
|
this.source = source;
|
|
this.chunkSize = chunkSize;
|
|
buffer.length = chunkSize;
|
|
foreach (i; 0 .. chunkSize)
|
|
{
|
|
if (!this.source.empty)
|
|
{
|
|
buffer[i] = this.source.front;
|
|
this.source.popFront;
|
|
bufferLength++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
auto front() @property
|
|
{
|
|
assert(!empty);
|
|
return buffer[0 .. bufferLength];
|
|
}
|
|
|
|
void popFront()
|
|
{
|
|
assert(!empty);
|
|
bufferLength = 0;
|
|
if (!source.empty)
|
|
{
|
|
foreach (i; 0 .. chunkSize)
|
|
{
|
|
if (!source.empty)
|
|
{
|
|
buffer[i] = source.front;
|
|
source.popFront;
|
|
bufferLength++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static if (isInfinite!Source)
|
|
{
|
|
enum empty = false;
|
|
}
|
|
else
|
|
{
|
|
bool empty() @property
|
|
{
|
|
return bufferLength == 0;
|
|
}
|
|
}
|
|
|
|
static if (isForwardRange!Source)
|
|
{
|
|
auto save()
|
|
{
|
|
auto ret = this;
|
|
ret.source = source.save;
|
|
ret.buffer = buffer.dup;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
private:
|
|
Source source;
|
|
size_t chunkSize;
|
|
ElementType!Source[] buffer;
|
|
size_t bufferLength;
|
|
}
|
|
|
|
return BufferedChunks(source, chunkSize);
|
|
}
|
|
|
|
version (unittest) private import std.array;
|
|
|
|
@safe unittest
|
|
{
|
|
int[] testArray;
|
|
auto _bufferedChunks = bufferedChunks(testArray, 1);
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
int[] testArray;
|
|
auto _bufferedChunks = bufferedChunks(testArray, 2);
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0], 1);
|
|
assert(_bufferedChunks.front == [0]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0], 2);
|
|
assert(_bufferedChunks.front == [0]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0, 1], 1);
|
|
assert(_bufferedChunks.front == [0]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.front == [1]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0, 1], 2);
|
|
assert(_bufferedChunks.front == [0, 1]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0, 1, 2], 2);
|
|
assert(_bufferedChunks.front == [0, 1]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.front == [2]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0, 1, 2, 3], 2);
|
|
assert(_bufferedChunks.front == [0, 1]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.front == [2, 3]);
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
}
|
|
|
|
@system unittest
|
|
{
|
|
import std.exception : assertThrown;
|
|
import core.exception : AssertError;
|
|
|
|
assertThrown!AssertError(bufferedChunks([0], 0));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0], 1);
|
|
auto otherBufferedChunks = _bufferedChunks.save;
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.empty);
|
|
assert(otherBufferedChunks.front == [0]);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto _bufferedChunks = bufferedChunks([0, 1], 1);
|
|
auto otherBufferedChunks = _bufferedChunks.save;
|
|
_bufferedChunks.popFront;
|
|
assert(_bufferedChunks.front == [1]);
|
|
assert(otherBufferedChunks.front == [0]);
|
|
}
|