learncrypto/source/utility.d

211 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]);
}