summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/tanya/algorithm/iteration.d8
-rw-r--r--source/tanya/algorithm/mutation.d5
-rw-r--r--source/tanya/conv.d22
-rw-r--r--source/tanya/memory/smartref.d15
-rw-r--r--source/tanya/range/primitive.d80
-rw-r--r--source/tanya/test/stub.d39
-rw-r--r--source/tanya/typecons.d22
7 files changed, 133 insertions, 58 deletions
diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d
index 9ad8cdd..bfd1f13 100644
--- a/source/tanya/algorithm/iteration.d
+++ b/source/tanya/algorithm/iteration.d
@@ -3,13 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
- * Range adapters.
+ * Iteration algorithms.
*
- * A range adapter wraps another range and modifies the way, how the original
+ * These algorithms wrap other ranges and modify the way, how the original
* range is iterated, or the order in which its elements are accessed.
*
- * All adapters are lazy algorithms, they request the next element of the
- * adapted range on demand.
+ * All algorithms in this module are lazy, they request the next element of the
+ * original range on demand.
*
* Copyright: Eugene Wissner 2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d
index 9c05826..bd71f40 100644
--- a/source/tanya/algorithm/mutation.d
+++ b/source/tanya/algorithm/mutation.d
@@ -19,6 +19,7 @@ static import tanya.memory.op;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range;
+version (unittest) import tanya.test.stub;
private void deinitialize(bool zero, T)(ref T value)
{
@@ -554,10 +555,6 @@ if (isInputRange!Range && hasLvalueElements!Range)
@nogc nothrow pure @safe unittest
{
- static struct NonCopyable
- {
- @disable this(this);
- }
NonCopyable[] nonCopyable;
initializeAll(nonCopyable);
}
diff --git a/source/tanya/conv.d b/source/tanya/conv.d
index e19ea7f..97fafa4 100644
--- a/source/tanya/conv.d
+++ b/source/tanya/conv.d
@@ -27,6 +27,7 @@ import tanya.range.primitive;
version (unittest)
{
import tanya.test.assertion;
+ import tanya.test.stub;
}
/**
@@ -257,32 +258,23 @@ out(result; memory.ptr is result)
// Can emplace structs without a constructor
@nogc nothrow pure @safe unittest
{
- static struct SWithDtor
- {
- ~this() @nogc nothrow pure @safe
- {
- }
- }
- static assert(is(typeof(emplace!SWithDtor(null, SWithDtor()))));
- static assert(is(typeof(emplace!SWithDtor(null))));
+ static assert(is(typeof(emplace!WithDtor(null, WithDtor()))));
+ static assert(is(typeof(emplace!WithDtor(null))));
}
// Doesn't call a destructor on uninitialized elements
@nogc nothrow pure @system unittest
{
- static struct WithDtor
+ static struct SWithDtor
{
private bool canBeInvoked = false;
~this() @nogc nothrow pure @safe
{
- if (!this.canBeInvoked)
- {
- assert(false);
- }
+ assert(this.canBeInvoked);
}
}
- void[WithDtor.sizeof] memory = void;
- auto actual = emplace!WithDtor(memory[], WithDtor(true));
+ void[SWithDtor.sizeof] memory = void;
+ auto actual = emplace!SWithDtor(memory[], SWithDtor(true));
assert(actual.canBeInvoked);
}
diff --git a/source/tanya/memory/smartref.d b/source/tanya/memory/smartref.d
index 962752f..020627d 100644
--- a/source/tanya/memory/smartref.d
+++ b/source/tanya/memory/smartref.d
@@ -30,6 +30,7 @@ import tanya.exception;
import tanya.memory;
import tanya.meta.trait;
import tanya.range.primitive;
+version (unittest) import tanya.test.stub;
private template Payload(T)
{
@@ -611,19 +612,11 @@ do
@nogc @system unittest
{
- static bool destroyed;
-
- static struct F
+ size_t destroyed;
{
- ~this() @nogc nothrow @safe
- {
- destroyed = true;
- }
- }
- {
- auto rc = defaultAllocator.refCounted!F();
+ auto rc = defaultAllocator.refCounted!WithDtor(destroyed);
}
- assert(destroyed);
+ assert(destroyed == 1);
}
/**
diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d
index 099208a..8cf45f2 100644
--- a/source/tanya/range/primitive.d
+++ b/source/tanya/range/primitive.d
@@ -316,6 +316,26 @@ private template isDynamicArrayRange(R)
}
}
+private struct Primitive(Candidate, string primitive)
+{
+ auto ref returnType(Candidate candidate)
+ {
+ mixin("return candidate." ~ primitive ~ ";");
+ }
+
+ alias ReturnType = .ReturnType!returnType;
+ static assert(!is(ReturnType == void));
+
+ enum uint attributes = functionAttributes!returnType
+ & FunctionAttribute.ref_;
+
+ bool opEquals(That)(That) const
+ {
+ return is(ReturnType == That.ReturnType)
+ && attributes == That.attributes;
+ }
+}
+
/**
* Determines whether $(D_PARAM R) is an input range.
*
@@ -335,11 +355,11 @@ private template isDynamicArrayRange(R)
*/
template isInputRange(R)
{
- static if (is(ReturnType!((R r) => r.front()) U)
+ static if (is(Primitive!(R, "front()") U)
&& is(ReturnType!((R r) => r.empty) == bool)
&& is(typeof(R.popFront())))
{
- enum bool isInputRange = !is(U == void);
+ enum bool isInputRange = true;
}
else
{
@@ -415,6 +435,28 @@ template isInputRange(R)
static assert(isInputRange!Range4);
}
+// Ranges with non-copyable elements can be input ranges
+@nogc nothrow pure @safe unittest
+{
+ @WithLvalueElements
+ static struct R
+ {
+ mixin InputRangeStub!NonCopyable;
+ }
+ static assert(isInputRange!R);
+}
+
+// Ranges with const non-copyable elements can be input ranges
+@nogc nothrow pure @safe unittest
+{
+ @WithLvalueElements
+ static struct R
+ {
+ mixin InputRangeStub!(const(NonCopyable));
+ }
+ static assert(isInputRange!R);
+}
+
/**
* Determines whether $(D_PARAM R) is a forward range.
*
@@ -521,11 +563,11 @@ template isForwardRange(R)
*/
template isBidirectionalRange(R)
{
- static if (is(ReturnType!((R r) => r.back()) U)
+ static if (is(Primitive!(R, "back()") U)
&& is(typeof(R.popBack())))
{
enum bool isBidirectionalRange = isForwardRange!R
- && is(U == ReturnType!((R r) => r.front()));
+ && (U() == Primitive!(R, "front()")());
}
else
{
@@ -591,6 +633,17 @@ template isBidirectionalRange(R)
static assert(!isBidirectionalRange!(Range!(int, const int)));
}
+// Ranges with non-copyable elements can be bidirectional ranges
+@nogc nothrow pure @safe unittest
+{
+ @WithLvalueElements
+ static struct R
+ {
+ mixin BidirectionalRangeStub!NonCopyable;
+ }
+ static assert(isBidirectionalRange!R);
+}
+
/**
* Determines whether $(D_PARAM R) is a random-access range.
*
@@ -616,11 +669,11 @@ template isBidirectionalRange(R)
*/
template isRandomAccessRange(R)
{
- static if (is(ReturnType!((R r) => r.opIndex(size_t.init)) U))
+ static if (is(Primitive!(R, "opIndex(size_t.init)") U))
{
enum bool isRandomAccessRange = isInputRange!R
&& (hasLength!R || isInfinite!R)
- && is(U == ReturnType!((R r) => r.front()));
+ && (U() == Primitive!(R, "front()")());
}
else
{
@@ -731,6 +784,17 @@ template isRandomAccessRange(R)
static assert(!isRandomAccessRange!Range4);
}
+// Ranges with non-copyable elements can be random-access ranges
+@nogc nothrow pure @safe unittest
+{
+ @WithLvalueElements @Infinite
+ static struct R
+ {
+ mixin RandomAccessRangeStub!NonCopyable;
+ }
+ static assert(isRandomAccessRange!R);
+}
+
/**
* Puts $(D_PARAM e) into the $(D_PARAM range).
*
@@ -1698,10 +1762,6 @@ template hasLvalueElements(R)
// Works with non-copyable elements
@nogc nothrow pure @safe unittest
{
- static struct NonCopyable
- {
- @disable this(this);
- }
static assert(hasLvalueElements!(NonCopyable[]));
}
diff --git a/source/tanya/test/stub.d b/source/tanya/test/stub.d
index 2be252e..234e409 100644
--- a/source/tanya/test/stub.d
+++ b/source/tanya/test/stub.d
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
- * Range generators.
+ * Range and generic type generators.
*
* Copyright: Eugene Wissner 2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
@@ -248,6 +248,9 @@ mixin template BidirectionalRangeStub(E = int)
* This mixin includes input range primitives as well, but can be combined with
* $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub).
*
+ * Note that a random-access range also requires $(D_PSYMBOL Length) or
+ * $(D_PARAM Infinite) by definition.
+ *
* Params:
* E = Element type.
*/
@@ -273,3 +276,37 @@ mixin template RandomAccessRangeStub(E = int)
}
}
}
+
+/**
+ * Struct with a disabled postblit constructor.
+ */
+struct NonCopyable
+{
+ @disable this(this);
+}
+
+/**
+ * Struct with an elaborate destructor.
+ *
+ * The constructor of $(D_PSYMBOL WithDtor) accepts an additional `counter`
+ * argument, which is incremented by the destructor. $(D_PSYMBOL WithDtor)
+ * stores a pointer to the passed variable, so the variable can be
+ * investigated after the struct isn't available anymore.
+ */
+struct WithDtor
+{
+ size_t* counter;
+
+ this(ref size_t counter) @nogc nothrow pure @trusted
+ {
+ this.counter = &counter;
+ }
+
+ ~this() @nogc nothrow pure @safe
+ {
+ if (this.counter !is null)
+ {
+ ++*this.counter;
+ }
+ }
+}
diff --git a/source/tanya/typecons.d b/source/tanya/typecons.d
index 52fcbb2..becb1e3 100644
--- a/source/tanya/typecons.d
+++ b/source/tanya/typecons.d
@@ -22,6 +22,7 @@ import tanya.format;
import tanya.functional;
import tanya.meta.metafunction;
import tanya.meta.trait;
+version (unittest) import tanya.test.stub;
/**
* $(D_PSYMBOL Tuple) can store two or more heterogeneous objects.
@@ -454,29 +455,24 @@ struct Option(T)
// Moving
@nogc nothrow pure @safe unittest
{
- static struct NotCopyable
- {
- @disable this(this);
- }
-
- static assert(is(typeof(Option!NotCopyable(NotCopyable()))));
+ static assert(is(typeof(Option!NonCopyable(NonCopyable()))));
// The value cannot be returned by reference because the default value
// isn't passed by reference
- static assert(!is(typeof(Option!DisabledPostblit().or(NotCopyable()))));
+ static assert(!is(typeof(Option!DisabledPostblit().or(NonCopyable()))));
{
- NotCopyable notCopyable;
- static assert(is(typeof(Option!NotCopyable().or(notCopyable))));
+ NonCopyable notCopyable;
+ static assert(is(typeof(Option!NonCopyable().or(notCopyable))));
}
{
- Option!NotCopyable option;
+ Option!NonCopyable option;
assert(option.isNothing);
- option = NotCopyable();
+ option = NonCopyable();
assert(!option.isNothing);
}
{
- Option!NotCopyable option;
+ Option!NonCopyable option;
assert(option.isNothing);
- option = Option!NotCopyable(NotCopyable());
+ option = Option!NonCopyable(NonCopyable());
assert(!option.isNothing);
}
}