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