mirror of
https://github.com/dlang/phobos.git
synced 2025-05-05 17:42:58 +03:00
string, wstring are now bidirectional (not random) ranges
std.algorithm: defined move with one argument; levenshtein distance generalized to with all forward ranges; take now has swapped arguments std.array: empty for arrays is now a @property; front and back for a string and wstring automatically decodes the first/last character; popFront, popBack for string and wstring obey the UTF stride std.conv: changed the default array formatting from "[a, b, c]" to "a b c" std.range: swapped order of arguments in take std.stdio: added readln template std.variant: now works with statically-sized arrays and const data std.traits: added isNarrowString
This commit is contained in:
parent
35e5e25943
commit
2a9a6e336c
16 changed files with 790 additions and 400 deletions
202
std/algorithm.d
202
std/algorithm.d
|
@ -138,6 +138,7 @@ struct Map(alias fun, Range) if (isInputRange!(Range))
|
|||
|
||||
unittest
|
||||
{
|
||||
scope(failure) writeln("Unittest failed at line ", __LINE__);
|
||||
int[] arr1 = [ 1, 2, 3, 4 ];
|
||||
int[] arr2 = [ 5, 6 ];
|
||||
auto squares = map!("a * a")(arr1);
|
||||
|
@ -319,7 +320,7 @@ unittest
|
|||
a = [ 1, 2, 3, 4, 5 ];
|
||||
// Stringize with commas
|
||||
string rep = reduce!("a ~ `, ` ~ to!(string)(b)")("", a);
|
||||
assert(rep[2 .. $] == "1, 2, 3, 4, 5");
|
||||
assert(rep[2 .. $] == "1, 2, 3, 4, 5", "["~rep[2 .. $]~"]");
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -529,6 +530,14 @@ unittest
|
|||
assert(s21.a == 1 && s21.b == null && s22.a == 10 && s22.b != null);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
T move(T)(ref T src)
|
||||
{
|
||||
T result;
|
||||
move(src, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// moveAll
|
||||
/**
|
||||
For each element $(D a) in $(D src) and each element $(D b) in $(D
|
||||
|
@ -667,6 +676,7 @@ assert(i == 3);
|
|||
----
|
||||
*/
|
||||
struct Splitter(Range, Separator)
|
||||
if (!is(typeof(ElementType!Range.init == Separator.init)))
|
||||
{
|
||||
private:
|
||||
Range _input;
|
||||
|
@ -675,17 +685,8 @@ private:
|
|||
size_t _frontLength = size_t.max;
|
||||
static if (isBidirectionalRange!Range)
|
||||
size_t _backLength = size_t.max;
|
||||
enum bool separatorIsRange =
|
||||
!is(typeof(ElementType!Range.init == _separator));
|
||||
|
||||
static if (separatorIsRange)
|
||||
{
|
||||
size_t separatorLength() { return _separator.length; }
|
||||
}
|
||||
else
|
||||
{
|
||||
enum size_t separatorLength = 1;
|
||||
}
|
||||
size_t separatorLength() { return _separator.length; }
|
||||
|
||||
void ensureFrontLength()
|
||||
{
|
||||
|
@ -693,24 +694,21 @@ private:
|
|||
assert(!_input.empty);
|
||||
// compute front length
|
||||
_frontLength = _input.length - find(_input, _separator).length;
|
||||
if (_frontLength == _input.length) _backLength = _frontLength;
|
||||
static if (isBidirectionalRange!Range)
|
||||
if (_frontLength == _input.length) _backLength = _frontLength;
|
||||
}
|
||||
|
||||
void ensureBackLength()
|
||||
{
|
||||
if (_backLength != _backLength.max) return;
|
||||
static if (isBidirectionalRange!Range)
|
||||
if (_backLength != _backLength.max) return;
|
||||
assert(!_input.empty);
|
||||
// compute back length
|
||||
static if (separatorIsRange)
|
||||
static if (isBidirectionalRange!Range)
|
||||
{
|
||||
_backLength = _input.length -
|
||||
find(retro(_input), retro(_separator)).length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_backLength = _input.length -
|
||||
find(retro(_input), _separator).length;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -741,7 +739,8 @@ public:
|
|||
// done, there's no separator in sight
|
||||
_input = _input[_frontLength .. _frontLength];
|
||||
_frontLength = _frontLength.max;
|
||||
_backLength = _backLength.max;
|
||||
static if (isBidirectionalRange!Range)
|
||||
_backLength = _backLength.max;
|
||||
return;
|
||||
}
|
||||
if (_frontLength + separatorLength == _input.length)
|
||||
|
@ -750,7 +749,8 @@ public:
|
|||
// an empty item right after this.
|
||||
_input = _input[_input.length .. _input.length];
|
||||
_frontLength = 0;
|
||||
_backLength = 0;
|
||||
static if (isBidirectionalRange!Range)
|
||||
_backLength = 0;
|
||||
return;
|
||||
}
|
||||
// Normal case, pop one item and the separator, get ready for
|
||||
|
@ -761,36 +761,124 @@ public:
|
|||
}
|
||||
|
||||
// Bidirectional functionality as suggested by Brad Roberts.
|
||||
static if (isBidirectionalRange!Range)
|
||||
{
|
||||
Range back()
|
||||
{
|
||||
ensureBackLength;
|
||||
return _input[_input.length - _backLength .. _input.length];
|
||||
}
|
||||
|
||||
void popBack()
|
||||
{
|
||||
ensureBackLength;
|
||||
if (_backLength == _input.length)
|
||||
{
|
||||
// done
|
||||
_input = _input[0 .. 0];
|
||||
_frontLength = _frontLength.max;
|
||||
_backLength = _backLength.max;
|
||||
return;
|
||||
}
|
||||
if (_backLength + separatorLength == _input.length)
|
||||
{
|
||||
// Special case: popping the first-to-first item; there is
|
||||
// an empty item right before this. Leave the separator in.
|
||||
_input = _input[0 .. 0];
|
||||
_frontLength = 0;
|
||||
_backLength = 0;
|
||||
return;
|
||||
}
|
||||
// Normal case
|
||||
_input = _input[0 .. _input.length - _backLength - separatorLength];
|
||||
_backLength = _backLength.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Splitter(Range, Separator)
|
||||
if (is(typeof(ElementType!Range.init == Separator.init)))
|
||||
{
|
||||
Range _input;
|
||||
Separator _separator;
|
||||
size_t _frontLength = size_t.max;
|
||||
size_t _backLength = size_t.max;
|
||||
|
||||
this(Range input, Separator separator)
|
||||
{
|
||||
_input = input;
|
||||
_separator = separator;
|
||||
computeFront();
|
||||
computeBack();
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return _input.empty;
|
||||
}
|
||||
|
||||
Range front()
|
||||
{
|
||||
if (_frontLength == _frontLength.max)
|
||||
{
|
||||
// This is not the first iteration, clean up separators
|
||||
while (!_input.empty && _input.front == _separator)
|
||||
_input.popFront();
|
||||
computeFront();
|
||||
}
|
||||
return _input[0 .. _frontLength];
|
||||
}
|
||||
|
||||
void popFront()
|
||||
{
|
||||
computeFront();
|
||||
_input = _input[_frontLength .. $];
|
||||
_frontLength = _frontLength.max;
|
||||
}
|
||||
|
||||
Range back()
|
||||
{
|
||||
ensureBackLength;
|
||||
return _input[_input.length - _backLength .. _input.length];
|
||||
if (_backLength == _backLength.max)
|
||||
{
|
||||
while (!_input.empty && _input.back == _separator) _input.popBack();
|
||||
computeBack();
|
||||
}
|
||||
assert(_backLength <= _input.length, text(_backLength));
|
||||
return _input[$ - _backLength .. $];
|
||||
}
|
||||
|
||||
void popBack()
|
||||
{
|
||||
ensureBackLength;
|
||||
if (_backLength == _input.length)
|
||||
{
|
||||
// done
|
||||
_input = _input[0 .. 0];
|
||||
_frontLength = _frontLength.max;
|
||||
_backLength = _backLength.max;
|
||||
return;
|
||||
}
|
||||
if (_backLength + separatorLength == _input.length)
|
||||
{
|
||||
// Special case: popping the first-to-first item; there is
|
||||
// an empty item right before this. Leave the separator in.
|
||||
_input = _input[0 .. 0];
|
||||
_frontLength = 0;
|
||||
_backLength = 0;
|
||||
return;
|
||||
}
|
||||
// Normal case
|
||||
_input = _input[0 .. _input.length - _backLength - separatorLength];
|
||||
computeBack();
|
||||
enforce(_backLength <= _input.length);
|
||||
_input = _input[0 .. $ - _backLength];
|
||||
_backLength = _backLength.max;
|
||||
}
|
||||
|
||||
private:
|
||||
void computeFront()
|
||||
{
|
||||
if (_frontLength == _frontLength.max)
|
||||
{
|
||||
_frontLength = _input.length - _input.find(_separator).length;
|
||||
}
|
||||
}
|
||||
void computeBack()
|
||||
{
|
||||
if (_backLength == _backLength.max)
|
||||
{
|
||||
//_backLength = find(retro(_input), _separator).length;
|
||||
_backLength = 0;
|
||||
auto i = _input;
|
||||
while (!i.empty)
|
||||
{
|
||||
if (i.back == _separator) break;
|
||||
++_backLength;
|
||||
i.popBack();
|
||||
}
|
||||
}
|
||||
assert(_backLength <= _input.length);
|
||||
}
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
|
@ -824,8 +912,9 @@ unittest
|
|||
}
|
||||
assert(i == w.length);
|
||||
// Now go back
|
||||
//auto s = splitter(a, 0);
|
||||
foreach_reverse (e; splitter(a, 0))
|
||||
auto s2 = splitter(a, 0);
|
||||
|
||||
foreach_reverse (e; s2)
|
||||
{
|
||||
assert(i > 0);
|
||||
assert(equal(e, w[--i]), text(e));
|
||||
|
@ -1415,7 +1504,7 @@ is ignored.
|
|||
&& needle[virtual_begin - 1] == needle[$ - portion - 1])
|
||||
return 0;
|
||||
|
||||
invariant delta = portion - ignore;
|
||||
immutable delta = portion - ignore;
|
||||
return equal(needle[needle.length - delta .. needle.length],
|
||||
needle[virtual_begin .. virtual_begin + delta]);
|
||||
}
|
||||
|
@ -1475,7 +1564,7 @@ public:
|
|||
/// Ditto
|
||||
BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder
|
||||
(alias pred = "a == b", Range)
|
||||
(Range needle) if (isRandomAccessRange!(Range))
|
||||
(Range needle) if (isRandomAccessRange!(Range) || isSomeString!Range)
|
||||
{
|
||||
return typeof(return)(needle);
|
||||
}
|
||||
|
@ -2405,13 +2494,18 @@ struct Levenshtein(Range, alias equals, CostType = size_t)
|
|||
|
||||
CostType distance(Range s, Range t)
|
||||
{
|
||||
AllocMatrix(s.length + 1, t.length + 1);
|
||||
auto slen = walkLength(s), tlen = walkLength(t);
|
||||
AllocMatrix(slen + 1, tlen + 1);
|
||||
foreach (i; 1 .. rows)
|
||||
{
|
||||
auto sfront = s.front;
|
||||
s.popFront();
|
||||
auto tt = t;
|
||||
foreach (j; 1 .. cols)
|
||||
{
|
||||
auto cSub = _matrix[i - 1][j - 1]
|
||||
+ (equals(s[i - 1], t[j - 1]) ? 0 : _substitutionIncrement);
|
||||
+ (equals(sfront, tt.front) ? 0 : _substitutionIncrement);
|
||||
tt.popFront();
|
||||
auto cIns = _matrix[i][j - 1] + _insertionIncrement;
|
||||
auto cDel = _matrix[i - 1][j] + _deletionIncrement;
|
||||
switch (min_index(cSub, cIns, cDel)) {
|
||||
|
@ -2427,7 +2521,7 @@ struct Levenshtein(Range, alias equals, CostType = size_t)
|
|||
}
|
||||
}
|
||||
}
|
||||
return _matrix[s.length][t.length];
|
||||
return _matrix[slen][tlen];
|
||||
}
|
||||
|
||||
EditOp[] path(Range s, Range t)
|
||||
|
@ -2528,7 +2622,7 @@ assert(levenshteinDistance!("toupper(a) == toupper(b)")
|
|||
*/
|
||||
size_t levenshteinDistance(alias equals = "a == b", Range1, Range2)
|
||||
(Range1 s, Range2 t)
|
||||
if (isRandomAccessRange!(Range1) && isRandomAccessRange!(Range2))
|
||||
if (isForwardRange!(Range1) && isForwardRange!(Range2))
|
||||
{
|
||||
Levenshtein!(Range1, binaryFun!(equals), uint) lev;
|
||||
return lev.distance(s, t);
|
||||
|
@ -2549,7 +2643,7 @@ assert(equals(p.field[1], "nrrnsnnn"));
|
|||
Tuple!(size_t, EditOp[])
|
||||
levenshteinDistanceAndPath(alias equals = "a == b", Range1, Range2)
|
||||
(Range1 s, Range2 t)
|
||||
if (isRandomAccessRange!(Range1) && isRandomAccessRange!(Range2))
|
||||
if (isForwardRange!(Range1) && isForwardRange!(Range2))
|
||||
{
|
||||
Levenshtein!(Range, binaryFun!(equals)) lev;
|
||||
auto d = lev.distance(s, t);
|
||||
|
@ -2603,7 +2697,7 @@ auto d = copy(a, b);
|
|||
----
|
||||
|
||||
To copy at most $(D n) elements from range $(D a) to range $(D b), you
|
||||
may want to use $(D copy(take(n, a), b)). To copy those elements from
|
||||
may want to use $(D copy(take(a, n), b)). To copy those elements from
|
||||
range $(D a) that satisfy predicate $(D pred) to range $(D b), you may
|
||||
want to use $(D copy(filter!(pred)(a), b)).
|
||||
|
||||
|
@ -2699,7 +2793,7 @@ assert(arr == [ 3, 2, 1 ]);
|
|||
----
|
||||
*/
|
||||
void reverse(Range)(Range r)
|
||||
//if (isBidirectionalRange!(Range) && hasSwappableElements!(Range))
|
||||
if (isBidirectionalRange!(Range) && hasSwappableElements!(Range))
|
||||
{
|
||||
while (!r.empty)
|
||||
{
|
||||
|
|
184
std/array.d
184
std/array.d
|
@ -15,7 +15,7 @@ module std.array;
|
|||
import std.c.stdio;
|
||||
import core.memory;
|
||||
import std.algorithm, std.contracts, std.conv, std.encoding, std.range,
|
||||
std.string, std.traits, std.typecons;
|
||||
std.string, std.traits, std.typecons, std.utf;
|
||||
version(unittest) private import std.stdio;
|
||||
|
||||
/**
|
||||
|
@ -160,7 +160,7 @@ void main()
|
|||
----
|
||||
*/
|
||||
|
||||
bool empty(T)(in T[] a) { return !a.length; }
|
||||
@property bool empty(T)(in T[] a) { return !a.length; }
|
||||
|
||||
unittest
|
||||
{
|
||||
|
@ -187,7 +187,7 @@ void main()
|
|||
----
|
||||
*/
|
||||
|
||||
void popFront(T)(ref T[] a)
|
||||
void popFront(T)(ref T[] a) if (!is(Unqual!T == char) && !is(Unqual!T == wchar))
|
||||
{
|
||||
assert(a.length, "Attempting to popFront() past the end of an array of "
|
||||
~ T.stringof);
|
||||
|
@ -203,6 +203,25 @@ unittest
|
|||
assert(a == [ 2, 3 ]);
|
||||
}
|
||||
|
||||
void popFront(T)(ref T[] a) if (is(Unqual!T == char) || is(Unqual!T == wchar))
|
||||
{
|
||||
assert(a.length, "Attempting to popFront() past the end of an array of "
|
||||
~ T.stringof);
|
||||
a = a[std.utf.stride(a, 0) .. $];
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
string s1 = "\xC2\xA9hello";
|
||||
s1.popFront();
|
||||
assert(s1 == "hello");
|
||||
wstring s2 = "\xC2\xA9hello";
|
||||
s2.popFront();
|
||||
assert(s2 == "hello");
|
||||
string s3 = "\u20AC100";
|
||||
//write(s3, '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
Implements the range interface primitive $(D popBack) for built-in
|
||||
arrays. Due to the fact that nonmember functions can be called with
|
||||
|
@ -221,7 +240,11 @@ void main()
|
|||
----
|
||||
*/
|
||||
|
||||
void popBack(T)(ref T[] a) { assert(a.length); a = a[0 .. $ - 1]; }
|
||||
void popBack(T)(ref T[] a) if (!is(Unqual!T == char) && !is(Unqual!T == wchar))
|
||||
{
|
||||
assert(a.length);
|
||||
a = a[0 .. $ - 1];
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
|
@ -232,6 +255,63 @@ unittest
|
|||
assert(a == [ 1, 2 ]);
|
||||
}
|
||||
|
||||
void popBack(T)(ref T[] a) if (is(Unqual!T == char))
|
||||
{
|
||||
immutable n = a.length;
|
||||
const p = a.ptr + n;
|
||||
if (n >= 1 && (p[-1] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
a = a[0 .. n - 1];
|
||||
}
|
||||
else if (n >= 2 && (p[-2] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
a = a[0 .. n - 2];
|
||||
}
|
||||
else if (n >= 3 && (p[-3] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
a = a[0 .. n - 3];
|
||||
}
|
||||
else if (n >= 4 && (p[-4] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
a = a[0 .. n - 4];
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Invalid UTF character at end of string");
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
string s = "hello\xE2\x89\xA0";
|
||||
s.popBack();
|
||||
assert(s == "hello", s);
|
||||
|
||||
string s3 = "\xE2\x89\xA0";
|
||||
auto c = decodeBack(s3);
|
||||
assert(c == cast(dchar)'\u2260');
|
||||
assert(s3 == "");
|
||||
}
|
||||
|
||||
void popBack(T)(ref T[] a) if (is(Unqual!T == wchar))
|
||||
{
|
||||
assert(a.length);
|
||||
if (a.length == 1)
|
||||
{
|
||||
a = a[0 .. 0];
|
||||
return;
|
||||
}
|
||||
invariant c = a[$ - 2];
|
||||
a = a[0 .. $ - 1 - (c >= 0xD800 && c <= 0xDBFF)];
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
wstring s = "hello\xE2\x89\xA0";
|
||||
s.popBack();
|
||||
assert(s == "hello");
|
||||
}
|
||||
|
||||
/**
|
||||
Implements the range interface primitive $(D front) for built-in
|
||||
arrays. Due to the fact that nonmember functions can be called with
|
||||
|
@ -248,14 +328,24 @@ void main()
|
|||
}
|
||||
----
|
||||
*/
|
||||
ref typeof(A[0]) front(A)(A a) if (is(typeof(A[0])))
|
||||
ref typeof(A[0]) front(A)(A a) if (is(typeof(A[0])) && !isNarrowString!A)
|
||||
{
|
||||
assert(a.length, "Attempting to fetch the front of an empty array");
|
||||
return a[0];
|
||||
}
|
||||
|
||||
dchar front(A)(A a) if (is(typeof(A[0])) && isNarrowString!A)
|
||||
{
|
||||
assert(a.length, "Attempting to fetch the front of an empty array");
|
||||
size_t i = 0;
|
||||
return decode(a, i);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
void front(T)(T[] a, T v) { assert(a.length); a[0] = v; }
|
||||
void front(T)(T[] a, T v) if (!isNarrowString!A)
|
||||
{
|
||||
assert(a.length); a[0] = v;
|
||||
}
|
||||
|
||||
/**
|
||||
Implements the range interface primitive $(D back) for built-in
|
||||
|
@ -272,7 +362,45 @@ void main()
|
|||
}
|
||||
----
|
||||
*/
|
||||
ref T back(T)(T[] a) { assert(a.length); return a[a.length - 1]; }
|
||||
ref typeof(A.init[0]) back(A)(A a) if (is(typeof(A.init[0]))
|
||||
&& !isNarrowString!A)
|
||||
{
|
||||
enforce(a.length, "Attempting to fetch the back of an empty array");
|
||||
return a[$ - 1];
|
||||
}
|
||||
|
||||
dchar back(A)(A a)
|
||||
if (is(typeof(A.init[0])) && isNarrowString!A && a[0].sizeof < 4)
|
||||
{
|
||||
assert(a.length, "Attempting to fetch the back of an empty array");
|
||||
auto n = a.length;
|
||||
const p = a.ptr + n;
|
||||
if (n >= 1 && (p[-1] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
--n;
|
||||
return std.utf.decode(a, n);
|
||||
}
|
||||
else if (n >= 2 && (p[-2] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
n -= 2;
|
||||
return decode(a, n);
|
||||
}
|
||||
else if (n >= 3 && (p[-3] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
n -= 3;
|
||||
return decode(a, n);
|
||||
}
|
||||
else if (n >= 4 && (p[-4] & 0b1100_0000) != 0b1000_0000)
|
||||
{
|
||||
n -= 4;
|
||||
return decode(a, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UtfException("Invalid UTF character at end of string");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Implements the range interface primitive $(D put) for built-in
|
||||
|
@ -521,21 +649,24 @@ managed array can accommodate before triggering a reallocation).
|
|||
Appends one item to the managed array.
|
||||
*/
|
||||
void put(U)(U item) if (isImplicitlyConvertible!(U, T) ||
|
||||
isSomeString!(T[]) && isSomeString!(U[]))
|
||||
isSomeChar!T && isSomeChar!U)
|
||||
{
|
||||
static if (isSomeString!(T[]) && T.sizeof != U.sizeof)
|
||||
static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
|
||||
{
|
||||
// must do some transcoding around here
|
||||
encode!(T)(item, this);
|
||||
Unqual!T[T.sizeof == 1 ? 4 : 2] encoded;
|
||||
auto len = std.utf.encode(encoded, item);
|
||||
put(encoded[0 .. len]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||
if (pArray.length < _capacity)
|
||||
immutable len = pArray.length;
|
||||
if (len < _capacity)
|
||||
{
|
||||
// Should do in-place construction here
|
||||
pArray.ptr[pArray.length] = item;
|
||||
*pArray = pArray.ptr[0 .. pArray.length + 1];
|
||||
pArray.ptr[len] = item;
|
||||
*pArray = pArray.ptr[0 .. len + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -550,34 +681,21 @@ Appends one item to the managed array.
|
|||
Appends an entire range to the managed array.
|
||||
*/
|
||||
void put(Range)(Range items) if (isForwardRange!Range
|
||||
&& is(typeof(Appender.init.put(ElementType!(Range).init))))
|
||||
&& is(typeof(Appender.init.put(items.front))))
|
||||
{
|
||||
// @@@ UNCOMMENT WHEN BUG 2912 IS FIXED @@@
|
||||
// static if (is(typeof(*cast(T[]*) pArray ~= items)))
|
||||
// {
|
||||
// if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||
// *pArray ~= items;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Generic input range
|
||||
// for (; !items.empty; items.popFront)
|
||||
// {
|
||||
// put(items.front());
|
||||
// }
|
||||
// }
|
||||
|
||||
// @@@ Doctored version taking BUG 2912 into account @@@
|
||||
static if (is(typeof(*cast(T[]*) pArray ~= items)) &&
|
||||
T.sizeof == ElementType!Range.sizeof)
|
||||
static if (is(typeof(*pArray ~= items)))
|
||||
{
|
||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||
*pArray ~= items;
|
||||
}
|
||||
else
|
||||
{
|
||||
//pragma(msg, Range.stringof);
|
||||
// Generic input range
|
||||
foreach (e; items) put(e);
|
||||
for (; !items.empty; items.popFront)
|
||||
{
|
||||
put(items.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ class Base64CharException: Base64Exception
|
|||
|
||||
immutable array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of bytes needed to encode a string of length slen.
|
||||
*/
|
||||
|
@ -163,7 +162,6 @@ unittest
|
|||
assert(encode("all your base64 are belong to foo") == "YWxsIHlvdXIgYmFzZTY0IGFyZSBiZWxvbmcgdG8gZm9v");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of bytes needed to decode an encoded string of this
|
||||
* length.
|
||||
|
@ -173,7 +171,6 @@ uint decodeLength(uint elen)
|
|||
return elen / 4 * 3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes str[] and places the result in buf[].
|
||||
* Params:
|
||||
|
@ -203,7 +200,8 @@ body
|
|||
uint arrayIndex(char ch)
|
||||
out(result)
|
||||
{
|
||||
assert(ch == array[result]);
|
||||
//@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=3667");
|
||||
//assert(ch == array[result]);
|
||||
}
|
||||
body
|
||||
{
|
||||
|
@ -221,7 +219,6 @@ body
|
|||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
if(!estr.length)
|
||||
return buf[0 .. 0];
|
||||
|
||||
|
|
|
@ -710,7 +710,7 @@ string decimal(Big b)
|
|||
b = t.q;
|
||||
result ~= cast(char)(t.r + '0');
|
||||
}
|
||||
reverse(result);
|
||||
reverse(cast(ubyte[]) result);
|
||||
return assumeUnique(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -336,7 +336,8 @@ invariant(T[U]) assumeUnique(T, U)(ref T[U] array)
|
|||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
// @@@BUG@@@
|
||||
version(none) unittest
|
||||
{
|
||||
int[string] arr = ["a":1];
|
||||
auto arr1 = assumeUnique(arr);
|
||||
|
|
96
std/conv.d
96
std/conv.d
|
@ -152,11 +152,11 @@ Converts array (other than strings) to string. The left bracket,
|
|||
separator, and right bracket are configurable. Each element is
|
||||
converted by calling $(D to!T).
|
||||
*/
|
||||
T to(T, S)(S s, in T leftBracket = "[", in T separator = ", ",
|
||||
in T rightBracket = "]")
|
||||
T to(T, S)(S s, in T leftBracket = "", in T separator = " ",
|
||||
in T rightBracket = "")
|
||||
if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
||||
{
|
||||
alias Unqual!(ElementType!(T)) Char;
|
||||
alias Unqual!(typeof(T.init[0])) Char;
|
||||
// array-to-string conversion
|
||||
static if (is(S == void[])
|
||||
|| is(S == const(void)[]) || is(S == invariant(void)[])) {
|
||||
|
@ -171,7 +171,7 @@ if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
|||
result.put(leftBracket);
|
||||
foreach (i, e; s) {
|
||||
if (i) result.put(separator);
|
||||
result.put(to!(T)(e));
|
||||
result.put(to!T(e));
|
||||
}
|
||||
result.put(rightBracket);
|
||||
return cast(T) result.data;
|
||||
|
@ -180,11 +180,13 @@ if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
|||
|
||||
unittest
|
||||
{
|
||||
long[] b = [ 1, 3, 5 ];
|
||||
auto s = to!string(b);
|
||||
//printf("%d, |%*s|\n", s.length, s.length, s.ptr);
|
||||
assert(to!string(b) == "1 3 5", s);
|
||||
double[2] a = [ 1.5, 2.5 ];
|
||||
//writeln(to!string(a));
|
||||
assert(to!string(a) == "[1.5, 2.5]");
|
||||
short[] b = [ 1, 3, 5 ];
|
||||
assert(to!string(b) == "[1, 3, 5]");
|
||||
assert(to!string(a) == "1.5 2.5");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +198,7 @@ T to(T, S)(S s, in T leftBracket = "[", in T keyval = ":",
|
|||
in T separator = ", ", in T rightBracket = "]")
|
||||
if (isAssociativeArray!(S) && isSomeString!(T))
|
||||
{
|
||||
alias Unqual!(ElementType!(T)) Char;
|
||||
alias Unqual!(typeof(T.init[0])) Char;
|
||||
Appender!(Char[]) result;
|
||||
// hash-to-string conversion
|
||||
result.put(leftBracket);
|
||||
|
@ -261,7 +263,7 @@ if (is(S == struct) && isSomeString!(T) && !is(typeof(&S.init.toString)))
|
|||
{
|
||||
// ok, attempt to forge the tuple
|
||||
t = cast(typeof(t)) &s;
|
||||
alias Unqual!(ElementType!(T)) Char;
|
||||
alias Unqual!(typeof(T.init[0])) Char;
|
||||
Appender!(Char[]) app;
|
||||
app.put(left);
|
||||
foreach (i, e; t.field)
|
||||
|
@ -874,7 +876,7 @@ unittest {
|
|||
// test array to string conversion
|
||||
foreach (T ; AllNumerics) {
|
||||
auto a = [to!(T)(1), 2, 3];
|
||||
assert(to!(string)(a) == "[1, 2, 3]");
|
||||
assert(to!(string)(a) == "1 2 3");
|
||||
}
|
||||
// test enum to int conversion
|
||||
// enum Testing { Test1, Test2 };
|
||||
|
@ -1096,13 +1098,8 @@ if (!isSomeString!Source && isFloatingPoint!Target)
|
|||
Target parse(Target, Source)(ref Source s)
|
||||
if (isSomeString!Source && isFloatingPoint!Target)
|
||||
{
|
||||
//writefln("toFloat('%s')", s);
|
||||
auto sz = toStringz(to!(const char[])(s));
|
||||
if (std.ctype.isspace(*sz))
|
||||
goto Lerr;
|
||||
|
||||
// issue 1589
|
||||
version (Windows)
|
||||
//version (Windows)
|
||||
{
|
||||
if (icmp(s, "nan") == 0)
|
||||
{
|
||||
|
@ -1111,27 +1108,52 @@ if (isSomeString!Source && isFloatingPoint!Target)
|
|||
}
|
||||
}
|
||||
|
||||
// BUG: should set __locale_decpoint to "." for DMC
|
||||
auto t = s;
|
||||
if (t.startsWith('+', '-')) t.popFront();
|
||||
munch(t, "0-9"); // integral part
|
||||
if (t.startsWith('.'))
|
||||
{
|
||||
t.popFront(); // decimal point
|
||||
munch(t, "0-9"); // fractionary part
|
||||
}
|
||||
if (t.startsWith('E', 'e'))
|
||||
{
|
||||
t.popFront();
|
||||
if (t.startsWith('+', '-')) t.popFront();
|
||||
munch(t, "0-9"); // exponent
|
||||
}
|
||||
auto len = s.length - t.length;
|
||||
char sz[80] = void;
|
||||
enforce(len < sz.length);
|
||||
foreach (i; 0 .. len) sz[i] = s[i];
|
||||
sz[len] = 0;
|
||||
|
||||
// //writefln("toFloat('%s')", s);
|
||||
// auto sz = toStringz(to!(const char[])(s));
|
||||
// if (std.ctype.isspace(*sz))
|
||||
// goto Lerr;
|
||||
|
||||
// // BUG: should set __locale_decpoint to "." for DMC
|
||||
|
||||
setErrno(0);
|
||||
char* endptr;
|
||||
static if (is(Target == float))
|
||||
auto f = strtof(sz, &endptr);
|
||||
auto f = strtof(sz.ptr, &endptr);
|
||||
else static if (is(Target == double))
|
||||
auto f = strtod(sz, &endptr);
|
||||
auto f = strtod(sz.ptr, &endptr);
|
||||
else static if (is(Target == real))
|
||||
auto f = strtold(sz, &endptr);
|
||||
auto f = strtold(sz.ptr, &endptr);
|
||||
else
|
||||
static assert(false);
|
||||
if (getErrno() == ERANGE)
|
||||
goto Lerr;
|
||||
assert(endptr);
|
||||
if (endptr == sz)
|
||||
if (endptr == sz.ptr)
|
||||
{
|
||||
// no progress
|
||||
goto Lerr;
|
||||
}
|
||||
s = s[endptr - sz .. $];
|
||||
s = s[endptr - sz.ptr .. $];
|
||||
return f;
|
||||
Lerr:
|
||||
conv_error!(Source, Target)(s);
|
||||
|
@ -1573,7 +1595,6 @@ unittest
|
|||
try
|
||||
{
|
||||
i = to!short(errors[j]);
|
||||
printf("i = %d\n", i);
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
|
@ -1637,7 +1658,7 @@ unittest
|
|||
try
|
||||
{
|
||||
i = to!ushort(errors[j]);
|
||||
printf("i = %d\n", i);
|
||||
debug(conv) printf("i = %d\n", i);
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
|
@ -1706,7 +1727,7 @@ unittest
|
|||
try
|
||||
{
|
||||
i = to!byte(errors[j]);
|
||||
printf("i = %d\n", i);
|
||||
debug(conv) printf("i = %d\n", i);
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
|
@ -1770,7 +1791,7 @@ unittest
|
|||
try
|
||||
{
|
||||
i = to!ubyte(errors[j]);
|
||||
printf("i = %d\n", i);
|
||||
debug(conv) printf("i = %d\n", i);
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
|
@ -2506,8 +2527,9 @@ T to(T, S)(S input)
|
|||
if (std.typetuple.staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T)
|
||||
{
|
||||
Unqual!S value = input;
|
||||
alias Unqual!(ElementType!T) Char;
|
||||
static if (is(ElementType!T == const) || is(ElementType!T == immutable))
|
||||
alias Unqual!(typeof(T.init[0])) Char;
|
||||
static if (is(typeof(T.init[0]) == const) ||
|
||||
is(typeof(T.init[0]) == immutable))
|
||||
{
|
||||
if (value < 10)
|
||||
{
|
||||
|
@ -2522,21 +2544,23 @@ if (std.typetuple.staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T)
|
|||
else
|
||||
auto maxlength = (value > uint.max ? S.sizeof : uint.sizeof) * 3;
|
||||
|
||||
Char [] result;
|
||||
if (__ctfe) result = new Char[maxlength];
|
||||
Char[] result;
|
||||
if (__ctfe)
|
||||
result = new Char[maxlength];
|
||||
else
|
||||
result = cast(Char[])
|
||||
GC.malloc(Char.sizeof * maxlength, GC.BlkAttr.NO_SCAN)
|
||||
[0 .. Char.sizeof * maxlength];
|
||||
|
||||
uint ndigits = 0;
|
||||
while (value)
|
||||
do
|
||||
{
|
||||
const c = cast(Char) ((value % 10) + '0');
|
||||
value /= 10;
|
||||
ndigits++;
|
||||
result[$ - ndigits] = c;
|
||||
}
|
||||
while (value);
|
||||
return cast(T) result[$ - ndigits .. $];
|
||||
}
|
||||
|
||||
|
@ -2544,20 +2568,22 @@ unittest
|
|||
{
|
||||
assert(wtext(int.max) == "2147483647"w);
|
||||
assert(wtext(int.min) == "-2147483648"w);
|
||||
assert(to!string(0L) == "0");
|
||||
}
|
||||
|
||||
/// $(D char), $(D wchar), $(D dchar) to a string type.
|
||||
T to(T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 0
|
||||
&& isSomeString!(T))
|
||||
{
|
||||
static if (ElementType!T.sizeof >= S.sizeof)
|
||||
alias typeof(T.init[0]) Char;
|
||||
static if (Char.sizeof >= S.sizeof)
|
||||
{
|
||||
return [ c ];
|
||||
}
|
||||
else
|
||||
{
|
||||
Unqual!(ElementType!T)[] result;
|
||||
encode(result, cast(dchar) c);
|
||||
Unqual!Char[] result;
|
||||
encode(result, c);
|
||||
return cast(T) result;
|
||||
}
|
||||
}
|
||||
|
@ -2588,7 +2614,7 @@ if (staticIndexOf!(Unqual!S, int, long) >= 0 && isSomeString!T)
|
|||
{
|
||||
if (value >= 0)
|
||||
return to!T(cast(Unsigned!(S)) value);
|
||||
alias Unqual!(ElementType!T) Char;
|
||||
alias Unqual!(typeof(T.init[0])) Char;
|
||||
|
||||
// Cache read-only data only for const and immutable - mutable
|
||||
// data is supposed to use allocation in all cases
|
||||
|
|
|
@ -1749,7 +1749,7 @@ body
|
|||
// EncoderInstance!(E).encode(c,buffer);
|
||||
// }
|
||||
|
||||
/**
|
||||
/*
|
||||
Encodes $(D c) in units of type $(D E) and writes the result to the
|
||||
output range $(D R). Returns the number of $(D E)s written.
|
||||
*/
|
||||
|
|
58
std/format.d
58
std/format.d
|
@ -1566,7 +1566,7 @@ struct FormatInfo
|
|||
bool, "flHash", 1,
|
||||
ubyte, "", 3));
|
||||
/* For arrays only: the trailing */
|
||||
const(char)[] innerTrailing;
|
||||
const(char)[] innerTrailing, trailing;
|
||||
|
||||
/*
|
||||
* Given a string format specification fmt, parses a format
|
||||
|
@ -1577,6 +1577,7 @@ struct FormatInfo
|
|||
{
|
||||
FormatInfo result;
|
||||
if (fmt.empty) return result;
|
||||
scope(success) result.trailing = to!(const(char)[])(fmt);
|
||||
size_t i = 0;
|
||||
for (;;)
|
||||
switch (fmt[i])
|
||||
|
@ -2867,7 +2868,8 @@ void skipData(Range)(ref Range input, FormatInfo spec)
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
T unformat(T, Range)(ref Range input, FormatInfo spec) if (isArray!T)
|
||||
T unformat(T, Range)(ref Range input, FormatInfo spec)
|
||||
if (isArray!T && !isSomeString!T)
|
||||
{
|
||||
Appender!(T) app;
|
||||
for (;;)
|
||||
|
@ -2882,6 +2884,42 @@ T unformat(T, Range)(ref Range input, FormatInfo spec) if (isArray!T)
|
|||
return app.data;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
T unformat(T, Range)(ref Range input, FormatInfo spec) if (isSomeString!T)
|
||||
{
|
||||
Appender!(T) app;
|
||||
if (spec.trailing.empty)
|
||||
{
|
||||
for (; !input.empty; input.popFront())
|
||||
{
|
||||
app.put(input.front);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; !input.empty && !input.startsWith(spec.trailing.front);
|
||||
input.popFront())
|
||||
{
|
||||
app.put(input.front);
|
||||
}
|
||||
}
|
||||
//input = input[spec.innerTrailing.length .. $];
|
||||
return app.data;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
string s1, s2;
|
||||
char[] line = "hello, world".dup;
|
||||
formattedRead(line, "%s", &s1);
|
||||
assert(s1 == "hello, world", s1);
|
||||
|
||||
line = "hello, world;yah".dup;
|
||||
formattedRead(line, "%s;%s", &s1, &s2);
|
||||
assert(s1 == "hello, world", s1);
|
||||
assert(s2 == "yah", s2);
|
||||
}
|
||||
|
||||
private template acceptedSpecs(T)
|
||||
{
|
||||
static if (isIntegral!T) enum acceptedSpecs = "sdu";// + "coxX" (todo)
|
||||
|
@ -2908,17 +2946,25 @@ T unformat(T, Range)(ref Range input, FormatInfo spec) if (isFloatingPoint!T)
|
|||
{
|
||||
// raw read
|
||||
enforce(input.length >= T.sizeof);
|
||||
enforce(ElementType!(Range).sizeof == 1);
|
||||
enforce(isSomeString!Range || ElementType!(Range).sizeof == 1);
|
||||
union X
|
||||
{
|
||||
char[T.sizeof] raw;
|
||||
ubyte[T.sizeof] raw;
|
||||
T typed;
|
||||
}
|
||||
X x;
|
||||
foreach (i; 0 .. T.sizeof)
|
||||
{
|
||||
x.raw[i] = input.front;
|
||||
input.popFront;
|
||||
static if (isSomeString!Range)
|
||||
{
|
||||
x.raw[i] = input[0];
|
||||
input = input[1 .. $];
|
||||
}
|
||||
else
|
||||
{
|
||||
x.raw[i] = input.front;
|
||||
input.popFront();
|
||||
}
|
||||
}
|
||||
return x.typed;
|
||||
}
|
||||
|
|
67
std/json.d
67
std/json.d
|
@ -64,14 +64,14 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
if(json.empty()) return root;
|
||||
|
||||
int depth = -1;
|
||||
char next = 0;
|
||||
dchar next = 0;
|
||||
int line = 1, pos = 1;
|
||||
|
||||
void error(string msg) {
|
||||
throw new JSONException(msg, line, pos);
|
||||
}
|
||||
|
||||
char peekChar() {
|
||||
dchar peekChar() {
|
||||
if(!next) {
|
||||
if(json.empty()) return '\0';
|
||||
next = json.front();
|
||||
|
@ -84,10 +84,10 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
while(isspace(peekChar())) next = 0;
|
||||
}
|
||||
|
||||
char getChar(bool SkipWhitespace = false)() {
|
||||
dchar getChar(bool SkipWhitespace = false)() {
|
||||
static if(SkipWhitespace) skipWhitespace();
|
||||
|
||||
char c = void;
|
||||
dchar c = void;
|
||||
if(next) {
|
||||
c = next;
|
||||
next = 0;
|
||||
|
@ -111,16 +111,17 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
|
||||
void checkChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c) {
|
||||
static if(SkipWhitespace) skipWhitespace();
|
||||
char c2 = getChar();
|
||||
static if(!CaseSensitive) c2 = cast(char)tolower(c2);
|
||||
auto c2 = getChar();
|
||||
static if(!CaseSensitive) c2 = tolower(c2);
|
||||
|
||||
if(c2 != c) error(text("Found '", c2, "' when expecting '", c, "'."));
|
||||
}
|
||||
|
||||
bool testChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c) {
|
||||
bool testChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c)
|
||||
{
|
||||
static if(SkipWhitespace) skipWhitespace();
|
||||
char c2 = peekChar();
|
||||
static if(!CaseSensitive) c2 = cast(char)tolower(c2);
|
||||
auto c2 = peekChar();
|
||||
static if (!CaseSensitive) c2 = tolower(c2);
|
||||
|
||||
if(c2 != c) return false;
|
||||
|
||||
|
@ -139,7 +140,7 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
|
||||
case '\\':
|
||||
getChar();
|
||||
char c = getChar();
|
||||
auto c = getChar();
|
||||
switch(c) {
|
||||
case '"': str.put('"'); break;
|
||||
case '\\': str.put('\\'); break;
|
||||
|
@ -152,7 +153,7 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
case 'u':
|
||||
dchar val = 0;
|
||||
foreach_reverse(i; 0 .. 4) {
|
||||
char hex = cast(char)toupper(getChar());
|
||||
auto hex = toupper(getChar());
|
||||
if(!isxdigit(hex)) error("Expecting hex character");
|
||||
val += (isdigit(hex) ? hex - '0' : hex - 'A') << (4 * i);
|
||||
}
|
||||
|
@ -166,8 +167,8 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
goto Next;
|
||||
|
||||
default:
|
||||
char c = getChar();
|
||||
appendJSONChar(&str, c, getChar(), &error);
|
||||
auto c = getChar();
|
||||
appendJSONChar(&str, c, &error);
|
||||
goto Next;
|
||||
}
|
||||
|
||||
|
@ -179,7 +180,7 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
|||
|
||||
if(maxDepth != -1 && depth > maxDepth) error("Nesting too deep.");
|
||||
|
||||
char c = getChar!true();
|
||||
auto c = getChar!true();
|
||||
|
||||
switch(c) {
|
||||
case '{':
|
||||
|
@ -314,8 +315,8 @@ string toJSON(in JSONValue* root) {
|
|||
void toString(string str) {
|
||||
json.put('"');
|
||||
|
||||
for(int i; i != str.length; i++) {
|
||||
switch(str[i]) {
|
||||
foreach (dchar c; str) {
|
||||
switch(c) {
|
||||
case '"': json.put("\\\""); break;
|
||||
case '\\': json.put("\\\\"); break;
|
||||
case '/': json.put("\\/"); break;
|
||||
|
@ -325,7 +326,7 @@ string toJSON(in JSONValue* root) {
|
|||
case '\r': json.put("\\r"); break;
|
||||
case '\t': json.put("\\t"); break;
|
||||
default:
|
||||
appendJSONChar(&json, str[i], str[++i],
|
||||
appendJSONChar(&json, c,
|
||||
(string msg){throw new JSONException(msg);});
|
||||
}
|
||||
}
|
||||
|
@ -388,23 +389,25 @@ string toJSON(in JSONValue* root) {
|
|||
return json.data;
|
||||
}
|
||||
|
||||
private void appendJSONChar(Appender!string* dst, char c, lazy char next,
|
||||
private void appendJSONChar(Appender!string* dst, dchar c,
|
||||
scope void delegate(string) error)
|
||||
{
|
||||
int stride = UTFStride((&c)[0 .. 1], 0);
|
||||
if(stride == 1) {
|
||||
if(iscntrl(c)) error("Illegal control character.");
|
||||
dst.put(c);
|
||||
}
|
||||
else {
|
||||
char[6] utf = void;
|
||||
utf[0] = c;
|
||||
foreach(i; 1 .. stride) utf[i] = next;
|
||||
size_t index = 0;
|
||||
if(iscntrl(toUnicode(utf[0 .. stride], index)))
|
||||
error("Illegal control character");
|
||||
dst.put(utf[0 .. stride]);
|
||||
}
|
||||
if(iscntrl(c)) error("Illegal control character.");
|
||||
dst.put(c);
|
||||
// int stride = UTFStride((&c)[0 .. 1], 0);
|
||||
// if(stride == 1) {
|
||||
// if(iscntrl(c)) error("Illegal control character.");
|
||||
// dst.put(c);
|
||||
// }
|
||||
// else {
|
||||
// char[6] utf = void;
|
||||
// utf[0] = c;
|
||||
// foreach(i; 1 .. stride) utf[i] = next;
|
||||
// size_t index = 0;
|
||||
// if(iscntrl(toUnicode(utf[0 .. stride], index)))
|
||||
// error("Illegal control character");
|
||||
// dst.put(utf[0 .. stride]);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
77
std/range.d
77
std/range.d
|
@ -235,11 +235,8 @@ template isRandomAccessRange(R)
|
|||
{
|
||||
enum bool isRandomAccessRange =
|
||||
(isBidirectionalRange!(R) || isInfinite!(R))
|
||||
&& is(typeof(
|
||||
{
|
||||
R r;
|
||||
auto e = r[1]; // can index
|
||||
}()));
|
||||
&& is(typeof(R.init[1]))
|
||||
&& !isNarrowString!R;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -295,9 +292,9 @@ unittest
|
|||
{
|
||||
enum XYZ : string { a = "foo" };
|
||||
auto x = front(XYZ.a);
|
||||
static assert(is(ElementType!(XYZ) : char));
|
||||
static assert(is(ElementType!(XYZ) : dchar));
|
||||
immutable char[3] a = "abc";
|
||||
static assert(is(ElementType!(typeof(a)) : char));
|
||||
static assert(is(ElementType!(typeof(a)) : dchar));
|
||||
int[] i;
|
||||
static assert(is(ElementType!(typeof(i)) : int));
|
||||
}
|
||||
|
@ -328,7 +325,7 @@ unittest
|
|||
static assert(!hasSwappableElements!(const int[]));
|
||||
static assert(!hasSwappableElements!(const(int)[]));
|
||||
static assert(hasSwappableElements!(int[]));
|
||||
static assert(hasSwappableElements!(char[]));
|
||||
//static assert(hasSwappableElements!(char[]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -371,7 +368,8 @@ other ranges may be infinite.
|
|||
*/
|
||||
template hasLength(R)
|
||||
{
|
||||
enum bool hasLength = is(typeof(R.init.length) : ulong);
|
||||
enum bool hasLength = is(typeof(R.init.length) : ulong) &&
|
||||
!isNarrowString!R;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -458,7 +456,7 @@ upTo) steps have been taken and returns $(D upTo).
|
|||
size_t walkLength(Range)(Range range, size_t upTo = size_t.max)
|
||||
if (isInputRange!(Range))
|
||||
{
|
||||
static if (hasLength!(Range))
|
||||
static if (isRandomAccessRange!Range && hasLength!Range)
|
||||
{
|
||||
return range.length;
|
||||
}
|
||||
|
@ -558,7 +556,7 @@ Forwards to $(D _input[_input.length - n + 1]). Defined only if $(D R)
|
|||
is a random access range and if $(D R) defines $(D R.length).
|
||||
*/
|
||||
static if (isRandomAccessRange!(R) && hasLength!(R))
|
||||
ref ElementType!(R) opIndex(uint n)
|
||||
ref ElementType!R opIndex(uint n)
|
||||
{
|
||||
return _input[_input.length - n - 1];
|
||||
}
|
||||
|
@ -568,7 +566,7 @@ Range primitive operation that returns the length of the
|
|||
range. Forwards to $(D _input.length) and is defined only if $(D
|
||||
hasLength!(R)).
|
||||
*/
|
||||
static if (hasLength!(R))
|
||||
static if (hasLength!R || isNarrowString!R)
|
||||
size_t length()
|
||||
{
|
||||
return _input.length;
|
||||
|
@ -1180,7 +1178,7 @@ offers random access and $(D length), $(D Take) offers them as well.
|
|||
Example:
|
||||
----
|
||||
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
|
||||
auto s = take(5, arr1);
|
||||
auto s = take(arr1, 5);
|
||||
assert(s.length == 5);
|
||||
assert(s[4] == 5);
|
||||
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
|
||||
|
@ -1190,8 +1188,8 @@ assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
|
|||
struct Take(R) if (isInputRange!(R))
|
||||
{
|
||||
private:
|
||||
size_t _maxAvailable;
|
||||
R _input;
|
||||
size_t _maxAvailable;
|
||||
enum bool byRef = is(typeof(&(R.init[0])));
|
||||
|
||||
public:
|
||||
|
@ -1293,20 +1291,18 @@ public:
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
Take opSlice() { return this; }
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
Take!(R) take(R)(size_t n, R input) if (isInputRange!(R))
|
||||
Take!(R) take(R)(R input, size_t n) if (isInputRange!(R))
|
||||
{
|
||||
return Take!(R)(n, input);
|
||||
return Take!(R)(input, n);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
|
||||
auto s = take(5, arr1);
|
||||
auto s = take(arr1, 5);
|
||||
assert(s.length == 5);
|
||||
assert(s[4] == 5);
|
||||
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
|
||||
|
@ -1394,7 +1390,7 @@ unittest
|
|||
/**
|
||||
Repeats one value forever. Example:
|
||||
----
|
||||
enforce(equal(take(4, repeat(5)), [ 5, 5, 5, 5 ][]));
|
||||
enforce(equal(take(repeat(5), 4), [ 5, 5, 5, 5 ][]));
|
||||
----
|
||||
*/
|
||||
|
||||
|
@ -1418,21 +1414,21 @@ Repeat!(T) repeat(T)(T value) { return Repeat!(T)(value); }
|
|||
|
||||
unittest
|
||||
{
|
||||
enforce(equal(take(4, repeat(5)), [ 5, 5, 5, 5 ][]));
|
||||
enforce(equal(take(repeat(5), 4), [ 5, 5, 5, 5 ][]));
|
||||
}
|
||||
|
||||
/**
|
||||
Replicates $(D value) exactly $(D n) times. Equivalent to $(D take(n,
|
||||
repeat(value))).
|
||||
Replicates $(D value) exactly $(D n) times. Equivalent to $(D
|
||||
take(repeat(value), n)).
|
||||
*/
|
||||
Take!(Repeat!(T)) replicate(T)(size_t n, T value)
|
||||
Take!(Repeat!(T)) replicate(T)(T value, size_t n)
|
||||
{
|
||||
return take(n, repeat(value));
|
||||
return take(repeat(value), n);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
enforce(equal(replicate(4, 5), [ 5, 5, 5, 5 ][]));
|
||||
enforce(equal(replicate(5, 4), [ 5, 5, 5, 5 ][]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1446,7 +1442,7 @@ mostly for performance reasons.
|
|||
|
||||
Example:
|
||||
----
|
||||
assert(equal(take(5, cycle([1, 2][])), [ 1, 2, 1, 2, 1 ][]));
|
||||
assert(equal(take(cycle([1, 2][]), 5), [ 1, 2, 1, 2, 1 ][]));
|
||||
----
|
||||
|
||||
Tip: This is a great way to implement simple circular buffers.
|
||||
|
@ -1543,12 +1539,12 @@ Cycle!(R) cycle(R)(ref R input, size_t index = 0) if (isStaticArray!R)
|
|||
|
||||
unittest
|
||||
{
|
||||
assert(equal(take(5, cycle([1, 2][])), [ 1, 2, 1, 2, 1 ][]));
|
||||
assert(equal(take(cycle([1, 2][]), 5), [ 1, 2, 1, 2, 1 ][]));
|
||||
int[3] a = [ 1, 2, 3 ];
|
||||
static assert(isStaticArray!(typeof(a)));
|
||||
auto c = cycle(a);
|
||||
assert(a.ptr == c._ptr);
|
||||
assert(equal(take(5, cycle(a)), [ 1, 2, 3, 1, 2 ][]));
|
||||
assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1978,9 +1974,9 @@ Example:
|
|||
// a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
|
||||
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
|
||||
// print the first 10 Fibonacci numbers
|
||||
foreach (e; take(10, fib)) { writeln(e); }
|
||||
foreach (e; take(fib, 10)) { writeln(e); }
|
||||
// print the first 10 factorials
|
||||
foreach (e; take(10, recurrence!("a[n-1] * n")(1))) { writeln(e); }
|
||||
foreach (e; take(recurrence!("a[n-1] * n")(1), 10)) { writeln(e); }
|
||||
----
|
||||
*/
|
||||
struct Recurrence(alias fun, StateType, size_t stateSize)
|
||||
|
@ -2021,15 +2017,15 @@ version(none) unittest
|
|||
{
|
||||
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
|
||||
int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
|
||||
//foreach (e; take(10, fib)) writeln(e);
|
||||
assert(equal(take(10, fib), witness));
|
||||
foreach (e; take(10, fib)) {}//writeln(e);
|
||||
//foreach (e; take(fib, 10)) writeln(e);
|
||||
assert(equal(take(fib, 10), witness));
|
||||
foreach (e; take(fib, 10)) {}//writeln(e);
|
||||
//writeln(s.front);
|
||||
auto fact = recurrence!("n * a[n-1]")(1);
|
||||
assert( equal(take(10, fact), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
|
||||
assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
|
||||
2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
|
||||
auto piapprox = recurrence!("a[n] + (n & 1 ? 4. : -4.) / (2 * n + 3)")(4.);
|
||||
foreach (e; take(20, piapprox)) {}//writeln(e);
|
||||
foreach (e; take(piapprox, 20)) {}//writeln(e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2098,14 +2094,14 @@ unittest
|
|||
// alias Sequence!("a.field[0] += a.field[1]",
|
||||
// Tuple!(int, int)) Gen;
|
||||
// Gen x = Gen(tuple(0, 5));
|
||||
// foreach (e; take(15, x))
|
||||
// foreach (e; take(x, 15))
|
||||
// {}//writeln(e);
|
||||
|
||||
auto y = Sequence!("a.field[0] + n * a.field[1]", Tuple!(int, int))
|
||||
(tuple(0, 4));
|
||||
//@@BUG
|
||||
//auto y = sequence!("a.field[0] + n * a.field[1]")(0, 4);
|
||||
//foreach (e; take(15, y))
|
||||
//foreach (e; take(y, 15))
|
||||
{}//writeln(e);
|
||||
}
|
||||
|
||||
|
@ -2163,9 +2159,8 @@ if (is(typeof((E.init - B.init) + 1 * S.init)))
|
|||
"; count=", count));
|
||||
assert(!myless(count * step, end - begin), text("begin=", begin,
|
||||
"; end=", end, "; step=", step, "; count=", count));
|
||||
return typeof(return)(count,
|
||||
typeof(return).Source(
|
||||
Tuple!(CommonType!(B, E), S)(begin, step), 0u));
|
||||
return typeof(return)(typeof(return).Source(
|
||||
Tuple!(CommonType!(B, E), S)(begin, step), 0u), count);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
|
|
129
std/regex.d
129
std/regex.d
|
@ -1516,7 +1516,7 @@ Returns the number of parenthesized captures
|
|||
}
|
||||
|
||||
/// Ditto
|
||||
Regex!(Unqual!(ElementType!(String))) regex(String)
|
||||
Regex!(Unqual!(typeof(String.init[0]))) regex(String)
|
||||
(String pattern, string flags = null)
|
||||
{
|
||||
return typeof(return)(pattern, flags);
|
||||
|
@ -1528,9 +1528,9 @@ stores the matching state and can be inspected and iterated.
|
|||
*/
|
||||
struct RegexMatch(Range = string)
|
||||
{
|
||||
alias .ElementType!(Range) E;
|
||||
alias typeof(Range.init[0]) E;
|
||||
// Engine
|
||||
alias .Regex!(Unqual!(.ElementType!(Range))) Regex;
|
||||
alias .Regex!(Unqual!E) Regex;
|
||||
private alias Regex.regmatch_t regmatch_t;
|
||||
|
||||
/**
|
||||
|
@ -1623,34 +1623,35 @@ void main()
|
|||
|
||||
unittest
|
||||
{
|
||||
uint i;
|
||||
foreach(m; match(to!(Range)("abcabcabab"), regex(to!(Range)("ab"))))
|
||||
{
|
||||
++i;
|
||||
assert(m.hit == "ab");
|
||||
//writefln("%s[%s]%s", m.pre, m.hit, m.post);
|
||||
}
|
||||
assert(i == 4);
|
||||
// @@@BUG@@@ This doesn't work if a client module uses -unittest
|
||||
// uint i;
|
||||
// foreach (m; match(to!(Range)("abcabcabab"), regex(to!(Range)("ab"))))
|
||||
// {
|
||||
// ++i;
|
||||
// assert(m.hit == "ab");
|
||||
// //writefln("%s[%s]%s", m.pre, m.hit, m.post);
|
||||
// }
|
||||
// assert(i == 4);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
// @@@
|
||||
debug(regex) printf("regex.search.unittest()\n");
|
||||
// @@@BUG@@@ This doesn't work if a client module uses -unittest
|
||||
// debug(regex) printf("regex.search.unittest()\n");
|
||||
|
||||
int i;
|
||||
//foreach(m; RegexMatch("ab").search("abcabcabab"))
|
||||
foreach(m; .match("abcabcabab", regex("ab")))
|
||||
{
|
||||
auto s = std.string.format("%s[%s]%s", m.pre, m.hit, m.post);
|
||||
if (i == 0) assert(s == "[ab]cabcabab");
|
||||
else if (i == 1) assert(s == "abc[ab]cabab");
|
||||
else if (i == 2) assert(s == "abcabc[ab]ab");
|
||||
else if (i == 3) assert(s == "abcabcab[ab]");
|
||||
else assert(0);
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
// int i;
|
||||
// //foreach(m; RegexMatch("ab").search("abcabcabab"))
|
||||
// foreach(m; .match("abcabcabab", regex("ab")))
|
||||
// {
|
||||
// auto s = std.string.format("%s[%s]%s", m.pre, m.hit, m.post);
|
||||
// if (i == 0) assert(s == "[ab]cabcabab");
|
||||
// else if (i == 1) assert(s == "abc[ab]cabab");
|
||||
// else if (i == 2) assert(s == "abcabc[ab]ab");
|
||||
// else if (i == 3) assert(s == "abcabcab[ab]");
|
||||
// else assert(0);
|
||||
// i++;
|
||||
// }
|
||||
// assert(i == 4);
|
||||
}
|
||||
|
||||
struct Captures
|
||||
|
@ -1716,14 +1717,15 @@ foreach (m; match("abracadabra", "(.)a(.)"))
|
|||
|
||||
unittest
|
||||
{
|
||||
Appender!(char[]) app;
|
||||
foreach (m; match("abracadabra", "(.)a(.)"))
|
||||
{
|
||||
assert(m.captures.length == 3);
|
||||
foreach (c; m.captures)
|
||||
app.put(c), app.put(';');
|
||||
}
|
||||
assert(app.data == "rac;r;c;dab;d;b;");
|
||||
// @@@BUG@@@ This doesn't work if a client module uses -unittest
|
||||
// Appender!(char[]) app;
|
||||
// foreach (m; match("abracadabra", "(.)a(.)"))
|
||||
// {
|
||||
// assert(m.captures.length == 3);
|
||||
// foreach (c; m.captures)
|
||||
// app.put(c), app.put(';');
|
||||
// }
|
||||
// assert(app.data == "rac;r;c;dab;d;b;");
|
||||
}
|
||||
|
||||
/*******************
|
||||
|
@ -1821,26 +1823,6 @@ Returns $(D hit) (converted to $(D string) if necessary).
|
|||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
//@@@
|
||||
// debug(regex) printf("regex.replace.unittest()\n");
|
||||
|
||||
auto r = match("1ab2ac3", regex("a[bc]", "g"));
|
||||
auto result = r.replaceAll("x$&y");
|
||||
auto i = std.string.cmp(result, "1xaby2xacy3");
|
||||
assert(i == 0);
|
||||
|
||||
r = match("1ab2ac3", regex("ab", "g"));
|
||||
result = r.replaceAll("xy");
|
||||
i = std.string.cmp(result, "1xy2ac3");
|
||||
assert(i == 0);
|
||||
|
||||
r = match("wyda", regex("(giba)"));
|
||||
assert(r.captures.length == 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test s[] starting at startindex against regular expression.
|
||||
* Returns: 0 for no match, !=0 for match
|
||||
|
@ -1863,7 +1845,7 @@ Returns $(D hit) (converted to $(D string) if necessary).
|
|||
pmatch[0].endIdx = 0;
|
||||
|
||||
// First character optimization
|
||||
Unqual!(ElementType!(Range)) firstc = 0;
|
||||
Unqual!(typeof(Range.init[0])) firstc = 0;
|
||||
if (engine.program[0] == engine.REchar)
|
||||
{
|
||||
firstc = engine.program[1];
|
||||
|
@ -1922,13 +1904,6 @@ Returns $(D hit) (converted to $(D string) if necessary).
|
|||
*/
|
||||
//alias test opEquals;
|
||||
|
||||
unittest
|
||||
{
|
||||
//@@@
|
||||
assert(!match("abc", regex(".b.")).empty);
|
||||
assert(match("abc", regex(".b..")).empty);
|
||||
}
|
||||
|
||||
private bool chr(ref uint si, E c)
|
||||
{
|
||||
for (; si < input.length; si++)
|
||||
|
@ -2697,6 +2672,30 @@ and, using the format string, generate and return a new string.
|
|||
}
|
||||
} // end of class RegexMatch
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(regex) printf("regex.replace.unittest()\n");
|
||||
auto r = match("1ab2ac3", regex("a[bc]", "g"));
|
||||
auto result = r.replaceAll("x$&y");
|
||||
auto i = std.string.cmp(result, "1xaby2xacy3");
|
||||
assert(i == 0);
|
||||
|
||||
r = match("1ab2ac3", regex("ab", "g"));
|
||||
result = r.replaceAll("xy");
|
||||
i = std.string.cmp(result, "1xy2ac3");
|
||||
assert(i == 0);
|
||||
|
||||
r = match("wyda", regex("(giba)"));
|
||||
assert(r.captures.length == 0);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
//@@@
|
||||
assert(!match("abc", regex(".b.")).empty);
|
||||
assert(match("abc", regex(".b..")).empty);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -2707,7 +2706,7 @@ inspection or for iterating over all matches (if the regular
|
|||
expression was built with the "g" option).
|
||||
*/
|
||||
RegexMatch!(Range) match(Range, Engine)(Range r, Engine engine)
|
||||
if (is(Engine == Regex!(Unqual!(ElementType!(Range)))))
|
||||
if (is(Engine == Regex!(Unqual!(typeof(Range.init[0])))))
|
||||
{
|
||||
return typeof(return)(engine, r);
|
||||
}
|
||||
|
@ -2789,7 +2788,7 @@ assert(replace("noon", regex("^n"), "[$&]") == "[n]oon");
|
|||
*/
|
||||
|
||||
Range replace(Range, Engine, String)(Range input, Engine regex, String format)
|
||||
if (is(Engine == Regex!(Unqual!(ElementType!(Range)))))
|
||||
if (is(Engine == Regex!(Unqual!(typeof(Range.init[0])))))
|
||||
{
|
||||
return RegexMatch!(Range)(regex, input).replaceAll(format);
|
||||
}
|
||||
|
@ -2915,7 +2914,7 @@ struct Splitter(Range)
|
|||
{
|
||||
Range _input;
|
||||
size_t _offset;
|
||||
alias Regex!(Unqual!(ElementType!(Range))) Rx;
|
||||
alias Regex!(Unqual!(typeof(Range.init[0]))) Rx;
|
||||
// Rx _rx;
|
||||
RegexMatch!(Range) _match;
|
||||
|
||||
|
|
121
std/stdio.d
121
std/stdio.d
|
@ -20,9 +20,9 @@ Distributed under the Boost Software License, Version 1.0.
|
|||
module std.stdio;
|
||||
|
||||
public import core.stdc.stdio;
|
||||
private import std.stdiobase;
|
||||
private import core.memory, core.stdc.errno, core.stdc.stddef,
|
||||
core.stdc.stdlib, core.stdc.string, core.stdc.wchar_;
|
||||
private import std.stdiobase;
|
||||
private import std.algorithm, std.array, std.contracts, std.conv, std.file, std.format,
|
||||
/*std.metastrings,*/ std.range, std.string, std.traits, std.typecons,
|
||||
std.typetuple, std.utf;
|
||||
|
@ -618,47 +618,88 @@ This method is more efficient than the one in the previous example
|
|||
because $(D stdin.readln(buf)) reuses (if possible) memory allocated
|
||||
by $(D buf), whereas $(D buf = stdin.readln()) makes a new memory allocation
|
||||
with every line. */
|
||||
|
||||
size_t readln(ref char[] buf, dchar terminator = '\n')
|
||||
S readln(S = string)(dchar terminator = '\n')
|
||||
{
|
||||
enforce(p && p.handle, "Attempt to read from an unopened file.");
|
||||
return readlnImpl(p.handle, buf, terminator);
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
string readln(dchar terminator = '\n')
|
||||
{
|
||||
char[] buf;
|
||||
Unqual!(typeof(S.init[0]))[] buf;
|
||||
readln(buf, terminator);
|
||||
return assumeUnique(buf);
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
// TODO: optimize this
|
||||
size_t readln(ref wchar[] buf, dchar terminator = '\n')
|
||||
unittest
|
||||
{
|
||||
string s = readln(terminator);
|
||||
if (!s.length) return 0;
|
||||
buf.length = 0;
|
||||
foreach (wchar c; s)
|
||||
std.file.write("deleteme", "hello\nworld\n");
|
||||
scope(exit) std.file.remove("deleteme");
|
||||
foreach (C; Tuple!(char, wchar, dchar).Types)
|
||||
{
|
||||
buf ~= c;
|
||||
auto witness = [ "hello\n", "world\n" ];
|
||||
auto f = File("deleteme");
|
||||
uint i = 0;
|
||||
immutable(C)[] buf;
|
||||
while ((buf = f.readln!(typeof(buf))()).length)
|
||||
{
|
||||
assert(i < witness.length);
|
||||
assert(equal(buf, witness[i++]));
|
||||
}
|
||||
assert(i == witness.length);
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
size_t readln(C)(ref C[] buf, dchar terminator = '\n') if (isSomeChar!C)
|
||||
{
|
||||
static if (is(C == char))
|
||||
{
|
||||
enforce(p && p.handle, "Attempt to read from an unopened file.");
|
||||
return readlnImpl(p.handle, buf, terminator);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: optimize this
|
||||
string s = readln(terminator);
|
||||
if (!s.length) return 0;
|
||||
buf.length = 0;
|
||||
foreach (wchar c; s)
|
||||
{
|
||||
buf ~= c;
|
||||
}
|
||||
return buf.length;
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
size_t readln(C, R)(ref C[] buf, R terminator)
|
||||
if (isBidirectionalRange!R && is(typeof(terminator.front == buf[0])))
|
||||
{
|
||||
auto last = terminator.back();
|
||||
C[] buf2;
|
||||
swap(buf, buf2);
|
||||
for (;;) {
|
||||
if (!readln(buf2, last) || endsWith(buf2, terminator)) {
|
||||
if (buf.empty) {
|
||||
buf = buf2;
|
||||
} else {
|
||||
buf ~= buf2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
buf ~= buf2;
|
||||
}
|
||||
return buf.length;
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
// TODO: fold this together with wchar
|
||||
size_t readln(ref dchar[] buf, dchar terminator = '\n')
|
||||
unittest
|
||||
{
|
||||
string s = readln(terminator);
|
||||
if (!s.length) return 0;
|
||||
buf.length = 0;
|
||||
foreach (dchar c; s)
|
||||
std.file.write("deleteme", "hello\n\rworld\nhow\n\rare ya");
|
||||
auto witness = [ "hello\n\r", "world\nhow\n\r", "are ya" ];
|
||||
scope(exit) std.file.remove("deleteme");
|
||||
auto f = File("deleteme");
|
||||
uint i = 0;
|
||||
char[] buf;
|
||||
while (f.readln(buf, "\n\r"))
|
||||
{
|
||||
buf ~= c;
|
||||
assert(i < witness.length);
|
||||
assert(buf == witness[i++]);
|
||||
}
|
||||
return buf.length;
|
||||
}
|
||||
|
||||
size_t readf(Data...)(in char[] format, Data data)
|
||||
|
@ -882,7 +923,10 @@ $(D Range) that locks the file and allows fast writing to it.
|
|||
/// Range primitive implementations.
|
||||
void put(A)(A writeme) if (is(ElementType!A : const(dchar)))
|
||||
{
|
||||
alias ElementType!A C;
|
||||
static if (isSomeString!A)
|
||||
alias typeof(writeme[0]) C;
|
||||
else
|
||||
alias ElementType!A C;
|
||||
static assert(!is(C == void));
|
||||
// writeln("typeof(A.init[0]) = ", typeof(A.init[0]),
|
||||
// ", ElementType!A = ", ElementType!A);
|
||||
|
@ -1053,7 +1097,8 @@ $(D Range) that locks the file and allows fast writing to it.
|
|||
|
||||
void popFront()
|
||||
{
|
||||
enforce(_f.p && _f.p.handle, "Attempt to read from an unopened file.");
|
||||
enforce(_f.p && _f.p.handle,
|
||||
"Attempt to read from an unopened file.");
|
||||
assert(!empty);
|
||||
_crt = getc(cast(FILE*) _f.p.handle);
|
||||
}
|
||||
|
@ -1176,16 +1221,16 @@ unittest
|
|||
scope(failure) printf("Failed test at line %d\n", __LINE__);
|
||||
void[] buf;
|
||||
write(buf);
|
||||
// // test write
|
||||
// test write
|
||||
string file = "dmd-build-test.deleteme.txt";
|
||||
auto f = File(file, "w");
|
||||
scope(exit) { std.file.remove(file); }
|
||||
f.write("Hello, ", "world number ", 42, "!");
|
||||
f.close;
|
||||
assert(cast(char[]) std.file.read(file) == "Hello, world number 42!");
|
||||
// scope(exit) { std.file.remove(file); }
|
||||
f.write("Hello, ", "world number ", 42, "!");
|
||||
f.close;
|
||||
assert(cast(char[]) std.file.read(file) == "Hello, world number 42!");
|
||||
// // test write on stdout
|
||||
auto saveStdout = stdout;
|
||||
scope(exit) stdout = saveStdout;
|
||||
//auto saveStdout = stdout;
|
||||
//scope(exit) stdout = saveStdout;
|
||||
//stdout.open(file, "w");
|
||||
Object obj;
|
||||
//write("Hello, ", "world number ", 42, "! ", obj);
|
||||
|
@ -1837,8 +1882,6 @@ Initialize with a message and an error code. */
|
|||
|
||||
extern(C) void std_stdio_static_this()
|
||||
{
|
||||
//printf("std_stdio_static_this()\n");
|
||||
|
||||
//Bind stdin, stdout, stderr
|
||||
__gshared File.Impl stdinImpl;
|
||||
stdinImpl.handle = core.stdc.stdio.stdin;
|
||||
|
|
10
std/string.d
10
std/string.d
|
@ -742,8 +742,9 @@ unittest
|
|||
|
||||
S tolower(S)(S s) if (isSomeString!S)
|
||||
{
|
||||
alias typeof(s[0]) Char;
|
||||
int changed;
|
||||
Unqual!(ElementType!S)[] r;
|
||||
Unqual!(Char)[] r;
|
||||
|
||||
for (size_t i = 0; i < s.length; i++)
|
||||
{
|
||||
|
@ -755,7 +756,7 @@ S tolower(S)(S s) if (isSomeString!S)
|
|||
r = s.dup;
|
||||
changed = 1;
|
||||
}
|
||||
r[i] = cast(Unqual!(ElementType!S)) (c + ('a' - 'A'));
|
||||
r[i] = cast(Unqual!Char) (c + ('a' - 'A'));
|
||||
}
|
||||
else if (c > 0x7F)
|
||||
{
|
||||
|
@ -866,8 +867,9 @@ unittest
|
|||
|
||||
S toupper(S)(S s) if (isSomeString!S)
|
||||
{
|
||||
alias typeof(s[0]) Char;
|
||||
int changed;
|
||||
Unqual!(ElementType!S)[] r;
|
||||
Unqual!(Char)[] r;
|
||||
|
||||
foreach (i; 0 .. s.length)
|
||||
{
|
||||
|
@ -879,7 +881,7 @@ S toupper(S)(S s) if (isSomeString!S)
|
|||
r = to!(typeof(r))(s);
|
||||
changed = 1;
|
||||
}
|
||||
r[i] = cast(Unqual!(ElementType!S)) (c - ('a' - 'A'));
|
||||
r[i] = cast(Unqual!(Char)) (c - ('a' - 'A'));
|
||||
}
|
||||
else if (c > 0x7F)
|
||||
{
|
||||
|
|
21
std/traits.d
21
std/traits.d
|
@ -952,8 +952,7 @@ Detect whether T is one of the built-in string types
|
|||
|
||||
template isSomeString(T)
|
||||
{
|
||||
enum isSomeString = is(T : const(char[]))
|
||||
|| is(T : const(wchar[])) || is(T : const(dchar[]));
|
||||
enum isSomeString = isNarrowString!T || is(T : const(dchar[]));
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -969,6 +968,24 @@ unittest
|
|||
static assert(isSomeString!(char[4]));
|
||||
}
|
||||
|
||||
template isNarrowString(T)
|
||||
{
|
||||
enum isNarrowString = is(T : const(char[])) || is(T : const(wchar[]));
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
static assert(!isNarrowString!(int));
|
||||
static assert(!isNarrowString!(int[]));
|
||||
static assert(!isNarrowString!(byte[]));
|
||||
static assert(isNarrowString!(char[]));
|
||||
static assert(!isNarrowString!(dchar[]));
|
||||
static assert(isNarrowString!(string));
|
||||
static assert(isNarrowString!(wstring));
|
||||
static assert(!isNarrowString!(dstring));
|
||||
static assert(isNarrowString!(char[4]));
|
||||
}
|
||||
|
||||
/**
|
||||
Detect whether T is one of the built-in character types
|
||||
*/
|
||||
|
|
41
std/utf.d
41
std/utf.d
|
@ -129,7 +129,9 @@ private invariant ubyte[256] UTF8stride =
|
|||
|
||||
uint stride(in char[] s, size_t i)
|
||||
{
|
||||
return UTF8stride[s[i]];
|
||||
invariant result = UTF8stride[s[i]];
|
||||
assert(result > 0 && result <= 6);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -469,7 +471,7 @@ body
|
|||
|
||||
// Decodes one dchar from input range $(D r). Returns the decoded
|
||||
// character and the shortened range.
|
||||
dchar decodeFront(Range)(ref Range r)
|
||||
dchar decodeFront(Range)(ref Range r) if (!isSomeString!Range)
|
||||
out (result)
|
||||
{
|
||||
assert(isValidDchar(result));
|
||||
|
@ -528,6 +530,7 @@ body
|
|||
* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
|
||||
* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
||||
*/
|
||||
assert(!r.empty);
|
||||
auto u2 = r.front;
|
||||
enforce(!((u & 0xFE) == 0xC0 ||
|
||||
(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
|
||||
|
@ -597,7 +600,7 @@ unittest
|
|||
|
||||
// Decodes one dchar from input range $(D r). Returns the decoded
|
||||
// character and the shortened range.
|
||||
dchar decodeBack(Range)(ref Range r)
|
||||
dchar decodeBack(Range)(ref Range r) if (!isSomeString!Range)
|
||||
{
|
||||
enforce(!r.empty);
|
||||
Unqual!(ElementType!Range)[4] chars;
|
||||
|
@ -627,13 +630,28 @@ dchar decodeBack(Range)(ref Range r)
|
|||
return decoded;
|
||||
}
|
||||
|
||||
dchar decodeFront(Range)(ref Range r) if (isSomeString!Range)
|
||||
{
|
||||
auto result = r.front;
|
||||
r.popFront();
|
||||
return result;
|
||||
}
|
||||
|
||||
dchar decodeBack(Range)(ref Range r) if (isSomeString!Range)
|
||||
{
|
||||
auto result = r.back;
|
||||
r.popBack();
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(utf) printf("utf.decodeBack.unittest\n");
|
||||
|
||||
static string s1 = "abcd";
|
||||
string s1 = "abcd";
|
||||
auto c = decodeBack(s1);
|
||||
assert(c == cast(dchar)'d');
|
||||
|
||||
assert(s1 == "abc");
|
||||
c = decodeBack(s1);
|
||||
assert(c == cast(dchar)'c');
|
||||
|
@ -644,7 +662,7 @@ unittest
|
|||
assert(c == cast(dchar)'\u00A9');
|
||||
assert(s2 == "");
|
||||
|
||||
static string s3 = "\xE2\x89\xA0";
|
||||
string s3 = "\xE2\x89\xA0";
|
||||
c = decodeBack(s3);
|
||||
assert(c == cast(dchar)'\u2260');
|
||||
assert(s3 == "");
|
||||
|
@ -1178,7 +1196,6 @@ unittest
|
|||
assert(w == "hello");
|
||||
d = toUTF32(c);
|
||||
assert(d == "hello");
|
||||
|
||||
c = toUTF8(w);
|
||||
assert(c == "hello");
|
||||
d = toUTF32(w);
|
||||
|
@ -1238,10 +1255,16 @@ Standards: Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252
|
|||
Params:
|
||||
s = the string to be counted
|
||||
*/
|
||||
uint count(E)(const(E)[] s)
|
||||
size_t count(E)(const(E)[] s) if (isSomeChar!E && E.sizeof < 4)
|
||||
{
|
||||
//assert(isValid(s));
|
||||
return walkLength(byDchar(s));
|
||||
return walkLength(s);
|
||||
// size_t result = 0;
|
||||
// while (!s.empty)
|
||||
// {
|
||||
// ++result;
|
||||
// s.popFront();
|
||||
// }
|
||||
// return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
|
170
std/variant.d
170
std/variant.d
|
@ -66,8 +66,10 @@
|
|||
module std.variant;
|
||||
|
||||
import std.traits, std.c.string, std.typetuple, std.conv;
|
||||
import std.stdio; // for testing only
|
||||
import std.contracts; // for testing only
|
||||
version(unittest)
|
||||
{
|
||||
import std.contracts, std.stdio;
|
||||
}
|
||||
|
||||
private template maxSize(T...)
|
||||
{
|
||||
|
@ -149,9 +151,9 @@ template This2Variant(V, T...)
|
|||
|
||||
struct VariantN(size_t maxDataSize, AllowedTypesX...)
|
||||
{
|
||||
private:
|
||||
alias This2Variant!(VariantN, AllowedTypesX) AllowedTypes;
|
||||
|
||||
private:
|
||||
// Compute the largest practical size from maxDataSize
|
||||
struct SizeChecker
|
||||
{
|
||||
|
@ -253,7 +255,21 @@ private:
|
|||
alias TypeTuple!(A, ImplicitConversionTargets!(A)) AllTypes;
|
||||
foreach (T ; AllTypes)
|
||||
{
|
||||
if (targetType != typeid(T)) continue;
|
||||
if (targetType != typeid(T) &&
|
||||
targetType != typeid(const(T)))
|
||||
{
|
||||
static if (isImplicitlyConvertible!(T, immutable(T)))
|
||||
{
|
||||
if (targetType != typeid(immutable(T)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// found!!!
|
||||
static if (is(typeof(*cast(T*) target = *src)))
|
||||
{
|
||||
|
@ -363,7 +379,11 @@ private:
|
|||
case OpID.index:
|
||||
// Added allowed!(...) prompted by a bug report by Chris
|
||||
// Nicholson-Sauls.
|
||||
static if (isArray!(A) && allowed!(typeof(A.init[0])))
|
||||
static if (isStaticArray!(A) && allowed!(typeof(A.init)))
|
||||
{
|
||||
enforce(0, "Not implemented");
|
||||
}
|
||||
static if (isDynamicArray!(A) && allowed!(typeof(A.init[0])))
|
||||
{
|
||||
// array type; input and output are the same VariantN
|
||||
auto result = cast(VariantN*) parm;
|
||||
|
@ -422,7 +442,7 @@ private:
|
|||
// append a whole array to the array
|
||||
(*zis) ~= arg[0].get!(A);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -466,44 +486,35 @@ public:
|
|||
|
||||
VariantN opAssign(T)(T rhs)
|
||||
{
|
||||
assert(&this !is null); // weird bug in hashtables
|
||||
//writeln(typeid(rhs));
|
||||
static assert(allowed!(T), "Cannot store a " ~ T.stringof
|
||||
~ " in a " ~ VariantN.stringof ~ ". Valid types are "
|
||||
~ AllowedTypes.stringof);
|
||||
static if (isStaticArray!(T))
|
||||
static if (is(T : VariantN))
|
||||
{
|
||||
// Fix for Brad's bug
|
||||
auto temp = to!(DecayStaticToDynamicArray!(T))(rhs);
|
||||
return opAssign(temp);
|
||||
rhs.fptr(OpID.copyOut, &rhs.store, &this);
|
||||
}
|
||||
else static if (is(T : const(VariantN)))
|
||||
{
|
||||
static assert(false,
|
||||
"Assigning Variant objects from const Variant"
|
||||
" objects is currently not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
static if (is(T : VariantN))
|
||||
static if (T.sizeof <= size)
|
||||
{
|
||||
rhs.fptr(OpID.copyOut, &rhs.store, &this);
|
||||
}
|
||||
else static if (is(T : const(VariantN)))
|
||||
{
|
||||
static assert(false,
|
||||
"Assigning Variant objects from const Variant"
|
||||
" objects is currently not supported.");
|
||||
memcpy(&store, &rhs, rhs.sizeof);
|
||||
}
|
||||
else
|
||||
{
|
||||
static if (T.sizeof <= size)
|
||||
{
|
||||
memcpy(&store, &rhs, rhs.sizeof);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto p = new T;
|
||||
*p = rhs;
|
||||
memcpy(&store, &p, p.sizeof);
|
||||
}
|
||||
fptr = &handler!(T);
|
||||
auto p = new T;
|
||||
*p = rhs;
|
||||
memcpy(&store, &p, p.sizeof);
|
||||
}
|
||||
return this;
|
||||
fptr = &handler!(T);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns true if and only if the $(D_PARAM VariantN) object
|
||||
|
@ -575,31 +586,31 @@ public:
|
|||
return fptr(OpID.testConversion, null, &info) == 0;
|
||||
}
|
||||
|
||||
private T[] testing123(T)(T*);
|
||||
// private T[] testing123(T)(T*);
|
||||
|
||||
/**
|
||||
* A workaround for the fact that functions cannot return
|
||||
* statically-sized arrays by value. Essentially $(D_PARAM
|
||||
* DecayStaticToDynamicArray!(T[N])) is an alias for $(D_PARAM
|
||||
* T[]) and $(D_PARAM DecayStaticToDynamicArray!(T)) is an alias
|
||||
* for $(D_PARAM T).
|
||||
*/
|
||||
// /**
|
||||
// * A workaround for the fact that functions cannot return
|
||||
// * statically-sized arrays by value. Essentially $(D_PARAM
|
||||
// * DecayStaticToDynamicArray!(T[N])) is an alias for $(D_PARAM
|
||||
// * T[]) and $(D_PARAM DecayStaticToDynamicArray!(T)) is an alias
|
||||
// * for $(D_PARAM T).
|
||||
// */
|
||||
|
||||
template DecayStaticToDynamicArray(T)
|
||||
{
|
||||
static if (isStaticArray!(T))
|
||||
{
|
||||
alias typeof(testing123(&T[0])) DecayStaticToDynamicArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
alias T DecayStaticToDynamicArray;
|
||||
}
|
||||
}
|
||||
// template DecayStaticToDynamicArray(T)
|
||||
// {
|
||||
// static if (isStaticArray!(T))
|
||||
// {
|
||||
// alias typeof(testing123(&T[0])) DecayStaticToDynamicArray;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// alias T DecayStaticToDynamicArray;
|
||||
// }
|
||||
// }
|
||||
|
||||
static assert(is(DecayStaticToDynamicArray!(invariant(char)[21]) ==
|
||||
invariant(char)[]),
|
||||
DecayStaticToDynamicArray!(invariant(char)[21]).stringof);
|
||||
// static assert(is(DecayStaticToDynamicArray!(invariant(char)[21]) ==
|
||||
// invariant(char)[]),
|
||||
// DecayStaticToDynamicArray!(invariant(char)[21]).stringof);
|
||||
|
||||
/**
|
||||
* Returns the value stored in the $(D_PARAM VariantN) object,
|
||||
|
@ -609,15 +620,15 @@ public:
|
|||
* VariantException).
|
||||
*/
|
||||
|
||||
DecayStaticToDynamicArray!(T) get(T)() if (!is(T == const))
|
||||
T get(T)() if (!is(T == const))
|
||||
{
|
||||
union Buf
|
||||
{
|
||||
TypeInfo info;
|
||||
DecayStaticToDynamicArray!(T) result;
|
||||
T result;
|
||||
};
|
||||
auto p = *cast(T**) &store;
|
||||
Buf buf = { typeid(DecayStaticToDynamicArray!(T)) };
|
||||
Buf buf = { typeid(T) };
|
||||
if (fptr(OpID.get, &store, &buf))
|
||||
{
|
||||
throw new VariantException(type, typeid(T));
|
||||
|
@ -625,16 +636,16 @@ public:
|
|||
return buf.result;
|
||||
}
|
||||
|
||||
DecayStaticToDynamicArray!(T) get(T)() const if (is(T == const))
|
||||
T get(T)() const if (is(T == const))
|
||||
{
|
||||
union Buf
|
||||
{
|
||||
TypeInfo info;
|
||||
DecayStaticToDynamicArray!(Unqual!T) result;
|
||||
Unqual!T result;
|
||||
};
|
||||
auto p = *cast(T**) &store;
|
||||
Buf buf = { typeid(DecayStaticToDynamicArray!(T)) };
|
||||
if (fptr(OpID.get, cast(Unqual!(typeof(&store))) &store, &buf))
|
||||
Buf buf = { typeid(T) };
|
||||
if (fptr(OpID.get, cast(typeof(&store)) &store, &buf))
|
||||
{
|
||||
throw new VariantException(type, typeid(T));
|
||||
}
|
||||
|
@ -1103,30 +1114,31 @@ static class VariantException : Exception
|
|||
|
||||
unittest
|
||||
{
|
||||
// alias This2Variant!(char, int, This[int]) W1;
|
||||
// alias TypeTuple!(int, char[int]) W2;
|
||||
// static assert(is(W1 == W2));
|
||||
alias This2Variant!(char, int, This[int]) W1;
|
||||
alias TypeTuple!(int, char[int]) W2;
|
||||
static assert(is(W1 == W2));
|
||||
|
||||
// alias Algebraic!(void, string) var_t;
|
||||
// var_t foo = "quux";
|
||||
alias Algebraic!(void, string) var_t;
|
||||
var_t foo = "quux";
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
// @@@BUG@@@
|
||||
// alias Algebraic!(real, This[], This[int], This[This]) A;
|
||||
// A v1, v2, v3;
|
||||
// v2 = 5.0L;
|
||||
// v3 = 42.0L;
|
||||
// //v1 = [ v2 ][];
|
||||
// auto v = v1.peek!(A[]);
|
||||
//writeln(v[0]);
|
||||
//v1 = [ 9 : v3 ];
|
||||
// //writeln(v[0]);
|
||||
// v1 = [ 9 : v3 ];
|
||||
// //writeln(v1);
|
||||
// v1 = [ v3 : v3 ];
|
||||
//writeln(v1);
|
||||
// //writeln(v1);
|
||||
}
|
||||
|
||||
version(none) unittest
|
||||
unittest
|
||||
{
|
||||
// try it with an oddly small size
|
||||
VariantN!(1) test;
|
||||
|
@ -1224,8 +1236,15 @@ unittest
|
|||
assert( v.get!(string) == "Hello, World!" );
|
||||
|
||||
v = [1,2,3,4,5];
|
||||
assert( v.peek!(int[]) );
|
||||
assert( v.get!(int[]) == [1,2,3,4,5] );
|
||||
assert( v.peek!(int[5]) );
|
||||
assert( v.get!(int[5]) == [1,2,3,4,5] );
|
||||
|
||||
{
|
||||
// @@@BUG@@@: array literals should have type T[], not T[5] (I guess)
|
||||
// v = [1,2,3,4,5];
|
||||
// assert( v.peek!(int[]) );
|
||||
// assert( v.get!(int[]) == [1,2,3,4,5] );
|
||||
}
|
||||
|
||||
v = 3.1413;
|
||||
assert( v.peek!(double) );
|
||||
|
@ -1303,6 +1322,9 @@ unittest
|
|||
assert( hash[v2] == 1 );
|
||||
assert( hash[v3] == 2 );
|
||||
}
|
||||
/+
|
||||
// @@@BUG@@@
|
||||
// dmd: mtype.c:3886: StructDeclaration* TypeAArray::getImpl(): Assertion `impl' failed.
|
||||
{
|
||||
int[char[]] hash;
|
||||
hash["a"] = 1;
|
||||
|
@ -1314,6 +1336,7 @@ unittest
|
|||
assert( vhash.get!(int[char[]])["b"] == 2 );
|
||||
assert( vhash.get!(int[char[]])["c"] == 3 );
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -1359,7 +1382,9 @@ unittest
|
|||
unittest
|
||||
{
|
||||
const x = Variant(42);
|
||||
auto y = x.get!(const int)();
|
||||
auto y1 = x.get!(const int)();
|
||||
// @@@BUG@@@
|
||||
//auto y2 = x.get!(immutable int)();
|
||||
}
|
||||
|
||||
// test iteration
|
||||
|
@ -1371,4 +1396,5 @@ unittest
|
|||
{
|
||||
assert(i == ++j);
|
||||
}
|
||||
assert(j == 4);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue