summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/tanya/algorithm/iteration.d1
-rw-r--r--source/tanya/algorithm/mutation.d1
-rw-r--r--source/tanya/container/array.d1
-rw-r--r--source/tanya/container/hashtable.d1
-rw-r--r--source/tanya/container/list.d1
-rw-r--r--source/tanya/container/set.d1
-rw-r--r--source/tanya/container/string.d1
-rw-r--r--source/tanya/conv.d1
-rw-r--r--source/tanya/format.d1
-rw-r--r--source/tanya/hash/lookup.d1
-rw-r--r--source/tanya/net/iface.d1
-rw-r--r--source/tanya/net/inet.d1
-rw-r--r--source/tanya/net/ip.d1
-rw-r--r--source/tanya/range/adapter.d1
-rw-r--r--source/tanya/range/primitive.d1364
15 files changed, 15 insertions, 1363 deletions
diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d
index df1027d..b4e1403 100644
--- a/source/tanya/algorithm/iteration.d
+++ b/source/tanya/algorithm/iteration.d
@@ -20,6 +20,7 @@
*/
module tanya.algorithm.iteration;
+import std.range : isBidirectionalRange;
import std.traits;
import std.typecons;
import tanya.memory.lifetime;
diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d
index 1a1bb56..956ee4a 100644
--- a/source/tanya/algorithm/mutation.d
+++ b/source/tanya/algorithm/mutation.d
@@ -14,6 +14,7 @@
*/
module tanya.algorithm.mutation;
+import std.range : hasLvalueElements, isInputRange, isOutputRange, put;
import std.traits;
static import tanya.memory.lifetime;
static import tanya.memory.op;
diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d
index b6c9c5d..aa6dc76 100644
--- a/source/tanya/container/array.d
+++ b/source/tanya/container/array.d
@@ -18,6 +18,7 @@ import core.checkedint;
import std.algorithm.comparison;
import std.algorithm.iteration;
import std.algorithm.mutation : bringToFront;
+import std.range : isInfinite, isInputRange;
import std.traits;
import tanya.algorithm.mutation;
import tanya.memory.allocator;
diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d
index 5e9a4e4..f1f8666 100644
--- a/source/tanya/container/hashtable.d
+++ b/source/tanya/container/hashtable.d
@@ -15,6 +15,7 @@
module tanya.container.hashtable;
import std.algorithm.iteration;
+import std.range : isInfinite, isForwardRange;
import std.traits;
import tanya.algorithm.mutation;
import tanya.container.array;
diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d
index ddef391..513ea49 100644
--- a/source/tanya/container/list.d
+++ b/source/tanya/container/list.d
@@ -17,6 +17,7 @@ module tanya.container.list;
import std.algorithm.comparison;
import std.algorithm.iteration;
+import std.range : isInfinite, isInputRange;
import std.traits;
import tanya.container.entry;
import tanya.memory.allocator;
diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d
index 5a4f64c..a8d9572 100644
--- a/source/tanya/container/set.d
+++ b/source/tanya/container/set.d
@@ -15,6 +15,7 @@
*/
module tanya.container.set;
+import std.range : isInfinite, isForwardRange;
import std.traits;
import tanya.container.array;
import tanya.container.entry;
diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d
index 10db553..0401881 100644
--- a/source/tanya/container/string.d
+++ b/source/tanya/container/string.d
@@ -28,6 +28,7 @@ module tanya.container.string;
import std.algorithm.comparison;
import std.algorithm.mutation : bringToFront;
+import std.range : isInfinite, popFrontN, isInputRange;
import std.traits;
import tanya.algorithm.mutation;
import tanya.hash.lookup;
diff --git a/source/tanya/conv.d b/source/tanya/conv.d
index 3a75d62..e373d07 100644
--- a/source/tanya/conv.d
+++ b/source/tanya/conv.d
@@ -14,6 +14,7 @@
*/
module tanya.conv;
+import std.range : isInputRange;
import std.traits;
import tanya.container.string;
import tanya.memory.allocator;
diff --git a/source/tanya/format.d b/source/tanya/format.d
index 089ed49..18d6a76 100644
--- a/source/tanya/format.d
+++ b/source/tanya/format.d
@@ -51,6 +51,7 @@ import std.algorithm.comparison;
import std.ascii;
import std.math : signbit;
import std.meta;
+import std.range : isInfinite, popFrontExactly, isInputRange, isOutputRange, put;
import std.traits;
import tanya.container.string;
import tanya.math;
diff --git a/source/tanya/hash/lookup.d b/source/tanya/hash/lookup.d
index eb26caa..2b5116d 100644
--- a/source/tanya/hash/lookup.d
+++ b/source/tanya/hash/lookup.d
@@ -14,6 +14,7 @@
*/
module tanya.hash.lookup;
+import std.range : isInfinite, isInputRange;
import std.traits;
import tanya.meta;
import tanya.range.primitive;
diff --git a/source/tanya/net/iface.d b/source/tanya/net/iface.d
index c910b29..6c5a962 100644
--- a/source/tanya/net/iface.d
+++ b/source/tanya/net/iface.d
@@ -14,6 +14,7 @@
*/
module tanya.net.iface;
+import std.range : isInputRange;
import std.traits;
import tanya.algorithm.mutation;
import tanya.container.string;
diff --git a/source/tanya/net/inet.d b/source/tanya/net/inet.d
index 141fd77..a919c9d 100644
--- a/source/tanya/net/inet.d
+++ b/source/tanya/net/inet.d
@@ -14,6 +14,7 @@
*/
module tanya.net.inet;
+import std.range : isInfinite, isInputRange;
import std.traits;
import tanya.meta;
import tanya.range;
diff --git a/source/tanya/net/ip.d b/source/tanya/net/ip.d
index 87268bd..4baa6e2 100644
--- a/source/tanya/net/ip.d
+++ b/source/tanya/net/ip.d
@@ -16,6 +16,7 @@ module tanya.net.ip;
import std.algorithm.comparison;
import std.ascii;
+import std.range : isForwardRange, isInputRange, isOutputRange, put;
import std.sumtype;
import std.typecons;
import std.traits;
diff --git a/source/tanya/range/adapter.d b/source/tanya/range/adapter.d
index 287e868..f342d2d 100644
--- a/source/tanya/range/adapter.d
+++ b/source/tanya/range/adapter.d
@@ -14,6 +14,7 @@
*/
module tanya.range.adapter;
+import std.range : isInputRange, isOutputRange, put;
import std.traits;
import tanya.algorithm.mutation;
import tanya.memory.lifetime;
diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d
index d8abe3d..ec1eb0b 100644
--- a/source/tanya/range/primitive.d
+++ b/source/tanya/range/primitive.d
@@ -15,6 +15,7 @@
module tanya.range.primitive;
import std.algorithm.comparison;
+import std.range : isInfinite, hasSlicing, hasLvalueElements, isInputRange, isBidirectionalRange;
import std.traits;
import tanya.memory.lifetime;
import tanya.meta;
@@ -107,190 +108,6 @@ enum bool hasLength(R) = is(ReturnType!((R r) => r.length) == size_t);
static assert(!hasLength!C);
}
-/**
- * Determines whether $(D_PARAM R) is a forward range with slicing support
- * ($(D_INLINECODE R[i .. j])).
- *
- * For finite ranges, the result of `opSlice()` must be of the same type as the
- * original range. If the range defines opDollar, it must support subtraction.
- *
- * For infinite ranges, the result of `opSlice()` must be of the same type as
- * the original range only if it defines `opDollar()`. Otherwise it can be any
- * forward range.
- *
- * For both finite and infinite ranges, the result of `opSlice()` must have
- * length.
- *
- * Params:
- * R = The type to be tested.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) supports slicing,
- * $(D_KEYWORD false) otherwise.
- */
-template hasSlicing(R)
-{
- private enum bool hasDollar = is(typeof((R r) => r[0 .. $]));
- private enum bool subDollar = !hasDollar
- || isInfinite!R
- || is(ReturnType!((R r) => r[0 .. $ - 1]) == R);
-
- static if (isForwardRange!R
- && is(ReturnType!((R r) => r[0 .. 0]) T)
- && (!hasDollar || is(ReturnType!((R r) => r[0 .. $]) == R))
- && subDollar
- && isForwardRange!(ReturnType!((ref R r) => r[0 .. 0])))
- {
- enum bool hasSlicing = (is(T == R) || isInfinite!R)
- && hasLength!T;
- }
- else
- {
- enum bool hasSlicing = false;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static assert(hasSlicing!(int[]));
- static assert(hasSlicing!(const(int)[]));
- static assert(hasSlicing!(dstring));
- static assert(hasSlicing!(string));
- static assert(!hasSlicing!(const int[]));
- static assert(!hasSlicing!(void[]));
-
- struct A
- {
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- void popFront() @nogc nothrow pure @safe
- {
- }
- bool empty() const @nogc nothrow pure @safe
- {
- return false;
- }
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- @property size_t length() const @nogc nothrow pure @safe
- {
- return 0;
- }
- typeof(this) opSlice(const size_t i, const size_t j)
- pure nothrow @safe @nogc
- {
- return this;
- }
- }
- static assert(hasSlicing!A);
-
- struct B
- {
- struct Dollar
- {
- }
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- void popFront() @nogc nothrow pure @safe
- {
- }
- bool empty() const @nogc nothrow pure @safe
- {
- return false;
- }
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- @property size_t length() const @nogc nothrow pure @safe
- {
- return 0;
- }
- @property Dollar opDollar() const @nogc nothrow pure @safe
- {
- return Dollar();
- }
- typeof(this) opSlice(const size_t i, const Dollar j)
- pure nothrow @safe @nogc
- {
- return this;
- }
- }
- static assert(!hasSlicing!B);
-
- struct C
- {
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- void popFront() @nogc nothrow pure @safe
- {
- }
- enum bool empty = false;
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- typeof(this) opSlice(const size_t i, const size_t j)
- pure nothrow @safe @nogc
- {
- return this;
- }
- }
- static assert(!hasSlicing!C);
-
- struct D
- {
- struct Range
- {
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- void popFront() @nogc nothrow pure @safe
- {
- }
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- @property size_t length() const @nogc nothrow pure @safe
- {
- return 0;
- }
- }
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- void popFront() @nogc nothrow pure @safe
- {
- }
- enum bool empty = false;
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- Range opSlice(const size_t i, const size_t j)
- pure nothrow @safe @nogc
- {
- return Range();
- }
- }
- static assert(hasSlicing!D);
-}
-
private template isDynamicArrayRange(R)
{
static if (is(R E : E[]))
@@ -324,1185 +141,6 @@ private struct Primitive(Candidate, string primitive)
}
/**
- * Determines whether $(D_PARAM R) is an input range.
- *
- * An input range should define following primitives:
- *
- * $(UL
- * $(LI front)
- * $(LI empty)
- * $(LI popFront)
- * )
- *
- * Params:
- * R = The type to be tested.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) is an input range,
- * $(D_KEYWORD false) otherwise.
- */
-template isInputRange(R)
-{
- static if (is(Primitive!(R, "front()") U)
- && is(ReturnType!((R r) => r.empty) == bool)
- && is(typeof(R.popFront())))
- {
- enum bool isInputRange = true;
- }
- else
- {
- enum bool isInputRange = isDynamicArrayRange!R;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct Range
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
- }
- static assert(isInputRange!Range);
- static assert(isInputRange!(int[]));
- static assert(!isInputRange!(void[]));
-}
-
-/**
- * Determines whether $(D_PARAM R) is a forward range.
- *
- * A forward range is an input range that also defines:
- *
- * $(UL
- * $(LI save)
- * )
- *
- * Params:
- * R = The type to be tested.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) is a forward range,
- * $(D_KEYWORD false) otherwise.
- *
- * See_Also: $(D_PSYMBOL isInputRange).
- */
-template isForwardRange(R)
-{
- static if (is(ReturnType!((R r) => r.save()) U))
- {
- enum bool isForwardRange = isInputRange!R && is(U == R);
- }
- else
- {
- enum bool isForwardRange = false;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct Range
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
-
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- }
- static assert(isForwardRange!Range);
- static assert(isForwardRange!(int[]));
- static assert(!isForwardRange!(void[]));
-}
-
-/**
- * Determines whether $(D_PARAM R) is a bidirectional range.
- *
- * A bidirectional range is a forward range that also defines:
- *
- * $(UL
- * $(LI back)
- * $(LI popBack)
- * )
- *
- * Params:
- * R = The type to be tested.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) is a bidirectional range,
- * $(D_KEYWORD false) otherwise.
- *
- * See_Also: $(D_PSYMBOL isForwardRange).
- */
-template isBidirectionalRange(R)
-{
- static if (is(Primitive!(R, "back()") U)
- && is(typeof(R.popBack())))
- {
- enum bool isBidirectionalRange = isForwardRange!R
- && (U() == Primitive!(R, "front()")());
- }
- else
- {
- enum bool isBidirectionalRange = isDynamicArrayRange!R;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct Range
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- void popBack() @nogc nothrow pure @safe
- {
- }
-
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- @property int back() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
-
- Range save() @nogc nothrow pure @safe
- {
- return this;
- }
- }
- static assert(isBidirectionalRange!Range);
- static assert(isBidirectionalRange!(int[]));
- static assert(!isBidirectionalRange!(void[]));
-}
-
-/**
- * Determines whether $(D_PARAM R) is a random-access range.
- *
- * A random-access range is a range that allows random access to its
- * elements by index using $(D_INLINECODE [])-operator (defined with
- * $(D_INLINECODE opIndex())). Further a random access range should
- * have a length or be infinite.
- *
- * Params:
- * R = The type to be tested.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) is a random-access range,
- * $(D_KEYWORD false) otherwise.
- *
- * See_Also: $(D_PSYMBOL isInfinite),
- * $(D_PSYMBOL hasLength).
- *
- * Note: This definition differs from `std.range.primitives.isRandomAccessRange`
- * in the D standard library in that it does not also require $(D_PARAM R) to
- * be a forward range and a bidirectional range. Those properties may be tested
- * separately with $(D_PSYMBOL isForwardRange) and
- * $(D_PSYMBOL isBidirectionalRange).
- */
-template isRandomAccessRange(R)
-{
- static if (is(Primitive!(R, "opIndex(size_t.init)") U))
- {
- enum bool isRandomAccessRange = isInputRange!R
- && (hasLength!R || isInfinite!R)
- && (U() == Primitive!(R, "front()")());
- }
- else
- {
- enum bool isRandomAccessRange = isDynamicArrayRange!R;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct A
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
-
- int opIndex(size_t) @nogc nothrow pure @safe
- {
- return 0;
- }
-
- size_t length() const @nogc nothrow pure @safe
- {
- return 0;
- }
- }
- static assert(isRandomAccessRange!A);
- static assert(isRandomAccessRange!(int[]));
- static assert(!isRandomAccessRange!(void[]));
-
- static struct B
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- enum bool empty = false;
-
- int opIndex(const size_t pos) @nogc nothrow pure @safe
- {
- return 0;
- }
- }
- static assert(isRandomAccessRange!B);
-}
-
-/**
- * Puts $(D_PARAM e) into the $(D_PARAM range).
- *
- * $(D_PSYMBOL R) should be an output range for $(D_PARAM E), i.e. at least one
- * of the following conditions should met:
- *
- * $(OL
- * $(LI $(D_PARAM e) can be put into $(D_PARAM range) using
- * $(D_INLINECODE range(e))
- * $(LI $(D_PARAM e) can be assigned to $(D_INLINECODE range.front))
- * )
- * )
- *
- * The method to put $(D_PARAM e) into $(D_PARAM range) is chosen based on the
- * order specified above.
- *
- * If $(D_PARAM E) is an input range and $(D_PARAM R) is an output range for
- * its elements as well, use $(D_PSYMBOL tanya.algorithm.mutation.copy)
- * instead.
- *
- * $(D_PARAM range) is advanced after putting an element into it if it is an
- * input range that doesn't define a `put`-method.
- *
- * Params:
- * R = Target range type.
- * E = Source element type.
- * range = Target range.
- * e = Source element.
- *
- * See_Also: $(D_PSYMBOL isOutputRange).
- */
-void put(R, E)(ref R range, auto ref E e)
-{
- static if (is(typeof((R r, E e) => r(e))))
- {
- range(e);
- }
- else static if (isInputRange!R
- && is(typeof((R r, E e) => r.front = e)))
- {
- range.front = e;
- range.popFront();
- }
- else
- {
- static assert(false, R.stringof ~ " is not an output range for "
- ~ E.stringof);
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int[2] actual;
- auto slice = actual[];
-
- put(slice, 2);
- assert(actual == [2, 0]);
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct OpCall
- {
- int e;
-
- void opCall(int e)
- {
- this.e = e;
- }
- }
- OpCall oc;
- put(oc, 2);
- assert(oc.e == 2);
-}
-
-/**
- * Determines whether $(D_PARAM R) is an output range for the elemens of type
- * $(D_PARAM E).
- *
- * If $(D_PARAM R) is an output range for the elements of type $(D_PARAM E)
- * if an element `e` of type $(D_PARAM E) can be put into the range instance
- * `r` in one of the following ways:
- *
- * $(TABLE
- * $(TR
- * $(TH Code)
- * $(TH Scenario)
- * )
- * $(TR
- * $(TD r(e))
- * $(TD $(D_PARAM R) defines `opCall` for $(D_PARAM E).)
- * )
- * $(TR
- * $(TD r.front = e)
- * $(TD $(D_PARAM R) is an input range with assignable elements of type
- * $(D_PARAM E).)
- * )
- * )
- *
- * Output ranges don't have element type (so $(D_PSYMBOL ElementType) returns
- * $(D_KEYWORD void) when applied to an output range). It is because an output
- * range can support puting differently typed elements into it.
- *
- * Params:
- * R = The type to be tested.
- * E = Element type should be tested for.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) is an output range for the
- * elements of the type $(D_PARAM E), $(D_KEYWORD false) otherwise.
- *
- * See_Also: $(D_PSYMBOL put).
- */
-template isOutputRange(R, E)
-{
- static if (is(typeof((R r, E e) => put(r, e))))
- {
- enum bool isOutputRange = true;
- }
- else static if (isInputRange!E)
- {
- pragma(msg, "Deprecation. An input range whose element type is "
- ~ "supported by the output range isn't considered itself to "
- ~ "be a source for such an output range. Don't rely on this "
- ~ "behavior and use tanya.algorithm.copy() to write one "
- ~ "range into another one.");
- alias ET = ElementType!E;
- enum bool isOutputRange = is(typeof((R r, ET e) => put(r, e)));
- }
- else
- {
- enum bool isOutputRange = false;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct R1
- {
- void opCall(int) @nogc nothrow pure @safe
- {
- }
- }
- static assert(isOutputRange!(R1, int));
-
- static struct R2
- {
- int value;
-
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- ref int front() @nogc nothrow pure @safe
- {
- return value;
- }
-
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
- }
- static assert(isOutputRange!(R2, int));
-
- static struct R3
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
-
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
- }
- static assert(!isOutputRange!(R3, int));
-}
-
-/**
- * Determines whether $(D_PARAM R) is an infinite range.
- *
- * An infinite range is an input range whose `empty` member is defined as
- * $(D_KEYWORD enum) which is always $(D_KEYWORD false).
- *
- * Params:
- * R = A type.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) is an infinite range,
- * $(D_KEYWORD false) otherwise.
- */
-template isInfinite(R)
-{
- static if (isInputRange!R && is(typeof({enum bool e = R.empty;})))
- {
- enum bool isInfinite = R.empty == false;
- }
- else
- {
- enum bool isInfinite = false;
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static assert(!isInfinite!int);
-
- static struct NotRange
- {
- enum bool empty = false;
- }
- static assert(!isInfinite!NotRange);
-
- static struct InfiniteRange
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- enum bool empty = false;
- }
- static assert(isInfinite!InfiniteRange);
-
- static struct InputRange
- {
- void popFront() @nogc nothrow pure @safe
- {
- }
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- @property bool empty() const @nogc nothrow pure @safe
- {
- return false;
- }
- }
- static assert(!isInfinite!InputRange);
-}
-
-/**
- * Removes exactly $(D_PARAM count) first elements from the input range
- * $(D_PARAM range).
- *
- * $(D_PARAM R) must have length or be infinite.
- *
- * Params:
- * R = Range type.
- * range = Some input range.
- * count = Number of elements to remove.
- *
- * See_Also: $(D_PSYMBOL popBackExactly),
- * $(D_PSYMBOL popFrontN),
- * $(D_PSYMBOL isInputRange),
- * $(D_PSYMBOL hasLength),
- * $(D_PSYMBOL isInfinite).
- *
- * Precondition: If $(D_PARAM R) has length, it must be less than or equal to
- * $(D_PARAM count).
- */
-void popFrontExactly(R)(ref R range, size_t count)
-if (isInputRange!R && (hasLength!R || isInfinite!R))
-in
-{
- static if (hasLength!R)
- {
- assert(count <= range.length);
- }
-}
-do
-{
- static if (hasSlicing!R)
- {
- range = range[count .. $];
- }
- else
- {
- while (count-- != 0)
- {
- range.popFront();
- }
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int[5] a = [1, 2, 3, 4, 5];
- auto slice = a[];
-
- popFrontExactly(slice, 3);
- assert(slice.length == 2);
- assert(slice[0] == 4);
- assert(slice[$ - 1] == 5);
-
- popFrontExactly(slice, 2);
- assert(slice.length == 0);
-}
-
-/**
- * Removes exactly $(D_PARAM count) last elements from the bidirectional range
- * $(D_PARAM range).
- *
- * $(D_PARAM R) must have length or be infinite.
- *
- * Params:
- * R = Range type.
- * range = Some bidirectional range.
- * count = Number of elements to remove.
- *
- * See_Also: $(D_PSYMBOL popFrontExactly),
- * $(D_PSYMBOL popBackN),
- * $(D_PSYMBOL isBidirectionalRange),
- * $(D_PSYMBOL hasLength),
- * $(D_PSYMBOL isInfinite).
- *
- * Precondition: If $(D_PARAM R) has length, it must be less than or equal to
- * $(D_PARAM count).
- */
-void popBackExactly(R)(ref R range, size_t count)
-if (isBidirectionalRange!R && (hasLength!R || isInfinite!R))
-in
-{
- static if (hasLength!R)
- {
- assert(count <= range.length);
- }
-}
-do
-{
- static if (hasSlicing!R)
- {
- range = range[0 .. $ - count];
- }
- else
- {
- while (count-- != 0)
- {
- range.popBack();
- }
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int[5] a = [1, 2, 3, 4, 5];
- auto slice = a[];
-
- popBackExactly(slice, 3);
- assert(slice.length == 2);
- assert(slice[0] == 1);
- assert(slice[$ - 1] == 2);
-
- popBackExactly(slice, 2);
- assert(slice.length == 0);
-}
-
-/**
- * Removes maximum $(D_PARAM count) first elements from the input range
- * $(D_PARAM range).
- *
- * Params:
- * R = Range type.
- * range = Some input range.
- * count = Number of elements to remove.
- *
- * See_Also: $(D_PSYMBOL popBackN),
- * $(D_PSYMBOL popFrontExactly),
- * $(D_PSYMBOL isInputRange).
- */
-void popFrontN(R)(ref R range, size_t count)
-if (isInputRange!R)
-{
- static if (hasLength!R && hasSlicing!R)
- {
- range = range[min(count, range.length) .. $];
- }
- else static if (hasLength!R)
- {
- size_t length = min(count, range.length);
- while (length--)
- {
- range.popFront();
- }
- }
- else
- {
- while (count-- != 0 && !range.empty)
- {
- range.popFront();
- }
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int[5] a = [1, 2, 3, 4, 5];
- auto slice = a[];
-
- popFrontN(slice, 3);
- assert(slice.length == 2);
- assert(slice[0] == 4);
- assert(slice[$ - 1] == 5);
-
- popFrontN(slice, 20);
- assert(slice.length == 0);
-}
-
-/**
- * Removes maximum $(D_PARAM count) last elements from the bidirectional range
- * $(D_PARAM range).
- *
- * Params:
- * R = Range type.
- * range = Some bidirectional range.
- * count = Number of elements to remove.
- *
- * See_Also: $(D_PSYMBOL popFrontN),
- * $(D_PSYMBOL popBackExactly),
- * $(D_PSYMBOL isBidirectionalRange).
- */
-void popBackN(R)(ref R range, size_t count)
-if (isBidirectionalRange!R)
-{
- static if (hasLength!R && hasSlicing!R)
- {
- range = range[0 .. $ - min(count, range.length)];
- }
- else static if (hasLength!R)
- {
- size_t length = min(count, range.length);
- while (length--)
- {
- range.popBack();
- }
- }
- else
- {
- while (count-- != 0 && !range.empty)
- {
- range.popBack();
- }
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- int[5] a = [1, 2, 3, 4, 5];
- auto slice = a[];
-
- popBackN(slice, 3);
- assert(slice.length == 2);
- assert(slice[0] == 1);
- assert(slice[$ - 1] == 2);
-
- popBackN(slice, 20);
- assert(slice.length == 0);
-}
-
-/**
- * Moves the front element of an input range.
- *
- * The front element is left in a valid but unspecified state.
- * $(D_PSYMBOL moveFront) doesn't advances the range, so `popFront` should be
- * probably called after this function.
- *
- * Params:
- * R = Type of the range.
- * range = Input range.
- *
- * Returns: The front element of the $(D_PSYMBOL range).
- *
- * See_Also: $(D_PSYMBOL move).
- */
-ElementType!R moveFront(R)(R range)
-if (isInputRange!R)
-{
- static if (!hasElaborateCopyConstructor!(ElementType!R))
- {
- return range.front;
- }
- else static if (is(typeof(((ref ElementType!R e) => e)(range.front))))
- {
- return move(range.front);
- }
- else
- {
- static assert(false, "Front element cannot be moved");
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- // Has elements without a postblit constructor.
- int[2] a = 5;
-
- assert(moveFront(a[]) == 5);
-}
-
-/**
- * Moves the back element of a bidirectional range.
- *
- * The back element is left in a valid but unspecified state.
- * $(D_PSYMBOL moveBack) doesn't advances the range, so `popBack` should be
- * probably called after this function.
- *
- * Params:
- * R = Type of the range.
- * range = Bidirectional range.
- *
- * Returns: The back element of the $(D_PSYMBOL range).
- *
- * See_Also: $(D_PSYMBOL move).
- */
-ElementType!R moveBack(R)(R range)
-if (isBidirectionalRange!R)
-{
- static if (!hasElaborateCopyConstructor!(ElementType!R))
- {
- return range.back;
- }
- else static if (is(typeof(((ref ElementType!R e) => e)(range.back))))
- {
- return move(range.back);
- }
- else
- {
- static assert(false, "Back element cannot be moved");
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- // Has elements without a postblit constructor.
- int[2] a = 5;
-
- assert(moveBack(a[]) == 5);
-}
-
-/**
- * Moves the element at the position $(D_PARAM n) out of the range.
- *
- * The moved element is left in a valid but unspecified state.
- *
- * Params:
- * R = Range type.
- * range = Random-access range.
- * n = Element position.
- *
- * Returns: The element at the position $(D_PARAM n).
- *
- * See_Also: $(D_PSYMBOL move).
- */
-ElementType!R moveAt(R)(R range, size_t n)
-if (isRandomAccessRange!R)
-{
- static if (!hasElaborateCopyConstructor!(ElementType!R))
- {
- return range[n];
- }
- else static if (is(typeof(((ref ElementType!R e) => e)(range[0]))))
- {
- return move(range[n]);
- }
- else
- {
- static assert(false, "Random element cannot be moved");
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- // Has elements without a postblit constructor.
- int[3] a = 5;
-
- assert(moveAt(a[], 1) == 5);
-}
-
-/**
- * Determines whether $(D_PSYMBOL R) is a range containing mobile elements,
- * i.e. elements that can be moved out of the range.
- *
- * Having mobile elements means for an input range to support
- * $(D_PSYMBOL moveFront), for a bidirectional range - both,
- * $(D_PSYMBOL moveFront) and $(D_PSYMBOL moveBack), for a random-access
- * range - $(D_PSYMBOL moveFront) and $(D_PSYMBOL moveAt).
- *
- * Params:
- * R = Range type.
- *
- * Returns: $(D_KEYWORD true) if $(D_PSYMBOL R) has mobile elements,
- * $(D_KEYWORD false) otherwise.
- *
- * See_Also: $(D_PSYMBOL moveFront), $(D_PSYMBOL moveBack),
- * $(D_PSYMBOL moveAt).
- */
-template hasMobileElements(R)
-{
- static if (isRandomAccessRange!R)
- {
- enum bool hasMobileElements = is(typeof((R r) => moveFront(r)))
- && is(typeof((R r) => moveAt(r, 0)));
- }
- else static if (isBidirectionalRange!R)
- {
- enum bool hasMobileElements = is(typeof((R r) => moveFront(r)))
- && is(typeof((R r) => moveBack(r)));
- }
- else
- {
- enum bool hasMobileElements = is(typeof((R r) => moveFront(r)));
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static assert(hasMobileElements!(int[]));
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct Element
- {
- this(this) @nogc nothrow pure @safe
- {
- }
- }
-
- static struct R1
- {
- enum bool empty = false;
-
- Element front() @nogc nothrow pure @safe
- {
- return Element();
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- }
- static assert(!hasMobileElements!R1);
-
- static struct R2
- {
- enum bool empty = false;
- private Element front_;
-
- ref Element front() @nogc nothrow pure @safe
- {
- return front_;
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- }
- static assert(hasMobileElements!R2);
-}
-
-/**
- * Determines whether $(D_PARAM R) provides access to its elements by
- * reference.
- *
- * Params:
- * R = Range type.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) has lvalue elements,
- * $(D_KEYWORD false) otherwise.
- */
-template hasLvalueElements(R)
-{
- private alias refDg = (ref ElementType!R e) => &e;
-
- static if (isRandomAccessRange!R)
- {
- enum bool hasLvalueElements = is(typeof(refDg(R.init.front)))
- && is(typeof(refDg(R.init[0])));
- }
- else static if (isBidirectionalRange!R)
- {
- enum bool hasLvalueElements = is(typeof(refDg(R.init.front)))
- && is(typeof(refDg(R.init.back)));
- }
- else
- {
- enum bool hasLvalueElements = is(typeof(refDg(R.init.front)));
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct R1
- {
- enum bool empty = false;
-
- int front() @nogc nothrow pure @safe
- {
- return 5;
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- }
- static assert(!hasLvalueElements!R1);
-
- static struct R2
- {
- int element;
- enum bool empty = false;
-
- ref const(int) front() const @nogc nothrow pure @safe
- {
- return element;
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- ref const(int) opIndex(size_t) const @nogc nothrow pure @safe
- {
- return element;
- }
- }
- static assert(hasLvalueElements!R2);
-}
-
-/**
- * Determines whether the elements of $(D_PARAM R) are assignable.
- *
- * Params:
- * R = Range type.
- *
- * Returns: $(D_KEYWORD true) if the elements of $(D_PARAM R) are assignable
- * $(D_KEYWORD false) otherwise.
- */
-template hasAssignableElements(R)
-{
- static if (isRandomAccessRange!R)
- {
- enum bool assignable = is(typeof({R.init.front = R.init.front;}))
- && is(typeof({R.init[0] = R.init[0];}));
- }
- else static if (isBidirectionalRange!R)
- {
- enum bool assignable = is(typeof({R.init.front = R.init.front;}))
- && is(typeof({R.init.back = R.init.back;}));
- }
- else
- {
- enum bool assignable = is(typeof({R.init.front = R.init.front;}));
- }
- enum bool hasAssignableElements = assignable;
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct R1
- {
- int element;
- enum bool empty = false;
-
- ref int front() @nogc nothrow pure @safe
- {
- return element;
- }
- alias back = front;
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- alias popBack = popFront;
-
- R1 save() const @nogc nothrow pure @safe
- {
- return this;
- }
- }
- static assert(hasAssignableElements!R1);
-
- static struct R2
- {
- int element;
- enum bool empty = false;
-
- ref const(int) front() const @nogc nothrow pure @safe
- {
- return element;
- }
- alias back = front;
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- alias popBack = popFront;
-
- R2 save() const @nogc nothrow pure @safe
- {
- return this;
- }
- }
- static assert(!hasAssignableElements!R2);
-}
-
-/**
- * Determines whether the elements of $(D_PSYMBOL R) can be swapped with
- * $(D_PSYMBOL swap).
- *
- * Params:
- * R = Range type.
- *
- * Returns: $(D_KEYWORD true) if $(D_PARAM R) has swappable elements,
- * $(D_KEYWORD false) otherwise.
- */
-template hasSwappableElements(R)
-{
- static if (isRandomAccessRange!R)
- {
- enum bool hasSwappableElements = is(typeof(swap(R.init.front, R.init.front)))
- && is(typeof(swap(R.init[0], R.init[0])));
- }
- else static if (isBidirectionalRange!R)
- {
- enum bool hasSwappableElements = is(typeof(swap(R.init.front, R.init.front)))
- && is(typeof(swap(R.init.back, R.init.back)));
- }
- else
- {
- enum bool hasSwappableElements = is(typeof(swap(R.init.front, R.init.front)));
- }
-}
-
-///
-@nogc nothrow pure @safe unittest
-{
- static struct R1
- {
- int element;
- enum bool empty = false;
-
- ref int front() @nogc nothrow pure @safe
- {
- return element;
- }
- alias back = front;
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- alias popBack = popFront;
-
- R1 save() const @nogc nothrow pure @safe
- {
- return this;
- }
- }
- static assert(hasSwappableElements!R1);
-
- static struct R2
- {
- int element;
- enum bool empty = false;
-
- int front() const @nogc nothrow pure @safe
- {
- return element;
- }
- alias back = front;
-
- void popFront() @nogc nothrow pure @safe
- {
- }
- alias popBack = popFront;
-
- R2 save() const @nogc nothrow pure @safe
- {
- return this;
- }
- }
- static assert(!hasSwappableElements!R2);
-}
-
-/**
* Determines whether `r1.front` and `r2.front` point to the same element.
*
* Params: