mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +03:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
6f9c22bfa9
10 changed files with 686 additions and 407 deletions
|
@ -455,7 +455,7 @@ private struct MapResult(alias fun, Range)
|
|||
}
|
||||
}
|
||||
|
||||
static if (hasLength!R || isSomeString!R)
|
||||
static if (hasLength!R)
|
||||
{
|
||||
@property auto length()
|
||||
{
|
||||
|
@ -9949,10 +9949,7 @@ assert(!all!"a & 1"([1, 2, 3, 5, 7, 9]));
|
|||
bool all(alias pred, R)(R range)
|
||||
if (isInputRange!R && is(typeof(unaryFun!pred(range.front))))
|
||||
{
|
||||
// dmd @@@BUG9578@@@ workaround
|
||||
// return find!(not!(unaryFun!pred))(range).empty;
|
||||
bool notPred(ElementType!R a) { return !unaryFun!pred(a); }
|
||||
return find!notPred(range).empty;
|
||||
return find!(not!(unaryFun!pred))(range).empty;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
|
|
@ -1577,6 +1577,9 @@ unittest
|
|||
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
|
||||
// InputRange to ubyte[] or char[]
|
||||
auto encoded = Base64.encode(map!(to!(ubyte))(["20", "251", "156", "3", "217", "126"]));
|
||||
|
|
127
std/conv.d
127
std/conv.d
|
@ -3911,3 +3911,130 @@ unittest
|
|||
toTextRange(-1, result);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ $(I Integer):
|
|||
$(I Digit):
|
||||
$(B '0')|$(B '1')|$(B '2')|$(B '3')|$(B '4')|$(B '5')|$(B '6')|$(B '7')|$(B '8')|$(B '9')
|
||||
$(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
|
||||
|
|
34
std/random.d
34
std/random.d
|
@ -801,8 +801,8 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
|
|||
if(isUnsigned!UIntType)
|
||||
{
|
||||
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:
|
||||
///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];
|
||||
else static if (bits == 160)
|
||||
UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321];
|
||||
else
|
||||
{ // 192bits
|
||||
else static if (bits == 192)
|
||||
{
|
||||
UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321, 6615241];
|
||||
UIntType value_;
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(false, "Phobos Error: Xorshift has no instantiation rule for "
|
||||
~ to!string(bits) ~ " bits.");
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
@ -887,7 +892,7 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
|
|||
static if (bits == 32)
|
||||
{
|
||||
temp = seeds_[0] ^ (seeds_[0] << a);
|
||||
temp = temp >> b;
|
||||
temp = temp ^ (temp >> b);
|
||||
seeds_[0] = temp ^ (temp << c);
|
||||
}
|
||||
else static if (bits == 64)
|
||||
|
@ -913,15 +918,15 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
|
|||
}
|
||||
else static if (bits == 160)
|
||||
{
|
||||
temp = seeds_[0] ^ (seeds_[0] >> a);
|
||||
temp = seeds_[0] ^ (seeds_[0] << a);
|
||||
seeds_[0] = seeds_[1];
|
||||
seeds_[1] = seeds_[2];
|
||||
seeds_[2] = seeds_[3];
|
||||
seeds_[3] = seeds_[4];
|
||||
seeds_[4] = seeds_[4] ^ (seeds_[4] >> c) ^ temp ^ (temp >> b);
|
||||
}
|
||||
else
|
||||
{ // 192bits
|
||||
else static if (bits == 192)
|
||||
{
|
||||
temp = seeds_[0] ^ (seeds_[0] >> a);
|
||||
seeds_[0] = seeds_[1];
|
||||
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);
|
||||
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
|
||||
* -----
|
||||
*/
|
||||
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, 96, 10, 5, 26) Xorshift96; /// ditto
|
||||
alias XorshiftEngine!(uint, 128, 11, 8, 19) Xorshift128; /// ditto
|
||||
|
@ -1013,11 +1023,11 @@ unittest
|
|||
|
||||
// Result from reference implementation.
|
||||
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],
|
||||
[521288629UL, 1950277231, 185954712, 1582725458, 3580567609, 2303633688, 2394948066, 4108622809, 1116800180, 3357585673],
|
||||
[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]
|
||||
];
|
||||
|
||||
|
@ -1131,7 +1141,7 @@ take $(D urng) uses the default generator $(D rndGen).
|
|||
Example:
|
||||
|
||||
----
|
||||
Random gen(unpredictableSeed);
|
||||
auto gen = Random(unpredictableSeed);
|
||||
// Generate an integer in [0, 1023]
|
||||
auto a = uniform(0, 1024, gen);
|
||||
// Generate a float in [0, 1$(RPAREN)
|
||||
|
|
96
std/regex.d
96
std/regex.d
|
@ -1987,6 +1987,70 @@ public struct Regex(Char)
|
|||
+/
|
||||
@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:
|
||||
NamedGroup[] dict; //maps name -> user group number
|
||||
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)
|
||||
{//equal is @system?
|
||||
|
|
230
std/stdio.d
230
std/stdio.d
|
@ -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
|
||||
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:
|
||||
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')
|
||||
|
||||
Returns:
|
||||
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:
|
||||
---
|
||||
// Reads $(D stdin) and writes it to $(D stdout).
|
||||
import std.stdio;
|
||||
|
||||
int main()
|
||||
void main()
|
||||
{
|
||||
string buf;
|
||||
while ((buf = readln()) !is null)
|
||||
write(buf);
|
||||
return 0;
|
||||
string line;
|
||||
while ((line = stdin.readln()) !is null)
|
||||
write(line);
|
||||
}
|
||||
---
|
||||
*/
|
||||
|
@ -842,7 +844,7 @@ int main()
|
|||
{
|
||||
Unqual!(ElementEncodingType!S)[] buf;
|
||||
readln(buf, terminator);
|
||||
return assumeUnique(buf);
|
||||
return cast(S)buf;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -850,13 +852,13 @@ int main()
|
|||
auto deleteme = testFilename();
|
||||
std.file.write(deleteme, "hello\nworld\n");
|
||||
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 f = File(deleteme);
|
||||
uint i = 0;
|
||||
immutable(C)[] buf;
|
||||
while ((buf = f.readln!(typeof(buf))()).length)
|
||||
String buf;
|
||||
while ((buf = f.readln!String()).length)
|
||||
{
|
||||
assert(i < witness.length);
|
||||
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.
|
||||
|
||||
This is often faster than $(D buf = File.readln()) because the buffer
|
||||
is reused each call. Note that reusing the buffer means that the
|
||||
previous contents of it has to be copied if needed.
|
||||
This can be faster than $(D line = File.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.
|
||||
|
||||
Params:
|
||||
fp = input stream
|
||||
buf = buffer used to store the resulting line data. buf is
|
||||
resized as necessary.
|
||||
terminator = line terminator (by default, '\n')
|
||||
|
||||
Returns:
|
||||
0 for end of file, otherwise number of characters read
|
||||
|
@ -886,35 +888,31 @@ conversion error.
|
|||
|
||||
Example:
|
||||
---
|
||||
// Reads $(D stdin) into a buffer
|
||||
// Dumps the buffer to $(D stdout) when it gets a "q"
|
||||
// Read lines from $(D stdin) into a string
|
||||
// Ignore lines starting with '#'
|
||||
// Write the string to $(D stdout)
|
||||
|
||||
int main()
|
||||
void main()
|
||||
{
|
||||
string[] outBuf;
|
||||
string buf;
|
||||
string output;
|
||||
char[] buf;
|
||||
|
||||
while (stdin.readln(buf))
|
||||
{
|
||||
if (buf[0] == 'q')
|
||||
break;
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
|
||||
outBuf ~= buf.idup;
|
||||
output ~= buf;
|
||||
}
|
||||
|
||||
foreach (line; outBuf)
|
||||
{
|
||||
write(line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
write(output);
|
||||
}
|
||||
---
|
||||
|
||||
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
|
||||
by $(D buf), whereas $(D buf = stdin.readln()) makes a new memory allocation
|
||||
with every line.
|
||||
for $(D buf), whereas $(D line = stdin.readln()) makes a new memory allocation
|
||||
for every line.
|
||||
*/
|
||||
size_t readln(C)(ref C[] buf, dchar terminator = '\n')
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Range that reads one line at a time. Returned by $(LREF byLine).
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -1155,13 +1121,56 @@ void main()
|
|||
}
|
||||
|
||||
/**
|
||||
Convenience function that returns the $(D LinesReader) corresponding
|
||||
to this file. */
|
||||
ByLine!(Char, Terminator) byLine(Terminator = char, Char = char)
|
||||
Returns an input range set up to read from the file handle one line
|
||||
at a time.
|
||||
|
||||
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,
|
||||
Terminator terminator = '\n')
|
||||
{
|
||||
return typeof(return)(this, keepTerminator, terminator);
|
||||
return ByLine!(Char, Terminator)(this, keepTerminator, terminator);
|
||||
}
|
||||
|
||||
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:
|
||||
* $(D null) for end of file,
|
||||
* $(D char[]) for line read from $(D fp), including terminating character
|
||||
* The line that was read, including the line terminator character.
|
||||
* Params:
|
||||
* $(D fp) = input stream
|
||||
* $(D terminator) = line terminator, '\n' by default
|
||||
* S = Template parameter; the type of the allocated buffer, and the type returned. Defaults to $(D string).
|
||||
* terminator = line terminator (by default, '\n')
|
||||
* Throws:
|
||||
* $(D StdioException) on error
|
||||
* $(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;
|
||||
|
||||
int main()
|
||||
void main()
|
||||
{
|
||||
string buf;
|
||||
while ((buf = stdin.readln()) !is null)
|
||||
write(buf);
|
||||
return 0;
|
||||
string line;
|
||||
while ((line = readln()) !is null)
|
||||
write(line);
|
||||
}
|
||||
---
|
||||
*/
|
||||
S readln(S = string)(dchar terminator = '\n')
|
||||
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')
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
* (to $(D _wfopen) on Windows)
|
||||
|
|
101
std/traits.d
101
std/traits.d
|
@ -5396,10 +5396,11 @@ template Unqual(T)
|
|||
}
|
||||
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 == 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 alias T Unqual;
|
||||
}
|
||||
|
@ -5407,12 +5408,13 @@ template Unqual(T)
|
|||
|
||||
unittest
|
||||
{
|
||||
static assert(is(Unqual!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!(shared int) == int));
|
||||
static assert(is(Unqual!(shared(const int)) == int));
|
||||
static assert(is(Unqual!( int) == int));
|
||||
static assert(is(Unqual!( const 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 const int) == int));
|
||||
static assert(is(Unqual!(shared inout int) == int));
|
||||
alias immutable(int[]) ImmIntArr;
|
||||
static assert(is(Unqual!ImmIntArr == immutable(int)[]));
|
||||
}
|
||||
|
@ -5420,7 +5422,9 @@ unittest
|
|||
// [For internal use]
|
||||
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 == immutable U )) alias immutable(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
|
||||
{
|
||||
static assert(is(ModifyTypePreservingSTC!(Intify, const real) == const 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(const real)) == shared(const int)));
|
||||
static assert(is(ModifyTypePreservingSTC!(Intify, real) == int));
|
||||
static assert(is(ModifyTypePreservingSTC!(Intify, shared real) == shared 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; }
|
||||
|
||||
|
@ -5652,72 +5659,14 @@ unittest
|
|||
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
|
||||
{
|
||||
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));
|
||||
}
|
||||
// Remove import when unsigned is removed.
|
||||
import std.conv;
|
||||
|
||||
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));
|
||||
}
|
||||
// Purposefully undocumented. Will be removed in June 2014.
|
||||
deprecated("unsigned has been moved to std.conv. Please adjust your imports accordingly.")
|
||||
alias std.conv.unsigned unsigned;
|
||||
|
||||
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.
|
||||
|
|
487
std/uri.d
487
std/uri.d
|
@ -26,21 +26,21 @@
|
|||
*/
|
||||
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 ================ */
|
||||
|
||||
private import std.ascii;
|
||||
private import std.c.stdlib;
|
||||
private import std.utf;
|
||||
private import std.stdio;
|
||||
import std.exception;
|
||||
|
||||
class URIerror : Error
|
||||
{
|
||||
this()
|
||||
{
|
||||
super("URI error");
|
||||
super("URI error");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,19 +60,18 @@ __gshared ubyte[128] uri_flags; // indexed by character
|
|||
shared static this()
|
||||
{
|
||||
// Initialize uri_flags[]
|
||||
|
||||
static void helper(immutable char[] p, uint flags)
|
||||
{ int i;
|
||||
|
||||
for (i = 0; i < p.length; i++)
|
||||
uri_flags[p[i]] |= flags;
|
||||
{
|
||||
for (int i = 0; i < p.length; i++)
|
||||
uri_flags[p[i]] |= flags;
|
||||
}
|
||||
|
||||
uri_flags['#'] |= URI_Hash;
|
||||
|
||||
for (int i = 'A'; i <= 'Z'; i++)
|
||||
{ uri_flags[i] |= URI_Alpha;
|
||||
uri_flags[i + 0x20] |= URI_Alpha; // lowercase letters
|
||||
{
|
||||
uri_flags[i] |= URI_Alpha;
|
||||
uri_flags[i + 0x20] |= URI_Alpha; // lowercase letters
|
||||
}
|
||||
helper("0123456789", URI_Digit);
|
||||
helper(";/?:@&=+$,", URI_Reserved);
|
||||
|
@ -101,110 +100,118 @@ private string URI_Encode(dstring string, uint unescapedSet)
|
|||
|
||||
for (k = 0; k != len; k++)
|
||||
{
|
||||
C = string[k];
|
||||
// if (C in unescapedSet)
|
||||
if (C < uri_flags.length && uri_flags[C] & unescapedSet)
|
||||
{
|
||||
if (Rlen == Rsize)
|
||||
{ char* R2;
|
||||
C = string[k];
|
||||
// if (C in unescapedSet)
|
||||
if (C < uri_flags.length && uri_flags[C] & unescapedSet)
|
||||
{
|
||||
if (Rlen == Rsize)
|
||||
{
|
||||
char* R2;
|
||||
|
||||
Rsize *= 2;
|
||||
if (Rsize > 1024)
|
||||
R2 = (new char[Rsize]).ptr;
|
||||
Rsize *= 2;
|
||||
if (Rsize > 1024) {
|
||||
R2 = (new char[Rsize]).ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
R2 = cast(char *)alloca(Rsize * char.sizeof);
|
||||
if (!R2)
|
||||
goto LthrowURIerror;
|
||||
}
|
||||
R2[0..Rlen] = R[0..Rlen];
|
||||
R = R2;
|
||||
}
|
||||
R[Rlen] = cast(char)C;
|
||||
Rlen++;
|
||||
}
|
||||
else
|
||||
{ R2 = cast(char *)alloca(Rsize * char.sizeof);
|
||||
if (!R2)
|
||||
goto LthrowURIerror;
|
||||
}
|
||||
R2[0..Rlen] = R[0..Rlen];
|
||||
R = R2;
|
||||
}
|
||||
R[Rlen] = cast(char)C;
|
||||
Rlen++;
|
||||
}
|
||||
else
|
||||
{ char[6] Octet;
|
||||
uint L;
|
||||
{
|
||||
char[6] Octet;
|
||||
uint L;
|
||||
|
||||
V = C;
|
||||
V = C;
|
||||
|
||||
// Transform V into octets
|
||||
if (V <= 0x7F)
|
||||
{
|
||||
Octet[0] = cast(char) V;
|
||||
L = 1;
|
||||
}
|
||||
else if (V <= 0x7FF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xC0 | (V >> 6));
|
||||
Octet[1] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 2;
|
||||
}
|
||||
else if (V <= 0xFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xE0 | (V >> 12));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 3;
|
||||
}
|
||||
else if (V <= 0x1FFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xF0 | (V >> 18));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 12) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[3] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 4;
|
||||
}
|
||||
/+
|
||||
else if (V <= 0x3FFFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xF8 | (V >> 24));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 18) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | ((V >> 12) & 0x3F));
|
||||
Octet[3] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[4] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 5;
|
||||
}
|
||||
else if (V <= 0x7FFFFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xFC | (V >> 30));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 24) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | ((V >> 18) & 0x3F));
|
||||
Octet[3] = cast(char)(0x80 | ((V >> 12) & 0x3F));
|
||||
Octet[4] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[5] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 6;
|
||||
}
|
||||
+/
|
||||
else
|
||||
{ goto LthrowURIerror; // undefined UTF-32 code
|
||||
}
|
||||
// Transform V into octets
|
||||
if (V <= 0x7F)
|
||||
{
|
||||
Octet[0] = cast(char) V;
|
||||
L = 1;
|
||||
}
|
||||
else if (V <= 0x7FF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xC0 | (V >> 6));
|
||||
Octet[1] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 2;
|
||||
}
|
||||
else if (V <= 0xFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xE0 | (V >> 12));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 3;
|
||||
}
|
||||
else if (V <= 0x1FFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xF0 | (V >> 18));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 12) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[3] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 4;
|
||||
}
|
||||
/+
|
||||
else if (V <= 0x3FFFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xF8 | (V >> 24));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 18) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | ((V >> 12) & 0x3F));
|
||||
Octet[3] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[4] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 5;
|
||||
}
|
||||
else if (V <= 0x7FFFFFFF)
|
||||
{
|
||||
Octet[0] = cast(char)(0xFC | (V >> 30));
|
||||
Octet[1] = cast(char)(0x80 | ((V >> 24) & 0x3F));
|
||||
Octet[2] = cast(char)(0x80 | ((V >> 18) & 0x3F));
|
||||
Octet[3] = cast(char)(0x80 | ((V >> 12) & 0x3F));
|
||||
Octet[4] = cast(char)(0x80 | ((V >> 6) & 0x3F));
|
||||
Octet[5] = cast(char)(0x80 | (V & 0x3F));
|
||||
L = 6;
|
||||
}
|
||||
+/
|
||||
else
|
||||
{
|
||||
goto LthrowURIerror; // undefined UTF-32 code
|
||||
}
|
||||
|
||||
if (Rlen + L * 3 > Rsize)
|
||||
{ char *R2;
|
||||
if (Rlen + L * 3 > Rsize)
|
||||
{
|
||||
char *R2;
|
||||
|
||||
Rsize = 2 * (Rlen + L * 3);
|
||||
if (Rsize > 1024)
|
||||
R2 = (new char[Rsize]).ptr;
|
||||
else
|
||||
{ R2 = cast(char *)alloca(Rsize * char.sizeof);
|
||||
if (!R2)
|
||||
goto LthrowURIerror;
|
||||
}
|
||||
R2[0..Rlen] = R[0..Rlen];
|
||||
R = R2;
|
||||
}
|
||||
Rsize = 2 * (Rlen + L * 3);
|
||||
if (Rsize > 1024) {
|
||||
R2 = (new char[Rsize]).ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
R2 = cast(char *)alloca(Rsize * char.sizeof);
|
||||
if (!R2)
|
||||
goto LthrowURIerror;
|
||||
}
|
||||
R2[0..Rlen] = R[0..Rlen];
|
||||
R = R2;
|
||||
}
|
||||
|
||||
for (j = 0; j < L; j++)
|
||||
{
|
||||
R[Rlen] = '%';
|
||||
R[Rlen + 1] = hex2ascii[Octet[j] >> 4];
|
||||
R[Rlen + 2] = hex2ascii[Octet[j] & 15];
|
||||
for (j = 0; j < L; j++)
|
||||
{
|
||||
R[Rlen] = '%';
|
||||
R[Rlen + 1] = hex2ascii[Octet[j] >> 4];
|
||||
R[Rlen + 2] = hex2ascii[Octet[j] & 15];
|
||||
|
||||
Rlen += 3;
|
||||
Rlen += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R[0..Rlen].idup;
|
||||
|
||||
|
@ -215,8 +222,8 @@ LthrowURIerror:
|
|||
uint ascii2hex(dchar c)
|
||||
{
|
||||
return (c <= '9') ? c - '0' :
|
||||
(c <= 'F') ? c - 'A' + 10 :
|
||||
c - 'a' + 10;
|
||||
(c <= 'F') ? c - 'A' + 10 :
|
||||
c - 'a' + 10;
|
||||
}
|
||||
|
||||
private dstring URI_Decode(string string, uint reservedSet)
|
||||
|
@ -226,8 +233,6 @@ private dstring URI_Decode(string string, uint reservedSet)
|
|||
uint V;
|
||||
dchar C;
|
||||
|
||||
//printf("URI_Decode('%.*s')\n", string);
|
||||
|
||||
// Result array, allocated on stack
|
||||
dchar* R;
|
||||
uint Rlen;
|
||||
|
@ -237,86 +242,91 @@ private dstring URI_Decode(string string, uint reservedSet)
|
|||
|
||||
// Preallocate result buffer R guaranteed to be large enough for result
|
||||
auto Rsize = len;
|
||||
if (Rsize > 1024 / dchar.sizeof)
|
||||
R = (new dchar[Rsize]).ptr;
|
||||
if (Rsize > 1024 / dchar.sizeof) {
|
||||
R = (new dchar[Rsize]).ptr;
|
||||
}
|
||||
else
|
||||
{ R = cast(dchar *)alloca(Rsize * dchar.sizeof);
|
||||
if (!R)
|
||||
goto LthrowURIerror;
|
||||
{
|
||||
R = cast(dchar *)alloca(Rsize * dchar.sizeof);
|
||||
if (!R)
|
||||
goto LthrowURIerror;
|
||||
}
|
||||
Rlen = 0;
|
||||
|
||||
for (k = 0; k != len; k++)
|
||||
{ char B;
|
||||
uint start;
|
||||
|
||||
C = s[k];
|
||||
if (C != '%')
|
||||
{ R[Rlen] = C;
|
||||
Rlen++;
|
||||
continue;
|
||||
}
|
||||
start = k;
|
||||
if (k + 2 >= len)
|
||||
goto LthrowURIerror;
|
||||
if (!isHexDigit(s[k + 1]) || !isHexDigit(s[k + 2]))
|
||||
goto LthrowURIerror;
|
||||
B = cast(char)((ascii2hex(s[k + 1]) << 4) + ascii2hex(s[k + 2]));
|
||||
k += 2;
|
||||
if ((B & 0x80) == 0)
|
||||
{
|
||||
C = B;
|
||||
}
|
||||
else
|
||||
{ uint n;
|
||||
char B;
|
||||
uint start;
|
||||
|
||||
for (n = 1; ; n++)
|
||||
C = s[k];
|
||||
if (C != '%')
|
||||
{
|
||||
if (n > 4)
|
||||
goto LthrowURIerror;
|
||||
if (((B << n) & 0x80) == 0)
|
||||
{
|
||||
if (n == 1)
|
||||
goto LthrowURIerror;
|
||||
break;
|
||||
R[Rlen] = C;
|
||||
Rlen++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick off (7 - n) significant bits of B from first byte of octet
|
||||
V = B & ((1 << (7 - n)) - 1); // (!!!)
|
||||
|
||||
if (k + (3 * (n - 1)) >= len)
|
||||
goto LthrowURIerror;
|
||||
for (j = 1; j != n; j++)
|
||||
{
|
||||
k++;
|
||||
if (s[k] != '%')
|
||||
start = k;
|
||||
if (k + 2 >= len)
|
||||
goto LthrowURIerror;
|
||||
if (!isHexDigit(s[k + 1]) || !isHexDigit(s[k + 2]))
|
||||
goto LthrowURIerror;
|
||||
B = cast(char)((ascii2hex(s[k + 1]) << 4) + ascii2hex(s[k + 2]));
|
||||
if ((B & 0xC0) != 0x80)
|
||||
goto LthrowURIerror;
|
||||
k += 2;
|
||||
V = (V << 6) | (B & 0x3F);
|
||||
if ((B & 0x80) == 0)
|
||||
{
|
||||
C = B;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint n;
|
||||
|
||||
for (n = 1; ; n++)
|
||||
{
|
||||
if (n > 4)
|
||||
goto LthrowURIerror;
|
||||
if (((B << n) & 0x80) == 0)
|
||||
{
|
||||
if (n == 1)
|
||||
goto LthrowURIerror;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick off (7 - n) significant bits of B from first byte of octet
|
||||
V = B & ((1 << (7 - n)) - 1); // (!!!)
|
||||
|
||||
if (k + (3 * (n - 1)) >= len)
|
||||
goto LthrowURIerror;
|
||||
for (j = 1; j != n; j++)
|
||||
{
|
||||
k++;
|
||||
if (s[k] != '%')
|
||||
goto LthrowURIerror;
|
||||
if (!isHexDigit(s[k + 1]) || !isHexDigit(s[k + 2]))
|
||||
goto LthrowURIerror;
|
||||
B = cast(char)((ascii2hex(s[k + 1]) << 4) + ascii2hex(s[k + 2]));
|
||||
if ((B & 0xC0) != 0x80)
|
||||
goto LthrowURIerror;
|
||||
k += 2;
|
||||
V = (V << 6) | (B & 0x3F);
|
||||
}
|
||||
if (V > 0x10FFFF)
|
||||
goto LthrowURIerror;
|
||||
C = V;
|
||||
}
|
||||
if (C < uri_flags.length && uri_flags[C] & reservedSet)
|
||||
{
|
||||
// R ~= s[start .. k + 1];
|
||||
int width = (k + 1) - start;
|
||||
for (int ii = 0; ii < width; ii++)
|
||||
R[Rlen + ii] = s[start + ii];
|
||||
Rlen += width;
|
||||
}
|
||||
else
|
||||
{
|
||||
R[Rlen] = C;
|
||||
Rlen++;
|
||||
}
|
||||
if (V > 0x10FFFF)
|
||||
goto LthrowURIerror;
|
||||
C = V;
|
||||
}
|
||||
if (C < uri_flags.length && uri_flags[C] & reservedSet)
|
||||
{
|
||||
// R ~= s[start .. k + 1];
|
||||
int width = (k + 1) - start;
|
||||
for (int ii = 0; ii < width; ii++)
|
||||
R[Rlen + ii] = s[start + ii];
|
||||
Rlen += width;
|
||||
}
|
||||
else
|
||||
{
|
||||
R[Rlen] = C;
|
||||
Rlen++;
|
||||
}
|
||||
}
|
||||
assert(Rlen <= Rsize); // enforce our preallocation size guarantee
|
||||
|
||||
|
@ -392,39 +402,42 @@ size_t uriLength(string s)
|
|||
size_t i;
|
||||
|
||||
if (s.length <= 4)
|
||||
goto Lno;
|
||||
goto Lno;
|
||||
|
||||
//writefln("isURL(%s)", s);
|
||||
if (s.length > 7 && std.string.icmp(s[0 .. 7], "http://") == 0)
|
||||
i = 7;
|
||||
else if (s.length > 8 && std.string.icmp(s[0 .. 8], "https://") == 0)
|
||||
i = 8;
|
||||
// if (icmp(s[0 .. 4], "www.") == 0)
|
||||
// i = 4;
|
||||
if (s.length > 7 && std.string.icmp(s[0 .. 7], "http://") == 0) {
|
||||
i = 7;
|
||||
}
|
||||
else
|
||||
goto Lno;
|
||||
{
|
||||
if (s.length > 8 && std.string.icmp(s[0 .. 8], "https://") == 0)
|
||||
i = 8;
|
||||
else
|
||||
goto Lno;
|
||||
}
|
||||
// if (icmp(s[0 .. 4], "www.") == 0)
|
||||
// i = 4;
|
||||
|
||||
size_t lastdot;
|
||||
for (; i < s.length; i++)
|
||||
{
|
||||
auto c = s[i];
|
||||
if (isAlphaNum(c))
|
||||
continue;
|
||||
if (c == '-' || c == '_' || c == '?' ||
|
||||
c == '=' || c == '%' || c == '&' ||
|
||||
c == '/' || c == '+' || c == '#' ||
|
||||
c == '~' || c == '$')
|
||||
continue;
|
||||
if (c == '.')
|
||||
{
|
||||
lastdot = i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
auto c = s[i];
|
||||
if (isAlphaNum(c))
|
||||
continue;
|
||||
if (c == '-' || c == '_' || c == '?' ||
|
||||
c == '=' || c == '%' || c == '&' ||
|
||||
c == '/' || c == '+' || c == '#' ||
|
||||
c == '~' || c == '$')
|
||||
continue;
|
||||
if (c == '.')
|
||||
{
|
||||
lastdot = i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//if (!lastdot || (i - lastdot != 3 && i - lastdot != 4))
|
||||
if (!lastdot)
|
||||
goto Lno;
|
||||
goto Lno;
|
||||
|
||||
return i;
|
||||
|
||||
|
@ -432,6 +445,15 @@ Lno:
|
|||
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?
|
||||
* Returns:
|
||||
|
@ -441,46 +463,46 @@ Lno:
|
|||
* RFC2822
|
||||
*/
|
||||
size_t emailLength(string s)
|
||||
{ size_t i;
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!isAlpha(s[0]))
|
||||
goto Lno;
|
||||
goto Lno;
|
||||
|
||||
for (i = 1; 1; i++)
|
||||
{
|
||||
if (i == s.length)
|
||||
goto Lno;
|
||||
auto c = s[i];
|
||||
if (isAlphaNum(c))
|
||||
continue;
|
||||
if (c == '-' || c == '_' || c == '.')
|
||||
continue;
|
||||
if (c != '@')
|
||||
goto Lno;
|
||||
i++;
|
||||
break;
|
||||
if (i == s.length)
|
||||
goto Lno;
|
||||
auto c = s[i];
|
||||
if (isAlphaNum(c))
|
||||
continue;
|
||||
if (c == '-' || c == '_' || c == '.')
|
||||
continue;
|
||||
if (c != '@')
|
||||
goto Lno;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
//writefln("test1 '%s'", s[0 .. i]);
|
||||
|
||||
/* Now do the part past the '@'
|
||||
*/
|
||||
size_t lastdot;
|
||||
for (; i < s.length; i++)
|
||||
{
|
||||
auto c = s[i];
|
||||
if (isAlphaNum(c))
|
||||
continue;
|
||||
if (c == '-' || c == '_')
|
||||
continue;
|
||||
if (c == '.')
|
||||
{
|
||||
lastdot = i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
auto c = s[i];
|
||||
if (isAlphaNum(c))
|
||||
continue;
|
||||
if (c == '-' || c == '_')
|
||||
continue;
|
||||
if (c == '.')
|
||||
{
|
||||
lastdot = i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!lastdot || (i - lastdot != 3 && i - lastdot != 4))
|
||||
goto Lno;
|
||||
goto Lno;
|
||||
|
||||
return i;
|
||||
|
||||
|
@ -488,34 +510,41 @@ Lno:
|
|||
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
|
||||
{
|
||||
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 t = "http://www.digitalmars.com/~fred/fred's%20RX.html#foo";
|
||||
|
||||
auto r = encode(s);
|
||||
debug(uri) printf("r = '%.*s'\n", r);
|
||||
debug(uri) writefln("r = '%s'", r);
|
||||
assert(r == t);
|
||||
r = decode(t);
|
||||
debug(uri) printf("r = '%.*s'\n", r);
|
||||
debug(uri) writefln("r = '%s'", r);
|
||||
assert(r == s);
|
||||
|
||||
r = encode( decode("%E3%81%82%E3%81%82") );
|
||||
assert(r == "%E3%81%82%E3%81%82");
|
||||
|
||||
r = encodeComponent("c++");
|
||||
//printf("r = '%.*s'\n", r);
|
||||
assert(r == "c%2B%2B");
|
||||
|
||||
auto str = new char[10_000_000];
|
||||
str[] = 'A';
|
||||
r = encodeComponent(assumeUnique(str));
|
||||
foreach (char c; r)
|
||||
assert(c == 'A');
|
||||
assert(c == 'A');
|
||||
|
||||
r = decode("%41%42%43");
|
||||
debug(uri) writefln(r);
|
||||
debug(uri) writeln(r);
|
||||
}
|
||||
|
|
|
@ -787,6 +787,12 @@ public:
|
|||
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 ">="
|
||||
* operators. In case comparison is not sensible between the held
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue