std.file.read implementation contest
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Mon Feb 16 11:28:45 PST 2009
Someone mentioned an old bug in std.file.read here:
http://www.reddit.com/r/programming/comments/7xnty/walter_bright_on_porting_d_to_the_mac/
Two programmers sent in patches for the function. Which is to be
committed and why? (Linux versions shown. Apologies for noisy line breaks.)
Andrei
// Implementation 1
void[] read(string name)
{
invariant fd = std.c.linux.linux.open(toStringz(name), O_RDONLY);
cenforce(fd != -1, name);
scope(exit) std.c.linux.linux.close(fd);
struct_stat statbuf = void;
cenforce(std.c.linux.linux.fstat(fd, &statbuf) == 0, name);
void[] buf;
auto size = statbuf.st_size;
if (size == 0)
{ /* The size could be 0 if the file is a device or a procFS file,
* so we just have to try reading it.
*/
int readsize = 1024;
while (1)
{
buf = GC.realloc(buf.ptr, size + readsize, GC.BlkAttr.NO_SCAN)[0 ..
cast(int)size + readsize];
enforce(buf, "Out of memory");
scope(failure) delete buf;
auto toread = readsize;
while (toread)
{
auto numread = std.c.linux.linux.read(fd, buf.ptr + size, toread);
cenforce(numread != -1, name);
size += numread;
if (numread == 0)
{ if (size == 0) // it really was 0 size
delete buf; // don't need the buffer
return buf[0 .. size]; // end of file
}
toread -= numread;
}
}
}
else
{
buf = GC.malloc(size, GC.BlkAttr.NO_SCAN)[0 .. size];
enforce(buf, "Out of memory");
scope(failure) delete buf;
cenforce(std.c.linux.linux.read(fd, buf.ptr, size) == size, name);
return buf[0 .. size];
}
}
// Implementation 2
void[] read(string name)
{
immutable fd = std.c.linux.linux.open(toStringz(name), O_RDONLY);
cenforce(fd != -1, name);
scope(exit) std.c.linux.linux.close(fd);
struct_stat statbuf = void;
cenforce(std.c.linux.linux.fstat(fd, &statbuf) == 0, name);
immutable initialAlloc = statbuf.st_size ? statbuf.st_size + 1 : 1024;
void[] result = GC.malloc(initialAlloc, GC.BlkAttr.NO_SCAN)
[0 .. initialAlloc];
scope(failure) delete result;
size_t size = 0;
for (;;)
{
immutable actual = std.c.linux.linux.read(fd, result.ptr + size,
result.length - size);
cenforce(actual != actual.max, name);
size += actual;
if (size < result.length) break;
auto newAlloc = size + 1024 * 4;
result = GC.realloc(result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)
[0 .. newAlloc];
}
return result[0 .. size];
}
More information about the Digitalmars-d
mailing list