Remove support for moveFront/moveBack/moveAt

Range elements are movable (mobile) if they are returned by reference
and can be moved or if the elements doesn't define an elaborate postblit
constructor. Allowing to define custom moveFront/moveBack/moveAt makes
the range definition more complex (particulary writing range adapters)
without a good reason.
This commit is contained in:
Eugen Wissner 2018-04-03 21:44:50 +02:00
parent a0ac8355f9
commit f15a90543f
3 changed files with 56 additions and 192 deletions

View File

@ -31,7 +31,7 @@
* (D_INLINECODE dchar[])) are treated as any other normal array, they aren't * (D_INLINECODE dchar[])) are treated as any other normal array, they aren't
* auto-decoded. * auto-decoded.
* *
* Copyright: Eugene Wissner 2017. * Copyright: Eugene Wissner 2017-2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -6,7 +6,7 @@
* This package contains generic functions and templates to be used with D * This package contains generic functions and templates to be used with D
* ranges. * ranges.
* *
* Copyright: Eugene Wissner 2017. * Copyright: Eugene Wissner 2017-2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)

View File

@ -5,7 +5,7 @@
/** /**
* This module defines primitives for working with ranges. * This module defines primitives for working with ranges.
* *
* Copyright: Eugene Wissner 2017. * Copyright: Eugene Wissner 2017-2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0). * Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@ -1464,11 +1464,7 @@ if (isBidirectionalRange!R)
ElementType!R moveFront(R)(R range) ElementType!R moveFront(R)(R range)
if (isInputRange!R) if (isInputRange!R)
{ {
static if (__traits(hasMember, R, "moveFront")) static if (!hasElaborateCopyConstructor!(ElementType!R))
{
return range.moveFront();
}
else static if (!hasElaborateCopyConstructor!(ElementType!R))
{ {
return range.front; return range.front;
} }
@ -1485,48 +1481,24 @@ if (isInputRange!R)
/// ///
@nogc nothrow pure @safe unittest @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. // Has elements without a postblit constructor.
static struct R2 int[2] a = 5;
{
enum bool empty = false;
int front() const @nogc nothrow pure @safe assert(moveFront(a[]) == 5);
{
return 5;
} }
void popFront() @nogc nothrow pure @safe @nogc nothrow pure @safe unittest
{ {
}
}
assert(moveFront(R2()) == 5);
static struct Element static struct Element
{ {
this(this) this(this) @nogc nothrow pure @safe
{ {
assert(false); assert(false);
} }
} }
// Returns its elements by reference. // Returns its elements by reference.
static struct R3 static struct R1
{ {
Element element; Element element;
enum bool empty = false; enum bool empty = false;
@ -1540,10 +1512,10 @@ if (isInputRange!R)
{ {
} }
} }
static assert(is(typeof(moveFront(R3())))); static assert(is(typeof(moveFront(R1()))));
// Returns elements with a postblit constructor by value. moveFront fails. // Returns elements with a postblit constructor by value. moveFront fails.
static struct R4 static struct R2
{ {
enum bool empty = false; enum bool empty = false;
@ -1556,7 +1528,7 @@ if (isInputRange!R)
{ {
} }
} }
static assert(!is(typeof(moveFront(R4())))); static assert(!is(typeof(moveFront(R2()))));
} }
/** /**
@ -1577,11 +1549,7 @@ if (isInputRange!R)
ElementType!R moveBack(R)(R range) ElementType!R moveBack(R)(R range)
if (isBidirectionalRange!R) if (isBidirectionalRange!R)
{ {
static if (__traits(hasMember, R, "moveBack")) static if (!hasElaborateCopyConstructor!(ElementType!R))
{
return range.moveBack();
}
else static if (!hasElaborateCopyConstructor!(ElementType!R))
{ {
return range.back; return range.back;
} }
@ -1598,62 +1566,24 @@ if (isBidirectionalRange!R)
/// ///
@nogc nothrow pure @safe unittest @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. // Has elements without a postblit constructor.
static struct R2 int[2] a = 5;
{
enum bool empty = false;
int back() const @nogc nothrow pure @safe assert(moveBack(a[]) == 5);
{
return 5;
} }
alias front = back;
void popBack() @nogc nothrow pure @safe @nogc nothrow pure @safe unittest
{ {
}
alias popFront = popBack;
R2 save() @nogc nothrow pure @safe
{
return this;
}
}
assert(moveBack(R2()) == 5);
static struct Element static struct Element
{ {
this(this) this(this) @nogc nothrow pure @safe
{ {
assert(false); assert(false);
} }
} }
// Returns its elements by reference. // Returns its elements by reference.
static struct R3 static struct R1
{ {
Element element; Element element;
enum bool empty = false; enum bool empty = false;
@ -1669,15 +1599,15 @@ if (isBidirectionalRange!R)
} }
alias popFront = popBack; alias popFront = popBack;
R3 save() @nogc nothrow pure @safe R1 save() @nogc nothrow pure @safe
{ {
return this; return this;
} }
} }
static assert(is(typeof(moveBack(R3())))); static assert(is(typeof(moveBack(R1()))));
// Returns elements with a postblit constructor by value. moveBack fails. // Returns elements with a postblit constructor by value. moveBack fails.
static struct R4 static struct R2
{ {
enum bool empty = false; enum bool empty = false;
@ -1692,12 +1622,12 @@ if (isBidirectionalRange!R)
} }
alias popFront = popBack; alias popFront = popBack;
R4 save() @nogc nothrow pure @safe R2 save() @nogc nothrow pure @safe
{ {
return this; return this;
} }
} }
static assert(!is(typeof(moveBack(R4())))); static assert(!is(typeof(moveBack(R2()))));
} }
/** /**
@ -1717,11 +1647,7 @@ if (isBidirectionalRange!R)
ElementType!R moveAt(R)(R range, size_t n) ElementType!R moveAt(R)(R range, size_t n)
if (isRandomAccessRange!R) if (isRandomAccessRange!R)
{ {
static if (__traits(hasMember, R, "moveAt")) static if (!hasElaborateCopyConstructor!(ElementType!R))
{
return range.moveAt(n);
}
else static if (!hasElaborateCopyConstructor!(ElementType!R))
{ {
return range[n]; return range[n];
} }
@ -1731,65 +1657,31 @@ if (isRandomAccessRange!R)
} }
else else
{ {
static assert(false, "Back element cannot be moved"); static assert(false, "Random element cannot be moved");
} }
} }
/// ///
@nogc nothrow pure @safe unittest @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. // Has elements without a postblit constructor.
static struct R2 int[3] a = 5;
{
enum bool empty = false;
int front() const @nogc nothrow pure @safe assert(moveAt(a[], 1) == 5);
{
return 5;
} }
void popFront() @nogc nothrow pure @safe @nogc nothrow pure @safe unittest
{ {
}
int opIndex(size_t) const @nogc nothrow pure @safe
{
return 5;
}
}
assert(moveAt(R2(), 0) == 5);
static struct Element static struct Element
{ {
this(this) this(this) @nogc nothrow pure @safe
{ {
assert(false); assert(false);
} }
} }
// Returns its elements by reference. // Returns its elements by reference.
static struct R3 static struct R1
{ {
Element element; Element element;
enum bool empty = false; enum bool empty = false;
@ -1808,10 +1700,10 @@ if (isRandomAccessRange!R)
return element; return element;
} }
} }
static assert(is(typeof(moveAt(R3(), 0)))); static assert(is(typeof(moveAt(R1(), 0))));
// Returns elements with a postblit constructor by value. moveAt fails. // Returns elements with a postblit constructor by value. moveAt fails.
static struct R4 static struct R2
{ {
enum bool empty = false; enum bool empty = false;
@ -1829,7 +1721,7 @@ if (isRandomAccessRange!R)
return Element(); return Element();
} }
} }
static assert(!is(typeof(moveAt(R4(), 0)))); static assert(!is(typeof(moveAt(R2(), 0))));
} }
/** /**
@ -1871,32 +1763,20 @@ template hasMobileElements(R)
/// ///
@nogc nothrow pure @safe unittest @nogc nothrow pure @safe unittest
{ {
// Input range with elements without a postblit constructor. static assert(hasMobileElements!(int[]));
// 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 ///
@nogc nothrow pure @safe unittest
{ {
}
}
static assert(hasMobileElements!InputRange);
static struct Element static struct Element
{ {
this(this) this(this) @nogc nothrow pure @safe
{ {
} }
} }
// Bidirectional range, whose elements cannot be moved. The range defines
// only moveFront, but not moveBack. So it doesn't have mobile elements. static struct R1
static struct BidirectionalRange
{ {
enum bool empty = false; enum bool empty = false;
@ -1904,44 +1784,28 @@ template hasMobileElements(R)
{ {
return Element(); return Element();
} }
alias back = front;
alias moveFront = front;
void popFront() @nogc nothrow pure @safe void popFront() @nogc nothrow pure @safe
{ {
} }
alias popBack = popFront;
BidirectionalRange save() @nogc nothrow pure @safe
{
return this;
} }
} static assert(!hasMobileElements!R1);
static assert(!hasMobileElements!BidirectionalRange);
// Access-random range, whose elements cannot be moved, but the range static struct R2
// defines both, moveFront and moveAt.
static struct RandomAccessRange
{ {
enum bool empty = false; enum bool empty = false;
private Element front_;
Element front() @nogc nothrow pure @safe ref Element front() @nogc nothrow pure @safe
{ {
return Element(); return front_;
} }
alias moveFront = front;
void popFront() @nogc nothrow pure @safe void popFront() @nogc nothrow pure @safe
{ {
} }
Element opIndex(size_t) @nogc nothrow pure @safe
{
return Element();
} }
alias moveAt = opIndex; static assert(hasMobileElements!R2);
}
static assert(hasMobileElements!RandomAccessRange);
} }
/** /**