summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-03-25 08:17:38 +0200
committerEugen Wissner <belka@caraus.de>2018-06-10 14:46:40 +0200
commitcd9960db2ab3cdf9434fc5caf954d25aea484108 (patch)
tree11123dba3f0cfbfab225154a6f2434a3c55c2ce1
parent7357503c5a90b841c3392fa98ae21c5695632605 (diff)
downloadtanya-cd9960db2ab3cdf9434fc5caf954d25aea484108.tar.gz
Add take range adapter
-rw-r--r--source/tanya/range/package.d284
1 files changed, 284 insertions, 0 deletions
diff --git a/source/tanya/range/package.d b/source/tanya/range/package.d
index 8894c95..1d03e22 100644
--- a/source/tanya/range/package.d
+++ b/source/tanya/range/package.d
@@ -15,5 +15,289 @@
*/
module tanya.range;
+import tanya.algorithm.mutation;
+import tanya.math;
public import tanya.range.array;
public import tanya.range.primitive;
+
+/**
+ *
+ */
+struct Take(R)
+if (isInputRange!R)
+{
+ private R source;
+ size_t length_;
+
+ @disable this();
+
+ private this(R source, size_t length)
+ {
+ this.source = source;
+ static if (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 (isInfinite!R)
+ {
+ return length == 0;
+ }
+ else
+ {
+ return length == 0 || this.source.empty;
+ }
+ }
+
+ @property size_t length()
+ {
+ return this.length_;
+ }
+
+ static if (hasMobileElements!R)
+ {
+ auto moveFront()
+ in
+ {
+ assert(!empty);
+ }
+ do
+ {
+ return this.source.moveFront();
+ }
+ }
+ 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 (hasMobileElements!R)
+ {
+ auto moveBack()
+ in
+ {
+ assert(!empty);
+ }
+ do
+ {
+ return this.source.moveAt(length - 1);
+ }
+
+ auto moveAt(size_t i)
+ in
+ {
+ assert(i < length);
+ }
+ do
+ {
+ return this.source.moveAt(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);
+ }
+ }
+}
+
+/**
+ * ditto
+ */
+Take!R take(R)(R range, size_t n)
+if (isInputRange!R)
+{
+ return Take!R(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);
+}