Merge pull request #84 from n8sh/inoutConstIteration
In tanya.algorithm.iteration.take & retro preserve const/inout for `empty`/`front`/etc.
This commit is contained in:
commit
b55bb767e5
@ -27,6 +27,50 @@ import tanya.meta.transform;
|
|||||||
import tanya.range;
|
import tanya.range;
|
||||||
import tanya.typecons;
|
import tanya.typecons;
|
||||||
|
|
||||||
|
// These predicates are used to help preserve `const` and `inout` for
|
||||||
|
// ranges built on other ranges.
|
||||||
|
|
||||||
|
private enum hasInoutFront(T) = is(typeof((inout ref T a) => a.front));
|
||||||
|
private enum hasInoutBack(T) = is(typeof((inout ref T a) => a.back));
|
||||||
|
private enum hasInoutIndex(T) = is(typeof((inout ref T a, size_t i) => a[i]));
|
||||||
|
|
||||||
|
private enum hasConstEmpty(T) = is(typeof(((const T* a) => (*a).empty)(null)) : bool);
|
||||||
|
private enum hasConstLength(T) = is(typeof(((const T* a) => (*a).length)(null)) : size_t);
|
||||||
|
private enum hasConstSave(T) = is(typeof(((const T* a) => (*a).save())(null)) : T);
|
||||||
|
private enum hasConstSlice(T) = is(typeof(((const T* a) => (*a)[0 .. $])(null)) : T);
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
// Test the definitions.
|
||||||
|
static assert(hasInoutFront!string);
|
||||||
|
static assert(hasInoutBack!string);
|
||||||
|
static assert(hasInoutIndex!string);
|
||||||
|
static assert(hasConstEmpty!string);
|
||||||
|
static assert(hasConstLength!string);
|
||||||
|
static assert(hasConstSave!string);
|
||||||
|
static assert(hasConstSlice!string);
|
||||||
|
|
||||||
|
// Test that Take propagates const/inout correctly.
|
||||||
|
alias TakeString = Take!(string, false);
|
||||||
|
static assert(hasInoutFront!TakeString);
|
||||||
|
static assert(hasInoutBack!TakeString);
|
||||||
|
static assert(hasInoutIndex!TakeString);
|
||||||
|
static assert(hasConstEmpty!TakeString);
|
||||||
|
static assert(hasConstLength!TakeString);
|
||||||
|
static assert(hasConstSave!TakeString);
|
||||||
|
static assert(hasConstSlice!TakeString);
|
||||||
|
|
||||||
|
// Test that Retro propagates const/inout correctly.
|
||||||
|
alias RetroString = Retro!string;
|
||||||
|
static assert(hasInoutFront!RetroString);
|
||||||
|
static assert(hasInoutBack!RetroString);
|
||||||
|
static assert(hasInoutIndex!RetroString);
|
||||||
|
static assert(hasConstEmpty!RetroString);
|
||||||
|
static assert(hasConstLength!RetroString);
|
||||||
|
static assert(hasConstSave!RetroString);
|
||||||
|
static assert(hasConstSlice!RetroString);
|
||||||
|
}
|
||||||
|
|
||||||
private struct Take(R, bool exactly)
|
private struct Take(R, bool exactly)
|
||||||
{
|
{
|
||||||
private R source;
|
private R source;
|
||||||
@ -47,11 +91,11 @@ private struct Take(R, bool exactly)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@property auto ref front()
|
mixin(`@property auto ref front() ` ~ (hasInoutFront!R ? `inout ` : ``) ~
|
||||||
in (!empty)
|
`in (!empty)
|
||||||
{
|
{
|
||||||
return this.source.front;
|
return this.source.front;
|
||||||
}
|
}`);
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
in (!empty)
|
in (!empty)
|
||||||
@ -60,8 +104,8 @@ private struct Take(R, bool exactly)
|
|||||||
--this.length_;
|
--this.length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property bool empty()
|
mixin(`@property bool empty() ` ~ (exactly || isInfinite!R || hasConstEmpty!R ? `const ` : ``) ~
|
||||||
{
|
`{
|
||||||
static if (exactly || isInfinite!R)
|
static if (exactly || isInfinite!R)
|
||||||
{
|
{
|
||||||
return length == 0;
|
return length == 0;
|
||||||
@ -70,11 +114,11 @@ private struct Take(R, bool exactly)
|
|||||||
{
|
{
|
||||||
return this.length_ == 0 || this.source.empty;
|
return this.length_ == 0 || this.source.empty;
|
||||||
}
|
}
|
||||||
}
|
}`);
|
||||||
|
|
||||||
static if (exactly || hasLength!R)
|
static if (exactly || hasLength!R)
|
||||||
{
|
{
|
||||||
@property size_t length()
|
@property size_t length() const
|
||||||
{
|
{
|
||||||
return this.length_;
|
return this.length_;
|
||||||
}
|
}
|
||||||
@ -97,18 +141,18 @@ private struct Take(R, bool exactly)
|
|||||||
|
|
||||||
static if (isForwardRange!R)
|
static if (isForwardRange!R)
|
||||||
{
|
{
|
||||||
typeof(this) save()
|
mixin(`typeof(this) save() ` ~ (hasConstSave!R ? `const ` : ``) ~
|
||||||
{
|
`{
|
||||||
return typeof(this)(this.source.save(), length);
|
return typeof(this)(this.source.save(), length);
|
||||||
}
|
}`);
|
||||||
}
|
}
|
||||||
static if (isRandomAccessRange!R)
|
static if (isRandomAccessRange!R)
|
||||||
{
|
{
|
||||||
@property auto ref back()
|
mixin(`@property auto ref back() ` ~ (hasInoutBack!R ? `inout ` : ``) ~
|
||||||
in (!empty)
|
`in (!empty)
|
||||||
{
|
{
|
||||||
return this.source[this.length - 1];
|
return this.source[this.length - 1];
|
||||||
}
|
}`);
|
||||||
|
|
||||||
void popBack()
|
void popBack()
|
||||||
in (!empty)
|
in (!empty)
|
||||||
@ -116,11 +160,11 @@ private struct Take(R, bool exactly)
|
|||||||
--this.length_;
|
--this.length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref opIndex(size_t i)
|
mixin(`auto ref opIndex(size_t i) ` ~ (hasInoutIndex!R ? `inout ` : ``) ~
|
||||||
in (i < length)
|
`in (i < length)
|
||||||
{
|
{
|
||||||
return this.source[i];
|
return this.source[i];
|
||||||
}
|
}`);
|
||||||
|
|
||||||
static if (hasAssignableElements!R)
|
static if (hasAssignableElements!R)
|
||||||
{
|
{
|
||||||
@ -152,12 +196,14 @@ private struct Take(R, bool exactly)
|
|||||||
|
|
||||||
static if (!exactly && hasSlicing!R)
|
static if (!exactly && hasSlicing!R)
|
||||||
{
|
{
|
||||||
auto opSlice(size_t i, size_t j)
|
static if (is(typeof(length))) alias opDollar = length;
|
||||||
in (i <= j)
|
|
||||||
|
mixin(`auto opSlice(size_t i, size_t j) ` ~ (hasConstSlice!R ? `const ` : ``) ~
|
||||||
|
`in (i <= j)
|
||||||
in (j <= length)
|
in (j <= length)
|
||||||
{
|
{
|
||||||
return typeof(this)(this.source[i .. j], length);
|
return typeof(this)(this.source[i .. j], length);
|
||||||
}
|
}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
version (unittest) static assert(isInputRange!Take);
|
version (unittest) static assert(isInputRange!Take);
|
||||||
@ -379,16 +425,16 @@ private struct Retro(Range)
|
|||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
Retro save()
|
mixin(`Retro save() ` ~ (hasConstSave!Range ? `const ` : ``) ~
|
||||||
{
|
`{
|
||||||
return this;
|
return Retro(source.save());
|
||||||
}
|
}`);
|
||||||
|
|
||||||
@property auto ref front()
|
mixin(`@property auto ref front() ` ~ (hasInoutBack!Range ? `inout ` : ``) ~
|
||||||
in (!empty)
|
`in (!empty)
|
||||||
{
|
{
|
||||||
return this.source.back;
|
return this.source.back;
|
||||||
}
|
}`);
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
in (!empty)
|
in (!empty)
|
||||||
@ -396,11 +442,11 @@ private struct Retro(Range)
|
|||||||
this.source.popBack();
|
this.source.popBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@property auto ref back()
|
mixin(`@property auto ref back() ` ~ (hasInoutFront!Range ? `inout ` : ``) ~
|
||||||
in (!empty)
|
`in (!empty)
|
||||||
{
|
{
|
||||||
return this.source.front;
|
return this.source.front;
|
||||||
}
|
}`);
|
||||||
|
|
||||||
void popBack()
|
void popBack()
|
||||||
in (!empty)
|
in (!empty)
|
||||||
@ -408,38 +454,38 @@ private struct Retro(Range)
|
|||||||
this.source.popFront();
|
this.source.popFront();
|
||||||
}
|
}
|
||||||
|
|
||||||
@property bool empty()
|
mixin(`@property bool empty() ` ~ (hasConstEmpty!Range ? `const ` : ``) ~
|
||||||
{
|
`{
|
||||||
return this.source.empty;
|
return this.source.empty;
|
||||||
}
|
}`);
|
||||||
|
|
||||||
static if (hasLength!Range)
|
static if (hasLength!Range)
|
||||||
{
|
{
|
||||||
@property size_t length()
|
mixin(`@property size_t length() ` ~ (hasConstLength!Range ? `const ` : ``) ~
|
||||||
{
|
`{
|
||||||
return this.source.length;
|
return this.source.length;
|
||||||
}
|
}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (isRandomAccessRange!Range && hasLength!Range)
|
static if (isRandomAccessRange!Range && hasLength!Range)
|
||||||
{
|
{
|
||||||
auto ref opIndex(size_t i)
|
mixin(`auto ref opIndex(size_t i) ` ~ (hasInoutIndex!Range ? `inout ` : ``) ~
|
||||||
in (i < length)
|
`in (i < length)
|
||||||
{
|
{
|
||||||
return this.source[$ - ++i];
|
return this.source[$ - ++i];
|
||||||
}
|
}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (hasLength!Range && hasSlicing!Range)
|
static if (hasLength!Range && hasSlicing!Range)
|
||||||
{
|
{
|
||||||
alias opDollar = length;
|
alias opDollar = length;
|
||||||
|
|
||||||
auto opSlice(size_t i, size_t j)
|
mixin(`auto opSlice(size_t i, size_t j) ` ~ (hasConstSlice!Range ? `const ` : ``) ~
|
||||||
in (i <= j)
|
`in (i <= j)
|
||||||
in (j <= length)
|
in (j <= length)
|
||||||
{
|
{
|
||||||
return typeof(this)(this.source[$-j .. $-i]);
|
return typeof(this)(this.source[$-j .. $-i]);
|
||||||
}
|
}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (hasAssignableElements!Range)
|
static if (hasAssignableElements!Range)
|
||||||
|
Loading…
Reference in New Issue
Block a user