Further reductions

This commit is contained in:
Andrei Alexandrescu 2013-12-22 22:26:56 -08:00
parent 56da8e597d
commit 1e80655e52
3 changed files with 68 additions and 12 deletions

View file

@ -352,10 +352,7 @@ module std.algorithm;
import std.functional : unaryFun, binaryFun;
import std.range;
import std.traits : isIntegral, mostNegative, isSomeString, isMutable, Select,
isArray, hasElaborateAssign, isStaticArray, isNarrowString, isIterable,
Unqual, hasElaborateDestructor, unsigned, ForeachType, isDynamicArray,
hasElaborateCopyConstructor, CommonType;
import std.traits;
import std.typetuple : TypeTuple, staticMap, allSatisfy;
version(unittest)
@ -657,6 +654,7 @@ unittest
unittest
{
import std.range;
// Issue #10130 - map of iota with const step.
const step = 2;
static assert(__traits(compiles, map!(i => i)(iota(0, 10, step))));

View file

@ -2091,6 +2091,7 @@ assert(stride(stride(a, 2), 3) == stride(a, 6));
auto stride(Range)(Range r, size_t n)
if (isInputRange!(Unqual!Range))
{
import std.exception;
enforce(n > 0, "Stride cannot have step zero.");
static if (is(typeof(stride(r.source, n)) == Range))
@ -3019,6 +3020,7 @@ unittest
import std.conv : text;
void test(int[] input, int[] witness)
{
import std.exception;
enforce(equal(radial(input), witness),
text(radial(input), " vs. ", witness));
}
@ -4219,6 +4221,7 @@ Take!(Repeat!T) repeat(T)(T value, size_t n)
unittest
{
import std.exception;
enforce(equal(repeat(5, 4), [ 5, 5, 5, 5 ][]));
}
@ -4627,6 +4630,7 @@ struct Zip(Ranges...)
case StoppingPolicy.requireSameLength:
foreach (i, Unused; R[1 .. $])
{
import std.exception;
enforce(ranges[0].empty ==
ranges[i + 1].empty,
"Inequal-length ranges passed to Zip");
@ -4806,6 +4810,7 @@ struct Zip(Ranges...)
case StoppingPolicy.requireSameLength:
foreach (i, Unused; R)
{
import std.exception;
enforce(!ranges[i].empty, "Invalid Zip object");
ranges[i].popFront();
}
@ -4837,6 +4842,7 @@ struct Zip(Ranges...)
case StoppingPolicy.requireSameLength:
foreach (i, Unused; R)
{
import std.exception;
enforce(!ranges[i].empty, "Invalid Zip object");
ranges[i].popBack();
}
@ -5158,6 +5164,7 @@ private string lockstepMixin(Ranges...)(bool withIndex)
if (_stoppingPolicy == StoppingPolicy.requireSameLength)
{
import std.exception;
foreach(range; ranges)
enforce(range.empty);
}
@ -5208,6 +5215,7 @@ struct Lockstep(Ranges...)
this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
{
_ranges = ranges;
import std.exception;
enforce(sp != StoppingPolicy.longest,
"Can't use StoppingPolicy.Longest on Lockstep.");
_stoppingPolicy = sp;
@ -5605,6 +5613,7 @@ if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
if ((current < pastLast && step >= 0) ||
(current > pastLast && step <= 0))
{
import std.exception;
enforce(step != 0);
this.step = step;
this.current = current;
@ -5761,6 +5770,7 @@ if (isFloatingPoint!(CommonType!(B, E, S)))
{
this.start = start;
this.step = step;
import std.exception;
enforce(step != 0);
immutable fcount = (end - start) / step;
enforce(fcount >= 0, "iota: incorrect startup parameters");
@ -6078,6 +6088,7 @@ struct FrontTransversal(Ror,
immutable commonLength = _input.front.length;
foreach (e; _input)
{
import std.exception;
enforce(e.length == commonLength);
}
}
@ -6352,6 +6363,7 @@ struct Transversal(Ror,
immutable commonLength = _input.front.length;
foreach (e; _input)
{
import std.exception;
enforce(e.length == commonLength);
}
}

View file

@ -18,16 +18,10 @@ module std.stdio;
public import core.stdc.stdio, std.string : KeepTerminator;
static import std.c.stdio;
import std.algorithm : equal, swap, endsWith;
import std.stdiobase;
import core.stdc.errno, core.stdc.stddef, core.stdc.stdlib, core.memory,
core.stdc.string, core.stdc.wchar_, core.exception;
import std.conv : text, to, toTextRange;
import std.exception : assumeUnique, collectException, enforce, errnoEnforce;
import std.format : formattedRead;
import std.array : empty;
import std.range;
import std.string : format, toStringz, chomp;
import std.traits : Unqual, isSomeChar, isAggregateType, isSomeString,
isIntegral, isBoolean, ParameterTypeTuple;
@ -225,6 +219,7 @@ public:
/// Ditto
void popFront()
{
import std.exception;
enforce(file.isOpen);
file.readln(line);
if (!line.length)
@ -233,8 +228,11 @@ public:
}
else
{
import std.conv, std.format, std.string : chomp;
line = chomp(line);
formattedRead(line, format, &current);
import std.conv;
import std.array;
enforce(line.empty, text("Leftover characters in record: `",
line, "'"));
}
@ -297,6 +295,7 @@ Hello, Jimmy!
*/
struct File
{
import std.traits;
private struct Impl
{
FILE * handle = null; // Is null iff this Impl is closed by another File
@ -309,6 +308,7 @@ struct File
package this(FILE* handle, string name, uint refs = 1, bool isPopened = false)
{
assert(!_p);
import std.exception;
_p = cast(Impl*) enforce(malloc(Impl.sizeof), "Out of memory");
_p.handle = handle;
_p.refs = refs;
@ -332,6 +332,7 @@ Throws: $(D ErrnoException) if the file could not be opened.
*/
this(string name, in char[] stdioOpenmode = "rb")
{
import std.conv, std.exception;
this(errnoEnforce(.fopen(name, stdioOpenmode),
text("Cannot open file `", name, "' in mode `",
stdioOpenmode, "'")),
@ -357,6 +358,7 @@ file.
*/
void opAssign(File rhs)
{
import std.algorithm;
swap(this, rhs);
}
@ -384,6 +386,7 @@ Throws: $(D ErrnoException) in case of error.
version(Posix) void popen(string command, in char[] stdioOpenmode = "r")
{
detach();
import std.exception;
this = File(errnoEnforce(.popen(command, stdioOpenmode),
"Cannot run command `"~command~"'"),
command, 1, true);
@ -403,6 +406,7 @@ Throws: $(D Exception) if the file is not opened.
*/
@property bool eof() const pure
{
import std.exception;
enforce(_p && _p.handle, "Calling eof() against an unopened file.");
return .feof(cast(FILE*) _p.handle) != 0;
}
@ -470,6 +474,7 @@ Throws: $(D ErrnoException) on error.
*/
void close()
{
import std.exception;
if (!_p) return; // succeed vacuously
scope(exit)
{
@ -488,6 +493,7 @@ Throws: $(D ErrnoException) on error.
auto res = .pclose(_p.handle);
errnoEnforce(res != -1,
"Could not close pipe `"~_name~"'");
import std.string;
errnoEnforce(res == 0, format("Command returned %d", res));
return;
}
@ -516,6 +522,7 @@ Throws: $(D Exception) if the file is not opened or if the call to $D(fflush) fa
*/
void flush()
{
import std.exception;
errnoEnforce
(.fflush(enforce(_p.handle, "Calling fflush() on an unopened file"))
== 0);
@ -537,6 +544,7 @@ $(D rawRead) always reads in binary mode on Windows.
*/
T[] rawRead(T)(T[] buffer)
{
import std.exception;
enforce(buffer.length, "rawRead must take a non-empty buffer");
version(Win32)
{
@ -602,6 +610,7 @@ Throws: $(D ErrnoException) if the file is not opened or if the call to $D(fread
auto result =
.fwrite(buffer.ptr, T.sizeof, buffer.length, _p.handle);
if (result == result.max) result = 0;
import std.conv, std.exception;
errnoEnforce(result == buffer.length,
text("Wrote ", result, " instead of ", buffer.length,
" objects of type ", T.stringof, " to file `",
@ -628,9 +637,11 @@ Throws: $(D Exception) if the file is not opened.
*/
void seek(long offset, int origin = SEEK_SET)
{
import std.exception;
enforce(isOpen, "Attempting to seek() in an unopened file");
version (Windows)
{
import std.conv;
errnoEnforce(fseek(_p.handle, to!int(offset), origin) == 0,
"Could not seek in file `"~_name~"'");
}
@ -659,6 +670,7 @@ Throws: $(D Exception) if the file is not opened.
{
auto bigOffset = cast(ulong) int.max + 100;
f.seek(bigOffset);
import std.conv;
assert(f.tell == bigOffset, text(f.tell));
// Uncomment the tests below only if you want to wait for
// a long time
@ -677,6 +689,7 @@ Throws: $(D Exception) if the file is not opened.
*/
@property ulong tell() const
{
import std.exception;
enforce(isOpen, "Attempting to tell() in an unopened file");
version (Windows)
{
@ -699,6 +712,7 @@ Throws: $(D Exception) if the file is not opened.
auto f = File(deleteme);
auto a = new ubyte[4];
f.rawRead(a);
import std.conv;
assert(f.tell == 4, text(f.tell));
}
@ -710,6 +724,7 @@ Throws: $(D Exception) if the file is not opened.
*/
void rewind()
{
import std.exception;
enforce(isOpen, "Attempting to rewind() an unopened file");
.rewind(_p.handle);
}
@ -723,6 +738,7 @@ Throws: $(D Exception) if the file is not opened.
*/
void setvbuf(size_t size, int mode = _IOFBF)
{
import std.exception;
enforce(isOpen, "Attempting to call setvbuf() on an unopened file");
errnoEnforce(.setvbuf(_p.handle, null, mode, size) == 0,
"Could not set buffering for file `"~_name~"'");
@ -737,6 +753,7 @@ Throws: $(D Exception) if the file is not opened.
*/
void setvbuf(void[] buf, int mode = _IOFBF)
{
import std.exception;
enforce(isOpen, "Attempting to call setvbuf() on an unopened file");
errnoEnforce(.setvbuf(_p.handle,
cast(char*) buf.ptr, mode, buf.length) == 0,
@ -765,6 +782,7 @@ Throws: $(D Exception) if the file is not opened.
}
else static if (isIntegral!A)
{
import std.conv;
toTextRange(arg, w);
}
else static if (isBoolean!A)
@ -860,6 +878,7 @@ void main()
unittest
{
import std.algorithm;
auto deleteme = testFilename();
std.file.write(deleteme, "hello\nworld\n");
scope(exit) std.file.remove(deleteme);
@ -943,6 +962,7 @@ for every line.
size_t readln(C)(ref C[] buf, dchar terminator = '\n')
if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum))
{
import std.exception;
static if (is(C == char))
{
enforce(_p && _p.handle, "Attempt to read from an unopened file.");
@ -967,6 +987,7 @@ for every line.
if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) &&
isBidirectionalRange!R && is(typeof(terminator.front == dchar.init)))
{
import std.algorithm;
auto last = terminator.back;
C[] buf2;
swap(buf, buf2);
@ -1013,6 +1034,7 @@ for every line.
{
assert(isOpen);
auto input = LockingTextReader(this);
import std.format;
return formattedRead(input, format, data);
}
@ -1033,6 +1055,7 @@ for every line.
Note that the created file has no $(LREF name).*/
static File tmpfile()
{
import std.exception;
return File(errnoEnforce(core.stdc.stdio.tmpfile(),
"Could not create temporary file with tmpfile()"),
null);
@ -1044,6 +1067,7 @@ File) never takes the initiative in closing the file.
Note that the created file has no $(LREF name)*/
/*private*/ static File wrapFile(FILE* f)
{
import std.exception;
return File(enforce(f, "Could not wrap null FILE*"),
null, /*uint.max / 2*/ 9999);
}
@ -1053,6 +1077,7 @@ Returns the $(D FILE*) corresponding to this object.
*/
FILE* getFP() pure
{
import std.exception;
enforce(_p && _p.handle,
"Attempting to call getFP() on an unopened file");
return _p.handle;
@ -1068,6 +1093,7 @@ Returns the file number corresponding to this object.
*/
/*version(Posix) */int fileno() const
{
import std.exception;
enforce(isOpen, "Attempting to call fileno() on an unopened file");
return .fileno(cast(FILE*) _p.handle);
}
@ -1169,6 +1195,7 @@ Allows to directly use range operations on lines of a file.
void popFront()
{
import std.algorithm;
assert(file.isOpen);
assumeSafeAppend(line);
file.readln(line, terminator);
@ -1195,7 +1222,6 @@ 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
at a time.
@ -1270,6 +1296,7 @@ the contents may well have changed).
unittest
{
import std.algorithm;
//printf("Entering test at line %d\n", __LINE__);
scope(failure) printf("Failed test at line %d\n", __LINE__);
auto deleteme = testFilename();
@ -1307,6 +1334,7 @@ the contents may well have changed).
{
assert(line == witness[i++]);
}
import std.conv;
assert(i == witness.length, text(i, " != ", witness.length));
}
/* Wrap with default args.
@ -1521,6 +1549,7 @@ $(D Range) that locks the file and allows fast writing to it.
this(ref File f)
{
import std.exception;
enforce(f._p && f._p.handle);
fps = f._p.handle;
orientation = fwide(fps, 0);
@ -1549,6 +1578,7 @@ $(D Range) that locks the file and allows fast writing to it.
/// Range primitive implementations.
void put(A)(A writeme) if (is(ElementType!A : const(dchar)))
{
import std.exception;
alias ElementEncodingType!A C;
static assert(!is(C == void));
if (writeme[0].sizeof == 1 && orientation <= 0)
@ -1661,6 +1691,7 @@ See $(LREF byChunk) for an example.
/// Get the size of the file, ulong.max if file is not searchable, but still throws if an actual error occurs.
@property ulong size()
{
import std.exception;
ulong pos = void;
if (collectException(pos = tell)) return ulong.max;
scope(exit) seek(pos);
@ -1671,6 +1702,7 @@ See $(LREF byChunk) for an example.
unittest
{
import std.exception;
auto deleteme = testFilename();
scope(exit) collectException(std.file.remove(deleteme));
std.file.write(deleteme, "1 2 3");
@ -1686,6 +1718,7 @@ struct LockingTextReader
this(File f)
{
import std.exception;
enforce(f.isOpen);
_f = f;
FLOCK(_f._p.handle);
@ -1704,11 +1737,13 @@ struct LockingTextReader
void opAssign(LockingTextReader r)
{
import std.algorithm;
swap(this, r);
}
@property bool empty()
{
import std.exception;
if (!_f.isOpen || _f.eof) return true;
if (_crt == _crt.init)
{
@ -1737,6 +1772,7 @@ struct LockingTextReader
version(assert) if (empty) throw new RangeError();
if (FGETC(cast(_iobuf*) _f._p.handle) == -1)
{
import std.exception;
enforce(_f.eof);
}
_crt = _crt.init;
@ -1902,6 +1938,7 @@ void writeln(T...)(T args)
{
static if (T.length == 0)
{
import std.exception;
enforce(fputc('\n', .stdout._p.handle) == '\n');
}
else static if (T.length == 1 &&
@ -1911,6 +1948,7 @@ void writeln(T...)(T args)
!isAggregateType!(typeof(args[0])))
{
// Specialization for strings - a very frequent case
import std.exception;
enforce(fprintf(.stdout._p.handle, "%.*s\n",
cast(int) args[0].length, args[0].ptr) >= 0);
}
@ -2259,6 +2297,7 @@ unittest
*/
private FILE* fopen(in char[] name, in char[] mode = "r")
{
import std.string;
version(Windows)
{
import std.utf;
@ -2290,6 +2329,7 @@ version (Posix)
*/
FILE* popen(in char[] name, in char[] mode = "r")
{
import std.string;
return core.sys.posix.stdio.popen(toStringz(name), toStringz(mode));
}
}
@ -2396,6 +2436,7 @@ struct lines
Parms[0] i = 0;
for (;;)
{
import std.conv;
if (!f.readln(line, terminator)) break;
auto copy = to!(Parms[$ - 1])(line);
static if (Parms.length == 2)
@ -2420,6 +2461,7 @@ struct lines
// no UTF checking
int opApplyRaw(D)(scope D dg)
{
import std.exception;
alias ParameterTypeTuple!(dg) Parms;
enum duplicate = is(Parms[$ - 1] : immutable(ubyte)[]);
int result = 1;
@ -2431,6 +2473,7 @@ struct lines
Parms[0] line = 0;
while ((c = FGETC(cast(_iobuf*)f._p.handle)) != -1)
{
import std.conv;
buffer ~= to!(ubyte)(c);
if (c == terminator)
{
@ -2719,6 +2762,7 @@ Initialize with a message and an error code. */
{
auto s = core.stdc.string.strerror(errno);
}
import std.conv;
auto sysmsg = to!string(s);
// If e is 0, we don't use the system error message. (The message
// is "Success", which is rather pointless for an exception.)
@ -3163,6 +3207,7 @@ version(linux)
File openNetwork(string host, ushort port)
{
import std.exception;
auto h = enforce( sock.gethostbyname(std.string.toStringz(host)),
new StdioException("gethostbyname"));
@ -3187,6 +3232,7 @@ version(linux)
enforce(sock.connect(s, cast(sock.sockaddr*) &addr, addr.sizeof) != -1,
new StdioException("Connect failed"));
import std.conv;
return File(enforce(fdopen(s, "w+".ptr)),
host ~ ":" ~ to!string(port));
}
@ -3194,7 +3240,7 @@ version(linux)
version(unittest) string testFilename(string file = __FILE__, size_t line = __LINE__)
{
import std.path;
import std.conv, std.path;
// Non-ASCII characters can't be used because of snn.lib @@@BUG8643@@@
version(DIGITAL_MARS_STDIO)