Rebased and fixed issues

This commit is contained in:
Andrei Alexandrescu 2013-12-19 15:22:55 -08:00
parent db687ef010
commit 919aa8f085
3 changed files with 63 additions and 36 deletions

View file

@ -862,6 +862,7 @@ unittest
// Mixing convertible types is fair game, too // Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ]; double[] c = [ 2.5, 3.0 ];
auto r1 = reduce!("a + b")(chain(a, b, c)); auto r1 = reduce!("a + b")(chain(a, b, c));
import std.math;
assert(approxEqual(r1, 112.5)); assert(approxEqual(r1, 112.5));
// To minimize nesting of parentheses, Uniform Function Call Syntax can be used // To minimize nesting of parentheses, Uniform Function Call Syntax can be used
@ -883,6 +884,7 @@ unittest
// Compute minimum and maximum in one pass // Compute minimum and maximum in one pass
auto r = reduce!(min, max)(a); auto r = reduce!(min, max)(a);
// The type of r is Tuple!(int, int) // The type of r is Tuple!(int, int)
import std.math;
assert(approxEqual(r[0], 2)); // minimum assert(approxEqual(r[0], 2)); // minimum
assert(approxEqual(r[1], 11)); // maximum assert(approxEqual(r[1], 11)); // maximum
@ -1392,6 +1394,7 @@ unittest
// Mixing convertible types is fair game, too // Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ]; double[] c = [ 2.5, 3.0 ];
auto r1 = chain(c, a, b).filter!(a => cast(int) a != a); auto r1 = chain(c, a, b).filter!(a => cast(int) a != a);
import std.math;
assert(approxEqual(r1, [ 2.5 ])); assert(approxEqual(r1, [ 2.5 ]));
} }
@ -1958,6 +1961,7 @@ See_Also:
void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow
if (allMutableFields!T && !is(typeof(T.init.proxySwap(T.init)))) if (allMutableFields!T && !is(typeof(T.init.proxySwap(T.init))))
{ {
import std.traits;
static if (!isAssignable!T || hasElaborateAssign!T) static if (!isAssignable!T || hasElaborateAssign!T)
{ {
if (&lhs != &rhs) if (&lhs != &rhs)
@ -2012,6 +2016,7 @@ void swap(T)(T lhs, T rhs) if (is(typeof(T.init.proxySwap(T.init))))
+/ +/
private template allMutableFields(T) private template allMutableFields(T)
{ {
import std.traits;
alias OT = OriginalType!T; alias OT = OriginalType!T;
static if (is(OT == struct) || is(OT == union)) static if (is(OT == struct) || is(OT == union))
enum allMutableFields = isMutable!OT && allSatisfy!(.allMutableFields, FieldTypeTuple!OT); enum allMutableFields = isMutable!OT && allSatisfy!(.allMutableFields, FieldTypeTuple!OT);
@ -2291,6 +2296,7 @@ if (is(typeof(ElementType!Range.init == Separator.init))
static if (isNarrowString!Range) static if (isNarrowString!Range)
{ {
import std.utf;
_separatorLength = codeLength!(ElementEncodingType!Range)(separator); _separatorLength = codeLength!(ElementEncodingType!Range)(separator);
} }
if (_input.empty) if (_input.empty)
@ -3798,6 +3804,7 @@ InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack,
if (isInputRange!InputRange && if (isInputRange!InputRange &&
is (typeof(binaryFun!pred(haystack.front, needle)) : bool)) is (typeof(binaryFun!pred(haystack.front, needle)) : bool))
{ {
import std.traits;
alias R = InputRange; alias R = InputRange;
alias E = Element; alias E = Element;
alias predFun = binaryFun!pred; alias predFun = binaryFun!pred;
@ -3822,10 +3829,12 @@ if (isInputRange!InputRange &&
//Note: "needle <= 0x7F" properly handles sign via unsigned promotion //Note: "needle <= 0x7F" properly handles sign via unsigned promotion
static if (is(UEEType == char)) static if (is(UEEType == char))
{ {
import std.utf;
if (!__ctfe && canSearchInCodeUnits!char(needle)) if (!__ctfe && canSearchInCodeUnits!char(needle))
{ {
static R trustedMemchr(ref R haystack, ref E needle) @trusted nothrow pure static R trustedMemchr(ref R haystack, ref E needle) @trusted nothrow pure
{ {
import core.stdc.string : memchr;
auto ptr = memchr(haystack.ptr, needle, haystack.length); auto ptr = memchr(haystack.ptr, needle, haystack.length);
return ptr ? return ptr ?
haystack[ptr - haystack.ptr .. $] : haystack[ptr - haystack.ptr .. $] :
@ -3890,8 +3899,13 @@ if (isInputRange!InputRange &&
{ {
EType* ptr = null; EType* ptr = null;
//Note: we use "min/max" to handle sign mismatch. //Note: we use "min/max" to handle sign mismatch.
if (min(EType.min, needle) == EType.min && max(EType.max, needle) == EType.max) if (min(EType.min, needle) == EType.min
ptr = cast(EType*) memchr(haystack.ptr, needle, haystack.length); && max(EType.max, needle) == EType.max)
{
import core.stdc.string : memchr;
ptr = cast(EType*) memchr(haystack.ptr, needle,
haystack.length);
}
return ptr ? return ptr ?
haystack[ptr - haystack.ptr .. $] : haystack[ptr - haystack.ptr .. $] :
@ -3925,6 +3939,7 @@ unittest
{ {
assert(find("hello, world", ',') == ", world"); assert(find("hello, world", ',') == ", world");
assert(find([1, 2, 3, 5], 4) == []); assert(find([1, 2, 3, 5], 4) == []);
import std.container;
assert(equal(find(SList!int(1, 2, 3, 4, 5)[], 4), SList!int(4, 5)[])); assert(equal(find(SList!int(1, 2, 3, 4, 5)[], 4), SList!int(4, 5)[]));
assert(find!"a > b"([1, 2, 3, 5], 2) == [3, 5]); assert(find!"a > b"([1, 2, 3, 5], 2) == [3, 5]);
@ -4020,6 +4035,7 @@ unittest
} }
} }
dg(); dg();
import std.exception;
assertCTFEable!dg; assertCTFEable!dg;
} }
@ -4084,6 +4100,7 @@ unittest
{ {
assert(find("hello, world", "World").empty); assert(find("hello, world", "World").empty);
assert(find("hello, world", "wo") == "world"); assert(find("hello, world", "wo") == "world");
import std.container;
assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]); assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]);
} }
@ -6442,6 +6459,7 @@ unittest
assert(equal([2, 4, 8, 6], map!"a*2"(a))); assert(equal([2, 4, 8, 6], map!"a*2"(a)));
double[] b = [ 1.0, 2, 4, 3]; double[] b = [ 1.0, 2, 4, 3];
double[] c = [ 1.005, 2, 4, 3]; double[] c = [ 1.005, 2, 4, 3];
import std.math;
assert(equal!approxEqual(map!"a*2"(b), map!"a*2"(c))); assert(equal!approxEqual(map!"a*2"(b), map!"a*2"(c)));
assert(!equal([2, 4, 1, 3], map!"a*2"(a))); assert(!equal([2, 4, 1, 3], map!"a*2"(a)));
assert(!equal([2, 4, 1], map!"a*2"(a))); assert(!equal([2, 4, 1], map!"a*2"(a)));
@ -6785,6 +6803,7 @@ minCount(alias pred = "a < b", Range)(Range range)
if (isInputRange!Range && !isInfinite!Range && if (isInputRange!Range && !isInfinite!Range &&
is(typeof(binaryFun!pred(range.front, range.front)))) is(typeof(binaryFun!pred(range.front, range.front))))
{ {
import std.traits;
alias T = ElementType!Range; alias T = ElementType!Range;
alias UT = Unqual!T; alias UT = Unqual!T;
alias RetType = Tuple!(T, size_t); alias RetType = Tuple!(T, size_t);
@ -6915,6 +6934,7 @@ unittest
int i; int i;
} }
alias IS1 = immutable(S1); alias IS1 = immutable(S1);
import std.traits;
static assert( isAssignable!S1); static assert( isAssignable!S1);
static assert( isAssignable!(S1, IS1)); static assert( isAssignable!(S1, IS1));
@ -7600,6 +7620,7 @@ Range stripLeft(Range, E)(Range range, E element)
Range stripLeft(alias pred, Range)(Range range) Range stripLeft(alias pred, Range)(Range range)
if (isInputRange!Range && is(typeof(pred(range.front)) : bool)) if (isInputRange!Range && is(typeof(pred(range.front)) : bool))
{ {
import std.functional;
return find!(not!pred)(range); return find!(not!pred)(range);
} }
@ -7798,6 +7819,7 @@ the example below, $(D r2) is a right subrange of $(D r1).
*/ */
unittest unittest
{ {
import std.container;
auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3); auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3);
auto r1 = list[]; auto r1 = list[];
auto r2 = list[]; popFrontN(r2, 4); auto r2 = list[]; popFrontN(r2, 4);
@ -7812,6 +7834,7 @@ Elements can be swapped across ranges of different types:
*/ */
unittest unittest
{ {
import std.container;
auto list = SList!(int)(4, 5, 6, 7); auto list = SList!(int)(4, 5, 6, 7);
auto vec = [ 1, 2, 3 ]; auto vec = [ 1, 2, 3 ];
bringToFront(list[], vec); bringToFront(list[], vec);
@ -10754,6 +10777,7 @@ template all(alias pred)
bool all(Range)(Range range) bool all(Range)(Range range)
if (isInputRange!Range && is(typeof(unaryFun!pred(range.front)))) if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))))
{ {
import std.functional;
return find!(not!(unaryFun!pred))(range).empty; return find!(not!(unaryFun!pred))(range).empty;
} }
} }

View file

@ -2886,6 +2886,7 @@ if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
{ {
struct Result struct Result
{ {
import std.conv;
public Rs source; public Rs source;
private size_t _current = size_t.max; private size_t _current = size_t.max;
@ -5124,7 +5125,7 @@ private string lockstepMixin(Ranges...)(bool withIndex)
} }
import std.string : format, outdent; import std.string : format, outdent;
foreach (idx, Range; Ranges) foreach (idx, Range; Ranges)
{ {
params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);

View file

@ -28,7 +28,7 @@ import std.format : formattedRead;
import std.array : empty; import std.array : empty;
import std.range; import std.range;
import std.string : format, toStringz, chomp; import std.string : format, toStringz, chomp;
import std.traits : Unqual, isSomeChar, isAggregateType, isSomeString, import std.traits : Unqual, isSomeChar, isAggregateType, isSomeString,
isIntegral, isBoolean, ParameterTypeTuple; isIntegral, isBoolean, ParameterTypeTuple;
version (DigitalMars) version (DigitalMars)
@ -509,7 +509,7 @@ _clearerr) for the file handle.
} }
/** /**
Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_fflush.html, _fflush) Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_fflush.html, _fflush)
for the file handle. for the file handle.
Throws: $(D Exception) if the file is not opened or if the call to $D(fflush) fails. Throws: $(D Exception) if the file is not opened or if the call to $D(fflush) fails.
@ -620,7 +620,7 @@ Throws: $(D ErrnoException) if the file is not opened or if the call to $D(fread
} }
/** /**
Calls $(WEB cplusplus.com/reference/clibrary/cstdio/fseek.html, fseek) Calls $(WEB cplusplus.com/reference/clibrary/cstdio/fseek.html, fseek)
for the file handle. for the file handle.
Throws: $(D Exception) if the file is not opened. Throws: $(D Exception) if the file is not opened.
@ -730,7 +730,7 @@ Throws: $(D Exception) if the file is not opened.
/** /**
Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_setvbuf.html, Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_setvbuf.html,
_setvbuf) for the file handle. _setvbuf) for the file handle.
Throws: $(D Exception) if the file is not opened. Throws: $(D Exception) if the file is not opened.
$(D ErrnoException) if the call to $D(setvbuf) fails. $(D ErrnoException) if the call to $D(setvbuf) fails.
@ -744,7 +744,7 @@ Throws: $(D Exception) if the file is not opened.
} }
/** /**
Writes its arguments in text format to the file. Writes its arguments in text format to the file.
Throws: $(D Exception) if the file is not opened. Throws: $(D Exception) if the file is not opened.
$(D ErrnoException) on an error writing to the file. $(D ErrnoException) on an error writing to the file.
@ -795,8 +795,8 @@ Throws: $(D Exception) if the file is not opened.
} }
/** /**
Writes its arguments in text format to the file, according to the Writes its arguments in text format to the file, according to the
format in the first argument. format in the first argument.
Throws: $(D Exception) if the file is not opened. Throws: $(D Exception) if the file is not opened.
$(D ErrnoException) on an error writing to the file. $(D ErrnoException) on an error writing to the file.
@ -807,7 +807,7 @@ Throws: $(D Exception) if the file is not opened.
} }
/** /**
Writes its arguments in text format to the file, according to the Writes its arguments in text format to the file, according to the
format in the first argument, followed by a newline. format in the first argument, followed by a newline.
Throws: $(D Exception) if the file is not opened. Throws: $(D Exception) if the file is not opened.
@ -823,8 +823,8 @@ Throws: $(D Exception) if the file is not opened.
/** /**
Read line from the file handle 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 can reuse its read buffer. better performance as it can reuse its read buffer.
Params: Params:
@ -832,7 +832,7 @@ Params:
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: Throws:
$(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error. $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error.
@ -938,7 +938,7 @@ void main()
This method can be 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
for $(D buf), whereas $(D line = stdin.readln()) makes a new memory allocation for $(D buf), whereas $(D line = stdin.readln()) makes a new memory allocation
for 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))
@ -1081,6 +1081,7 @@ Allows to directly use range operations on lines of a file.
struct ByLine(Char, Terminator) struct ByLine(Char, Terminator)
{ {
private: private:
import std.typecons;
/* Ref-counting stops the source range's ByLineImpl /* Ref-counting stops the source range's ByLineImpl
* from getting out of sync after the range is copied, e.g. * from getting out of sync after the range is copied, e.g.
* when accessing range.front, then using std.range.take, * when accessing range.front, then using std.range.take,
@ -1088,19 +1089,19 @@ Allows to directly use range operations on lines of a file.
alias Impl = RefCounted!(ByLineImpl!(Char, Terminator), alias Impl = RefCounted!(ByLineImpl!(Char, Terminator),
RefCountedAutoInitialize.no); RefCountedAutoInitialize.no);
Impl impl; Impl impl;
static if (isScalarType!Terminator) static if (isScalarType!Terminator)
enum defTerm = '\n'; enum defTerm = '\n';
else else
enum defTerm = cast(Terminator)"\n"; enum defTerm = cast(Terminator)"\n";
public: public:
this(File f, KeepTerminator kt = KeepTerminator.no, this(File f, KeepTerminator kt = KeepTerminator.no,
Terminator terminator = defTerm) Terminator terminator = defTerm)
{ {
impl = Impl(f, kt, terminator); impl = Impl(f, kt, terminator);
} }
@property bool empty() @property bool empty()
{ {
return impl.refCountedPayload.empty; return impl.refCountedPayload.empty;
@ -1194,21 +1195,22 @@ Allows to directly use range operations on lines of a file.
} }
} }
import std.traits;
/** /**
Returns an input range set up to read from the file handle one line Returns an input range set up to read from the file handle one line
at a time. at a time.
The element type for the range will be $(D Char[]). Range primitives The element type for the range will be $(D Char[]). Range primitives
may throw $(D StdioException) on I/O error. may throw $(D StdioException) on I/O error.
Note: Note:
Each $(D front) will not persist after $(D Each $(D front) will not persist after $(D
popFront) is called, so the caller must copy its contents (e.g. by popFront) is called, so the caller must copy its contents (e.g. by
calling $(D to!string)) if retention is needed. calling $(D to!string)) if retention is needed.
Params: Params:
Char = Character type for each line, defaulting to $(D char). Char = Character type for each line, defaulting to $(D char).
keepTerminator = Use $(D KeepTerminator.yes) to include the keepTerminator = Use $(D KeepTerminator.yes) to include the
terminator at the end of each line. terminator at the end of each line.
terminator = Line separator ($(D '\n') by default). terminator = Line separator ($(D '\n') by default).
@ -1350,14 +1352,14 @@ the contents may well have changed).
assert(fbl.equal(["2", "3"])); assert(fbl.equal(["2", "3"]));
assert(fbl.empty); assert(fbl.empty);
assert(file.isOpen); // we still have a valid reference assert(file.isOpen); // we still have a valid reference
file.rewind(); file.rewind();
fbl = file.byLine(); fbl = file.byLine();
assert(!fbl.drop(2).empty); assert(!fbl.drop(2).empty);
assert(fbl.equal(["3"])); assert(fbl.equal(["3"]));
assert(fbl.empty); assert(fbl.empty);
assert(file.isOpen); assert(file.isOpen);
file.detach(); file.detach();
assert(!file.isOpen); assert(!file.isOpen);
} }
@ -1444,14 +1446,14 @@ the contents may well have changed).
} }
/** /**
Returns an input range set up to read from the file handle a chunk at a Returns an input range set up to read from the file handle a chunk at a
time. time.
The element type for the range will be $(D ubyte[]). Range primitives The element type for the range will be $(D ubyte[]). Range primitives
may throw $(D StdioException) on I/O error. may throw $(D StdioException) on I/O error.
Note: Each $(D front) will not persist after $(D Note: Each $(D front) will not persist after $(D
popFront) is called, so the caller must copy its contents (e.g. by popFront) is called, so the caller must copy its contents (e.g. by
calling $(D buffer.dup)) if retention is needed. calling $(D buffer.dup)) if retention is needed.
Example: Example:
@ -2155,13 +2157,13 @@ unittest
/********************************** /**********************************
* Read line from $(D stdin). * Read line from $(D stdin).
* *
* 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 readln(buf)) version, which may offer * 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. * better performance as it can reuse its read buffer.
* *
* Returns: * Returns:
* The line that was read, including the line terminator character. * The line that was read, including the line terminator character.
* 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')
@ -2188,11 +2190,11 @@ if (isSomeString!S)
/********************************** /**********************************
* Read line from $(D stdin) and write it to buf[], including terminating character. * 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 * 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 * the buffer for each call. Note that reusing the buffer means that you
* must copy the previous contents if you wish to retain them. * must copy the previous contents if you wish to retain them.
* *
* Returns: * Returns:
* $(D size_t) 0 for end of file, otherwise number of characters read * $(D size_t) 0 for end of file, otherwise number of characters read
* Params: * Params: