mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +03:00
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:
parent
fe6cbe460b
commit
b597d23f83
8 changed files with 105 additions and 69 deletions
|
@ -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()
|
||||
{
|
||||
|
|
38
std/array.d
38
std/array.d
|
@ -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.
|
||||
*/
|
||||
|
|
10
std/conv.d
10
std/conv.d
|
@ -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,8 +182,13 @@ 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
|
||||
auto result = appender!(Char[])();
|
||||
|
@ -204,6 +209,7 @@ if (isSomeString!T && !isSomeChar!(ElementType!S) && isInputRange!S)
|
|||
result.put(rightBracket);
|
||||
return cast(T) result.data;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Converting static arrays forwards to their dynamic counterparts.
|
||||
|
|
|
@ -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`,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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))
|
||||
)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue