range.primitive: Support non copyable elements
... in all ranges.
This commit is contained in:
parent
7585bf59e7
commit
e67a05138e
@ -3,13 +3,13 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* 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.
|
* range is iterated, or the order in which its elements are accessed.
|
||||||
*
|
*
|
||||||
* All adapters are lazy algorithms, they request the next element of the
|
* All algorithms in this module are lazy, they request the next element of the
|
||||||
* adapted range on demand.
|
* original range on demand.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2018.
|
* Copyright: Eugene Wissner 2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
|
@ -19,6 +19,7 @@ static import tanya.memory.op;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
private void deinitialize(bool zero, T)(ref T value)
|
private void deinitialize(bool zero, T)(ref T value)
|
||||||
{
|
{
|
||||||
@ -554,10 +555,6 @@ if (isInputRange!Range && hasLvalueElements!Range)
|
|||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static struct NonCopyable
|
|
||||||
{
|
|
||||||
@disable this(this);
|
|
||||||
}
|
|
||||||
NonCopyable[] nonCopyable;
|
NonCopyable[] nonCopyable;
|
||||||
initializeAll(nonCopyable);
|
initializeAll(nonCopyable);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import tanya.range.primitive;
|
|||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
import tanya.test.assertion;
|
import tanya.test.assertion;
|
||||||
|
import tanya.test.stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,32 +258,23 @@ out(result; memory.ptr is result)
|
|||||||
// Can emplace structs without a constructor
|
// Can emplace structs without a constructor
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static struct SWithDtor
|
static assert(is(typeof(emplace!WithDtor(null, WithDtor()))));
|
||||||
{
|
static assert(is(typeof(emplace!WithDtor(null))));
|
||||||
~this() @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static assert(is(typeof(emplace!SWithDtor(null, SWithDtor()))));
|
|
||||||
static assert(is(typeof(emplace!SWithDtor(null))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doesn't call a destructor on uninitialized elements
|
// Doesn't call a destructor on uninitialized elements
|
||||||
@nogc nothrow pure @system unittest
|
@nogc nothrow pure @system unittest
|
||||||
{
|
{
|
||||||
static struct WithDtor
|
static struct SWithDtor
|
||||||
{
|
{
|
||||||
private bool canBeInvoked = false;
|
private bool canBeInvoked = false;
|
||||||
~this() @nogc nothrow pure @safe
|
~this() @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (!this.canBeInvoked)
|
assert(this.canBeInvoked);
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void[WithDtor.sizeof] memory = void;
|
void[SWithDtor.sizeof] memory = void;
|
||||||
auto actual = emplace!WithDtor(memory[], WithDtor(true));
|
auto actual = emplace!SWithDtor(memory[], SWithDtor(true));
|
||||||
assert(actual.canBeInvoked);
|
assert(actual.canBeInvoked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import tanya.exception;
|
|||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
private template Payload(T)
|
private template Payload(T)
|
||||||
{
|
{
|
||||||
@ -611,19 +612,11 @@ do
|
|||||||
|
|
||||||
@nogc @system unittest
|
@nogc @system unittest
|
||||||
{
|
{
|
||||||
static bool destroyed;
|
size_t destroyed;
|
||||||
|
|
||||||
static struct F
|
|
||||||
{
|
{
|
||||||
~this() @nogc nothrow @safe
|
auto rc = defaultAllocator.refCounted!WithDtor(destroyed);
|
||||||
{
|
|
||||||
destroyed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
{
|
assert(destroyed == 1);
|
||||||
auto rc = defaultAllocator.refCounted!F();
|
|
||||||
}
|
|
||||||
assert(destroyed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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.
|
* Determines whether $(D_PARAM R) is an input range.
|
||||||
*
|
*
|
||||||
@ -335,11 +355,11 @@ private template isDynamicArrayRange(R)
|
|||||||
*/
|
*/
|
||||||
template isInputRange(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(ReturnType!((R r) => r.empty) == bool)
|
||||||
&& is(typeof(R.popFront())))
|
&& is(typeof(R.popFront())))
|
||||||
{
|
{
|
||||||
enum bool isInputRange = !is(U == void);
|
enum bool isInputRange = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -415,6 +435,28 @@ template isInputRange(R)
|
|||||||
static assert(isInputRange!Range4);
|
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.
|
* Determines whether $(D_PARAM R) is a forward range.
|
||||||
*
|
*
|
||||||
@ -521,11 +563,11 @@ template isForwardRange(R)
|
|||||||
*/
|
*/
|
||||||
template isBidirectionalRange(R)
|
template isBidirectionalRange(R)
|
||||||
{
|
{
|
||||||
static if (is(ReturnType!((R r) => r.back()) U)
|
static if (is(Primitive!(R, "back()") U)
|
||||||
&& is(typeof(R.popBack())))
|
&& is(typeof(R.popBack())))
|
||||||
{
|
{
|
||||||
enum bool isBidirectionalRange = isForwardRange!R
|
enum bool isBidirectionalRange = isForwardRange!R
|
||||||
&& is(U == ReturnType!((R r) => r.front()));
|
&& (U() == Primitive!(R, "front()")());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -591,6 +633,17 @@ template isBidirectionalRange(R)
|
|||||||
static assert(!isBidirectionalRange!(Range!(int, const int)));
|
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.
|
* Determines whether $(D_PARAM R) is a random-access range.
|
||||||
*
|
*
|
||||||
@ -616,11 +669,11 @@ template isBidirectionalRange(R)
|
|||||||
*/
|
*/
|
||||||
template isRandomAccessRange(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
|
enum bool isRandomAccessRange = isInputRange!R
|
||||||
&& (hasLength!R || isInfinite!R)
|
&& (hasLength!R || isInfinite!R)
|
||||||
&& is(U == ReturnType!((R r) => r.front()));
|
&& (U() == Primitive!(R, "front()")());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -731,6 +784,17 @@ template isRandomAccessRange(R)
|
|||||||
static assert(!isRandomAccessRange!Range4);
|
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).
|
* Puts $(D_PARAM e) into the $(D_PARAM range).
|
||||||
*
|
*
|
||||||
@ -1698,10 +1762,6 @@ template hasLvalueElements(R)
|
|||||||
// Works with non-copyable elements
|
// Works with non-copyable elements
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static struct NonCopyable
|
|
||||||
{
|
|
||||||
@disable this(this);
|
|
||||||
}
|
|
||||||
static assert(hasLvalueElements!(NonCopyable[]));
|
static assert(hasLvalueElements!(NonCopyable[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Range generators.
|
* Range and generic type generators.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2018.
|
* Copyright: Eugene Wissner 2018.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* 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
|
* This mixin includes input range primitives as well, but can be combined with
|
||||||
* $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub).
|
* $(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:
|
* Params:
|
||||||
* E = Element type.
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import tanya.format;
|
|||||||
import tanya.functional;
|
import tanya.functional;
|
||||||
import tanya.meta.metafunction;
|
import tanya.meta.metafunction;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
|
version (unittest) import tanya.test.stub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $(D_PSYMBOL Tuple) can store two or more heterogeneous objects.
|
* $(D_PSYMBOL Tuple) can store two or more heterogeneous objects.
|
||||||
@ -454,29 +455,24 @@ struct Option(T)
|
|||||||
// Moving
|
// Moving
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static struct NotCopyable
|
static assert(is(typeof(Option!NonCopyable(NonCopyable()))));
|
||||||
{
|
|
||||||
@disable this(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static assert(is(typeof(Option!NotCopyable(NotCopyable()))));
|
|
||||||
// The value cannot be returned by reference because the default value
|
// The value cannot be returned by reference because the default value
|
||||||
// isn't passed by reference
|
// isn't passed by reference
|
||||||
static assert(!is(typeof(Option!DisabledPostblit().or(NotCopyable()))));
|
static assert(!is(typeof(Option!DisabledPostblit().or(NonCopyable()))));
|
||||||
{
|
{
|
||||||
NotCopyable notCopyable;
|
NonCopyable notCopyable;
|
||||||
static assert(is(typeof(Option!NotCopyable().or(notCopyable))));
|
static assert(is(typeof(Option!NonCopyable().or(notCopyable))));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Option!NotCopyable option;
|
Option!NonCopyable option;
|
||||||
assert(option.isNothing);
|
assert(option.isNothing);
|
||||||
option = NotCopyable();
|
option = NonCopyable();
|
||||||
assert(!option.isNothing);
|
assert(!option.isNothing);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Option!NotCopyable option;
|
Option!NonCopyable option;
|
||||||
assert(option.isNothing);
|
assert(option.isNothing);
|
||||||
option = Option!NotCopyable(NotCopyable());
|
option = Option!NonCopyable(NonCopyable());
|
||||||
assert(!option.isNothing);
|
assert(!option.isNothing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user