Bug 4888: Heavy reliance on Bug 3534 in Phobos range usage. I used a different approach here than the first one I tried. I only did what was necessary to make Phobos work instead of trying to fix the deeper issue of making std.algorithm to work w/ const/immutable arrays.

This commit is contained in:
David Simcha 2010-09-18 21:00:52 +00:00
parent fe6cbe460b
commit b597d23f83
8 changed files with 105 additions and 69 deletions

View file

@ -111,14 +111,15 @@ template map(fun...)
}
}
struct Map(alias fun, Range) if (isInputRange!(Range))
struct Map(alias fun, Range) if (isInputRange!(Unqual!Range))
{
alias Unqual!Range R;
alias fun _fun;
alias typeof({ return _fun(.ElementType!(Range).init); }()) ElementType;
Unqual!Range _input;
alias typeof({ return _fun(.ElementType!(R).init); }()) ElementType;
R _input;
Unqual!ElementType _cache;
static if (isBidirectionalRange!(Range))
static if (isBidirectionalRange!(R))
{
// Using a second cache would lead to at least 1 extra function evaluation
// and wasted space when 99% of the time this range will only be iterated
@ -152,19 +153,19 @@ struct Map(alias fun, Range) if (isInputRange!(Range))
{
if (!_input.empty) _cache = _fun(_input.front);
static if(isBidirectionalRange!(Range))
static if(isBidirectionalRange!(R))
{
cacheIsBack_ = false;
}
}
this(Range input)
this(R input)
{
_input = input;
fillCache;
}
static if (isInfinite!Range)
static if (isInfinite!R)
{
// Propagate infinite-ness.
enum bool empty = false;
@ -185,7 +186,7 @@ struct Map(alias fun, Range) if (isInputRange!(Range))
@property ElementType front()
{
static if (isBidirectionalRange!(Range))
static if (isBidirectionalRange!(R))
{
if (cacheIsBack_)
{
@ -195,7 +196,7 @@ struct Map(alias fun, Range) if (isInputRange!(Range))
return _cache;
}
static if (isRandomAccessRange!Range)
static if (isRandomAccessRange!R)
{
ElementType opIndex(size_t index)
{
@ -213,7 +214,7 @@ struct Map(alias fun, Range) if (isInputRange!(Range))
}
}
static if (hasSlicing!(Range))
static if (hasSlicing!(R))
{
typeof(this) opSlice(size_t lowerBound, size_t upperBound)
{
@ -221,7 +222,7 @@ struct Map(alias fun, Range) if (isInputRange!(Range))
}
}
static if (isForwardRange!Range)
static if (isForwardRange!R)
@property Map save()
{
auto result = this;
@ -850,11 +851,12 @@ filter(alias pred, Range)(Range rs)
return typeof(return)(rs);
}
struct Filter(alias pred, Range) if (isInputRange!(Range))
struct Filter(alias pred, Range) if (isInputRange!(Unqual!Range))
{
Unqual!Range _input;
alias Unqual!Range R;
R _input;
this(Range r)
this(R r)
{
_input = r;
while (!_input.empty && !pred(_input.front)) _input.popFront;
@ -879,7 +881,7 @@ struct Filter(alias pred, Range) if (isInputRange!(Range))
return _input.front;
}
static if(isForwardRange!Range)
static if(isForwardRange!R)
{
@property typeof(this) save()
{

View file

@ -253,6 +253,10 @@ void main()
return a;
}
private template notConst(T) {
enum notConst = !is(T == const) && !is(T == immutable);
}
/**
Implements the range interface primitive $(D popFront) for built-in
arrays. Due to the fact that nonmember functions can be called with
@ -271,8 +275,10 @@ void main()
----
*/
void popFront(T)(ref T[] a) if (!is(Unqual!T == char) && !is(Unqual!T == wchar))
void popFront(A)(ref A a)
if(!isNarrowString!A && isDynamicArray!A && notConst!A)
{
alias typeof(A[0]) T;
assert(a.length, "Attempting to popFront() past the end of an array of "
~ T.stringof);
a = a[1 .. $];
@ -285,10 +291,14 @@ unittest
int[] a = [ 1, 2, 3 ];
a.popFront;
assert(a == [ 2, 3 ]);
static assert(!__traits(compiles, popFront!(immutable int[])));
}
void popFront(T)(ref T[] a) if (is(Unqual!T == char) || is(Unqual!T == wchar))
void popFront(A)(ref A a)
if(isNarrowString!A && notConst!A)
{
alias typeof(a[0]) T;
assert(a.length, "Attempting to popFront() past the end of an array of "
~ T.stringof);
a = a[std.utf.stride(a, 0) .. $];
@ -304,6 +314,8 @@ unittest
assert(s2 == "hello");
string s3 = "\u20AC100";
//write(s3, '\n');
static assert(!__traits(compiles, popFront!(immutable string)));
}
/**
@ -324,7 +336,8 @@ void main()
----
*/
void popBack(T)(ref T[] a) if (!is(Unqual!T == char) && !is(Unqual!T == wchar))
void popBack(A)(ref A a)
if(isDynamicArray!A && !isNarrowString!A && notConst!A)
{
assert(a.length);
a = a[0 .. $ - 1];
@ -337,9 +350,12 @@ unittest
int[] a = [ 1, 2, 3 ];
a.popBack;
assert(a == [ 1, 2 ]);
static assert(!__traits(compiles, popBack!(immutable int[])));
}
void popBack(T)(ref T[] a) if (is(Unqual!T == char))
void popBack(A)(ref A a)
if(is(A : const(char)[]) && notConst!A)
{
immutable n = a.length;
const p = a.ptr + n;
@ -376,9 +392,12 @@ unittest
assert(c == cast(dchar)'\u2260');
s3.popBack();
assert(s3 == "");
static assert(!__traits(compiles, popBack!(immutable char[])));
}
void popBack(T)(ref T[] a) if (is(Unqual!T == wchar))
void popBack(A)(ref A a)
if(is(A : const(wchar)[]) && notConst!A)
{
assert(a.length);
if (a.length == 1)
@ -395,6 +414,8 @@ unittest
wstring s = "hello\xE2\x89\xA0";
s.popBack();
assert(s == "hello");
static assert(!__traits(compiles, popBack!(immutable wchar[])));
}
/**
@ -837,6 +858,13 @@ Appends one item to the managed array.
return newext > newlength ? newext : newlength;
}
// Const fixing hack.
void put(Range)(Range items)
if(isInputRange!(Unqual!Range) && !isInputRange!Range) {
alias put!(Unqual!Range) p;
p(items);
}
/**
Appends an entire range to the managed array.
*/

View file

@ -108,7 +108,7 @@ assert(b == "abc"w);
----
*/
T toImpl(T, S)(S s) if (!implicitlyConverts!(S, T) && isSomeString!T
&& isInputRange!S && isSomeChar!(ElementType!S))
&& isInputRange!(Unqual!S) && isSomeChar!(ElementType!S))
{
static if (isSomeString!S)
{
@ -182,10 +182,15 @@ converted by calling $(D to!T).
*/
T toImpl(T, S)(S s, in T leftBracket = "[", in T separator = " ",
in T rightBracket = "]")
if (isSomeString!T && !isSomeChar!(ElementType!S) && isInputRange!S)
if (isSomeString!T && !isSomeChar!(ElementType!S) &&
(isInputRange!S || isInputRange!(Unqual!S)))
{
static if(!isInputRange!S) {
alias toImpl!(T, Unqual!S) ti;
return ti(s, leftBracket, separator, rightBracket);
} else {
alias Unqual!(typeof(T.init[0])) Char;
// array-to-string conversion
// array-to-string conversion
auto result = appender!(Char[])();
result.put(leftBracket);
bool first = true;
@ -203,6 +208,7 @@ if (isSomeString!T && !isSomeChar!(ElementType!S) && isInputRange!S)
}
result.put(rightBracket);
return cast(T) result.data;
}
}
/*

View file

@ -57,7 +57,7 @@ struct JSONValue {
/**
Parses a serialized string and returns a tree of JSON values.
*/
JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
JSONValue parseJSON(T)(T json, int maxDepth = -1) if(isInputRange!T) {
JSONValue root = void;
root.type = JSON_TYPE.NULL;
@ -427,7 +427,7 @@ unittest {
// then use the resulting values tree to generate an identical
// serialization, both the decoder and encoder works.
immutable jsons = [
auto jsons = [
`null`,
`true`,
`false`,

View file

@ -2467,54 +2467,54 @@ void inverseFft(Ret, R)(R range, Ret buf) {
unittest {
// Test values from R.
const arr = [1,2,3,4,5,6,7,8];
const fft1 = fft(arr);
auto arr = [1,2,3,4,5,6,7,8];
auto fft1 = fft(arr);
assert(approxEqual(map!"a.re"(fft1),
[36.0, -4, -4, -4, -4, -4, -4, -4]));
assert(approxEqual(map!"a.im"(fft1),
[0, 9.6568, 4, 1.6568, 0, -1.6568, -4, -9.6568]));
alias Complex!float C;
const arr2 = [C(1,2), C(3,4), C(5,6), C(7,8), C(9,10),
auto arr2 = [C(1,2), C(3,4), C(5,6), C(7,8), C(9,10),
C(11,12), C(13,14), C(15,16)];
const fft2 = fft(arr2);
auto fft2 = fft(arr2);
assert(approxEqual(map!"a.re"(fft2),
[64.0, -27.3137, -16, -11.3137, -8, -4.6862, 0, 11.3137]));
assert(approxEqual(map!"a.im"(fft2),
[72, 11.3137, 0, -4.686, -8, -11.3137, -16, -27.3137]));
const inv1 = inverseFft(fft1);
auto inv1 = inverseFft(fft1);
assert(approxEqual(map!"a.re"(inv1), arr));
assert(reduce!max(map!"a.im"(inv1)) < 1e-10);
const inv2 = inverseFft(fft2);
auto inv2 = inverseFft(fft2);
assert(approxEqual(map!"a.re"(inv2), map!"a.re"(arr2)));
assert(approxEqual(map!"a.im"(inv2), map!"a.im"(arr2)));
// FFTs of size 0, 1 and 2 are handled as special cases. Test them here.
const ushort[] empty;
ushort[] empty;
assert(fft(empty) == null);
assert(inverseFft(fft(empty)) == null);
const real[] oneElem = [4.5L];
const oneFft = fft(oneElem);
real[] oneElem = [4.5L];
auto oneFft = fft(oneElem);
assert(oneFft.length == 1);
assert(oneFft[0].re == 4.5L);
assert(oneFft[0].im == 0);
const oneInv = inverseFft(oneFft);
auto oneInv = inverseFft(oneFft);
assert(oneInv.length == 1);
assert(approxEqual(oneInv[0].re, 4.5));
assert(approxEqual(oneInv[0].im, 0));
immutable long[2] twoElems = [8, 4];
const twoFft = fft(twoElems[]);
long[2] twoElems = [8, 4];
auto twoFft = fft(twoElems[]);
assert(twoFft.length == 2);
assert(approxEqual(twoFft[0].re, 12));
assert(approxEqual(twoFft[0].im, 0));
assert(approxEqual(twoFft[1].re, 4));
assert(approxEqual(twoFft[1].im, 0));
const twoInv = inverseFft(twoFft);
auto twoInv = inverseFft(twoFft);
assert(approxEqual(twoInv[0].re, 8));
assert(approxEqual(twoInv[0].im, 0));
assert(approxEqual(twoInv[1].re, 4));

View file

@ -3302,8 +3302,8 @@ else
{
// Work around DMD bugs 4676, 4652.
auto lockstep(Args...)(Args args)
if(allSatisfy!(isInputRange, Args) || (
allSatisfy!(isInputRange, Args[0..$ - 1]) &&
if(allSatisfy!(isInputRange, staticMap!(Unqual, Args)) || (
allSatisfy!(isInputRange, staticMap!(Unqual, Args[0..$ - 1])) &&
is(Args[$ - 1] == StoppingPolicy))
)
{

View file

@ -541,7 +541,7 @@ Index in $(D s) where $(D sub) is found, $(D -1) if not found.
*/
sizediff_t
indexOf(Char1, Char2)(in Char1[] s, in Char2[] sub,
indexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub,
CaseSensitive cs = CaseSensitive.yes)
{
if (cs == CaseSensitive.yes)

View file

@ -125,7 +125,7 @@ import std.array;
import std.string;
import std.encoding;
immutable cdata = "<![CDATA[";
enum cdata = "<![CDATA[";
/**
* Returns true if the character is a character according to the XML standard