Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Hackerpilot 2013-07-13 19:37:11 +00:00
commit 6f9c22bfa9
10 changed files with 686 additions and 407 deletions

View file

@ -455,7 +455,7 @@ private struct MapResult(alias fun, Range)
} }
} }
static if (hasLength!R || isSomeString!R) static if (hasLength!R)
{ {
@property auto length() @property auto length()
{ {
@ -9949,10 +9949,7 @@ assert(!all!"a & 1"([1, 2, 3, 5, 7, 9]));
bool all(alias pred, R)(R range) bool all(alias pred, R)(R range)
if (isInputRange!R && is(typeof(unaryFun!pred(range.front)))) if (isInputRange!R && is(typeof(unaryFun!pred(range.front))))
{ {
// dmd @@@BUG9578@@@ workaround return find!(not!(unaryFun!pred))(range).empty;
// return find!(not!(unaryFun!pred))(range).empty;
bool notPred(ElementType!R a) { return !unaryFun!pred(a); }
return find!notPred(range).empty;
} }
unittest unittest

View file

@ -1577,6 +1577,9 @@ unittest
assert(tv["foobar"] == b.data); a.clear(); b.clear(); assert(tv["foobar"] == b.data); a.clear(); b.clear();
} }
// @@@9543@@@ These tests were disabled because they actually relied on the input range having length.
// The implementation (currently) doesn't support encoding/decoding from a length-less source.
version(none)
{ // with InputRange { // with InputRange
// InputRange to ubyte[] or char[] // InputRange to ubyte[] or char[]
auto encoded = Base64.encode(map!(to!(ubyte))(["20", "251", "156", "3", "217", "126"])); auto encoded = Base64.encode(map!(to!(ubyte))(["20", "251", "156", "3", "217", "126"]));

View file

@ -3911,3 +3911,130 @@ unittest
toTextRange(-1, result); toTextRange(-1, result);
assert(result.data == "-1"); assert(result.data == "-1");
} }
/**
Returns the corresponding unsigned value for $(D x) (e.g. if $(D x) has type
$(D int), it returns $(D cast(uint) x)). The advantage compared to the cast
is that you do not need to rewrite the cast if $(D x) later changes type
(e.g from $(D int) to $(D long)).
Note that the result is always mutable even if the original type was const
or immutable. In order to retain the constness, use $(XREF traits, Unsigned).
*/
auto unsigned(T)(T x) if (isIntegral!T)
{
return cast(Unqual!(Unsigned!T))x;
}
///
unittest
{
uint s = 42;
auto u1 = unsigned(s); //not qualified
Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification
immutable u3 = unsigned(s); //totally qualified
}
unittest
{
foreach(T; TypeTuple!(byte, ubyte))
{
static assert(is(typeof(unsigned(cast(T)1)) == ubyte));
static assert(is(typeof(unsigned(cast(const T)1)) == ubyte));
static assert(is(typeof(unsigned(cast(immutable T)1)) == ubyte));
}
foreach(T; TypeTuple!(short, ushort))
{
static assert(is(typeof(unsigned(cast(T)1)) == ushort));
static assert(is(typeof(unsigned(cast(const T)1)) == ushort));
static assert(is(typeof(unsigned(cast(immutable T)1)) == ushort));
}
foreach(T; TypeTuple!(int, uint))
{
static assert(is(typeof(unsigned(cast(T)1)) == uint));
static assert(is(typeof(unsigned(cast(const T)1)) == uint));
static assert(is(typeof(unsigned(cast(immutable T)1)) == uint));
}
foreach(T; TypeTuple!(long, ulong))
{
static assert(is(typeof(unsigned(cast(T)1)) == ulong));
static assert(is(typeof(unsigned(cast(const T)1)) == ulong));
static assert(is(typeof(unsigned(cast(immutable T)1)) == ulong));
}
}
auto unsigned(T)(T x) if (isSomeChar!T)
{
// All characters are unsigned
static assert(T.min == 0);
return cast(Unqual!T) x;
}
unittest
{
foreach(T; TypeTuple!(char, wchar, dchar))
{
static assert(is(typeof(unsigned(cast(T)'A')) == T));
static assert(is(typeof(unsigned(cast(const T)'A')) == T));
static assert(is(typeof(unsigned(cast(immutable T)'A')) == T));
}
}
/**
Returns the corresponding signed value for $(D x) (e.g. if $(D x) has type
$(D uint), it returns $(D cast(int) x)). The advantage compared to the cast
is that you do not need to rewrite the cast if $(D x) later changes type
(e.g from $(D uint) to $(D ulong)).
Note that the result is always mutable even if the original type was const
or immutable. In order to retain the constness, use $(XREF traits, Signed).
*/
auto signed(T)(T x) if (isIntegral!T)
{
return cast(Unqual!(Signed!T))x;
}
///
unittest
{
uint u = 42;
auto s1 = unsigned(u); //not qualified
Unsigned!(typeof(u)) s2 = unsigned(u); //same qualification
immutable s3 = unsigned(u); //totally qualified
}
unittest
{
foreach(T; TypeTuple!(byte, ubyte))
{
static assert(is(typeof(signed(cast(T)1)) == byte));
static assert(is(typeof(signed(cast(const T)1)) == byte));
static assert(is(typeof(signed(cast(immutable T)1)) == byte));
}
foreach(T; TypeTuple!(short, ushort))
{
static assert(is(typeof(signed(cast(T)1)) == short));
static assert(is(typeof(signed(cast(const T)1)) == short));
static assert(is(typeof(signed(cast(immutable T)1)) == short));
}
foreach(T; TypeTuple!(int, uint))
{
static assert(is(typeof(signed(cast(T)1)) == int));
static assert(is(typeof(signed(cast(const T)1)) == int));
static assert(is(typeof(signed(cast(immutable T)1)) == int));
}
foreach(T; TypeTuple!(long, ulong))
{
static assert(is(typeof(signed(cast(T)1)) == long));
static assert(is(typeof(signed(cast(const T)1)) == long));
static assert(is(typeof(signed(cast(immutable T)1)) == long));
}
}

View file

@ -154,7 +154,7 @@ $(I Integer):
$(I Digit): $(I Digit):
$(B '0')|$(B '1')|$(B '2')|$(B '3')|$(B '4')|$(B '5')|$(B '6')|$(B '7')|$(B '8')|$(B '9') $(B '0')|$(B '1')|$(B '2')|$(B '3')|$(B '4')|$(B '5')|$(B '6')|$(B '7')|$(B '8')|$(B '9')
$(I FormatChar): $(I FormatChar):
$(B 's')|$(B 'b')|$(B 'd')|$(B 'o')|$(B 'x')|$(B 'X')|$(B 'e')|$(B 'E')|$(B 'f')|$(B 'F')|$(B 'g')|$(B 'G')|$(B 'a')|$(B 'A') $(B 's')|$(B 'c')|$(B 'b')|$(B 'd')|$(B 'o')|$(B 'x')|$(B 'X')|$(B 'e')|$(B 'E')|$(B 'f')|$(B 'F')|$(B 'g')|$(B 'G')|$(B 'a')|$(B 'A')
) )
$(BOOKTABLE Flags affect formatting depending on the specifier as $(BOOKTABLE Flags affect formatting depending on the specifier as

View file

@ -801,8 +801,8 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
if(isUnsigned!UIntType) if(isUnsigned!UIntType)
{ {
static assert(bits == 32 || bits == 64 || bits == 96 || bits == 128 || bits == 160 || bits == 192, static assert(bits == 32 || bits == 64 || bits == 96 || bits == 128 || bits == 160 || bits == 192,
"Supporting bits are 32, 64, 96, 128, 160 and 192. " ~ to!string(bits) ~ " is not supported."); "Xorshift supports only 32, 64, 96, 128, 160 and 192 bit versions. "
~ to!string(bits) ~ " is not supported.");
public: public:
///Mark this as a Rng ///Mark this as a Rng
@ -828,11 +828,16 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123]; UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123];
else static if (bits == 160) else static if (bits == 160)
UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321]; UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321];
else else static if (bits == 192)
{ // 192bits {
UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321, 6615241]; UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321, 6615241];
UIntType value_; UIntType value_;
} }
else
{
static assert(false, "Phobos Error: Xorshift has no instantiation rule for "
~ to!string(bits) ~ " bits.");
}
public: public:
@ -887,7 +892,7 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
static if (bits == 32) static if (bits == 32)
{ {
temp = seeds_[0] ^ (seeds_[0] << a); temp = seeds_[0] ^ (seeds_[0] << a);
temp = temp >> b; temp = temp ^ (temp >> b);
seeds_[0] = temp ^ (temp << c); seeds_[0] = temp ^ (temp << c);
} }
else static if (bits == 64) else static if (bits == 64)
@ -913,15 +918,15 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
} }
else static if (bits == 160) else static if (bits == 160)
{ {
temp = seeds_[0] ^ (seeds_[0] >> a); temp = seeds_[0] ^ (seeds_[0] << a);
seeds_[0] = seeds_[1]; seeds_[0] = seeds_[1];
seeds_[1] = seeds_[2]; seeds_[1] = seeds_[2];
seeds_[2] = seeds_[3]; seeds_[2] = seeds_[3];
seeds_[3] = seeds_[4]; seeds_[3] = seeds_[4];
seeds_[4] = seeds_[4] ^ (seeds_[4] >> c) ^ temp ^ (temp >> b); seeds_[4] = seeds_[4] ^ (seeds_[4] >> c) ^ temp ^ (temp >> b);
} }
else else static if (bits == 192)
{ // 192bits {
temp = seeds_[0] ^ (seeds_[0] >> a); temp = seeds_[0] ^ (seeds_[0] >> a);
seeds_[0] = seeds_[1]; seeds_[0] = seeds_[1];
seeds_[1] = seeds_[2]; seeds_[1] = seeds_[2];
@ -930,6 +935,11 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
seeds_[4] = seeds_[4] ^ (seeds_[4] << c) ^ temp ^ (temp << b); seeds_[4] = seeds_[4] ^ (seeds_[4] << c) ^ temp ^ (temp << b);
value_ = seeds_[4] + (seeds_[5] += 362437); value_ = seeds_[4] + (seeds_[5] += 362437);
} }
else
{
static assert(false, "Phobos Error: Xorshift has no popFront() update for "
~ to!string(bits) ~ " bits.");
}
} }
@ -994,7 +1004,7 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
* num = rnd.front; // different across runs * num = rnd.front; // different across runs
* ----- * -----
*/ */
alias XorshiftEngine!(uint, 32, 13, 17, 5) Xorshift32; alias XorshiftEngine!(uint, 32, 13, 17, 15) Xorshift32;
alias XorshiftEngine!(uint, 64, 10, 13, 10) Xorshift64; /// ditto alias XorshiftEngine!(uint, 64, 10, 13, 10) Xorshift64; /// ditto
alias XorshiftEngine!(uint, 96, 10, 5, 26) Xorshift96; /// ditto alias XorshiftEngine!(uint, 96, 10, 5, 26) Xorshift96; /// ditto
alias XorshiftEngine!(uint, 128, 11, 8, 19) Xorshift128; /// ditto alias XorshiftEngine!(uint, 128, 11, 8, 19) Xorshift128; /// ditto
@ -1013,11 +1023,11 @@ unittest
// Result from reference implementation. // Result from reference implementation.
auto checking = [ auto checking = [
[2463534242UL, 267649, 551450, 53765, 108832, 215250, 435468, 860211, 660133, 263375], [2463534242UL, 901999875, 3371835698, 2675058524, 1053936272, 3811264849, 472493137, 3856898176, 2131710969, 2312157505],
[362436069UL, 2113136921, 19051112, 3010520417, 951284840, 1213972223, 3173832558, 2611145638, 2515869689, 2245824891], [362436069UL, 2113136921, 19051112, 3010520417, 951284840, 1213972223, 3173832558, 2611145638, 2515869689, 2245824891],
[521288629UL, 1950277231, 185954712, 1582725458, 3580567609, 2303633688, 2394948066, 4108622809, 1116800180, 3357585673], [521288629UL, 1950277231, 185954712, 1582725458, 3580567609, 2303633688, 2394948066, 4108622809, 1116800180, 3357585673],
[88675123UL, 3701687786, 458299110, 2500872618, 3633119408, 516391518, 2377269574, 2599949379, 717229868, 137866584], [88675123UL, 3701687786, 458299110, 2500872618, 3633119408, 516391518, 2377269574, 2599949379, 717229868, 137866584],
[5783321UL, 93724048, 491642011, 136638118, 246438988, 238186808, 140181925, 533680092, 285770921, 462053907], [5783321UL, 393427209, 1947109840, 565829276, 1006220149, 971147905, 1436324242, 2800460115, 1484058076, 3823330032],
[0UL, 246875399, 3690007200, 1264581005, 3906711041, 1866187943, 2481925219, 2464530826, 1604040631, 3653403911] [0UL, 246875399, 3690007200, 1264581005, 3906711041, 1866187943, 2481925219, 2464530826, 1604040631, 3653403911]
]; ];
@ -1131,7 +1141,7 @@ take $(D urng) uses the default generator $(D rndGen).
Example: Example:
---- ----
Random gen(unpredictableSeed); auto gen = Random(unpredictableSeed);
// Generate an integer in [0, 1023] // Generate an integer in [0, 1023]
auto a = uniform(0, 1024, gen); auto a = uniform(0, 1024, gen);
// Generate a float in [0, 1$(RPAREN) // Generate a float in [0, 1$(RPAREN)

View file

@ -1987,6 +1987,70 @@ public struct Regex(Char)
+/ +/
@property bool empty() const nothrow { return ir is null; } @property bool empty() const nothrow { return ir is null; }
/++
A range of all the named captures in the regex.
Example:
----
import std.range;
import std.algorithm;
auto re = regex(`(?P<name>\w+) = (?P<var>\d+)`);
auto nc = re.namedCaptures;
static assert(isRandomAccessRange!(typeof(nc)));
assert(!nc.empty);
assert(nc.length == 2);
assert(nc.equal(["name", "var"]));
assert(nc[0] == "name");
assert(nc[1..$].equal(["var"]));
----
+/
@property auto namedCaptures()
{
static struct NamedGroupRange
{
private:
NamedGroup[] groups;
size_t start;
size_t end;
public:
this(NamedGroup[] g, size_t s, size_t e)
{
assert(s <= e);
assert(e <= g.length);
groups = g;
start = s;
end = e;
}
@property string front() { return groups[start].name; };
@property string back() { return groups[end-1].name; }
@property bool empty() { return start >= end; }
@property size_t length() { return end - start; }
alias length opDollar;
@property NamedGroupRange save()
{
return NamedGroupRange(groups, start, end);
};
void popFront() { assert(!empty); start++; }
void popBack() { assert(!empty); end--; }
string opIndex()(size_t i)
{
assert(start + i < end,
"Requested named group is out of range.");
return groups[start+i].name;
}
NamedGroupRange opSlice(size_t low, size_t high) {
assert(low <= high);
assert(start + high <= end);
return NamedGroupRange(groups, start + low, start + high);
}
NamedGroupRange opSlice() { return this.save; }
}
return NamedGroupRange(dict, 0, dict.length);
}
///
private: private:
NamedGroup[] dict; //maps name -> user group number NamedGroup[] dict; //maps name -> user group number
uint ngroup; //number of internal groups uint ngroup; //number of internal groups
@ -2154,6 +2218,38 @@ private:
} }
} }
unittest
{
auto re = regex(`(?P<name>\w+) = (?P<var>\d+)`);
auto nc = re.namedCaptures;
static assert(isRandomAccessRange!(typeof(nc)));
assert(!nc.empty);
assert(nc.length == 2);
assert(nc.equal(["name", "var"]));
assert(nc[0] == "name");
assert(nc[1..$].equal(["var"]));
re = regex(`(\w+) (?P<named>\w+) (\w+)`);
nc = re.namedCaptures;
assert(nc.length == 1);
assert(nc[0] == "named");
assert(nc.front == "named");
assert(nc.back == "named");
re = regex(`(\w+) (\w+)`);
nc = re.namedCaptures;
assert(nc.empty);
re = regex(`(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/`);
nc = re.namedCaptures;
auto cp = nc.save;
assert(nc.equal(cp));
nc.popFront();
assert(nc.equal(cp[1..$]));
nc.popBack();
assert(nc.equal(cp[1..$-1]));
}
// //
@trusted uint lookupNamedGroup(String)(NamedGroup[] dict, String name) @trusted uint lookupNamedGroup(String)(NamedGroup[] dict, String name)
{//equal is @system? {//equal is @system?

View file

@ -810,30 +810,32 @@ Throws: $(D Exception) if the file is not opened.
} }
/** /**
Read line from stream $(D fp) and return it as a specified type. Read line from the file handle and return it as a specified type.
This version manages its own read buffer, which means one memory allocation per call. If you are not This version manages its own read buffer, which means one memory allocation per call. If you are not
retaining a reference to the read data, consider the $(D File.readln(buf)) version, which may offer retaining a reference to the read data, consider the $(D File.readln(buf)) version, which may offer
better performance as it reuses its read buffer. better performance as it can reuse its read buffer.
Params: Params:
S = Template parameter; the type of the allocated buffer, and the type returned. Defaults to $(D string) S = Template parameter; the type of the allocated buffer, and the type returned. Defaults to $(D string).
terminator = line terminator (by default, '\n') terminator = line terminator (by default, '\n')
Returns: Returns:
The line that was read, including the line terminator character. The line that was read, including the line terminator character.
Throws:
$(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error.
Example: Example:
--- ---
// Reads $(D stdin) and writes it to $(D stdout). // Reads $(D stdin) and writes it to $(D stdout).
import std.stdio; import std.stdio;
int main() void main()
{ {
string buf; string line;
while ((buf = readln()) !is null) while ((line = stdin.readln()) !is null)
write(buf); write(line);
return 0;
} }
--- ---
*/ */
@ -842,7 +844,7 @@ int main()
{ {
Unqual!(ElementEncodingType!S)[] buf; Unqual!(ElementEncodingType!S)[] buf;
readln(buf, terminator); readln(buf, terminator);
return assumeUnique(buf); return cast(S)buf;
} }
unittest unittest
@ -850,13 +852,13 @@ int main()
auto deleteme = testFilename(); auto deleteme = testFilename();
std.file.write(deleteme, "hello\nworld\n"); std.file.write(deleteme, "hello\nworld\n");
scope(exit) std.file.remove(deleteme); scope(exit) std.file.remove(deleteme);
foreach (C; Tuple!(char, wchar, dchar).Types) foreach (String; TypeTuple!(string, char[], wstring, wchar[], dstring, dchar[]))
{ {
auto witness = [ "hello\n", "world\n" ]; auto witness = [ "hello\n", "world\n" ];
auto f = File(deleteme); auto f = File(deleteme);
uint i = 0; uint i = 0;
immutable(C)[] buf; String buf;
while ((buf = f.readln!(typeof(buf))()).length) while ((buf = f.readln!String()).length)
{ {
assert(i < witness.length); assert(i < witness.length);
assert(equal(buf, witness[i++])); assert(equal(buf, witness[i++]));
@ -866,17 +868,17 @@ int main()
} }
/** /**
Read line from stream $(D fp) and write it to $(D buf[]), including Read line from the file handle and write it to $(D buf[]), including
terminating character. terminating character.
This is often faster than $(D buf = File.readln()) because the buffer This can be faster than $(D line = File.readln()) because you can reuse
is reused each call. Note that reusing the buffer means that the the buffer for each call. Note that reusing the buffer means that you
previous contents of it has to be copied if needed. must copy the previous contents if you wish to retain them.
Params: Params:
fp = input stream
buf = buffer used to store the resulting line data. buf is buf = buffer used to store the resulting line data. buf is
resized as necessary. resized as necessary.
terminator = line terminator (by default, '\n')
Returns: Returns:
0 for end of file, otherwise number of characters read 0 for end of file, otherwise number of characters read
@ -886,35 +888,31 @@ conversion error.
Example: Example:
--- ---
// Reads $(D stdin) into a buffer // Read lines from $(D stdin) into a string
// Dumps the buffer to $(D stdout) when it gets a "q" // Ignore lines starting with '#'
// Write the string to $(D stdout)
int main() void main()
{ {
string[] outBuf; string output;
string buf; char[] buf;
while (stdin.readln(buf)) while (stdin.readln(buf))
{ {
if (buf[0] == 'q') if (buf[0] == '#')
break; continue;
outBuf ~= buf.idup; output ~= buf;
} }
foreach (line; outBuf) write(output);
{
write(line);
}
return 0;
} }
--- ---
This method is more efficient than the one in the previous example This method can be 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 for $(D buf), whereas $(D line = stdin.readln()) makes a new memory allocation
with every line. for every line.
*/ */
size_t readln(C)(ref C[] buf, dchar terminator = '\n') size_t readln(C)(ref C[] buf, dchar terminator = '\n')
if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum)) if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum))
@ -1048,42 +1046,10 @@ Returns the file number corresponding to this object.
return .fileno(cast(FILE*) _p.handle); return .fileno(cast(FILE*) _p.handle);
} }
/** /*
Range that reads one line at a time. Returned by $(LREF byLine). Range that reads one line at a time. Returned by $(LREF byLine).
Allows to directly use range operations on lines of a file. Allows to directly use range operations on lines of a file.
Example:
----
import std.algorithm, std.string, std.stdio;
// Count words in a file using ranges.
void main()
{
auto file = File("file.txt"); // Open for reading
const wordCount = file.byLine() // Read lines
.map!split // Split into words
.map!(a => a.length) // Count words per line
.reduce!((a, b) => a + b); // Total word count
writeln(wordCount);
}
----
Example:
----
import std.stdio;
// Count lines in file using a foreach
void main()
{
auto file = File("file.txt"); // open for reading
ulong lineCount = 0;
foreach (line; file.byLine())
{
++lineCount;
}
writeln("Lines in file: ", lineCount);
}
----
*/ */
struct ByLine(Char, Terminator) struct ByLine(Char, Terminator)
{ {
@ -1155,13 +1121,56 @@ void main()
} }
/** /**
Convenience function that returns the $(D LinesReader) corresponding Returns an input range set up to read from the file handle one line
to this file. */ at a time.
ByLine!(Char, Terminator) byLine(Terminator = char, Char = char)
The element type for the range will be $(D Char[]).
Params:
Char = Character type for each line, defaulting to $(D char). If
Char is mutable then each $(D front) will not persist after $(D
popFront) is called, so the caller must copy its contents (e.g. by
calling $(D to!string)) if retention is needed.
keepTerminator = Use $(D KeepTerminator.yes) to include the
terminator at the end of each line.
terminator = Line separator ($(D '\n') by default).
Example:
----
import std.algorithm, std.stdio, std.string;
// Count words in a file using ranges.
void main()
{
auto file = File("file.txt"); // Open for reading
const wordCount = file.byLine() // Read lines
.map!split // Split into words
.map!(a => a.length) // Count words per line
.reduce!((a, b) => a + b); // Total word count
writeln(wordCount);
}
----
Example:
----
import std.stdio;
// Count lines in file using a foreach
void main()
{
auto file = File("file.txt"); // open for reading
ulong lineCount = 0;
foreach (line; file.byLine())
{
++lineCount;
}
writeln("Lines in file: ", lineCount);
}
----
*/
auto byLine(Terminator = char, Char = char)
(KeepTerminator keepTerminator = KeepTerminator.no, (KeepTerminator keepTerminator = KeepTerminator.no,
Terminator terminator = '\n') Terminator terminator = '\n')
{ {
return typeof(return)(this, keepTerminator, terminator); return ByLine!(Char, Terminator)(this, keepTerminator, terminator);
} }
unittest unittest
@ -1972,35 +1981,65 @@ unittest
} }
/********************************** /**********************************
* Read line from stream $(D fp). * Read line from $(D stdin).
*
* This version manages its own read buffer, which means one memory allocation per call. If you are not
* retaining a reference to the read data, consider the $(D readln(buf)) version, which may offer
* better performance as it can reuse its read buffer.
*
* Returns: * Returns:
* $(D null) for end of file, * The line that was read, including the line terminator character.
* $(D char[]) for line read from $(D fp), including terminating character
* Params: * Params:
* $(D fp) = input stream * S = Template parameter; the type of the allocated buffer, and the type returned. Defaults to $(D string).
* $(D terminator) = line terminator, '\n' by default * terminator = line terminator (by default, '\n')
* Throws: * Throws:
* $(D StdioException) on error * $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error.
* Example: * Example:
* Reads $(D stdin) and writes it to $(D stdout). * Reads $(D stdin) and writes it to $(D stdout).
--- ---
import std.stdio; import std.stdio;
int main() void main()
{ {
string buf; string line;
while ((buf = stdin.readln()) !is null) while ((line = readln()) !is null)
write(buf); write(line);
return 0;
} }
--- ---
*/ */
S readln(S = string)(dchar terminator = '\n') S readln(S = string)(dchar terminator = '\n')
if (isSomeString!S) if (isSomeString!S)
{ {
return stdin.readln(terminator); return stdin.readln!S(terminator);
} }
/** ditto */
/**********************************
* Read line from $(D stdin) and write it to buf[], including terminating character.
*
* This can be faster than $(D line = readln()) because you can reuse
* the buffer for each call. Note that reusing the buffer means that you
* must copy the previous contents if you wish to retain them.
*
* Returns:
* $(D size_t) 0 for end of file, otherwise number of characters read
* Params:
* buf = Buffer used to store the resulting line data. buf is resized as necessary.
* terminator = line terminator (by default, '\n')
* Throws:
* $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error.
* Example:
* Reads $(D stdin) and writes it to $(D stdout).
---
import std.stdio;
void main()
{
char[] buf;
while (readln(buf))
write(buf);
}
---
*/
size_t readln(C)(ref C[] buf, dchar terminator = '\n') size_t readln(C)(ref C[] buf, dchar terminator = '\n')
if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum)) if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum))
{ {
@ -2015,6 +2054,29 @@ if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) &&
return stdin.readln(buf, terminator); return stdin.readln(buf, terminator);
} }
unittest
{
//we can't actually test readln, so at the very least,
//we test compilability
void foo()
{
readln();
readln('\t');
foreach (String; TypeTuple!(string, char[], wstring, wchar[], dstring, dchar[]))
{
readln!String();
readln!String('\t');
}
foreach (String; TypeTuple!(char[], wchar[], dchar[]))
{
String buf;
readln(buf);
readln(buf, '\t');
readln(buf, "<br />");
}
}
}
/* /*
* Convenience function that forwards to $(D core.stdc.stdio.fopen) * Convenience function that forwards to $(D core.stdc.stdio.fopen)
* (to $(D _wfopen) on Windows) * (to $(D _wfopen) on Windows)

View file

@ -5396,10 +5396,11 @@ template Unqual(T)
} }
else // workaround else // workaround
{ {
static if (is(T U == shared(const U))) alias U Unqual; static if (is(T U == shared(inout U))) alias U Unqual;
else static if (is(T U == shared(const U))) alias U Unqual;
else static if (is(T U == inout U )) alias U Unqual;
else static if (is(T U == const U )) alias U Unqual; else static if (is(T U == const U )) alias U Unqual;
else static if (is(T U == immutable U )) alias U Unqual; else static if (is(T U == immutable U )) alias U Unqual;
else static if (is(T U == inout U )) alias U Unqual;
else static if (is(T U == shared U )) alias U Unqual; else static if (is(T U == shared U )) alias U Unqual;
else alias T Unqual; else alias T Unqual;
} }
@ -5407,12 +5408,13 @@ template Unqual(T)
unittest unittest
{ {
static assert(is(Unqual!int == int)); static assert(is(Unqual!( int) == int));
static assert(is(Unqual!( const int) == int)); static assert(is(Unqual!( const int) == int));
static assert(is(Unqual!(immutable int) == int));
static assert(is(Unqual!( inout int) == int)); static assert(is(Unqual!( inout int) == int));
static assert(is(Unqual!( immutable int) == int));
static assert(is(Unqual!( shared int) == int)); static assert(is(Unqual!( shared int) == int));
static assert(is(Unqual!(shared(const int)) == int)); static assert(is(Unqual!(shared const int) == int));
static assert(is(Unqual!(shared inout int) == int));
alias immutable(int[]) ImmIntArr; alias immutable(int[]) ImmIntArr;
static assert(is(Unqual!ImmIntArr == immutable(int)[])); static assert(is(Unqual!ImmIntArr == immutable(int)[]));
} }
@ -5420,7 +5422,9 @@ unittest
// [For internal use] // [For internal use]
private template ModifyTypePreservingSTC(alias Modifier, T) private template ModifyTypePreservingSTC(alias Modifier, T)
{ {
static if (is(T U == shared(const U))) alias shared(const Modifier!U) ModifyTypePreservingSTC; static if (is(T U == shared(inout U))) alias shared(inout Modifier!U) ModifyTypePreservingSTC;
else static if (is(T U == shared(const U))) alias shared(const Modifier!U) ModifyTypePreservingSTC;
else static if (is(T U == inout U )) alias inout(Modifier!U) ModifyTypePreservingSTC;
else static if (is(T U == const U )) alias const(Modifier!U) ModifyTypePreservingSTC; else static if (is(T U == const U )) alias const(Modifier!U) ModifyTypePreservingSTC;
else static if (is(T U == immutable U )) alias immutable(Modifier!U) ModifyTypePreservingSTC; else static if (is(T U == immutable U )) alias immutable(Modifier!U) ModifyTypePreservingSTC;
else static if (is(T U == shared U )) alias shared(Modifier!U) ModifyTypePreservingSTC; else static if (is(T U == shared U )) alias shared(Modifier!U) ModifyTypePreservingSTC;
@ -5429,10 +5433,13 @@ private template ModifyTypePreservingSTC(alias Modifier, T)
unittest unittest
{ {
static assert(is(ModifyTypePreservingSTC!(Intify, const real) == const int)); static assert(is(ModifyTypePreservingSTC!(Intify, real) == int));
static assert(is(ModifyTypePreservingSTC!(Intify, immutable real) == immutable int));
static assert(is(ModifyTypePreservingSTC!(Intify, shared real) == shared int)); static assert(is(ModifyTypePreservingSTC!(Intify, shared real) == shared int));
static assert(is(ModifyTypePreservingSTC!(Intify, shared(const real)) == shared(const int))); static assert(is(ModifyTypePreservingSTC!(Intify, immutable real) == immutable int));
static assert(is(ModifyTypePreservingSTC!(Intify, const real) == const int));
static assert(is(ModifyTypePreservingSTC!(Intify, inout real) == inout int));
static assert(is(ModifyTypePreservingSTC!(Intify, shared const real) == shared const int));
static assert(is(ModifyTypePreservingSTC!(Intify, shared inout real) == shared inout int));
} }
version (unittest) private template Intify(T) { alias int Intify; } version (unittest) private template Intify(T) { alias int Intify; }
@ -5652,72 +5659,14 @@ unittest
static assert(is(S3 == immutable(int))); static assert(is(S3 == immutable(int)));
} }
/**
* Returns the corresponding unsigned value for $(D x), e.g. if $(D x)
* has type $(D int), returns $(D cast(uint) x). The advantage
* compared to the cast is that you do not need to rewrite the cast if
* $(D x) later changes type to e.g. $(D long).
*/
auto unsigned(T)(T x) if (isIntegral!T)
{
static if (is(Unqual!T == byte )) return cast(ubyte ) x;
else static if (is(Unqual!T == short)) return cast(ushort) x;
else static if (is(Unqual!T == int )) return cast(uint ) x;
else static if (is(Unqual!T == long )) return cast(ulong ) x;
else
{
static assert(T.min == 0, "Bug in either unsigned or isIntegral");
return cast(Unqual!T) x;
}
}
unittest // Remove import when unsigned is removed.
{ import std.conv;
foreach(T; TypeTuple!(byte, ubyte))
{
static assert(is(typeof(unsigned(cast(T)1)) == ubyte));
static assert(is(typeof(unsigned(cast(const T)1)) == ubyte));
static assert(is(typeof(unsigned(cast(immutable T)1)) == ubyte));
}
foreach(T; TypeTuple!(short, ushort)) // Purposefully undocumented. Will be removed in June 2014.
{ deprecated("unsigned has been moved to std.conv. Please adjust your imports accordingly.")
static assert(is(typeof(unsigned(cast(T)1)) == ushort)); alias std.conv.unsigned unsigned;
static assert(is(typeof(unsigned(cast(const T)1)) == ushort));
static assert(is(typeof(unsigned(cast(immutable T)1)) == ushort));
}
foreach(T; TypeTuple!(int, uint))
{
static assert(is(typeof(unsigned(cast(T)1)) == uint));
static assert(is(typeof(unsigned(cast(const T)1)) == uint));
static assert(is(typeof(unsigned(cast(immutable T)1)) == uint));
}
foreach(T; TypeTuple!(long, ulong))
{
static assert(is(typeof(unsigned(cast(T)1)) == ulong));
static assert(is(typeof(unsigned(cast(const T)1)) == ulong));
static assert(is(typeof(unsigned(cast(immutable T)1)) == ulong));
}
}
auto unsigned(T)(T x) if (isSomeChar!T)
{
// All characters are unsigned
static assert(T.min == 0);
return cast(Unqual!T) x;
}
unittest
{
foreach(T; TypeTuple!(char, wchar, dchar))
{
static assert(is(typeof(unsigned(cast(T)'A')) == T));
static assert(is(typeof(unsigned(cast(const T)'A')) == T));
static assert(is(typeof(unsigned(cast(immutable T)'A')) == T));
}
}
/** /**
Returns the most negative value of the numeric type T. Returns the most negative value of the numeric type T.

View file

@ -26,14 +26,14 @@
*/ */
module std.uri; module std.uri;
//debug=uri; // uncomment to turn on debugging printf's //debug=uri; // uncomment to turn on debugging writefln's
debug(uri) private import std.stdio;
/* ====================== URI Functions ================ */ /* ====================== URI Functions ================ */
private import std.ascii; private import std.ascii;
private import std.c.stdlib; private import std.c.stdlib;
private import std.utf; private import std.utf;
private import std.stdio;
import std.exception; import std.exception;
class URIerror : Error class URIerror : Error
@ -60,18 +60,17 @@ __gshared ubyte[128] uri_flags; // indexed by character
shared static this() shared static this()
{ {
// Initialize uri_flags[] // Initialize uri_flags[]
static void helper(immutable char[] p, uint flags) static void helper(immutable char[] p, uint flags)
{ int i; {
for (int i = 0; i < p.length; i++)
for (i = 0; i < p.length; i++)
uri_flags[p[i]] |= flags; uri_flags[p[i]] |= flags;
} }
uri_flags['#'] |= URI_Hash; uri_flags['#'] |= URI_Hash;
for (int i = 'A'; i <= 'Z'; i++) for (int i = 'A'; i <= 'Z'; i++)
{ uri_flags[i] |= URI_Alpha; {
uri_flags[i] |= URI_Alpha;
uri_flags[i + 0x20] |= URI_Alpha; // lowercase letters uri_flags[i + 0x20] |= URI_Alpha; // lowercase letters
} }
helper("0123456789", URI_Digit); helper("0123456789", URI_Digit);
@ -106,13 +105,16 @@ private string URI_Encode(dstring string, uint unescapedSet)
if (C < uri_flags.length && uri_flags[C] & unescapedSet) if (C < uri_flags.length && uri_flags[C] & unescapedSet)
{ {
if (Rlen == Rsize) if (Rlen == Rsize)
{ char* R2; {
char* R2;
Rsize *= 2; Rsize *= 2;
if (Rsize > 1024) if (Rsize > 1024) {
R2 = (new char[Rsize]).ptr; R2 = (new char[Rsize]).ptr;
}
else else
{ R2 = cast(char *)alloca(Rsize * char.sizeof); {
R2 = cast(char *)alloca(Rsize * char.sizeof);
if (!R2) if (!R2)
goto LthrowURIerror; goto LthrowURIerror;
} }
@ -123,7 +125,8 @@ private string URI_Encode(dstring string, uint unescapedSet)
Rlen++; Rlen++;
} }
else else
{ char[6] Octet; {
char[6] Octet;
uint L; uint L;
V = C; V = C;
@ -177,17 +180,21 @@ private string URI_Encode(dstring string, uint unescapedSet)
} }
+/ +/
else else
{ goto LthrowURIerror; // undefined UTF-32 code {
goto LthrowURIerror; // undefined UTF-32 code
} }
if (Rlen + L * 3 > Rsize) if (Rlen + L * 3 > Rsize)
{ char *R2; {
char *R2;
Rsize = 2 * (Rlen + L * 3); Rsize = 2 * (Rlen + L * 3);
if (Rsize > 1024) if (Rsize > 1024) {
R2 = (new char[Rsize]).ptr; R2 = (new char[Rsize]).ptr;
}
else else
{ R2 = cast(char *)alloca(Rsize * char.sizeof); {
R2 = cast(char *)alloca(Rsize * char.sizeof);
if (!R2) if (!R2)
goto LthrowURIerror; goto LthrowURIerror;
} }
@ -226,8 +233,6 @@ private dstring URI_Decode(string string, uint reservedSet)
uint V; uint V;
dchar C; dchar C;
//printf("URI_Decode('%.*s')\n", string);
// Result array, allocated on stack // Result array, allocated on stack
dchar* R; dchar* R;
uint Rlen; uint Rlen;
@ -237,22 +242,26 @@ private dstring URI_Decode(string string, uint reservedSet)
// Preallocate result buffer R guaranteed to be large enough for result // Preallocate result buffer R guaranteed to be large enough for result
auto Rsize = len; auto Rsize = len;
if (Rsize > 1024 / dchar.sizeof) if (Rsize > 1024 / dchar.sizeof) {
R = (new dchar[Rsize]).ptr; R = (new dchar[Rsize]).ptr;
}
else else
{ R = cast(dchar *)alloca(Rsize * dchar.sizeof); {
R = cast(dchar *)alloca(Rsize * dchar.sizeof);
if (!R) if (!R)
goto LthrowURIerror; goto LthrowURIerror;
} }
Rlen = 0; Rlen = 0;
for (k = 0; k != len; k++) for (k = 0; k != len; k++)
{ char B; {
char B;
uint start; uint start;
C = s[k]; C = s[k];
if (C != '%') if (C != '%')
{ R[Rlen] = C; {
R[Rlen] = C;
Rlen++; Rlen++;
continue; continue;
} }
@ -268,7 +277,8 @@ private dstring URI_Decode(string string, uint reservedSet)
C = B; C = B;
} }
else else
{ uint n; {
uint n;
for (n = 1; ; n++) for (n = 1; ; n++)
{ {
@ -394,15 +404,18 @@ size_t uriLength(string s)
if (s.length <= 4) if (s.length <= 4)
goto Lno; goto Lno;
//writefln("isURL(%s)", s); if (s.length > 7 && std.string.icmp(s[0 .. 7], "http://") == 0) {
if (s.length > 7 && std.string.icmp(s[0 .. 7], "http://") == 0)
i = 7; i = 7;
else if (s.length > 8 && std.string.icmp(s[0 .. 8], "https://") == 0) }
else
{
if (s.length > 8 && std.string.icmp(s[0 .. 8], "https://") == 0)
i = 8; i = 8;
// if (icmp(s[0 .. 4], "www.") == 0)
// i = 4;
else else
goto Lno; goto Lno;
}
// if (icmp(s[0 .. 4], "www.") == 0)
// i = 4;
size_t lastdot; size_t lastdot;
for (; i < s.length; i++) for (; i < s.length; i++)
@ -432,6 +445,15 @@ Lno:
return -1; return -1;
} }
unittest
{
string s1 = "http://www.digitalmars.com/~fred/fredsRX.html#foo end!";
assert (uriLength(s1) == 49);
string s2 = "no uri here";
assert (uriLength(s2) == -1);
}
/*************************** /***************************
* Does string s[] start with an email address? * Does string s[] start with an email address?
* Returns: * Returns:
@ -441,7 +463,8 @@ Lno:
* RFC2822 * RFC2822
*/ */
size_t emailLength(string s) size_t emailLength(string s)
{ size_t i; {
size_t i;
if (!isAlpha(s[0])) if (!isAlpha(s[0]))
goto Lno; goto Lno;
@ -460,7 +483,6 @@ size_t emailLength(string s)
i++; i++;
break; break;
} }
//writefln("test1 '%s'", s[0 .. i]);
/* Now do the part past the '@' /* Now do the part past the '@'
*/ */
@ -488,26 +510,33 @@ Lno:
return -1; return -1;
} }
unittest
{
string s1 = "my.e-mail@www.example-domain.com with garbage added";
assert (emailLength(s1) == 32);
string s2 = "no email address here";
assert (emailLength(s2) == -1);
}
unittest unittest
{ {
debug(uri) printf("uri.encodeURI.unittest\n"); debug(uri) writeln("uri.encodeURI.unittest");
string s = "http://www.digitalmars.com/~fred/fred's RX.html#foo"; string s = "http://www.digitalmars.com/~fred/fred's RX.html#foo";
string t = "http://www.digitalmars.com/~fred/fred's%20RX.html#foo"; string t = "http://www.digitalmars.com/~fred/fred's%20RX.html#foo";
auto r = encode(s); auto r = encode(s);
debug(uri) printf("r = '%.*s'\n", r); debug(uri) writefln("r = '%s'", r);
assert(r == t); assert(r == t);
r = decode(t); r = decode(t);
debug(uri) printf("r = '%.*s'\n", r); debug(uri) writefln("r = '%s'", r);
assert(r == s); assert(r == s);
r = encode( decode("%E3%81%82%E3%81%82") ); r = encode( decode("%E3%81%82%E3%81%82") );
assert(r == "%E3%81%82%E3%81%82"); assert(r == "%E3%81%82%E3%81%82");
r = encodeComponent("c++"); r = encodeComponent("c++");
//printf("r = '%.*s'\n", r);
assert(r == "c%2B%2B"); assert(r == "c%2B%2B");
auto str = new char[10_000_000]; auto str = new char[10_000_000];
@ -517,5 +546,5 @@ unittest
assert(c == 'A'); assert(c == 'A');
r = decode("%41%42%43"); r = decode("%41%42%43");
debug(uri) writefln(r); debug(uri) writeln(r);
} }

View file

@ -787,6 +787,12 @@ public:
cast(void*) &temp); cast(void*) &temp);
} }
// workaround for bug 10567 fix
int opCmp(ref const VariantN rhs) const
{
return (cast()this).opCmp!(VariantN)(cast()rhs);
}
/** /**
* Ordering comparison used by the "<", "<=", ">", and ">=" * Ordering comparison used by the "<", "<=", ">", and ">="
* operators. In case comparison is not sensible between the held * operators. In case comparison is not sensible between the held