Implement moveFront, moveBack, moveAt
... and hasMobileElements.
This commit is contained in:
parent
7829b1fe06
commit
a7c1e642e9
@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.range.primitive;
|
module tanya.range.primitive;
|
||||||
|
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
import tanya.math;
|
import tanya.math;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
@ -1355,3 +1356,501 @@ if (isBidirectionalRange!R)
|
|||||||
assert(range.empty);
|
assert(range.empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the front element of an input range.
|
||||||
|
*
|
||||||
|
* The front element is left in a valid but inspecified 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 (is(typeof(R.moveFront)))
|
||||||
|
{
|
||||||
|
return range.moveFront();
|
||||||
|
}
|
||||||
|
else 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
|
||||||
|
{
|
||||||
|
// Defines moveFront.
|
||||||
|
static struct R1
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int moveFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
alias front = moveFront;
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(moveFront(R1()) == 5);
|
||||||
|
|
||||||
|
// Has elements without a postblit constructor.
|
||||||
|
static struct R2
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int front() const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(moveFront(R2()) == 5);
|
||||||
|
|
||||||
|
static struct Element
|
||||||
|
{
|
||||||
|
this(this)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Returns its elements by reference.
|
||||||
|
static struct R3
|
||||||
|
{
|
||||||
|
Element element;
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
ref Element front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(is(typeof(moveFront(R3()))));
|
||||||
|
|
||||||
|
// Returns elements with a postblit constructor by value. moveFront fails.
|
||||||
|
static struct R4
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
Element front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return Element();
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(!is(typeof(moveFront(R4()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the back element of a bidirectional range.
|
||||||
|
*
|
||||||
|
* The back element is left in a valid but inspecified 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 (is(typeof(R.moveBack)))
|
||||||
|
{
|
||||||
|
return range.moveBack();
|
||||||
|
}
|
||||||
|
else 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
|
||||||
|
{
|
||||||
|
// Defines moveBack.
|
||||||
|
static struct R1
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int moveBack() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
alias back = moveBack;
|
||||||
|
alias front = moveBack;
|
||||||
|
|
||||||
|
void popBack() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
alias popFront = popBack;
|
||||||
|
|
||||||
|
R1 save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(moveBack(R1()) == 5);
|
||||||
|
|
||||||
|
// Has elements without a postblit constructor.
|
||||||
|
static struct R2
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int back() const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
alias front = back;
|
||||||
|
|
||||||
|
void popBack() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
alias popFront = popBack;
|
||||||
|
|
||||||
|
R2 save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(moveBack(R2()) == 5);
|
||||||
|
|
||||||
|
static struct Element
|
||||||
|
{
|
||||||
|
this(this)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Returns its elements by reference.
|
||||||
|
static struct R3
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
R3 save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(is(typeof(moveBack(R3()))));
|
||||||
|
|
||||||
|
// Returns elements with a postblit constructor by value. moveBack fails.
|
||||||
|
static struct R4
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
Element back() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return Element();
|
||||||
|
}
|
||||||
|
alias front = back;
|
||||||
|
|
||||||
|
void popBack() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
alias popFront = popBack;
|
||||||
|
|
||||||
|
R4 save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(!is(typeof(moveBack(R4()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the element at the position $(D_PARAM n) out of the range.
|
||||||
|
*
|
||||||
|
* The moved element is left in a valid but inspecified state.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Type of the range.
|
||||||
|
* 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 (is(typeof(R.moveAt)))
|
||||||
|
{
|
||||||
|
return range.moveAt(n);
|
||||||
|
}
|
||||||
|
else 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, "Back element cannot be moved");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
// Defines moveAt.
|
||||||
|
static struct R1
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int moveAt(size_t) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
alias opIndex = moveAt;
|
||||||
|
}
|
||||||
|
assert(moveAt(R1(), 0) == 5);
|
||||||
|
|
||||||
|
// Has elements without a postblit constructor.
|
||||||
|
static struct R2
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int front() const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int opIndex(size_t) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(moveAt(R2(), 0) == 5);
|
||||||
|
|
||||||
|
static struct Element
|
||||||
|
{
|
||||||
|
this(this)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Returns its elements by reference.
|
||||||
|
static struct R3
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(is(typeof(moveAt(R3(), 0))));
|
||||||
|
|
||||||
|
// Returns elements with a postblit constructor by value. moveAt fails.
|
||||||
|
static struct R4
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(!is(typeof(moveAt(R4(), 0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 -
|
||||||
|
* $(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
|
||||||
|
{
|
||||||
|
// Input range with elements without a postblit constructor.
|
||||||
|
// These can be moved.
|
||||||
|
static struct InputRange
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
int front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(hasMobileElements!InputRange);
|
||||||
|
|
||||||
|
static struct Element
|
||||||
|
{
|
||||||
|
this(this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bidirectional range, whose elements cannot be moved. The range defines
|
||||||
|
// only moveFront, but not moveBack. So it doesn't have mobile elements.
|
||||||
|
static struct BidirectionalRange
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
Element front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return Element();
|
||||||
|
}
|
||||||
|
alias back = front;
|
||||||
|
alias moveFront = front;
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
alias popBack = popFront;
|
||||||
|
|
||||||
|
BidirectionalRange save() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(!hasMobileElements!BidirectionalRange);
|
||||||
|
|
||||||
|
// Access-random range, whose elements cannot be moved, but the range
|
||||||
|
// defines both, moveFront and moveAt.
|
||||||
|
static struct RandomAccessRange
|
||||||
|
{
|
||||||
|
enum bool empty = false;
|
||||||
|
|
||||||
|
Element front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return Element();
|
||||||
|
}
|
||||||
|
alias moveFront = front;
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Element opIndex(size_t) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return Element();
|
||||||
|
}
|
||||||
|
alias moveAt = opIndex;
|
||||||
|
}
|
||||||
|
static assert(hasMobileElements!RandomAccessRange);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user