Commit 90743881cf

LemonBoy <thatlemon@gmail.com>
2020-09-04 09:28:43
std: Minor changes to the fs module
* Add a size_hint parameter to the read{toEnd,File}AllocOptions fns * Rename readAllAlloc{,Options} to readToEndAlloc{,Options} as they don't rewind the file before reading * Fix missing rewind in test case
1 parent 5f31d54
Changed files (5)
lib
src-self-hosted
lib/std/fs/file.zig
@@ -363,25 +363,29 @@ pub const File = struct {
         try os.futimens(self.handle, &times);
     }
 
+    /// Reads all the bytes from the current position to the end of the file.
     /// On success, caller owns returned buffer.
     /// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
-    pub fn readAllAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 {
-        return self.readAllAllocOptions(allocator, max_bytes, @alignOf(u8), null);
+    pub fn readToEndAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 {
+        return self.readToEndAllocOptions(allocator, max_bytes, null, @alignOf(u8), null);
     }
 
+    /// Reads all the bytes from the current position to the end of the file.
     /// On success, caller owns returned buffer.
     /// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
+    /// If `size_hint` is specified the initial buffer size is calculated using
+    /// that value, otherwise an arbitrary value is used instead.
     /// Allows specifying alignment and a sentinel value.
-    pub fn readAllAllocOptions(
+    pub fn readToEndAllocOptions(
         self: File,
         allocator: *mem.Allocator,
         max_bytes: usize,
+        size_hint: ?usize,
         comptime alignment: u29,
         comptime optional_sentinel: ?u8,
     ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) {
-        const stat_size = try self.getEndPos();
-        const size = math.cast(usize, stat_size) catch math.maxInt(usize);
-        if (size > max_bytes) return error.FileTooBig;
+        // If no size hint is provided fall back to the size=0 code path
+        const size = size_hint orelse 0;
 
         // The file size returned by stat is used as hint to set the buffer
         // size. If the reported size is zero, as it happens on Linux for files
lib/std/fs/test.zig
@@ -188,7 +188,7 @@ test "readAllAlloc" {
     var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });
     defer file.close();
 
-    const buf1 = try file.readAllAlloc(testing.allocator, 1024);
+    const buf1 = try file.readToEndAlloc(testing.allocator, 1024);
     defer testing.allocator.free(buf1);
     testing.expect(buf1.len == 0);
 
@@ -197,20 +197,21 @@ test "readAllAlloc" {
     try file.seekTo(0);
 
     // max_bytes > file_size
-    const buf2 = try file.readAllAlloc(testing.allocator, 1024);
+    const buf2 = try file.readToEndAlloc(testing.allocator, 1024);
     defer testing.allocator.free(buf2);
     testing.expectEqual(write_buf.len, buf2.len);
     testing.expect(std.mem.eql(u8, write_buf, buf2));
     try file.seekTo(0);
 
     // max_bytes == file_size
-    const buf3 = try file.readAllAlloc(testing.allocator, write_buf.len);
+    const buf3 = try file.readToEndAlloc(testing.allocator, write_buf.len);
     defer testing.allocator.free(buf3);
     testing.expectEqual(write_buf.len, buf3.len);
     testing.expect(std.mem.eql(u8, write_buf, buf3));
+    try file.seekTo(0);
 
     // max_bytes < file_size
-    testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, write_buf.len - 1));
+    testing.expectError(error.FileTooBig, file.readToEndAlloc(testing.allocator, write_buf.len - 1));
 }
 
 test "directory operations on files" {
lib/std/fs.zig
@@ -1437,24 +1437,29 @@ pub const Dir = struct {
     /// On success, caller owns returned buffer.
     /// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
     pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 {
-        return self.readFileAllocOptions(allocator, file_path, max_bytes, @alignOf(u8), null);
+        return self.readFileAllocOptions(allocator, file_path, max_bytes, null, @alignOf(u8), null);
     }
 
     /// On success, caller owns returned buffer.
     /// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
+    /// If `size_hint` is specified the initial buffer size is calculated using
+    /// that value, otherwise the effective file size is used instead.
     /// Allows specifying alignment and a sentinel value.
     pub fn readFileAllocOptions(
         self: Dir,
         allocator: *mem.Allocator,
         file_path: []const u8,
         max_bytes: usize,
+        size_hint: ?usize,
         comptime alignment: u29,
         comptime optional_sentinel: ?u8,
     ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) {
         var file = try self.openFile(file_path, .{});
         defer file.close();
 
-        return file.readAllAllocOptions(allocator, max_bytes, alignment, optional_sentinel);
+        const stat_size = size_hint orelse try file.getEndPos();
+
+        return file.readToEndAllocOptions(allocator, max_bytes, stat_size, alignment, optional_sentinel);
     }
 
     pub const DeleteTreeError = error{
src-self-hosted/main.zig
@@ -806,7 +806,13 @@ fn fmtPathFile(
     if (stat.kind == .Directory)
         return error.IsDir;
 
-    const source_code = source_file.readAllAlloc(fmt.gpa, max_src_size) catch |err| switch (err) {
+    const source_code = source_file.readToEndAllocOptions(
+        fmt.gpa,
+        max_src_size,
+        stat.size,
+        @alignOf(u8),
+        null,
+    ) catch |err| switch (err) {
         error.ConnectionResetByPeer => unreachable,
         error.ConnectionTimedOut => unreachable,
         error.NotOpenForReading => unreachable,
src-self-hosted/Module.zig
@@ -595,6 +595,7 @@ pub const Scope = struct {
                         module.gpa,
                         self.sub_file_path,
                         std.math.maxInt(u32),
+                        null,
                         1,
                         0,
                     );
@@ -697,6 +698,7 @@ pub const Scope = struct {
                         module.gpa,
                         self.sub_file_path,
                         std.math.maxInt(u32),
+                        null,
                         1,
                         0,
                     );