| author | |
| committer | |
| log | 90743881cf10c4f90da4a8c187997e9eab4d17d5 |
| tree | 18aa129e10ce74b673b58e8766cec8dbae99d1bc |
| parent | 5f31d54064b204910c18667d0b68b8bf2b57cffb |
* 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 case5 files changed, 31 insertions(+), 13 deletions(-)
lib/std/fs.zig+7-2| ... | @@ -1437,24 +1437,29 @@ pub const Dir = struct { | ... | @@ -1437,24 +1437,29 @@ pub const Dir = struct { |
| 1437 | /// On success, caller owns returned buffer. | 1437 | /// On success, caller owns returned buffer. |
| 1438 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 1438 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 1439 | pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 { | 1439 | pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 { |
| 1440 | return self.readFileAllocOptions(allocator, file_path, max_bytes, @alignOf(u8), null); | 1440 | return self.readFileAllocOptions(allocator, file_path, max_bytes, null, @alignOf(u8), null); |
| 1441 | } | 1441 | } |
| 1442 | 1442 | ||
| 1443 | /// On success, caller owns returned buffer. | 1443 | /// On success, caller owns returned buffer. |
| 1444 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 1444 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 1445 | /// If `size_hint` is specified the initial buffer size is calculated using | ||
| 1446 | /// that value, otherwise the effective file size is used instead. | ||
| 1445 | /// Allows specifying alignment and a sentinel value. | 1447 | /// Allows specifying alignment and a sentinel value. |
| 1446 | pub fn readFileAllocOptions( | 1448 | pub fn readFileAllocOptions( |
| 1447 | self: Dir, | 1449 | self: Dir, |
| 1448 | allocator: *mem.Allocator, | 1450 | allocator: *mem.Allocator, |
| 1449 | file_path: []const u8, | 1451 | file_path: []const u8, |
| 1450 | max_bytes: usize, | 1452 | max_bytes: usize, |
| 1453 | size_hint: ?usize, | ||
| 1451 | comptime alignment: u29, | 1454 | comptime alignment: u29, |
| 1452 | comptime optional_sentinel: ?u8, | 1455 | comptime optional_sentinel: ?u8, |
| 1453 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { | 1456 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { |
| 1454 | var file = try self.openFile(file_path, .{}); | 1457 | var file = try self.openFile(file_path, .{}); |
| 1455 | defer file.close(); | 1458 | defer file.close(); |
| 1456 | 1459 | ||
| 1457 | return file.readAllAllocOptions(allocator, max_bytes, alignment, optional_sentinel); | 1460 | const stat_size = size_hint orelse try file.getEndPos(); |
| 1461 | |||
| 1462 | return file.readToEndAllocOptions(allocator, max_bytes, stat_size, alignment, optional_sentinel); | ||
| 1458 | } | 1463 | } |
| 1459 | 1464 | ||
| 1460 | pub const DeleteTreeError = error{ | 1465 | pub const DeleteTreeError = error{ |
lib/std/fs/file.zig+10-6| ... | @@ -363,25 +363,29 @@ pub const File = struct { | ... | @@ -363,25 +363,29 @@ pub const File = struct { |
| 363 | try os.futimens(self.handle, &times); | 363 | try os.futimens(self.handle, &times); |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | /// Reads all the bytes from the current position to the end of the file. | ||
| 366 | /// On success, caller owns returned buffer. | 367 | /// On success, caller owns returned buffer. |
| 367 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 368 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 368 | pub fn readAllAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 { | 369 | pub fn readToEndAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 { |
| 369 | return self.readAllAllocOptions(allocator, max_bytes, @alignOf(u8), null); | 370 | return self.readToEndAllocOptions(allocator, max_bytes, null, @alignOf(u8), null); |
| 370 | } | 371 | } |
| 371 | 372 | ||
| 373 | /// Reads all the bytes from the current position to the end of the file. | ||
| 372 | /// On success, caller owns returned buffer. | 374 | /// On success, caller owns returned buffer. |
| 373 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 375 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 376 | /// If `size_hint` is specified the initial buffer size is calculated using | ||
| 377 | /// that value, otherwise an arbitrary value is used instead. | ||
| 374 | /// Allows specifying alignment and a sentinel value. | 378 | /// Allows specifying alignment and a sentinel value. |
| 375 | pub fn readAllAllocOptions( | 379 | pub fn readToEndAllocOptions( |
| 376 | self: File, | 380 | self: File, |
| 377 | allocator: *mem.Allocator, | 381 | allocator: *mem.Allocator, |
| 378 | max_bytes: usize, | 382 | max_bytes: usize, |
| 383 | size_hint: ?usize, | ||
| 379 | comptime alignment: u29, | 384 | comptime alignment: u29, |
| 380 | comptime optional_sentinel: ?u8, | 385 | comptime optional_sentinel: ?u8, |
| 381 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { | 386 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { |
| 382 | const stat_size = try self.getEndPos(); | 387 | // If no size hint is provided fall back to the size=0 code path |
| 383 | const size = math.cast(usize, stat_size) catch math.maxInt(usize); | 388 | const size = size_hint orelse 0; |
| 384 | if (size > max_bytes) return error.FileTooBig; | ||
| 385 | 389 | ||
| 386 | // The file size returned by stat is used as hint to set the buffer | 390 | // The file size returned by stat is used as hint to set the buffer |
| 387 | // size. If the reported size is zero, as it happens on Linux for files | 391 | // size. If the reported size is zero, as it happens on Linux for files |
lib/std/fs/test.zig+5-4| ... | @@ -188,7 +188,7 @@ test "readAllAlloc" { | ... | @@ -188,7 +188,7 @@ test "readAllAlloc" { |
| 188 | var file = try tmp_dir.dir.createFile("test_file", .{ .read = true }); | 188 | var file = try tmp_dir.dir.createFile("test_file", .{ .read = true }); |
| 189 | defer file.close(); | 189 | defer file.close(); |
| 190 | 190 | ||
| 191 | const buf1 = try file.readAllAlloc(testing.allocator, 1024); | 191 | const buf1 = try file.readToEndAlloc(testing.allocator, 1024); |
| 192 | defer testing.allocator.free(buf1); | 192 | defer testing.allocator.free(buf1); |
| 193 | testing.expect(buf1.len == 0); | 193 | testing.expect(buf1.len == 0); |
| 194 | 194 | ||
| ... | @@ -197,20 +197,21 @@ test "readAllAlloc" { | ... | @@ -197,20 +197,21 @@ test "readAllAlloc" { |
| 197 | try file.seekTo(0); | 197 | try file.seekTo(0); |
| 198 | 198 | ||
| 199 | // max_bytes > file_size | 199 | // max_bytes > file_size |
| 200 | const buf2 = try file.readAllAlloc(testing.allocator, 1024); | 200 | const buf2 = try file.readToEndAlloc(testing.allocator, 1024); |
| 201 | defer testing.allocator.free(buf2); | 201 | defer testing.allocator.free(buf2); |
| 202 | testing.expectEqual(write_buf.len, buf2.len); | 202 | testing.expectEqual(write_buf.len, buf2.len); |
| 203 | testing.expect(std.mem.eql(u8, write_buf, buf2)); | 203 | testing.expect(std.mem.eql(u8, write_buf, buf2)); |
| 204 | try file.seekTo(0); | 204 | try file.seekTo(0); |
| 205 | 205 | ||
| 206 | // max_bytes == file_size | 206 | // max_bytes == file_size |
| 207 | const buf3 = try file.readAllAlloc(testing.allocator, write_buf.len); | 207 | const buf3 = try file.readToEndAlloc(testing.allocator, write_buf.len); |
| 208 | defer testing.allocator.free(buf3); | 208 | defer testing.allocator.free(buf3); |
| 209 | testing.expectEqual(write_buf.len, buf3.len); | 209 | testing.expectEqual(write_buf.len, buf3.len); |
| 210 | testing.expect(std.mem.eql(u8, write_buf, buf3)); | 210 | testing.expect(std.mem.eql(u8, write_buf, buf3)); |
| 211 | try file.seekTo(0); | ||
| 211 | 212 | ||
| 212 | // max_bytes < file_size | 213 | // max_bytes < file_size |
| 213 | testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, write_buf.len - 1)); | 214 | testing.expectError(error.FileTooBig, file.readToEndAlloc(testing.allocator, write_buf.len - 1)); |
| 214 | } | 215 | } |
| 215 | 216 | ||
| 216 | test "directory operations on files" { | 217 | test "directory operations on files" { |
src-self-hosted/Module.zig+2| ... | @@ -595,6 +595,7 @@ pub const Scope = struct { | ... | @@ -595,6 +595,7 @@ pub const Scope = struct { |
| 595 | module.gpa, | 595 | module.gpa, |
| 596 | self.sub_file_path, | 596 | self.sub_file_path, |
| 597 | std.math.maxInt(u32), | 597 | std.math.maxInt(u32), |
| 598 | null, | ||
| 598 | 1, | 599 | 1, |
| 599 | 0, | 600 | 0, |
| 600 | ); | 601 | ); |
| ... | @@ -697,6 +698,7 @@ pub const Scope = struct { | ... | @@ -697,6 +698,7 @@ pub const Scope = struct { |
| 697 | module.gpa, | 698 | module.gpa, |
| 698 | self.sub_file_path, | 699 | self.sub_file_path, |
| 699 | std.math.maxInt(u32), | 700 | std.math.maxInt(u32), |
| 701 | null, | ||
| 700 | 1, | 702 | 1, |
| 701 | 0, | 703 | 0, |
| 702 | ); | 704 | ); |
src-self-hosted/main.zig+7-1| ... | @@ -806,7 +806,13 @@ fn fmtPathFile( | ... | @@ -806,7 +806,13 @@ fn fmtPathFile( |
| 806 | if (stat.kind == .Directory) | 806 | if (stat.kind == .Directory) |
| 807 | return error.IsDir; | 807 | return error.IsDir; |
| 808 | 808 | ||
| 809 | const source_code = source_file.readAllAlloc(fmt.gpa, max_src_size) catch |err| switch (err) { | 809 | const source_code = source_file.readToEndAllocOptions( |
| 810 | fmt.gpa, | ||
| 811 | max_src_size, | ||
| 812 | stat.size, | ||
| 813 | @alignOf(u8), | ||
| 814 | null, | ||
| 815 | ) catch |err| switch (err) { | ||
| 810 | error.ConnectionResetByPeer => unreachable, | 816 | error.ConnectionResetByPeer => unreachable, |
| 811 | error.ConnectionTimedOut => unreachable, | 817 | error.ConnectionTimedOut => unreachable, |
| 812 | error.NotOpenForReading => unreachable, | 818 | error.NotOpenForReading => unreachable, |