summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/tanya/algorithm/iteration.d5
-rw-r--r--source/tanya/meta/trait.d40
-rw-r--r--source/tanya/range/primitive.d329
-rw-r--r--source/tanya/test/package.d1
-rw-r--r--source/tanya/test/range.d59
-rw-r--r--source/tanya/test/stub.d275
6 files changed, 387 insertions, 322 deletions
diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d
index a66e980..9ad8cdd 100644
--- a/source/tanya/algorithm/iteration.d
+++ b/source/tanya/algorithm/iteration.d
@@ -23,7 +23,7 @@ module tanya.algorithm.iteration;
import tanya.algorithm.comparison;
import tanya.algorithm.mutation;
import tanya.range;
-version (unittest) import tanya.test.range;
+version (unittest) import tanya.test.stub;
private struct Take(R, bool exactly)
{
@@ -322,10 +322,9 @@ if (isInputRange!R)
// length is unknown when taking from a range without length
@nogc nothrow pure @safe unittest
{
- @Empty
static struct R
{
- mixin InputRange;
+ mixin InputRangeStub;
}
auto actual = take(R(), 100);
diff --git a/source/tanya/meta/trait.d b/source/tanya/meta/trait.d
index 5ecb234..69b97b9 100644
--- a/source/tanya/meta/trait.d
+++ b/source/tanya/meta/trait.d
@@ -2857,6 +2857,46 @@ template hasUDA(alias symbol, alias attr)
}
/**
+ * If $(D_PARAM T) is a type, constructs its default value, otherwise
+ * $(D_PSYMBOL evalUDA) aliases itself to $(D_PARAM T).
+ *
+ * This template is useful when working with UDAs with default parameters,
+ * i.e. if an attribute can be given as `@Attr` or `@Attr("param")`,
+ * $(D_PSYMBOL evalUDA) makes `@Attr()` from `@Attr`, but returns
+ * `@Attr("param")` as is.
+ *
+ * $(D_PARAM T) (or its type if it isn't a type already) should have a default
+ * constructor.
+ *
+ * Params:
+ * T = User Defined Attribute.
+ */
+alias evalUDA(alias T) = T;
+
+/// ditto
+alias evalUDA(T) = Alias!(T());
+
+///
+@nogc nothrow pure @safe unittest
+{
+ static struct Length
+ {
+ size_t length = 8;
+ }
+ @Length @Length(0) int i;
+ alias uda = AliasSeq!(__traits(getAttributes, i));
+
+ alias attr1 = evalUDA!(uda[0]);
+ alias attr2 = evalUDA!(uda[1]);
+
+ static assert(is(typeof(attr1) == Length));
+ static assert(is(typeof(attr2) == Length));
+
+ static assert(attr1.length == 8);
+ static assert(attr2.length == 0);
+}
+
+/**
* Tests whether $(D_PARAM T) is an inner class, i.e. a class nested inside
* another class.
*
diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d
index 934ff31..099208a 100644
--- a/source/tanya/range/primitive.d
+++ b/source/tanya/range/primitive.d
@@ -20,6 +20,19 @@ import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range.array;
+version (unittest)
+{
+ import tanya.test.stub;
+
+ private struct AssertPostblit
+ {
+ this(this) @nogc nothrow pure @safe
+ {
+ assert(false);
+ }
+ }
+}
+
/**
* Returns the element type of the range $(D_PARAM R).
*
@@ -73,10 +86,7 @@ template ElementType(R)
*
* See_Also: $(D_PSYMBOL isInfinite).
*/
-template hasLength(R)
-{
- enum bool hasLength = is(ReturnType!((R r) => r.length) == size_t);
-}
+enum bool hasLength(R) = is(ReturnType!((R r) => r.length) == size_t);
///
@nogc nothrow pure @safe unittest
@@ -294,34 +304,6 @@ template hasSlicing(R)
static assert(hasSlicing!D);
}
-version (unittest)
-{
- mixin template InputRangeStub()
- {
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
- @property bool empty() const @nogc nothrow pure @safe
- {
- return false;
- }
- void popFront() @nogc nothrow pure @safe
- {
- }
- }
- mixin template BidirectionalRangeStub()
- {
- @property int back() @nogc nothrow pure @safe
- {
- return 0;
- }
- void popBack() @nogc nothrow pure @safe
- {
- }
- }
-}
-
private template isDynamicArrayRange(R)
{
static if (is(R E : E[]))
@@ -373,10 +355,12 @@ template isInputRange(R)
void popFront() @nogc nothrow pure @safe
{
}
+
int front() @nogc nothrow pure @safe
{
return 0;
}
+
bool empty() const @nogc nothrow pure @safe
{
return true;
@@ -391,13 +375,8 @@ template isInputRange(R)
{
static struct Range1(T)
{
- void popFront()
- {
- }
- int front()
- {
- return 0;
- }
+ mixin InputRangeStub;
+
T empty() const
{
return true;
@@ -408,45 +387,29 @@ template isInputRange(R)
static struct Range2
{
+ mixin InputRangeStub;
+
int popFront() @nogc nothrow pure @safe
{
return 100;
}
- int front() @nogc nothrow pure @safe
- {
- return 100;
- }
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
}
static assert(isInputRange!Range2);
static struct Range3
{
- void popFront() @nogc nothrow pure @safe
- {
- }
+ mixin InputRangeStub;
+
void front() @nogc nothrow pure @safe
{
}
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
}
static assert(!isInputRange!Range3);
static struct Range4
{
- void popFront() @nogc nothrow pure @safe
- {
- }
- int front() @nogc nothrow pure @safe
- {
- return 0;
- }
+ mixin InputRangeStub;
+
enum bool empty = false;
}
static assert(isInputRange!Range4);
@@ -489,14 +452,17 @@ template isForwardRange(R)
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;
@@ -515,6 +481,7 @@ template isForwardRange(R)
static struct Range2
{
mixin InputRangeStub;
+
Range1 save() @nogc nothrow pure @safe
{
return Range1();
@@ -525,6 +492,7 @@ template isForwardRange(R)
static struct Range3
{
mixin InputRangeStub;
+
const(typeof(this)) save() const @nogc nothrow pure @safe
{
return this;
@@ -573,21 +541,26 @@ template isBidirectionalRange(R)
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;
@@ -602,28 +575,17 @@ template isBidirectionalRange(R)
{
static struct Range(T, U)
{
- void popFront() @nogc nothrow pure @safe
- {
- }
- void popBack() @nogc nothrow pure @safe
- {
- }
+ mixin BidirectionalRangeStub;
+
@property T front() @nogc nothrow pure @safe
{
return T.init;
}
+
@property U back() @nogc nothrow pure @safe
{
return U.init;
}
- bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
- Range save() @nogc nothrow pure @safe
- {
- return this;
- }
}
static assert(!isBidirectionalRange!(Range!(int, uint)));
static assert(!isBidirectionalRange!(Range!(int, const int)));
@@ -674,29 +636,22 @@ template isRandomAccessRange(R)
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;
}
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- int opIndex(const size_t pos) @nogc nothrow pure @safe
+
+ int opIndex(size_t) @nogc nothrow pure @safe
{
return 0;
}
+
size_t length() const @nogc nothrow pure @safe
{
return 0;
@@ -711,15 +666,14 @@ template isRandomAccessRange(R)
void popFront() @nogc nothrow pure @safe
{
}
+
@property int front() @nogc nothrow pure @safe
{
return 0;
}
+
enum bool empty = false;
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
+
int opIndex(const size_t pos) @nogc nothrow pure @safe
{
return 0;
@@ -732,76 +686,43 @@ template isRandomAccessRange(R)
{
static struct Range1
{
- mixin InputRangeStub;
mixin BidirectionalRangeStub;
-
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- int opIndex(const size_t pos) @nogc nothrow pure @safe
- {
- return 0;
- }
+ mixin RandomAccessRangeStub;
}
static assert(!isRandomAccessRange!Range1);
+ @Length
static struct Range2(Args...)
{
- mixin InputRangeStub;
mixin BidirectionalRangeStub;
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
int opIndex(Args) @nogc nothrow pure @safe
{
return 0;
}
- size_t length() const @nogc nothrow pure @safe
- {
- return 0;
- }
}
static assert(isRandomAccessRange!(Range2!size_t));
static assert(!isRandomAccessRange!(Range2!()));
static assert(!isRandomAccessRange!(Range2!(size_t, size_t)));
+ @Length
static struct Range3
{
- mixin InputRangeStub;
mixin BidirectionalRangeStub;
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
int opIndex(const size_t pos1, const size_t pos2 = 0)
@nogc nothrow pure @safe
{
return 0;
}
- size_t length() const @nogc nothrow pure @safe
- {
- return 0;
- }
}
static assert(isRandomAccessRange!Range3);
static struct Range4
{
- mixin InputRangeStub;
mixin BidirectionalRangeStub;
+ mixin RandomAccessRangeStub;
- typeof(this) save() @nogc nothrow pure @safe
- {
- return this;
- }
- int opIndex(const size_t pos1) @nogc nothrow pure @safe
- {
- return 0;
- }
size_t opDollar() const @nogc nothrow pure @safe
{
return 0;
@@ -1097,28 +1018,20 @@ template isInfinite(R)
@nogc nothrow pure @safe unittest
{
+ @Infinite
static struct StaticConstRange
{
- void popFront() @nogc nothrow pure @safe
- {
- }
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
+ mixin InputRangeStub;
+
static bool empty = false;
}
static assert(!isInfinite!StaticConstRange);
+ @Infinite
static struct TrueRange
{
- void popFront() @nogc nothrow pure @safe
- {
- }
- @property int front() @nogc nothrow pure @safe
- {
- return 0;
- }
+ mixin InputRangeStub;
+
static const bool empty = true;
}
static assert(!isInfinite!TrueRange);
@@ -1348,15 +1261,12 @@ if (isBidirectionalRange!R)
@nogc nothrow pure @safe unittest
{
+ @Infinite
static struct InfiniteRange
{
+ mixin ForwardRangeStub;
private int i;
- InfiniteRange save() @nogc nothrow pure @safe
- {
- return this;
- }
-
void popFront() @nogc nothrow pure @safe
{
++this.i;
@@ -1376,8 +1286,6 @@ if (isBidirectionalRange!R)
{
return this.i;
}
-
- enum bool empty = false;
}
{
InfiniteRange range;
@@ -1497,44 +1405,19 @@ if (isInputRange!R)
@nogc nothrow pure @safe unittest
{
- static struct Element
- {
- this(this) @nogc nothrow pure @safe
- {
- assert(false);
- }
- }
-
// Returns its elements by reference.
+ @Infinite @WithLvalueElements
static struct R1
{
- Element element;
- enum bool empty = false;
-
- ref Element front() @nogc nothrow pure @safe
- {
- return element;
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
+ mixin InputRangeStub!AssertPostblit;
}
static assert(is(typeof(moveFront(R1()))));
// Returns elements with a postblit constructor by value. moveFront fails.
+ @Infinite
static struct R2
{
- enum bool empty = false;
-
- Element front() @nogc nothrow pure @safe
- {
- return Element();
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
+ mixin InputRangeStub!AssertPostblit;
}
static assert(!is(typeof(moveFront(R2()))));
}
@@ -1582,58 +1465,19 @@ if (isBidirectionalRange!R)
@nogc nothrow pure @safe unittest
{
- static struct Element
- {
- this(this) @nogc nothrow pure @safe
- {
- assert(false);
- }
- }
-
// Returns its elements by reference.
+ @Infinite @WithLvalueElements
static struct R1
{
- Element element;
- enum bool empty = false;
-
- ref Element back() @nogc nothrow pure @safe
- {
- return element;
- }
- alias front = back;
-
- void popBack() @nogc nothrow pure @safe
- {
- }
- alias popFront = popBack;
-
- R1 save() @nogc nothrow pure @safe
- {
- return this;
- }
+ mixin BidirectionalRangeStub!AssertPostblit;
}
static assert(is(typeof(moveBack(R1()))));
// Returns elements with a postblit constructor by value. moveBack fails.
+ @Infinite
static struct R2
{
- enum bool empty = false;
-
- Element back() @nogc nothrow pure @safe
- {
- return Element();
- }
- alias front = back;
-
- void popBack() @nogc nothrow pure @safe
- {
- }
- alias popFront = popBack;
-
- R2 save() @nogc nothrow pure @safe
- {
- return this;
- }
+ mixin BidirectionalRangeStub!AssertPostblit;
}
static assert(!is(typeof(moveBack(R2()))));
}
@@ -1680,54 +1524,19 @@ if (isRandomAccessRange!R)
@nogc nothrow pure @safe unittest
{
- static struct Element
- {
- this(this) @nogc nothrow pure @safe
- {
- assert(false);
- }
- }
-
// Returns its elements by reference.
+ @Infinite @WithLvalueElements
static struct R1
{
- Element element;
- enum bool empty = false;
-
- ref Element front() @nogc nothrow pure @safe
- {
- return element;
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- ref Element opIndex(size_t)
- {
- return element;
- }
+ mixin RandomAccessRangeStub!AssertPostblit;
}
static assert(is(typeof(moveAt(R1(), 0))));
// Returns elements with a postblit constructor by value. moveAt fails.
+ @Infinite
static struct R2
{
- enum bool empty = false;
-
- Element front() @nogc nothrow pure @safe
- {
- return Element();
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- }
-
- Element opIndex() @nogc nothrow pure @safe
- {
- return Element();
- }
+ mixin RandomAccessRangeStub!AssertPostblit;
}
static assert(!is(typeof(moveAt(R2(), 0))));
}
diff --git a/source/tanya/test/package.d b/source/tanya/test/package.d
index 2e34702..ab6f861 100644
--- a/source/tanya/test/package.d
+++ b/source/tanya/test/package.d
@@ -15,3 +15,4 @@
module tanya.test;
public import tanya.test.assertion;
+public import tanya.test.stub;
diff --git a/source/tanya/test/range.d b/source/tanya/test/range.d
deleted file mode 100644
index 92a8c05..0000000
--- a/source/tanya/test/range.d
+++ /dev/null
@@ -1,59 +0,0 @@
-/* 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 generators for tests.
-
- * 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/test/range.d,
- * tanya/test/range.d)
- */
-module tanya.test.range;
-
-package(tanya) struct Empty
-{
-}
-
-package(tanya) template InputRange()
-{
- import tanya.meta.metafunction : AliasSeq;
-
- private alias attributes = AliasSeq!(__traits(getAttributes, typeof(this)));
-
- static foreach (attribute; attributes)
- {
- static if (is(attribute == Empty))
- {
- @property bool empty() const @nogc nothrow pure @safe
- {
- return true;
- }
- }
- }
-
- void popFront() @nogc nothrow pure @safe
- {
- static foreach (attribute; attributes)
- {
- static if (is(attribute == Empty))
- {
- assert(false);
- }
- }
- }
-
- int front() @nogc nothrow pure @safe
- {
- static foreach (attribute; attributes)
- {
- static if (is(attribute == Empty))
- {
- assert(false);
- }
- }
- }
-}
diff --git a/source/tanya/test/stub.d b/source/tanya/test/stub.d
new file mode 100644
index 0000000..2be252e
--- /dev/null
+++ b/source/tanya/test/stub.d
@@ -0,0 +1,275 @@
+/* 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 generators.
+ *
+ * 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/test/stub.d,
+ * tanya/test/stub.d)
+ */
+module tanya.test.stub;
+
+/**
+ * Attribute signalizing that the generated range should contain the given
+ * number of elements.
+ *
+ * $(D_PSYMBOL Count) should be always specified with some value and not as a
+ * type, so $(D_INLINECODE Count(1)) instead just $(D_INLINECODE Count),
+ * otherwise you can just omit $(D_PSYMBOL Count) and it will default to 0.
+ *
+ * $(D_PSYMBOL Count) doesn't generate `.length` property - use
+ * $(D_PSYMBOL Length) for that.
+ *
+ * If neither $(D_PSYMBOL Length) nor $(D_PSYMBOL Infinite) is given,
+ * $(D_ILNINECODE Count(0)) is assumed.
+ *
+ * This attribute conflicts with $(D_PSYMBOL Infinite) and $(D_PSYMBOL Length).
+ */
+struct Count
+{
+ /// Original range length.
+ size_t count = 0;
+
+ @disable this();
+
+ /**
+ * Constructs the attribute with the given length.
+ *
+ * Params:
+ * count = Original range length.
+ */
+ this(size_t count) @nogc nothrow pure @safe
+ {
+ this.count = count;
+ }
+}
+
+/**
+ * Attribute signalizing that the generated range should be infinite.
+ *
+ * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Length).
+ */
+struct Infinite
+{
+}
+
+/**
+ * Generates `.length` property for the range.
+ *
+ * The length of the range can be specified as a constructor argument,
+ * otherwise it is 0.
+ *
+ * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Infinite).
+ */
+struct Length
+{
+ /// Original range length.
+ size_t length = 0;
+}
+
+/**
+ * Attribute signalizing that the generated range should return values by
+ * reference.
+ *
+ * This atribute affects the return values of `.front`, `.back` and `[]`.
+ */
+struct WithLvalueElements
+{
+}
+
+/**
+ * Generates an input range.
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template InputRangeStub(E = int)
+{
+ import tanya.meta.metafunction : Alias;
+ import tanya.meta.trait : getUDAs, hasUDA;
+
+ /*
+ * Aliases for the attribute lookups to access them faster
+ */
+ private enum bool infinite = hasUDA!(typeof(this), Infinite);
+ private enum bool withLvalueElements = hasUDA!(typeof(this),
+ WithLvalueElements);
+ private alias Count = getUDAs!(typeof(this), .Count);
+ private alias Length = getUDAs!(typeof(this), .Length);
+
+ static if (Count.length != 0)
+ {
+ private enum size_t count = Count[0].count;
+
+ static assert (!infinite,
+ "Range cannot have count and be infinite at the same time");
+ static assert (Length.length == 0,
+ "Range cannot have count and length at the same time");
+ }
+ else static if (Length.length != 0)
+ {
+ private enum size_t count = evalUDA!(Length[0]).length;
+
+ static assert (!infinite,
+ "Range cannot have length and be infinite at the same time");
+ }
+ else static if (!infinite)
+ {
+ private enum size_t count = 0;
+ }
+
+ /*
+ * Member generation
+ */
+ static if (infinite)
+ {
+ enum bool empty = false;
+ }
+ else
+ {
+ private size_t length_ = count;
+
+ @property bool empty() const @nogc nothrow pure @safe
+ {
+ return this.length_ == 0;
+ }
+ }
+
+ static if (withLvalueElements)
+ {
+ private E* element; // Pointer to enable range copying in save()
+ }
+
+ void popFront() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ static if (!infinite)
+ {
+ --this.length_;
+ }
+ }
+
+ static if (withLvalueElements)
+ {
+ ref E front() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return *this.element;
+ }
+ }
+ else
+ {
+ E front() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return E.init;
+ }
+ }
+
+ static if (Length.length != 0)
+ {
+ size_t length() const @nogc nothrow pure @safe
+ {
+ return this.length_;
+ }
+ }
+}
+
+/**
+ * Generates a forward range.
+ *
+ * This mixin includes input range primitives as well, but can be combined with
+ * $(D_PSYMBOL RandomAccessRangeStub).
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template ForwardRangeStub(E = int)
+{
+ static if (!is(typeof(this.InputRangeMixin) == void))
+ {
+ mixin InputRangeStub!E InputRangeMixin;
+ }
+
+ auto save() @nogc nothrow pure @safe
+ {
+ return this;
+ }
+}
+
+/**
+ * Generates a bidirectional range.
+ *
+ * This mixin includes forward range primitives as well, but can be combined with
+ * $(D_PSYMBOL RandomAccessRangeStub).
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template BidirectionalRangeStub(E = int)
+{
+ mixin ForwardRangeStub!E;
+
+ void popBack() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ static if (!infinite)
+ {
+ --this.length_;
+ }
+ }
+
+ static if (withLvalueElements)
+ {
+ ref E back() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return *this.element;
+ }
+ }
+ else
+ {
+ E back() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return E.init;
+ }
+ }
+}
+
+/**
+ * Generates a random-access range.
+ *
+ * This mixin includes input range primitives as well, but can be combined with
+ * $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub).
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template RandomAccessRangeStub(E = int)
+{
+ static if (!is(typeof(this.InputRangeMixin) == void))
+ {
+ mixin InputRangeStub!E InputRangeMixin;
+ }
+
+ static if (withLvalueElements)
+ {
+ ref E opIndex(size_t) @nogc nothrow pure @safe
+ {
+ return *this.element;
+ }
+ }
+ else
+ {
+ E opIndex(size_t) @nogc nothrow pure @safe
+ {
+ return E.init;
+ }
+ }
+}