mirror of
https://github.com/dlang/phobos.git
synced 2025-05-06 19:16:13 +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
|
unittest
|
||||||
{
|
{
|
||||||
|
scope(failure) writeln("Unittest failed at line ", __LINE__);
|
||||||
int[] arr1 = [ 1, 2, 3, 4 ];
|
int[] arr1 = [ 1, 2, 3, 4 ];
|
||||||
int[] arr2 = [ 5, 6 ];
|
int[] arr2 = [ 5, 6 ];
|
||||||
auto squares = map!("a * a")(arr1);
|
auto squares = map!("a * a")(arr1);
|
||||||
|
@ -319,7 +320,7 @@ unittest
|
||||||
a = [ 1, 2, 3, 4, 5 ];
|
a = [ 1, 2, 3, 4, 5 ];
|
||||||
// Stringize with commas
|
// Stringize with commas
|
||||||
string rep = reduce!("a ~ `, ` ~ to!(string)(b)")("", a);
|
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
|
unittest
|
||||||
|
@ -529,6 +530,14 @@ unittest
|
||||||
assert(s21.a == 1 && s21.b == null && s22.a == 10 && s22.b != null);
|
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
|
// moveAll
|
||||||
/**
|
/**
|
||||||
For each element $(D a) in $(D src) and each element $(D b) in $(D
|
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)
|
struct Splitter(Range, Separator)
|
||||||
|
if (!is(typeof(ElementType!Range.init == Separator.init)))
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Range _input;
|
Range _input;
|
||||||
|
@ -675,17 +685,8 @@ private:
|
||||||
size_t _frontLength = size_t.max;
|
size_t _frontLength = size_t.max;
|
||||||
static if (isBidirectionalRange!Range)
|
static if (isBidirectionalRange!Range)
|
||||||
size_t _backLength = size_t.max;
|
size_t _backLength = size_t.max;
|
||||||
enum bool separatorIsRange =
|
|
||||||
!is(typeof(ElementType!Range.init == _separator));
|
|
||||||
|
|
||||||
static if (separatorIsRange)
|
size_t separatorLength() { return _separator.length; }
|
||||||
{
|
|
||||||
size_t separatorLength() { return _separator.length; }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enum size_t separatorLength = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ensureFrontLength()
|
void ensureFrontLength()
|
||||||
{
|
{
|
||||||
|
@ -693,24 +694,21 @@ private:
|
||||||
assert(!_input.empty);
|
assert(!_input.empty);
|
||||||
// compute front length
|
// compute front length
|
||||||
_frontLength = _input.length - find(_input, _separator).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()
|
void ensureBackLength()
|
||||||
{
|
{
|
||||||
if (_backLength != _backLength.max) return;
|
static if (isBidirectionalRange!Range)
|
||||||
|
if (_backLength != _backLength.max) return;
|
||||||
assert(!_input.empty);
|
assert(!_input.empty);
|
||||||
// compute back length
|
// compute back length
|
||||||
static if (separatorIsRange)
|
static if (isBidirectionalRange!Range)
|
||||||
{
|
{
|
||||||
_backLength = _input.length -
|
_backLength = _input.length -
|
||||||
find(retro(_input), retro(_separator)).length;
|
find(retro(_input), retro(_separator)).length;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_backLength = _input.length -
|
|
||||||
find(retro(_input), _separator).length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -741,7 +739,8 @@ public:
|
||||||
// done, there's no separator in sight
|
// done, there's no separator in sight
|
||||||
_input = _input[_frontLength .. _frontLength];
|
_input = _input[_frontLength .. _frontLength];
|
||||||
_frontLength = _frontLength.max;
|
_frontLength = _frontLength.max;
|
||||||
_backLength = _backLength.max;
|
static if (isBidirectionalRange!Range)
|
||||||
|
_backLength = _backLength.max;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_frontLength + separatorLength == _input.length)
|
if (_frontLength + separatorLength == _input.length)
|
||||||
|
@ -750,7 +749,8 @@ public:
|
||||||
// an empty item right after this.
|
// an empty item right after this.
|
||||||
_input = _input[_input.length .. _input.length];
|
_input = _input[_input.length .. _input.length];
|
||||||
_frontLength = 0;
|
_frontLength = 0;
|
||||||
_backLength = 0;
|
static if (isBidirectionalRange!Range)
|
||||||
|
_backLength = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Normal case, pop one item and the separator, get ready for
|
// Normal case, pop one item and the separator, get ready for
|
||||||
|
@ -761,36 +761,124 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bidirectional functionality as suggested by Brad Roberts.
|
// 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()
|
Range back()
|
||||||
{
|
{
|
||||||
ensureBackLength;
|
if (_backLength == _backLength.max)
|
||||||
return _input[_input.length - _backLength .. _input.length];
|
{
|
||||||
|
while (!_input.empty && _input.back == _separator) _input.popBack();
|
||||||
|
computeBack();
|
||||||
|
}
|
||||||
|
assert(_backLength <= _input.length, text(_backLength));
|
||||||
|
return _input[$ - _backLength .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack()
|
void popBack()
|
||||||
{
|
{
|
||||||
ensureBackLength;
|
computeBack();
|
||||||
if (_backLength == _input.length)
|
enforce(_backLength <= _input.length);
|
||||||
{
|
_input = _input[0 .. $ - _backLength];
|
||||||
// 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;
|
_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
|
/// Ditto
|
||||||
|
@ -824,8 +912,9 @@ unittest
|
||||||
}
|
}
|
||||||
assert(i == w.length);
|
assert(i == w.length);
|
||||||
// Now go back
|
// Now go back
|
||||||
//auto s = splitter(a, 0);
|
auto s2 = splitter(a, 0);
|
||||||
foreach_reverse (e; splitter(a, 0))
|
|
||||||
|
foreach_reverse (e; s2)
|
||||||
{
|
{
|
||||||
assert(i > 0);
|
assert(i > 0);
|
||||||
assert(equal(e, w[--i]), text(e));
|
assert(equal(e, w[--i]), text(e));
|
||||||
|
@ -1415,7 +1504,7 @@ is ignored.
|
||||||
&& needle[virtual_begin - 1] == needle[$ - portion - 1])
|
&& needle[virtual_begin - 1] == needle[$ - portion - 1])
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
invariant delta = portion - ignore;
|
immutable delta = portion - ignore;
|
||||||
return equal(needle[needle.length - delta .. needle.length],
|
return equal(needle[needle.length - delta .. needle.length],
|
||||||
needle[virtual_begin .. virtual_begin + delta]);
|
needle[virtual_begin .. virtual_begin + delta]);
|
||||||
}
|
}
|
||||||
|
@ -1475,7 +1564,7 @@ public:
|
||||||
/// Ditto
|
/// Ditto
|
||||||
BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder
|
BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder
|
||||||
(alias pred = "a == b", Range)
|
(alias pred = "a == b", Range)
|
||||||
(Range needle) if (isRandomAccessRange!(Range))
|
(Range needle) if (isRandomAccessRange!(Range) || isSomeString!Range)
|
||||||
{
|
{
|
||||||
return typeof(return)(needle);
|
return typeof(return)(needle);
|
||||||
}
|
}
|
||||||
|
@ -2405,13 +2494,18 @@ struct Levenshtein(Range, alias equals, CostType = size_t)
|
||||||
|
|
||||||
CostType distance(Range s, Range 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)
|
foreach (i; 1 .. rows)
|
||||||
{
|
{
|
||||||
|
auto sfront = s.front;
|
||||||
|
s.popFront();
|
||||||
|
auto tt = t;
|
||||||
foreach (j; 1 .. cols)
|
foreach (j; 1 .. cols)
|
||||||
{
|
{
|
||||||
auto cSub = _matrix[i - 1][j - 1]
|
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 cIns = _matrix[i][j - 1] + _insertionIncrement;
|
||||||
auto cDel = _matrix[i - 1][j] + _deletionIncrement;
|
auto cDel = _matrix[i - 1][j] + _deletionIncrement;
|
||||||
switch (min_index(cSub, cIns, cDel)) {
|
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)
|
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)
|
size_t levenshteinDistance(alias equals = "a == b", Range1, Range2)
|
||||||
(Range1 s, Range2 t)
|
(Range1 s, Range2 t)
|
||||||
if (isRandomAccessRange!(Range1) && isRandomAccessRange!(Range2))
|
if (isForwardRange!(Range1) && isForwardRange!(Range2))
|
||||||
{
|
{
|
||||||
Levenshtein!(Range1, binaryFun!(equals), uint) lev;
|
Levenshtein!(Range1, binaryFun!(equals), uint) lev;
|
||||||
return lev.distance(s, t);
|
return lev.distance(s, t);
|
||||||
|
@ -2549,7 +2643,7 @@ assert(equals(p.field[1], "nrrnsnnn"));
|
||||||
Tuple!(size_t, EditOp[])
|
Tuple!(size_t, EditOp[])
|
||||||
levenshteinDistanceAndPath(alias equals = "a == b", Range1, Range2)
|
levenshteinDistanceAndPath(alias equals = "a == b", Range1, Range2)
|
||||||
(Range1 s, Range2 t)
|
(Range1 s, Range2 t)
|
||||||
if (isRandomAccessRange!(Range1) && isRandomAccessRange!(Range2))
|
if (isForwardRange!(Range1) && isForwardRange!(Range2))
|
||||||
{
|
{
|
||||||
Levenshtein!(Range, binaryFun!(equals)) lev;
|
Levenshtein!(Range, binaryFun!(equals)) lev;
|
||||||
auto d = lev.distance(s, t);
|
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
|
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
|
range $(D a) that satisfy predicate $(D pred) to range $(D b), you may
|
||||||
want to use $(D copy(filter!(pred)(a), b)).
|
want to use $(D copy(filter!(pred)(a), b)).
|
||||||
|
|
||||||
|
@ -2699,7 +2793,7 @@ assert(arr == [ 3, 2, 1 ]);
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
void reverse(Range)(Range r)
|
void reverse(Range)(Range r)
|
||||||
//if (isBidirectionalRange!(Range) && hasSwappableElements!(Range))
|
if (isBidirectionalRange!(Range) && hasSwappableElements!(Range))
|
||||||
{
|
{
|
||||||
while (!r.empty)
|
while (!r.empty)
|
||||||
{
|
{
|
||||||
|
|
184
std/array.d
184
std/array.d
|
@ -15,7 +15,7 @@ module std.array;
|
||||||
import std.c.stdio;
|
import std.c.stdio;
|
||||||
import core.memory;
|
import core.memory;
|
||||||
import std.algorithm, std.contracts, std.conv, std.encoding, std.range,
|
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;
|
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
|
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 "
|
assert(a.length, "Attempting to popFront() past the end of an array of "
|
||||||
~ T.stringof);
|
~ T.stringof);
|
||||||
|
@ -203,6 +203,25 @@ unittest
|
||||||
assert(a == [ 2, 3 ]);
|
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
|
Implements the range interface primitive $(D popBack) for built-in
|
||||||
arrays. Due to the fact that nonmember functions can be called with
|
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
|
unittest
|
||||||
{
|
{
|
||||||
|
@ -232,6 +255,63 @@ unittest
|
||||||
assert(a == [ 1, 2 ]);
|
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
|
Implements the range interface primitive $(D front) for built-in
|
||||||
arrays. Due to the fact that nonmember functions can be called with
|
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");
|
assert(a.length, "Attempting to fetch the front of an empty array");
|
||||||
return a[0];
|
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
|
/// 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
|
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
|
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.
|
Appends one item to the managed array.
|
||||||
*/
|
*/
|
||||||
void put(U)(U item) if (isImplicitlyConvertible!(U, T) ||
|
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
|
// 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
|
else
|
||||||
{
|
{
|
||||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
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
|
// Should do in-place construction here
|
||||||
pArray.ptr[pArray.length] = item;
|
pArray.ptr[len] = item;
|
||||||
*pArray = pArray.ptr[0 .. pArray.length + 1];
|
*pArray = pArray.ptr[0 .. len + 1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -550,34 +681,21 @@ Appends one item to the managed array.
|
||||||
Appends an entire range to the managed array.
|
Appends an entire range to the managed array.
|
||||||
*/
|
*/
|
||||||
void put(Range)(Range items) if (isForwardRange!Range
|
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(*pArray ~= items)))
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||||
*pArray ~= items;
|
*pArray ~= items;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//pragma(msg, Range.stringof);
|
||||||
// Generic input range
|
// 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+/";
|
immutable array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of bytes needed to encode a string of length slen.
|
* 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");
|
assert(encode("all your base64 are belong to foo") == "YWxsIHlvdXIgYmFzZTY0IGFyZSBiZWxvbmcgdG8gZm9v");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of bytes needed to decode an encoded string of this
|
* Returns the number of bytes needed to decode an encoded string of this
|
||||||
* length.
|
* length.
|
||||||
|
@ -173,7 +171,6 @@ uint decodeLength(uint elen)
|
||||||
return elen / 4 * 3;
|
return elen / 4 * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes str[] and places the result in buf[].
|
* Decodes str[] and places the result in buf[].
|
||||||
* Params:
|
* Params:
|
||||||
|
@ -203,7 +200,8 @@ body
|
||||||
uint arrayIndex(char ch)
|
uint arrayIndex(char ch)
|
||||||
out(result)
|
out(result)
|
||||||
{
|
{
|
||||||
assert(ch == array[result]);
|
//@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=3667");
|
||||||
|
//assert(ch == array[result]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
|
@ -221,7 +219,6 @@ body
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!estr.length)
|
if(!estr.length)
|
||||||
return buf[0 .. 0];
|
return buf[0 .. 0];
|
||||||
|
|
||||||
|
|
|
@ -710,7 +710,7 @@ string decimal(Big b)
|
||||||
b = t.q;
|
b = t.q;
|
||||||
result ~= cast(char)(t.r + '0');
|
result ~= cast(char)(t.r + '0');
|
||||||
}
|
}
|
||||||
reverse(result);
|
reverse(cast(ubyte[]) result);
|
||||||
return assumeUnique(result);
|
return assumeUnique(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,8 @@ invariant(T[U]) assumeUnique(T, U)(ref T[U] array)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
// @@@BUG@@@
|
||||||
|
version(none) unittest
|
||||||
{
|
{
|
||||||
int[string] arr = ["a":1];
|
int[string] arr = ["a":1];
|
||||||
auto arr1 = assumeUnique(arr);
|
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
|
separator, and right bracket are configurable. Each element is
|
||||||
converted by calling $(D to!T).
|
converted by calling $(D to!T).
|
||||||
*/
|
*/
|
||||||
T to(T, S)(S s, in T leftBracket = "[", in T separator = ", ",
|
T to(T, S)(S s, in T leftBracket = "", in T separator = " ",
|
||||||
in T rightBracket = "]")
|
in T rightBracket = "")
|
||||||
if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
||||||
{
|
{
|
||||||
alias Unqual!(ElementType!(T)) Char;
|
alias Unqual!(typeof(T.init[0])) Char;
|
||||||
// array-to-string conversion
|
// array-to-string conversion
|
||||||
static if (is(S == void[])
|
static if (is(S == void[])
|
||||||
|| is(S == const(void)[]) || is(S == invariant(void)[])) {
|
|| is(S == const(void)[]) || is(S == invariant(void)[])) {
|
||||||
|
@ -171,7 +171,7 @@ if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
||||||
result.put(leftBracket);
|
result.put(leftBracket);
|
||||||
foreach (i, e; s) {
|
foreach (i, e; s) {
|
||||||
if (i) result.put(separator);
|
if (i) result.put(separator);
|
||||||
result.put(to!(T)(e));
|
result.put(to!T(e));
|
||||||
}
|
}
|
||||||
result.put(rightBracket);
|
result.put(rightBracket);
|
||||||
return cast(T) result.data;
|
return cast(T) result.data;
|
||||||
|
@ -180,11 +180,13 @@ if (isSomeString!(T) && !isSomeString!(S) && isArray!(S))
|
||||||
|
|
||||||
unittest
|
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 ];
|
double[2] a = [ 1.5, 2.5 ];
|
||||||
//writeln(to!string(a));
|
//writeln(to!string(a));
|
||||||
assert(to!string(a) == "[1.5, 2.5]");
|
assert(to!string(a) == "1.5 2.5");
|
||||||
short[] b = [ 1, 3, 5 ];
|
|
||||||
assert(to!string(b) == "[1, 3, 5]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,7 +198,7 @@ T to(T, S)(S s, in T leftBracket = "[", in T keyval = ":",
|
||||||
in T separator = ", ", in T rightBracket = "]")
|
in T separator = ", ", in T rightBracket = "]")
|
||||||
if (isAssociativeArray!(S) && isSomeString!(T))
|
if (isAssociativeArray!(S) && isSomeString!(T))
|
||||||
{
|
{
|
||||||
alias Unqual!(ElementType!(T)) Char;
|
alias Unqual!(typeof(T.init[0])) Char;
|
||||||
Appender!(Char[]) result;
|
Appender!(Char[]) result;
|
||||||
// hash-to-string conversion
|
// hash-to-string conversion
|
||||||
result.put(leftBracket);
|
result.put(leftBracket);
|
||||||
|
@ -261,7 +263,7 @@ if (is(S == struct) && isSomeString!(T) && !is(typeof(&S.init.toString)))
|
||||||
{
|
{
|
||||||
// ok, attempt to forge the tuple
|
// ok, attempt to forge the tuple
|
||||||
t = cast(typeof(t)) &s;
|
t = cast(typeof(t)) &s;
|
||||||
alias Unqual!(ElementType!(T)) Char;
|
alias Unqual!(typeof(T.init[0])) Char;
|
||||||
Appender!(Char[]) app;
|
Appender!(Char[]) app;
|
||||||
app.put(left);
|
app.put(left);
|
||||||
foreach (i, e; t.field)
|
foreach (i, e; t.field)
|
||||||
|
@ -874,7 +876,7 @@ unittest {
|
||||||
// test array to string conversion
|
// test array to string conversion
|
||||||
foreach (T ; AllNumerics) {
|
foreach (T ; AllNumerics) {
|
||||||
auto a = [to!(T)(1), 2, 3];
|
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
|
// test enum to int conversion
|
||||||
// enum Testing { Test1, Test2 };
|
// enum Testing { Test1, Test2 };
|
||||||
|
@ -1096,13 +1098,8 @@ if (!isSomeString!Source && isFloatingPoint!Target)
|
||||||
Target parse(Target, Source)(ref Source s)
|
Target parse(Target, Source)(ref Source s)
|
||||||
if (isSomeString!Source && isFloatingPoint!Target)
|
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
|
// issue 1589
|
||||||
version (Windows)
|
//version (Windows)
|
||||||
{
|
{
|
||||||
if (icmp(s, "nan") == 0)
|
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);
|
setErrno(0);
|
||||||
char* endptr;
|
char* endptr;
|
||||||
static if (is(Target == float))
|
static if (is(Target == float))
|
||||||
auto f = strtof(sz, &endptr);
|
auto f = strtof(sz.ptr, &endptr);
|
||||||
else static if (is(Target == double))
|
else static if (is(Target == double))
|
||||||
auto f = strtod(sz, &endptr);
|
auto f = strtod(sz.ptr, &endptr);
|
||||||
else static if (is(Target == real))
|
else static if (is(Target == real))
|
||||||
auto f = strtold(sz, &endptr);
|
auto f = strtold(sz.ptr, &endptr);
|
||||||
else
|
else
|
||||||
static assert(false);
|
static assert(false);
|
||||||
if (getErrno() == ERANGE)
|
if (getErrno() == ERANGE)
|
||||||
goto Lerr;
|
goto Lerr;
|
||||||
assert(endptr);
|
assert(endptr);
|
||||||
if (endptr == sz)
|
if (endptr == sz.ptr)
|
||||||
{
|
{
|
||||||
// no progress
|
// no progress
|
||||||
goto Lerr;
|
goto Lerr;
|
||||||
}
|
}
|
||||||
s = s[endptr - sz .. $];
|
s = s[endptr - sz.ptr .. $];
|
||||||
return f;
|
return f;
|
||||||
Lerr:
|
Lerr:
|
||||||
conv_error!(Source, Target)(s);
|
conv_error!(Source, Target)(s);
|
||||||
|
@ -1573,7 +1595,6 @@ unittest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
i = to!short(errors[j]);
|
i = to!short(errors[j]);
|
||||||
printf("i = %d\n", i);
|
|
||||||
}
|
}
|
||||||
catch (Error e)
|
catch (Error e)
|
||||||
{
|
{
|
||||||
|
@ -1637,7 +1658,7 @@ unittest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
i = to!ushort(errors[j]);
|
i = to!ushort(errors[j]);
|
||||||
printf("i = %d\n", i);
|
debug(conv) printf("i = %d\n", i);
|
||||||
}
|
}
|
||||||
catch (Error e)
|
catch (Error e)
|
||||||
{
|
{
|
||||||
|
@ -1706,7 +1727,7 @@ unittest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
i = to!byte(errors[j]);
|
i = to!byte(errors[j]);
|
||||||
printf("i = %d\n", i);
|
debug(conv) printf("i = %d\n", i);
|
||||||
}
|
}
|
||||||
catch (Error e)
|
catch (Error e)
|
||||||
{
|
{
|
||||||
|
@ -1770,7 +1791,7 @@ unittest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
i = to!ubyte(errors[j]);
|
i = to!ubyte(errors[j]);
|
||||||
printf("i = %d\n", i);
|
debug(conv) printf("i = %d\n", i);
|
||||||
}
|
}
|
||||||
catch (Error e)
|
catch (Error e)
|
||||||
{
|
{
|
||||||
|
@ -2506,8 +2527,9 @@ T to(T, S)(S input)
|
||||||
if (std.typetuple.staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T)
|
if (std.typetuple.staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T)
|
||||||
{
|
{
|
||||||
Unqual!S value = input;
|
Unqual!S value = input;
|
||||||
alias Unqual!(ElementType!T) Char;
|
alias Unqual!(typeof(T.init[0])) Char;
|
||||||
static if (is(ElementType!T == const) || is(ElementType!T == immutable))
|
static if (is(typeof(T.init[0]) == const) ||
|
||||||
|
is(typeof(T.init[0]) == immutable))
|
||||||
{
|
{
|
||||||
if (value < 10)
|
if (value < 10)
|
||||||
{
|
{
|
||||||
|
@ -2522,21 +2544,23 @@ if (std.typetuple.staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T)
|
||||||
else
|
else
|
||||||
auto maxlength = (value > uint.max ? S.sizeof : uint.sizeof) * 3;
|
auto maxlength = (value > uint.max ? S.sizeof : uint.sizeof) * 3;
|
||||||
|
|
||||||
Char [] result;
|
Char[] result;
|
||||||
if (__ctfe) result = new Char[maxlength];
|
if (__ctfe)
|
||||||
|
result = new Char[maxlength];
|
||||||
else
|
else
|
||||||
result = cast(Char[])
|
result = cast(Char[])
|
||||||
GC.malloc(Char.sizeof * maxlength, GC.BlkAttr.NO_SCAN)
|
GC.malloc(Char.sizeof * maxlength, GC.BlkAttr.NO_SCAN)
|
||||||
[0 .. Char.sizeof * maxlength];
|
[0 .. Char.sizeof * maxlength];
|
||||||
|
|
||||||
uint ndigits = 0;
|
uint ndigits = 0;
|
||||||
while (value)
|
do
|
||||||
{
|
{
|
||||||
const c = cast(Char) ((value % 10) + '0');
|
const c = cast(Char) ((value % 10) + '0');
|
||||||
value /= 10;
|
value /= 10;
|
||||||
ndigits++;
|
ndigits++;
|
||||||
result[$ - ndigits] = c;
|
result[$ - ndigits] = c;
|
||||||
}
|
}
|
||||||
|
while (value);
|
||||||
return cast(T) result[$ - ndigits .. $];
|
return cast(T) result[$ - ndigits .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2544,20 +2568,22 @@ unittest
|
||||||
{
|
{
|
||||||
assert(wtext(int.max) == "2147483647"w);
|
assert(wtext(int.max) == "2147483647"w);
|
||||||
assert(wtext(int.min) == "-2147483648"w);
|
assert(wtext(int.min) == "-2147483648"w);
|
||||||
|
assert(to!string(0L) == "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// $(D char), $(D wchar), $(D dchar) to a string type.
|
/// $(D char), $(D wchar), $(D dchar) to a string type.
|
||||||
T to(T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 0
|
T to(T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 0
|
||||||
&& isSomeString!(T))
|
&& isSomeString!(T))
|
||||||
{
|
{
|
||||||
static if (ElementType!T.sizeof >= S.sizeof)
|
alias typeof(T.init[0]) Char;
|
||||||
|
static if (Char.sizeof >= S.sizeof)
|
||||||
{
|
{
|
||||||
return [ c ];
|
return [ c ];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Unqual!(ElementType!T)[] result;
|
Unqual!Char[] result;
|
||||||
encode(result, cast(dchar) c);
|
encode(result, c);
|
||||||
return cast(T) result;
|
return cast(T) result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2588,7 +2614,7 @@ if (staticIndexOf!(Unqual!S, int, long) >= 0 && isSomeString!T)
|
||||||
{
|
{
|
||||||
if (value >= 0)
|
if (value >= 0)
|
||||||
return to!T(cast(Unsigned!(S)) value);
|
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
|
// Cache read-only data only for const and immutable - mutable
|
||||||
// data is supposed to use allocation in all cases
|
// data is supposed to use allocation in all cases
|
||||||
|
|
|
@ -1749,7 +1749,7 @@ body
|
||||||
// EncoderInstance!(E).encode(c,buffer);
|
// EncoderInstance!(E).encode(c,buffer);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/**
|
/*
|
||||||
Encodes $(D c) in units of type $(D E) and writes the result to the
|
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.
|
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,
|
bool, "flHash", 1,
|
||||||
ubyte, "", 3));
|
ubyte, "", 3));
|
||||||
/* For arrays only: the trailing */
|
/* For arrays only: the trailing */
|
||||||
const(char)[] innerTrailing;
|
const(char)[] innerTrailing, trailing;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a string format specification fmt, parses a format
|
* Given a string format specification fmt, parses a format
|
||||||
|
@ -1577,6 +1577,7 @@ struct FormatInfo
|
||||||
{
|
{
|
||||||
FormatInfo result;
|
FormatInfo result;
|
||||||
if (fmt.empty) return result;
|
if (fmt.empty) return result;
|
||||||
|
scope(success) result.trailing = to!(const(char)[])(fmt);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
switch (fmt[i])
|
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;
|
Appender!(T) app;
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -2882,6 +2884,42 @@ T unformat(T, Range)(ref Range input, FormatInfo spec) if (isArray!T)
|
||||||
return app.data;
|
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)
|
private template acceptedSpecs(T)
|
||||||
{
|
{
|
||||||
static if (isIntegral!T) enum acceptedSpecs = "sdu";// + "coxX" (todo)
|
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
|
// raw read
|
||||||
enforce(input.length >= T.sizeof);
|
enforce(input.length >= T.sizeof);
|
||||||
enforce(ElementType!(Range).sizeof == 1);
|
enforce(isSomeString!Range || ElementType!(Range).sizeof == 1);
|
||||||
union X
|
union X
|
||||||
{
|
{
|
||||||
char[T.sizeof] raw;
|
ubyte[T.sizeof] raw;
|
||||||
T typed;
|
T typed;
|
||||||
}
|
}
|
||||||
X x;
|
X x;
|
||||||
foreach (i; 0 .. T.sizeof)
|
foreach (i; 0 .. T.sizeof)
|
||||||
{
|
{
|
||||||
x.raw[i] = input.front;
|
static if (isSomeString!Range)
|
||||||
input.popFront;
|
{
|
||||||
|
x.raw[i] = input[0];
|
||||||
|
input = input[1 .. $];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x.raw[i] = input.front;
|
||||||
|
input.popFront();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return x.typed;
|
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;
|
if(json.empty()) return root;
|
||||||
|
|
||||||
int depth = -1;
|
int depth = -1;
|
||||||
char next = 0;
|
dchar next = 0;
|
||||||
int line = 1, pos = 1;
|
int line = 1, pos = 1;
|
||||||
|
|
||||||
void error(string msg) {
|
void error(string msg) {
|
||||||
throw new JSONException(msg, line, pos);
|
throw new JSONException(msg, line, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
char peekChar() {
|
dchar peekChar() {
|
||||||
if(!next) {
|
if(!next) {
|
||||||
if(json.empty()) return '\0';
|
if(json.empty()) return '\0';
|
||||||
next = json.front();
|
next = json.front();
|
||||||
|
@ -84,10 +84,10 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
||||||
while(isspace(peekChar())) next = 0;
|
while(isspace(peekChar())) next = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char getChar(bool SkipWhitespace = false)() {
|
dchar getChar(bool SkipWhitespace = false)() {
|
||||||
static if(SkipWhitespace) skipWhitespace();
|
static if(SkipWhitespace) skipWhitespace();
|
||||||
|
|
||||||
char c = void;
|
dchar c = void;
|
||||||
if(next) {
|
if(next) {
|
||||||
c = next;
|
c = next;
|
||||||
next = 0;
|
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) {
|
void checkChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c) {
|
||||||
static if(SkipWhitespace) skipWhitespace();
|
static if(SkipWhitespace) skipWhitespace();
|
||||||
char c2 = getChar();
|
auto c2 = getChar();
|
||||||
static if(!CaseSensitive) c2 = cast(char)tolower(c2);
|
static if(!CaseSensitive) c2 = tolower(c2);
|
||||||
|
|
||||||
if(c2 != c) error(text("Found '", c2, "' when expecting '", c, "'."));
|
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();
|
static if(SkipWhitespace) skipWhitespace();
|
||||||
char c2 = peekChar();
|
auto c2 = peekChar();
|
||||||
static if(!CaseSensitive) c2 = cast(char)tolower(c2);
|
static if (!CaseSensitive) c2 = tolower(c2);
|
||||||
|
|
||||||
if(c2 != c) return false;
|
if(c2 != c) return false;
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ JSONValue parseJSON(T)(in T json, int maxDepth = -1) if(isInputRange!T) {
|
||||||
|
|
||||||
case '\\':
|
case '\\':
|
||||||
getChar();
|
getChar();
|
||||||
char c = getChar();
|
auto c = getChar();
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '"': str.put('"'); break;
|
case '"': str.put('"'); break;
|
||||||
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':
|
case 'u':
|
||||||
dchar val = 0;
|
dchar val = 0;
|
||||||
foreach_reverse(i; 0 .. 4) {
|
foreach_reverse(i; 0 .. 4) {
|
||||||
char hex = cast(char)toupper(getChar());
|
auto hex = toupper(getChar());
|
||||||
if(!isxdigit(hex)) error("Expecting hex character");
|
if(!isxdigit(hex)) error("Expecting hex character");
|
||||||
val += (isdigit(hex) ? hex - '0' : hex - 'A') << (4 * i);
|
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;
|
goto Next;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
char c = getChar();
|
auto c = getChar();
|
||||||
appendJSONChar(&str, c, getChar(), &error);
|
appendJSONChar(&str, c, &error);
|
||||||
goto Next;
|
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.");
|
if(maxDepth != -1 && depth > maxDepth) error("Nesting too deep.");
|
||||||
|
|
||||||
char c = getChar!true();
|
auto c = getChar!true();
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '{':
|
case '{':
|
||||||
|
@ -314,8 +315,8 @@ string toJSON(in JSONValue* root) {
|
||||||
void toString(string str) {
|
void toString(string str) {
|
||||||
json.put('"');
|
json.put('"');
|
||||||
|
|
||||||
for(int i; i != str.length; i++) {
|
foreach (dchar c; str) {
|
||||||
switch(str[i]) {
|
switch(c) {
|
||||||
case '"': json.put("\\\""); break;
|
case '"': json.put("\\\""); break;
|
||||||
case '\\': json.put("\\\\"); break;
|
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 '\r': json.put("\\r"); break;
|
||||||
case '\t': json.put("\\t"); break;
|
case '\t': json.put("\\t"); break;
|
||||||
default:
|
default:
|
||||||
appendJSONChar(&json, str[i], str[++i],
|
appendJSONChar(&json, c,
|
||||||
(string msg){throw new JSONException(msg);});
|
(string msg){throw new JSONException(msg);});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,23 +389,25 @@ string toJSON(in JSONValue* root) {
|
||||||
return json.data;
|
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)
|
scope void delegate(string) error)
|
||||||
{
|
{
|
||||||
int stride = UTFStride((&c)[0 .. 1], 0);
|
if(iscntrl(c)) error("Illegal control character.");
|
||||||
if(stride == 1) {
|
dst.put(c);
|
||||||
if(iscntrl(c)) error("Illegal control character.");
|
// int stride = UTFStride((&c)[0 .. 1], 0);
|
||||||
dst.put(c);
|
// if(stride == 1) {
|
||||||
}
|
// if(iscntrl(c)) error("Illegal control character.");
|
||||||
else {
|
// dst.put(c);
|
||||||
char[6] utf = void;
|
// }
|
||||||
utf[0] = c;
|
// else {
|
||||||
foreach(i; 1 .. stride) utf[i] = next;
|
// char[6] utf = void;
|
||||||
size_t index = 0;
|
// utf[0] = c;
|
||||||
if(iscntrl(toUnicode(utf[0 .. stride], index)))
|
// foreach(i; 1 .. stride) utf[i] = next;
|
||||||
error("Illegal control character");
|
// size_t index = 0;
|
||||||
dst.put(utf[0 .. stride]);
|
// 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 =
|
enum bool isRandomAccessRange =
|
||||||
(isBidirectionalRange!(R) || isInfinite!(R))
|
(isBidirectionalRange!(R) || isInfinite!(R))
|
||||||
&& is(typeof(
|
&& is(typeof(R.init[1]))
|
||||||
{
|
&& !isNarrowString!R;
|
||||||
R r;
|
|
||||||
auto e = r[1]; // can index
|
|
||||||
}()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -295,9 +292,9 @@ unittest
|
||||||
{
|
{
|
||||||
enum XYZ : string { a = "foo" };
|
enum XYZ : string { a = "foo" };
|
||||||
auto x = front(XYZ.a);
|
auto x = front(XYZ.a);
|
||||||
static assert(is(ElementType!(XYZ) : char));
|
static assert(is(ElementType!(XYZ) : dchar));
|
||||||
immutable char[3] a = "abc";
|
immutable char[3] a = "abc";
|
||||||
static assert(is(ElementType!(typeof(a)) : char));
|
static assert(is(ElementType!(typeof(a)) : dchar));
|
||||||
int[] i;
|
int[] i;
|
||||||
static assert(is(ElementType!(typeof(i)) : int));
|
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!(const(int)[]));
|
static assert(!hasSwappableElements!(const(int)[]));
|
||||||
static assert(hasSwappableElements!(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)
|
template hasLength(R)
|
||||||
{
|
{
|
||||||
enum bool hasLength = is(typeof(R.init.length) : ulong);
|
enum bool hasLength = is(typeof(R.init.length) : ulong) &&
|
||||||
|
!isNarrowString!R;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
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)
|
size_t walkLength(Range)(Range range, size_t upTo = size_t.max)
|
||||||
if (isInputRange!(Range))
|
if (isInputRange!(Range))
|
||||||
{
|
{
|
||||||
static if (hasLength!(Range))
|
static if (isRandomAccessRange!Range && hasLength!Range)
|
||||||
{
|
{
|
||||||
return range.length;
|
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).
|
is a random access range and if $(D R) defines $(D R.length).
|
||||||
*/
|
*/
|
||||||
static if (isRandomAccessRange!(R) && hasLength!(R))
|
static if (isRandomAccessRange!(R) && hasLength!(R))
|
||||||
ref ElementType!(R) opIndex(uint n)
|
ref ElementType!R opIndex(uint n)
|
||||||
{
|
{
|
||||||
return _input[_input.length - n - 1];
|
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
|
range. Forwards to $(D _input.length) and is defined only if $(D
|
||||||
hasLength!(R)).
|
hasLength!(R)).
|
||||||
*/
|
*/
|
||||||
static if (hasLength!(R))
|
static if (hasLength!R || isNarrowString!R)
|
||||||
size_t length()
|
size_t length()
|
||||||
{
|
{
|
||||||
return _input.length;
|
return _input.length;
|
||||||
|
@ -1180,7 +1178,7 @@ offers random access and $(D length), $(D Take) offers them as well.
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
|
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.length == 5);
|
||||||
assert(s[4] == 5);
|
assert(s[4] == 5);
|
||||||
assert(equal(s, [ 1, 2, 3, 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))
|
struct Take(R) if (isInputRange!(R))
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
size_t _maxAvailable;
|
|
||||||
R _input;
|
R _input;
|
||||||
|
size_t _maxAvailable;
|
||||||
enum bool byRef = is(typeof(&(R.init[0])));
|
enum bool byRef = is(typeof(&(R.init[0])));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1293,20 +1291,18 @@ public:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Take opSlice() { return this; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
/// 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
|
unittest
|
||||||
{
|
{
|
||||||
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
|
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.length == 5);
|
||||||
assert(s[4] == 5);
|
assert(s[4] == 5);
|
||||||
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
|
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
|
||||||
|
@ -1394,7 +1390,7 @@ unittest
|
||||||
/**
|
/**
|
||||||
Repeats one value forever. Example:
|
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
|
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,
|
Replicates $(D value) exactly $(D n) times. Equivalent to $(D
|
||||||
repeat(value))).
|
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
|
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:
|
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.
|
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
|
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 ];
|
int[3] a = [ 1, 2, 3 ];
|
||||||
static assert(isStaticArray!(typeof(a)));
|
static assert(isStaticArray!(typeof(a)));
|
||||||
auto c = cycle(a);
|
auto c = cycle(a);
|
||||||
assert(a.ptr == c._ptr);
|
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]
|
// 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);
|
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
|
||||||
// print the first 10 Fibonacci numbers
|
// 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
|
// 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)
|
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);
|
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
|
||||||
int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
|
int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
|
||||||
//foreach (e; take(10, fib)) writeln(e);
|
//foreach (e; take(fib, 10)) writeln(e);
|
||||||
assert(equal(take(10, fib), witness));
|
assert(equal(take(fib, 10), witness));
|
||||||
foreach (e; take(10, fib)) {}//writeln(e);
|
foreach (e; take(fib, 10)) {}//writeln(e);
|
||||||
//writeln(s.front);
|
//writeln(s.front);
|
||||||
auto fact = recurrence!("n * a[n-1]")(1);
|
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][]) );
|
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.);
|
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]",
|
// alias Sequence!("a.field[0] += a.field[1]",
|
||||||
// Tuple!(int, int)) Gen;
|
// Tuple!(int, int)) Gen;
|
||||||
// Gen x = Gen(tuple(0, 5));
|
// Gen x = Gen(tuple(0, 5));
|
||||||
// foreach (e; take(15, x))
|
// foreach (e; take(x, 15))
|
||||||
// {}//writeln(e);
|
// {}//writeln(e);
|
||||||
|
|
||||||
auto y = Sequence!("a.field[0] + n * a.field[1]", Tuple!(int, int))
|
auto y = Sequence!("a.field[0] + n * a.field[1]", Tuple!(int, int))
|
||||||
(tuple(0, 4));
|
(tuple(0, 4));
|
||||||
//@@BUG
|
//@@BUG
|
||||||
//auto y = sequence!("a.field[0] + n * a.field[1]")(0, 4);
|
//auto y = sequence!("a.field[0] + n * a.field[1]")(0, 4);
|
||||||
//foreach (e; take(15, y))
|
//foreach (e; take(y, 15))
|
||||||
{}//writeln(e);
|
{}//writeln(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2163,9 +2159,8 @@ if (is(typeof((E.init - B.init) + 1 * S.init)))
|
||||||
"; count=", count));
|
"; count=", count));
|
||||||
assert(!myless(count * step, end - begin), text("begin=", begin,
|
assert(!myless(count * step, end - begin), text("begin=", begin,
|
||||||
"; end=", end, "; step=", step, "; count=", count));
|
"; end=", end, "; step=", step, "; count=", count));
|
||||||
return typeof(return)(count,
|
return typeof(return)(typeof(return).Source(
|
||||||
typeof(return).Source(
|
Tuple!(CommonType!(B, E), S)(begin, step), 0u), count);
|
||||||
Tuple!(CommonType!(B, E), S)(begin, step), 0u));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
/// Ditto
|
||||||
|
|
129
std/regex.d
129
std/regex.d
|
@ -1516,7 +1516,7 @@ Returns the number of parenthesized captures
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
/// Ditto
|
||||||
Regex!(Unqual!(ElementType!(String))) regex(String)
|
Regex!(Unqual!(typeof(String.init[0]))) regex(String)
|
||||||
(String pattern, string flags = null)
|
(String pattern, string flags = null)
|
||||||
{
|
{
|
||||||
return typeof(return)(pattern, flags);
|
return typeof(return)(pattern, flags);
|
||||||
|
@ -1528,9 +1528,9 @@ stores the matching state and can be inspected and iterated.
|
||||||
*/
|
*/
|
||||||
struct RegexMatch(Range = string)
|
struct RegexMatch(Range = string)
|
||||||
{
|
{
|
||||||
alias .ElementType!(Range) E;
|
alias typeof(Range.init[0]) E;
|
||||||
// Engine
|
// Engine
|
||||||
alias .Regex!(Unqual!(.ElementType!(Range))) Regex;
|
alias .Regex!(Unqual!E) Regex;
|
||||||
private alias Regex.regmatch_t regmatch_t;
|
private alias Regex.regmatch_t regmatch_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1623,34 +1623,35 @@ void main()
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
uint i;
|
// @@@BUG@@@ This doesn't work if a client module uses -unittest
|
||||||
foreach(m; match(to!(Range)("abcabcabab"), regex(to!(Range)("ab"))))
|
// uint i;
|
||||||
{
|
// foreach (m; match(to!(Range)("abcabcabab"), regex(to!(Range)("ab"))))
|
||||||
++i;
|
// {
|
||||||
assert(m.hit == "ab");
|
// ++i;
|
||||||
//writefln("%s[%s]%s", m.pre, m.hit, m.post);
|
// assert(m.hit == "ab");
|
||||||
}
|
// //writefln("%s[%s]%s", m.pre, m.hit, m.post);
|
||||||
assert(i == 4);
|
// }
|
||||||
|
// assert(i == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
// @@@
|
// @@@BUG@@@ This doesn't work if a client module uses -unittest
|
||||||
debug(regex) printf("regex.search.unittest()\n");
|
// debug(regex) printf("regex.search.unittest()\n");
|
||||||
|
|
||||||
int i;
|
// int i;
|
||||||
//foreach(m; RegexMatch("ab").search("abcabcabab"))
|
// //foreach(m; RegexMatch("ab").search("abcabcabab"))
|
||||||
foreach(m; .match("abcabcabab", regex("ab")))
|
// foreach(m; .match("abcabcabab", regex("ab")))
|
||||||
{
|
// {
|
||||||
auto s = std.string.format("%s[%s]%s", m.pre, m.hit, m.post);
|
// auto s = std.string.format("%s[%s]%s", m.pre, m.hit, m.post);
|
||||||
if (i == 0) assert(s == "[ab]cabcabab");
|
// if (i == 0) assert(s == "[ab]cabcabab");
|
||||||
else if (i == 1) assert(s == "abc[ab]cabab");
|
// else if (i == 1) assert(s == "abc[ab]cabab");
|
||||||
else if (i == 2) assert(s == "abcabc[ab]ab");
|
// else if (i == 2) assert(s == "abcabc[ab]ab");
|
||||||
else if (i == 3) assert(s == "abcabcab[ab]");
|
// else if (i == 3) assert(s == "abcabcab[ab]");
|
||||||
else assert(0);
|
// else assert(0);
|
||||||
i++;
|
// i++;
|
||||||
}
|
// }
|
||||||
assert(i == 4);
|
// assert(i == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Captures
|
struct Captures
|
||||||
|
@ -1716,14 +1717,15 @@ foreach (m; match("abracadabra", "(.)a(.)"))
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
Appender!(char[]) app;
|
// @@@BUG@@@ This doesn't work if a client module uses -unittest
|
||||||
foreach (m; match("abracadabra", "(.)a(.)"))
|
// Appender!(char[]) app;
|
||||||
{
|
// foreach (m; match("abracadabra", "(.)a(.)"))
|
||||||
assert(m.captures.length == 3);
|
// {
|
||||||
foreach (c; m.captures)
|
// assert(m.captures.length == 3);
|
||||||
app.put(c), app.put(';');
|
// foreach (c; m.captures)
|
||||||
}
|
// app.put(c), app.put(';');
|
||||||
assert(app.data == "rac;r;c;dab;d;b;");
|
// }
|
||||||
|
// assert(app.data == "rac;r;c;dab;d;b;");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************
|
/*******************
|
||||||
|
@ -1821,26 +1823,6 @@ Returns $(D hit) (converted to $(D string) if necessary).
|
||||||
return result;
|
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.
|
* Test s[] starting at startindex against regular expression.
|
||||||
* Returns: 0 for no match, !=0 for match
|
* 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;
|
pmatch[0].endIdx = 0;
|
||||||
|
|
||||||
// First character optimization
|
// First character optimization
|
||||||
Unqual!(ElementType!(Range)) firstc = 0;
|
Unqual!(typeof(Range.init[0])) firstc = 0;
|
||||||
if (engine.program[0] == engine.REchar)
|
if (engine.program[0] == engine.REchar)
|
||||||
{
|
{
|
||||||
firstc = engine.program[1];
|
firstc = engine.program[1];
|
||||||
|
@ -1922,13 +1904,6 @@ Returns $(D hit) (converted to $(D string) if necessary).
|
||||||
*/
|
*/
|
||||||
//alias test opEquals;
|
//alias test opEquals;
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
//@@@
|
|
||||||
assert(!match("abc", regex(".b.")).empty);
|
|
||||||
assert(match("abc", regex(".b..")).empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool chr(ref uint si, E c)
|
private bool chr(ref uint si, E c)
|
||||||
{
|
{
|
||||||
for (; si < input.length; si++)
|
for (; si < input.length; si++)
|
||||||
|
@ -2697,6 +2672,30 @@ and, using the format string, generate and return a new string.
|
||||||
}
|
}
|
||||||
} // end of class RegexMatch
|
} // 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).
|
expression was built with the "g" option).
|
||||||
*/
|
*/
|
||||||
RegexMatch!(Range) match(Range, Engine)(Range r, Engine engine)
|
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);
|
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)
|
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);
|
return RegexMatch!(Range)(regex, input).replaceAll(format);
|
||||||
}
|
}
|
||||||
|
@ -2915,7 +2914,7 @@ struct Splitter(Range)
|
||||||
{
|
{
|
||||||
Range _input;
|
Range _input;
|
||||||
size_t _offset;
|
size_t _offset;
|
||||||
alias Regex!(Unqual!(ElementType!(Range))) Rx;
|
alias Regex!(Unqual!(typeof(Range.init[0]))) Rx;
|
||||||
// Rx _rx;
|
// Rx _rx;
|
||||||
RegexMatch!(Range) _match;
|
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;
|
module std.stdio;
|
||||||
|
|
||||||
public import core.stdc.stdio;
|
public import core.stdc.stdio;
|
||||||
|
private import std.stdiobase;
|
||||||
private import core.memory, core.stdc.errno, core.stdc.stddef,
|
private import core.memory, core.stdc.errno, core.stdc.stddef,
|
||||||
core.stdc.stdlib, core.stdc.string, core.stdc.wchar_;
|
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,
|
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.metastrings,*/ std.range, std.string, std.traits, std.typecons,
|
||||||
std.typetuple, std.utf;
|
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
|
because $(D stdin.readln(buf)) reuses (if possible) memory allocated
|
||||||
by $(D buf), whereas $(D buf = stdin.readln()) makes a new memory allocation
|
by $(D buf), whereas $(D buf = stdin.readln()) makes a new memory allocation
|
||||||
with every line. */
|
with every line. */
|
||||||
|
S readln(S = string)(dchar terminator = '\n')
|
||||||
size_t readln(ref char[] buf, dchar terminator = '\n')
|
|
||||||
{
|
{
|
||||||
enforce(p && p.handle, "Attempt to read from an unopened file.");
|
Unqual!(typeof(S.init[0]))[] buf;
|
||||||
return readlnImpl(p.handle, buf, terminator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ditto */
|
|
||||||
string readln(dchar terminator = '\n')
|
|
||||||
{
|
|
||||||
char[] buf;
|
|
||||||
readln(buf, terminator);
|
readln(buf, terminator);
|
||||||
return assumeUnique(buf);
|
return assumeUnique(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ditto */
|
unittest
|
||||||
// TODO: optimize this
|
|
||||||
size_t readln(ref wchar[] buf, dchar terminator = '\n')
|
|
||||||
{
|
{
|
||||||
string s = readln(terminator);
|
std.file.write("deleteme", "hello\nworld\n");
|
||||||
if (!s.length) return 0;
|
scope(exit) std.file.remove("deleteme");
|
||||||
buf.length = 0;
|
foreach (C; Tuple!(char, wchar, dchar).Types)
|
||||||
foreach (wchar c; s)
|
|
||||||
{
|
{
|
||||||
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;
|
return buf.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ditto */
|
unittest
|
||||||
// TODO: fold this together with wchar
|
|
||||||
size_t readln(ref dchar[] buf, dchar terminator = '\n')
|
|
||||||
{
|
{
|
||||||
string s = readln(terminator);
|
std.file.write("deleteme", "hello\n\rworld\nhow\n\rare ya");
|
||||||
if (!s.length) return 0;
|
auto witness = [ "hello\n\r", "world\nhow\n\r", "are ya" ];
|
||||||
buf.length = 0;
|
scope(exit) std.file.remove("deleteme");
|
||||||
foreach (dchar c; s)
|
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)
|
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.
|
/// Range primitive implementations.
|
||||||
void put(A)(A writeme) if (is(ElementType!A : const(dchar)))
|
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));
|
static assert(!is(C == void));
|
||||||
// writeln("typeof(A.init[0]) = ", typeof(A.init[0]),
|
// writeln("typeof(A.init[0]) = ", typeof(A.init[0]),
|
||||||
// ", ElementType!A = ", ElementType!A);
|
// ", ElementType!A = ", ElementType!A);
|
||||||
|
@ -1053,7 +1097,8 @@ $(D Range) that locks the file and allows fast writing to it.
|
||||||
|
|
||||||
void popFront()
|
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);
|
assert(!empty);
|
||||||
_crt = getc(cast(FILE*) _f.p.handle);
|
_crt = getc(cast(FILE*) _f.p.handle);
|
||||||
}
|
}
|
||||||
|
@ -1176,16 +1221,16 @@ unittest
|
||||||
scope(failure) printf("Failed test at line %d\n", __LINE__);
|
scope(failure) printf("Failed test at line %d\n", __LINE__);
|
||||||
void[] buf;
|
void[] buf;
|
||||||
write(buf);
|
write(buf);
|
||||||
// // test write
|
// test write
|
||||||
string file = "dmd-build-test.deleteme.txt";
|
string file = "dmd-build-test.deleteme.txt";
|
||||||
auto f = File(file, "w");
|
auto f = File(file, "w");
|
||||||
scope(exit) { std.file.remove(file); }
|
// scope(exit) { std.file.remove(file); }
|
||||||
f.write("Hello, ", "world number ", 42, "!");
|
f.write("Hello, ", "world number ", 42, "!");
|
||||||
f.close;
|
f.close;
|
||||||
assert(cast(char[]) std.file.read(file) == "Hello, world number 42!");
|
assert(cast(char[]) std.file.read(file) == "Hello, world number 42!");
|
||||||
// // test write on stdout
|
// // test write on stdout
|
||||||
auto saveStdout = stdout;
|
//auto saveStdout = stdout;
|
||||||
scope(exit) stdout = saveStdout;
|
//scope(exit) stdout = saveStdout;
|
||||||
//stdout.open(file, "w");
|
//stdout.open(file, "w");
|
||||||
Object obj;
|
Object obj;
|
||||||
//write("Hello, ", "world number ", 42, "! ", 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()
|
extern(C) void std_stdio_static_this()
|
||||||
{
|
{
|
||||||
//printf("std_stdio_static_this()\n");
|
|
||||||
|
|
||||||
//Bind stdin, stdout, stderr
|
//Bind stdin, stdout, stderr
|
||||||
__gshared File.Impl stdinImpl;
|
__gshared File.Impl stdinImpl;
|
||||||
stdinImpl.handle = core.stdc.stdio.stdin;
|
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)
|
S tolower(S)(S s) if (isSomeString!S)
|
||||||
{
|
{
|
||||||
|
alias typeof(s[0]) Char;
|
||||||
int changed;
|
int changed;
|
||||||
Unqual!(ElementType!S)[] r;
|
Unqual!(Char)[] r;
|
||||||
|
|
||||||
for (size_t i = 0; i < s.length; i++)
|
for (size_t i = 0; i < s.length; i++)
|
||||||
{
|
{
|
||||||
|
@ -755,7 +756,7 @@ S tolower(S)(S s) if (isSomeString!S)
|
||||||
r = s.dup;
|
r = s.dup;
|
||||||
changed = 1;
|
changed = 1;
|
||||||
}
|
}
|
||||||
r[i] = cast(Unqual!(ElementType!S)) (c + ('a' - 'A'));
|
r[i] = cast(Unqual!Char) (c + ('a' - 'A'));
|
||||||
}
|
}
|
||||||
else if (c > 0x7F)
|
else if (c > 0x7F)
|
||||||
{
|
{
|
||||||
|
@ -866,8 +867,9 @@ unittest
|
||||||
|
|
||||||
S toupper(S)(S s) if (isSomeString!S)
|
S toupper(S)(S s) if (isSomeString!S)
|
||||||
{
|
{
|
||||||
|
alias typeof(s[0]) Char;
|
||||||
int changed;
|
int changed;
|
||||||
Unqual!(ElementType!S)[] r;
|
Unqual!(Char)[] r;
|
||||||
|
|
||||||
foreach (i; 0 .. s.length)
|
foreach (i; 0 .. s.length)
|
||||||
{
|
{
|
||||||
|
@ -879,7 +881,7 @@ S toupper(S)(S s) if (isSomeString!S)
|
||||||
r = to!(typeof(r))(s);
|
r = to!(typeof(r))(s);
|
||||||
changed = 1;
|
changed = 1;
|
||||||
}
|
}
|
||||||
r[i] = cast(Unqual!(ElementType!S)) (c - ('a' - 'A'));
|
r[i] = cast(Unqual!(Char)) (c - ('a' - 'A'));
|
||||||
}
|
}
|
||||||
else if (c > 0x7F)
|
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)
|
template isSomeString(T)
|
||||||
{
|
{
|
||||||
enum isSomeString = is(T : const(char[]))
|
enum isSomeString = isNarrowString!T || is(T : const(dchar[]));
|
||||||
|| is(T : const(wchar[])) || is(T : const(dchar[]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -969,6 +968,24 @@ unittest
|
||||||
static assert(isSomeString!(char[4]));
|
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
|
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)
|
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
|
// Decodes one dchar from input range $(D r). Returns the decoded
|
||||||
// character and the shortened range.
|
// character and the shortened range.
|
||||||
dchar decodeFront(Range)(ref Range r)
|
dchar decodeFront(Range)(ref Range r) if (!isSomeString!Range)
|
||||||
out (result)
|
out (result)
|
||||||
{
|
{
|
||||||
assert(isValidDchar(result));
|
assert(isValidDchar(result));
|
||||||
|
@ -528,6 +530,7 @@ body
|
||||||
* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
|
* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
|
||||||
* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
||||||
*/
|
*/
|
||||||
|
assert(!r.empty);
|
||||||
auto u2 = r.front;
|
auto u2 = r.front;
|
||||||
enforce(!((u & 0xFE) == 0xC0 ||
|
enforce(!((u & 0xFE) == 0xC0 ||
|
||||||
(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
|
(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
|
||||||
|
@ -597,7 +600,7 @@ unittest
|
||||||
|
|
||||||
// Decodes one dchar from input range $(D r). Returns the decoded
|
// Decodes one dchar from input range $(D r). Returns the decoded
|
||||||
// character and the shortened range.
|
// character and the shortened range.
|
||||||
dchar decodeBack(Range)(ref Range r)
|
dchar decodeBack(Range)(ref Range r) if (!isSomeString!Range)
|
||||||
{
|
{
|
||||||
enforce(!r.empty);
|
enforce(!r.empty);
|
||||||
Unqual!(ElementType!Range)[4] chars;
|
Unqual!(ElementType!Range)[4] chars;
|
||||||
|
@ -627,13 +630,28 @@ dchar decodeBack(Range)(ref Range r)
|
||||||
return decoded;
|
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
|
unittest
|
||||||
{
|
{
|
||||||
debug(utf) printf("utf.decodeBack.unittest\n");
|
debug(utf) printf("utf.decodeBack.unittest\n");
|
||||||
|
|
||||||
static string s1 = "abcd";
|
string s1 = "abcd";
|
||||||
auto c = decodeBack(s1);
|
auto c = decodeBack(s1);
|
||||||
assert(c == cast(dchar)'d');
|
assert(c == cast(dchar)'d');
|
||||||
|
|
||||||
assert(s1 == "abc");
|
assert(s1 == "abc");
|
||||||
c = decodeBack(s1);
|
c = decodeBack(s1);
|
||||||
assert(c == cast(dchar)'c');
|
assert(c == cast(dchar)'c');
|
||||||
|
@ -644,7 +662,7 @@ unittest
|
||||||
assert(c == cast(dchar)'\u00A9');
|
assert(c == cast(dchar)'\u00A9');
|
||||||
assert(s2 == "");
|
assert(s2 == "");
|
||||||
|
|
||||||
static string s3 = "\xE2\x89\xA0";
|
string s3 = "\xE2\x89\xA0";
|
||||||
c = decodeBack(s3);
|
c = decodeBack(s3);
|
||||||
assert(c == cast(dchar)'\u2260');
|
assert(c == cast(dchar)'\u2260');
|
||||||
assert(s3 == "");
|
assert(s3 == "");
|
||||||
|
@ -1178,7 +1196,6 @@ unittest
|
||||||
assert(w == "hello");
|
assert(w == "hello");
|
||||||
d = toUTF32(c);
|
d = toUTF32(c);
|
||||||
assert(d == "hello");
|
assert(d == "hello");
|
||||||
|
|
||||||
c = toUTF8(w);
|
c = toUTF8(w);
|
||||||
assert(c == "hello");
|
assert(c == "hello");
|
||||||
d = toUTF32(w);
|
d = toUTF32(w);
|
||||||
|
@ -1238,10 +1255,16 @@ Standards: Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252
|
||||||
Params:
|
Params:
|
||||||
s = the string to be counted
|
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(s);
|
||||||
return walkLength(byDchar(s));
|
// size_t result = 0;
|
||||||
|
// while (!s.empty)
|
||||||
|
// {
|
||||||
|
// ++result;
|
||||||
|
// s.popFront();
|
||||||
|
// }
|
||||||
|
// return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
|
170
std/variant.d
170
std/variant.d
|
@ -66,8 +66,10 @@
|
||||||
module std.variant;
|
module std.variant;
|
||||||
|
|
||||||
import std.traits, std.c.string, std.typetuple, std.conv;
|
import std.traits, std.c.string, std.typetuple, std.conv;
|
||||||
import std.stdio; // for testing only
|
version(unittest)
|
||||||
import std.contracts; // for testing only
|
{
|
||||||
|
import std.contracts, std.stdio;
|
||||||
|
}
|
||||||
|
|
||||||
private template maxSize(T...)
|
private template maxSize(T...)
|
||||||
{
|
{
|
||||||
|
@ -149,9 +151,9 @@ template This2Variant(V, T...)
|
||||||
|
|
||||||
struct VariantN(size_t maxDataSize, AllowedTypesX...)
|
struct VariantN(size_t maxDataSize, AllowedTypesX...)
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
alias This2Variant!(VariantN, AllowedTypesX) AllowedTypes;
|
alias This2Variant!(VariantN, AllowedTypesX) AllowedTypes;
|
||||||
|
|
||||||
|
private:
|
||||||
// Compute the largest practical size from maxDataSize
|
// Compute the largest practical size from maxDataSize
|
||||||
struct SizeChecker
|
struct SizeChecker
|
||||||
{
|
{
|
||||||
|
@ -253,7 +255,21 @@ private:
|
||||||
alias TypeTuple!(A, ImplicitConversionTargets!(A)) AllTypes;
|
alias TypeTuple!(A, ImplicitConversionTargets!(A)) AllTypes;
|
||||||
foreach (T ; 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!!!
|
// found!!!
|
||||||
static if (is(typeof(*cast(T*) target = *src)))
|
static if (is(typeof(*cast(T*) target = *src)))
|
||||||
{
|
{
|
||||||
|
@ -363,7 +379,11 @@ private:
|
||||||
case OpID.index:
|
case OpID.index:
|
||||||
// Added allowed!(...) prompted by a bug report by Chris
|
// Added allowed!(...) prompted by a bug report by Chris
|
||||||
// Nicholson-Sauls.
|
// 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
|
// array type; input and output are the same VariantN
|
||||||
auto result = cast(VariantN*) parm;
|
auto result = cast(VariantN*) parm;
|
||||||
|
@ -422,7 +442,7 @@ private:
|
||||||
// append a whole array to the array
|
// append a whole array to the array
|
||||||
(*zis) ~= arg[0].get!(A);
|
(*zis) ~= arg[0].get!(A);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -466,44 +486,35 @@ public:
|
||||||
|
|
||||||
VariantN opAssign(T)(T rhs)
|
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
|
static assert(allowed!(T), "Cannot store a " ~ T.stringof
|
||||||
~ " in a " ~ VariantN.stringof ~ ". Valid types are "
|
~ " in a " ~ VariantN.stringof ~ ". Valid types are "
|
||||||
~ AllowedTypes.stringof);
|
~ AllowedTypes.stringof);
|
||||||
static if (isStaticArray!(T))
|
static if (is(T : VariantN))
|
||||||
{
|
{
|
||||||
// Fix for Brad's bug
|
rhs.fptr(OpID.copyOut, &rhs.store, &this);
|
||||||
auto temp = to!(DecayStaticToDynamicArray!(T))(rhs);
|
}
|
||||||
return opAssign(temp);
|
else static if (is(T : const(VariantN)))
|
||||||
|
{
|
||||||
|
static assert(false,
|
||||||
|
"Assigning Variant objects from const Variant"
|
||||||
|
" objects is currently not supported.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static if (is(T : VariantN))
|
static if (T.sizeof <= size)
|
||||||
{
|
{
|
||||||
rhs.fptr(OpID.copyOut, &rhs.store, &this);
|
memcpy(&store, &rhs, rhs.sizeof);
|
||||||
}
|
|
||||||
else static if (is(T : const(VariantN)))
|
|
||||||
{
|
|
||||||
static assert(false,
|
|
||||||
"Assigning Variant objects from const Variant"
|
|
||||||
" objects is currently not supported.");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static if (T.sizeof <= size)
|
auto p = new T;
|
||||||
{
|
*p = rhs;
|
||||||
memcpy(&store, &rhs, rhs.sizeof);
|
memcpy(&store, &p, p.sizeof);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto p = new T;
|
|
||||||
*p = rhs;
|
|
||||||
memcpy(&store, &p, p.sizeof);
|
|
||||||
}
|
|
||||||
fptr = &handler!(T);
|
|
||||||
}
|
}
|
||||||
return this;
|
fptr = &handler!(T);
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if and only if the $(D_PARAM VariantN) object
|
/** Returns true if and only if the $(D_PARAM VariantN) object
|
||||||
|
@ -575,31 +586,31 @@ public:
|
||||||
return fptr(OpID.testConversion, null, &info) == 0;
|
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
|
// * A workaround for the fact that functions cannot return
|
||||||
* statically-sized arrays by value. Essentially $(D_PARAM
|
// * statically-sized arrays by value. Essentially $(D_PARAM
|
||||||
* DecayStaticToDynamicArray!(T[N])) is an alias for $(D_PARAM
|
// * DecayStaticToDynamicArray!(T[N])) is an alias for $(D_PARAM
|
||||||
* T[]) and $(D_PARAM DecayStaticToDynamicArray!(T)) is an alias
|
// * T[]) and $(D_PARAM DecayStaticToDynamicArray!(T)) is an alias
|
||||||
* for $(D_PARAM T).
|
// * for $(D_PARAM T).
|
||||||
*/
|
// */
|
||||||
|
|
||||||
template DecayStaticToDynamicArray(T)
|
// template DecayStaticToDynamicArray(T)
|
||||||
{
|
// {
|
||||||
static if (isStaticArray!(T))
|
// static if (isStaticArray!(T))
|
||||||
{
|
// {
|
||||||
alias typeof(testing123(&T[0])) DecayStaticToDynamicArray;
|
// alias typeof(testing123(&T[0])) DecayStaticToDynamicArray;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
alias T DecayStaticToDynamicArray;
|
// alias T DecayStaticToDynamicArray;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
static assert(is(DecayStaticToDynamicArray!(invariant(char)[21]) ==
|
// static assert(is(DecayStaticToDynamicArray!(invariant(char)[21]) ==
|
||||||
invariant(char)[]),
|
// invariant(char)[]),
|
||||||
DecayStaticToDynamicArray!(invariant(char)[21]).stringof);
|
// DecayStaticToDynamicArray!(invariant(char)[21]).stringof);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value stored in the $(D_PARAM VariantN) object,
|
* Returns the value stored in the $(D_PARAM VariantN) object,
|
||||||
|
@ -609,15 +620,15 @@ public:
|
||||||
* VariantException).
|
* VariantException).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DecayStaticToDynamicArray!(T) get(T)() if (!is(T == const))
|
T get(T)() if (!is(T == const))
|
||||||
{
|
{
|
||||||
union Buf
|
union Buf
|
||||||
{
|
{
|
||||||
TypeInfo info;
|
TypeInfo info;
|
||||||
DecayStaticToDynamicArray!(T) result;
|
T result;
|
||||||
};
|
};
|
||||||
auto p = *cast(T**) &store;
|
auto p = *cast(T**) &store;
|
||||||
Buf buf = { typeid(DecayStaticToDynamicArray!(T)) };
|
Buf buf = { typeid(T) };
|
||||||
if (fptr(OpID.get, &store, &buf))
|
if (fptr(OpID.get, &store, &buf))
|
||||||
{
|
{
|
||||||
throw new VariantException(type, typeid(T));
|
throw new VariantException(type, typeid(T));
|
||||||
|
@ -625,16 +636,16 @@ public:
|
||||||
return buf.result;
|
return buf.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecayStaticToDynamicArray!(T) get(T)() const if (is(T == const))
|
T get(T)() const if (is(T == const))
|
||||||
{
|
{
|
||||||
union Buf
|
union Buf
|
||||||
{
|
{
|
||||||
TypeInfo info;
|
TypeInfo info;
|
||||||
DecayStaticToDynamicArray!(Unqual!T) result;
|
Unqual!T result;
|
||||||
};
|
};
|
||||||
auto p = *cast(T**) &store;
|
auto p = *cast(T**) &store;
|
||||||
Buf buf = { typeid(DecayStaticToDynamicArray!(T)) };
|
Buf buf = { typeid(T) };
|
||||||
if (fptr(OpID.get, cast(Unqual!(typeof(&store))) &store, &buf))
|
if (fptr(OpID.get, cast(typeof(&store)) &store, &buf))
|
||||||
{
|
{
|
||||||
throw new VariantException(type, typeid(T));
|
throw new VariantException(type, typeid(T));
|
||||||
}
|
}
|
||||||
|
@ -1103,30 +1114,31 @@ static class VariantException : Exception
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
// alias This2Variant!(char, int, This[int]) W1;
|
alias This2Variant!(char, int, This[int]) W1;
|
||||||
// alias TypeTuple!(int, char[int]) W2;
|
alias TypeTuple!(int, char[int]) W2;
|
||||||
// static assert(is(W1 == W2));
|
static assert(is(W1 == W2));
|
||||||
|
|
||||||
// alias Algebraic!(void, string) var_t;
|
alias Algebraic!(void, string) var_t;
|
||||||
// var_t foo = "quux";
|
var_t foo = "quux";
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
|
// @@@BUG@@@
|
||||||
// alias Algebraic!(real, This[], This[int], This[This]) A;
|
// alias Algebraic!(real, This[], This[int], This[This]) A;
|
||||||
// A v1, v2, v3;
|
// A v1, v2, v3;
|
||||||
// v2 = 5.0L;
|
// v2 = 5.0L;
|
||||||
// v3 = 42.0L;
|
// v3 = 42.0L;
|
||||||
// //v1 = [ v2 ][];
|
// //v1 = [ v2 ][];
|
||||||
// auto v = v1.peek!(A[]);
|
// auto v = v1.peek!(A[]);
|
||||||
//writeln(v[0]);
|
// //writeln(v[0]);
|
||||||
//v1 = [ 9 : v3 ];
|
// v1 = [ 9 : v3 ];
|
||||||
// //writeln(v1);
|
// //writeln(v1);
|
||||||
// v1 = [ v3 : v3 ];
|
// v1 = [ v3 : v3 ];
|
||||||
//writeln(v1);
|
// //writeln(v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
version(none) unittest
|
unittest
|
||||||
{
|
{
|
||||||
// try it with an oddly small size
|
// try it with an oddly small size
|
||||||
VariantN!(1) test;
|
VariantN!(1) test;
|
||||||
|
@ -1224,8 +1236,15 @@ unittest
|
||||||
assert( v.get!(string) == "Hello, World!" );
|
assert( v.get!(string) == "Hello, World!" );
|
||||||
|
|
||||||
v = [1,2,3,4,5];
|
v = [1,2,3,4,5];
|
||||||
assert( v.peek!(int[]) );
|
assert( v.peek!(int[5]) );
|
||||||
assert( v.get!(int[]) == [1,2,3,4,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;
|
v = 3.1413;
|
||||||
assert( v.peek!(double) );
|
assert( v.peek!(double) );
|
||||||
|
@ -1303,6 +1322,9 @@ unittest
|
||||||
assert( hash[v2] == 1 );
|
assert( hash[v2] == 1 );
|
||||||
assert( hash[v3] == 2 );
|
assert( hash[v3] == 2 );
|
||||||
}
|
}
|
||||||
|
/+
|
||||||
|
// @@@BUG@@@
|
||||||
|
// dmd: mtype.c:3886: StructDeclaration* TypeAArray::getImpl(): Assertion `impl' failed.
|
||||||
{
|
{
|
||||||
int[char[]] hash;
|
int[char[]] hash;
|
||||||
hash["a"] = 1;
|
hash["a"] = 1;
|
||||||
|
@ -1314,6 +1336,7 @@ unittest
|
||||||
assert( vhash.get!(int[char[]])["b"] == 2 );
|
assert( vhash.get!(int[char[]])["b"] == 2 );
|
||||||
assert( vhash.get!(int[char[]])["c"] == 3 );
|
assert( vhash.get!(int[char[]])["c"] == 3 );
|
||||||
}
|
}
|
||||||
|
+/
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -1359,7 +1382,9 @@ unittest
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
const x = Variant(42);
|
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
|
// test iteration
|
||||||
|
@ -1371,4 +1396,5 @@ unittest
|
||||||
{
|
{
|
||||||
assert(i == ++j);
|
assert(i == ++j);
|
||||||
}
|
}
|
||||||
|
assert(j == 4);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue