| author | |
| committer | |
| log | 383afd19d73c7d98c8d1f7fe9d474b980517372e |
| tree | 48a66ca514f3b3610feb037fa4295fecc61114b1 |
| parent | 4ee25345668ff93f1a4a857436b14fc305f8cee7 |
it's the wrong abstraction and is only a footgun when used this way.7 files changed, 188 insertions(+), 175 deletions(-)
lib/std/fmt.zig+1-1| ... | @@ -856,7 +856,7 @@ pub fn count(comptime fmt: []const u8, args: anytype) usize { | ... | @@ -856,7 +856,7 @@ pub fn count(comptime fmt: []const u8, args: anytype) usize { |
| 856 | var buffer: [std.atomic.cache_line]u8 = undefined; | 856 | var buffer: [std.atomic.cache_line]u8 = undefined; |
| 857 | var bw = std.io.Writer.null.buffered(&buffer); | 857 | var bw = std.io.Writer.null.buffered(&buffer); |
| 858 | bw.print(fmt, args) catch unreachable; | 858 | bw.print(fmt, args) catch unreachable; |
| 859 | return bw.bytes_written; | 859 | return bw.count; |
| 860 | } | 860 | } |
| 861 | 861 | ||
| 862 | pub const AllocPrintError = error{OutOfMemory}; | 862 | pub const AllocPrintError = error{OutOfMemory}; |
lib/std/io/AllocatingWriter.zig+20-10| ... | @@ -27,19 +27,27 @@ const vtable: std.io.Writer.VTable = .{ | ... | @@ -27,19 +27,27 @@ const vtable: std.io.Writer.VTable = .{ |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | /// Sets the `AllocatingWriter` to an empty state. | 29 | /// Sets the `AllocatingWriter` to an empty state. |
| 30 | pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) *std.io.BufferedWriter { | 30 | pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) void { |
| 31 | initOwnedSlice(aw, allocator, &.{}); | ||
| 32 | } | ||
| 33 | |||
| 34 | pub fn initCapacity(aw: *AllocatingWriter, allocator: std.mem.Allocator, capacity: usize) error{OutOfMemory}!void { | ||
| 35 | const initial_buffer = try allocator.alloc(u8, capacity); | ||
| 36 | initOwnedSlice(aw, allocator, initial_buffer); | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn initOwnedSlice(aw: *AllocatingWriter, allocator: std.mem.Allocator, slice: []u8) void { | ||
| 31 | aw.* = .{ | 40 | aw.* = .{ |
| 32 | .written = &.{}, | 41 | .written = slice[0..0], |
| 33 | .allocator = allocator, | 42 | .allocator = allocator, |
| 34 | .buffered_writer = .{ | 43 | .buffered_writer = .{ |
| 35 | .unbuffered_writer = .{ | 44 | .unbuffered_writer = .{ |
| 36 | .context = aw, | 45 | .context = aw, |
| 37 | .vtable = &vtable, | 46 | .vtable = &vtable, |
| 38 | }, | 47 | }, |
| 39 | .buffer = &.{}, | 48 | .buffer = slice, |
| 40 | }, | 49 | }, |
| 41 | }; | 50 | }; |
| 42 | return &aw.buffered_writer; | ||
| 43 | } | 51 | } |
| 44 | 52 | ||
| 45 | pub fn deinit(aw: *AllocatingWriter) void { | 53 | pub fn deinit(aw: *AllocatingWriter) void { |
| ... | @@ -118,7 +126,7 @@ pub fn clearRetainingCapacity(aw: *AllocatingWriter) void { | ... | @@ -118,7 +126,7 @@ pub fn clearRetainingCapacity(aw: *AllocatingWriter) void { |
| 118 | aw.written.len = 0; | 126 | aw.written.len = 0; |
| 119 | } | 127 | } |
| 120 | 128 | ||
| 121 | fn writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | 129 | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |
| 122 | const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); | 130 | const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); |
| 123 | const start_len = aw.written.len; | 131 | const start_len = aw.written.len; |
| 124 | const bw = &aw.buffered_writer; | 132 | const bw = &aw.buffered_writer; |
| ... | @@ -150,9 +158,9 @@ fn appendPatternAssumeCapacity(list: *std.ArrayListUnmanaged(u8), pattern: []con | ... | @@ -150,9 +158,9 @@ fn appendPatternAssumeCapacity(list: *std.ArrayListUnmanaged(u8), pattern: []con |
| 150 | } | 158 | } |
| 151 | 159 | ||
| 152 | fn writeFile( | 160 | fn writeFile( |
| 153 | context: *anyopaque, | 161 | context: ?*anyopaque, |
| 154 | file: std.fs.File, | 162 | file: std.fs.File, |
| 155 | offset: u64, | 163 | offset: std.io.Writer.Offset, |
| 156 | len: std.io.Writer.FileLen, | 164 | len: std.io.Writer.FileLen, |
| 157 | headers_and_trailers_full: []const []const u8, | 165 | headers_and_trailers_full: []const []const u8, |
| 158 | headers_len_full: usize, | 166 | headers_len_full: usize, |
| ... | @@ -168,13 +176,14 @@ fn writeFile( | ... | @@ -168,13 +176,14 @@ fn writeFile( |
| 168 | break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; | 176 | break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; |
| 169 | } else .{ headers_and_trailers_full, headers_len_full }; | 177 | } else .{ headers_and_trailers_full, headers_len_full }; |
| 170 | const trailers = headers_and_trailers[headers_len..]; | 178 | const trailers = headers_and_trailers[headers_len..]; |
| 179 | const pos = offset.toInt() orelse @panic("TODO treat file as stream"); | ||
| 171 | if (len == .entire_file) { | 180 | if (len == .entire_file) { |
| 172 | var new_capacity: usize = list.capacity + std.atomic.cache_line; | 181 | var new_capacity: usize = list.capacity + std.atomic.cache_line; |
| 173 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; | 182 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; |
| 174 | try list.ensureTotalCapacity(gpa, new_capacity); | 183 | try list.ensureTotalCapacity(gpa, new_capacity); |
| 175 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); | 184 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); |
| 176 | const dest = list.items.ptr[list.items.len..list.capacity]; | 185 | const dest = list.items.ptr[list.items.len..list.capacity]; |
| 177 | const n = try file.pread(dest, offset); | 186 | const n = try file.pread(dest, pos); |
| 178 | if (n == 0) { | 187 | if (n == 0) { |
| 179 | new_capacity = list.capacity; | 188 | new_capacity = list.capacity; |
| 180 | for (trailers) |bytes| new_capacity += bytes.len; | 189 | for (trailers) |bytes| new_capacity += bytes.len; |
| ... | @@ -190,7 +199,7 @@ fn writeFile( | ... | @@ -190,7 +199,7 @@ fn writeFile( |
| 190 | try list.ensureTotalCapacity(gpa, new_capacity); | 199 | try list.ensureTotalCapacity(gpa, new_capacity); |
| 191 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); | 200 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); |
| 192 | const dest = list.items.ptr[list.items.len..][0..len.int()]; | 201 | const dest = list.items.ptr[list.items.len..][0..len.int()]; |
| 193 | const n = try file.pread(dest, offset); | 202 | const n = try file.pread(dest, pos); |
| 194 | list.items.len += n; | 203 | list.items.len += n; |
| 195 | if (n < dest.len) { | 204 | if (n < dest.len) { |
| 196 | return list.items.len - start_len; | 205 | return list.items.len - start_len; |
| ... | @@ -201,8 +210,9 @@ fn writeFile( | ... | @@ -201,8 +210,9 @@ fn writeFile( |
| 201 | 210 | ||
| 202 | test AllocatingWriter { | 211 | test AllocatingWriter { |
| 203 | var aw: AllocatingWriter = undefined; | 212 | var aw: AllocatingWriter = undefined; |
| 204 | const bw = aw.init(std.testing.allocator); | 213 | aw.init(std.testing.allocator); |
| 205 | defer aw.deinit(); | 214 | defer aw.deinit(); |
| 215 | const bw = &aw.buffered_writer; | ||
| 206 | 216 | ||
| 207 | const x: i32 = 42; | 217 | const x: i32 = 42; |
| 208 | const y: i32 = 1234; | 218 | const y: i32 = 1234; |
lib/std/io/BufferedReader.zig+54-51| ... | @@ -74,7 +74,7 @@ pub fn initFixed(br: *BufferedReader, buffer: []const u8) void { | ... | @@ -74,7 +74,7 @@ pub fn initFixed(br: *BufferedReader, buffer: []const u8) void { |
| 74 | br.* = .{ | 74 | br.* = .{ |
| 75 | .seek = 0, | 75 | .seek = 0, |
| 76 | .storage = .{ | 76 | .storage = .{ |
| 77 | .buffer = .fromOwnedSlice(@constCast(buffer)), | 77 | .buffer = @constCast(buffer), |
| 78 | .unbuffered_writer = .{ | 78 | .unbuffered_writer = .{ |
| 79 | .context = undefined, | 79 | .context = undefined, |
| 80 | .vtable = &eof_writer, | 80 | .vtable = &eof_writer, |
| ... | @@ -88,9 +88,10 @@ pub fn initFixed(br: *BufferedReader, buffer: []const u8) void { | ... | @@ -88,9 +88,10 @@ pub fn initFixed(br: *BufferedReader, buffer: []const u8) void { |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | pub fn storageBuffer(br: *BufferedReader) []u8 { | 90 | pub fn storageBuffer(br: *BufferedReader) []u8 { |
| 91 | assert(br.storage.unbuffered_writer.vtable == &eof_writer); | 91 | const storage = &br.storage; |
| 92 | assert(storage.unbuffered_writer.vtable == &eof_writer); | ||
| 92 | assert(br.unbuffered_reader.vtable == &eof_reader); | 93 | assert(br.unbuffered_reader.vtable == &eof_reader); |
| 93 | return br.storage.buffer.allocatedSlice(); | 94 | return storage.buffer; |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | /// Although `BufferedReader` can easily satisfy the `Reader` interface, it's | 97 | /// Although `BufferedReader` can easily satisfy the `Reader` interface, it's |
| ... | @@ -108,7 +109,8 @@ pub fn reader(br: *BufferedReader) Reader { | ... | @@ -108,7 +109,8 @@ pub fn reader(br: *BufferedReader) Reader { |
| 108 | 109 | ||
| 109 | fn passthru_read(ctx: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) anyerror!Reader.RwResult { | 110 | fn passthru_read(ctx: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) anyerror!Reader.RwResult { |
| 110 | const br: *BufferedReader = @alignCast(@ptrCast(ctx)); | 111 | const br: *BufferedReader = @alignCast(@ptrCast(ctx)); |
| 111 | const buffer = br.storage.buffer.items; | 112 | const storage = &br.storage; |
| 113 | const buffer = storage.buffer[0..storage.end]; | ||
| 112 | const buffered = buffer[br.seek..]; | 114 | const buffered = buffer[br.seek..]; |
| 113 | const limited = buffered[0..limit.min(buffered.len)]; | 115 | const limited = buffered[0..limit.min(buffered.len)]; |
| 114 | if (limited.len > 0) { | 116 | if (limited.len > 0) { |
| ... | @@ -135,7 +137,7 @@ pub fn seekBy(br: *BufferedReader, seek_by: i64) anyerror!void { | ... | @@ -135,7 +137,7 @@ pub fn seekBy(br: *BufferedReader, seek_by: i64) anyerror!void { |
| 135 | } | 137 | } |
| 136 | 138 | ||
| 137 | pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) anyerror!void { | 139 | pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) anyerror!void { |
| 138 | if (seek_by > br.storage.buffer.items.len - br.seek) return error.Unseekable; // TODO | 140 | if (seek_by > br.storage.end - br.seek) return error.Unseekable; // TODO |
| 139 | br.seek += @abs(seek_by); | 141 | br.seek += @abs(seek_by); |
| 140 | } | 142 | } |
| 141 | 143 | ||
| ... | @@ -178,10 +180,10 @@ pub fn peek(br: *BufferedReader, n: usize) anyerror![]u8 { | ... | @@ -178,10 +180,10 @@ pub fn peek(br: *BufferedReader, n: usize) anyerror![]u8 { |
| 178 | /// * `peek` | 180 | /// * `peek` |
| 179 | /// * `toss` | 181 | /// * `toss` |
| 180 | pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 { | 182 | pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 { |
| 181 | const list = &br.storage.buffer; | 183 | const storage = &br.storage; |
| 182 | assert(n <= list.capacity); | 184 | assert(n <= storage.buffer.len); |
| 183 | try br.fill(n); | 185 | try br.fill(n); |
| 184 | return list.items[br.seek..]; | 186 | return storage.buffer[br.seek..storage.end]; |
| 185 | } | 187 | } |
| 186 | 188 | ||
| 187 | /// Skips the next `n` bytes from the stream, advancing the seek position. This | 189 | /// Skips the next `n` bytes from the stream, advancing the seek position. This |
| ... | @@ -194,7 +196,7 @@ pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 { | ... | @@ -194,7 +196,7 @@ pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 { |
| 194 | /// * `discard`. | 196 | /// * `discard`. |
| 195 | pub fn toss(br: *BufferedReader, n: usize) void { | 197 | pub fn toss(br: *BufferedReader, n: usize) void { |
| 196 | br.seek += n; | 198 | br.seek += n; |
| 197 | assert(br.seek <= br.storage.buffer.items.len); | 199 | assert(br.seek <= br.storage.end); |
| 198 | } | 200 | } |
| 199 | 201 | ||
| 200 | /// Equivalent to `peek` + `toss`. | 202 | /// Equivalent to `peek` + `toss`. |
| ... | @@ -245,22 +247,22 @@ pub fn discard(br: *BufferedReader, n: usize) anyerror!void { | ... | @@ -245,22 +247,22 @@ pub fn discard(br: *BufferedReader, n: usize) anyerror!void { |
| 245 | /// * `toss` | 247 | /// * `toss` |
| 246 | /// * `discardUntilEnd` | 248 | /// * `discardUntilEnd` |
| 247 | pub fn discardUpTo(br: *BufferedReader, n: usize) anyerror!usize { | 249 | pub fn discardUpTo(br: *BufferedReader, n: usize) anyerror!usize { |
| 248 | const list = &br.storage.buffer; | 250 | const storage = &br.storage; |
| 249 | var remaining = n; | 251 | var remaining = n; |
| 250 | while (remaining > 0) { | 252 | while (remaining > 0) { |
| 251 | const proposed_seek = br.seek + remaining; | 253 | const proposed_seek = br.seek + remaining; |
| 252 | if (proposed_seek <= list.items.len) { | 254 | if (proposed_seek <= storage.end) { |
| 253 | br.seek = proposed_seek; | 255 | br.seek = proposed_seek; |
| 254 | return; | 256 | return; |
| 255 | } | 257 | } |
| 256 | remaining -= (list.items.len - br.seek); | 258 | remaining -= (storage.end - br.seek); |
| 257 | list.items.len = 0; | 259 | storage.end = 0; |
| 258 | br.seek = 0; | 260 | br.seek = 0; |
| 259 | const result = try br.unbuffered_reader.read(&br.storage, .none); | 261 | const result = try br.unbuffered_reader.read(&storage, .none); |
| 260 | result.write_err catch unreachable; | 262 | result.write_err catch unreachable; |
| 261 | try result.read_err; | 263 | try result.read_err; |
| 262 | assert(result.len == list.items.len); | 264 | assert(result.len == storage.end); |
| 263 | if (remaining <= list.items.len) continue; | 265 | if (remaining <= storage.end) continue; |
| 264 | if (result.end) return n - remaining; | 266 | if (result.end) return n - remaining; |
| 265 | } | 267 | } |
| 266 | } | 268 | } |
| ... | @@ -268,9 +270,9 @@ pub fn discardUpTo(br: *BufferedReader, n: usize) anyerror!usize { | ... | @@ -268,9 +270,9 @@ pub fn discardUpTo(br: *BufferedReader, n: usize) anyerror!usize { |
| 268 | /// Reads the stream until the end, ignoring all the data. | 270 | /// Reads the stream until the end, ignoring all the data. |
| 269 | /// Returns the number of bytes discarded. | 271 | /// Returns the number of bytes discarded. |
| 270 | pub fn discardUntilEnd(br: *BufferedReader) anyerror!usize { | 272 | pub fn discardUntilEnd(br: *BufferedReader) anyerror!usize { |
| 271 | const list = &br.storage.buffer; | 273 | const storage = &br.storage; |
| 272 | var total: usize = list.items.len; | 274 | var total: usize = storage.end; |
| 273 | list.items.len = 0; | 275 | storage.end = 0; |
| 274 | total += try br.unbuffered_reader.discardUntilEnd(); | 276 | total += try br.unbuffered_reader.discardUntilEnd(); |
| 275 | return total; | 277 | return total; |
| 276 | } | 278 | } |
| ... | @@ -286,8 +288,8 @@ pub fn discardUntilEnd(br: *BufferedReader) anyerror!usize { | ... | @@ -286,8 +288,8 @@ pub fn discardUntilEnd(br: *BufferedReader) anyerror!usize { |
| 286 | /// See also: | 288 | /// See also: |
| 287 | /// * `peek` | 289 | /// * `peek` |
| 288 | pub fn read(br: *BufferedReader, buffer: []u8) anyerror!void { | 290 | pub fn read(br: *BufferedReader, buffer: []u8) anyerror!void { |
| 289 | const list = &br.storage.buffer; | 291 | const storage = &br.storage; |
| 290 | const in_buffer = list.items; | 292 | const in_buffer = storage.buffer[0..storage.end]; |
| 291 | const seek = br.seek; | 293 | const seek = br.seek; |
| 292 | const proposed_seek = seek + in_buffer.len; | 294 | const proposed_seek = seek + in_buffer.len; |
| 293 | if (proposed_seek <= in_buffer.len) { | 295 | if (proposed_seek <= in_buffer.len) { |
| ... | @@ -296,21 +298,21 @@ pub fn read(br: *BufferedReader, buffer: []u8) anyerror!void { | ... | @@ -296,21 +298,21 @@ pub fn read(br: *BufferedReader, buffer: []u8) anyerror!void { |
| 296 | return; | 298 | return; |
| 297 | } | 299 | } |
| 298 | @memcpy(buffer[0..in_buffer.len], in_buffer); | 300 | @memcpy(buffer[0..in_buffer.len], in_buffer); |
| 299 | list.items.len = 0; | 301 | storage.end = 0; |
| 300 | br.seek = 0; | 302 | br.seek = 0; |
| 301 | var i: usize = in_buffer.len; | 303 | var i: usize = in_buffer.len; |
| 302 | while (true) { | 304 | while (true) { |
| 303 | const status = try br.unbuffered_reader.read(&br.storage, .none); | 305 | const status = try br.unbuffered_reader.read(storage, .none); |
| 304 | const next_i = i + list.items.len; | 306 | const next_i = i + storage.end; |
| 305 | if (next_i >= buffer.len) { | 307 | if (next_i >= buffer.len) { |
| 306 | const remaining = buffer[i..]; | 308 | const remaining = buffer[i..]; |
| 307 | @memcpy(remaining, list.items[0..remaining.len]); | 309 | @memcpy(remaining, storage.buffer[0..remaining.len]); |
| 308 | br.seek = remaining.len; | 310 | br.seek = remaining.len; |
| 309 | return; | 311 | return; |
| 310 | } | 312 | } |
| 311 | if (status.end) return error.EndOfStream; | 313 | if (status.end) return error.EndOfStream; |
| 312 | @memcpy(buffer[i..next_i], list.items); | 314 | @memcpy(buffer[i..next_i], storage.buffer[0..storage.end]); |
| 313 | list.items.len = 0; | 315 | storage.end = 0; |
| 314 | i = next_i; | 316 | i = next_i; |
| 315 | } | 317 | } |
| 316 | } | 318 | } |
| ... | @@ -347,8 +349,8 @@ pub fn takeDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 | ... | @@ -347,8 +349,8 @@ pub fn takeDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 347 | } | 349 | } |
| 348 | 350 | ||
| 349 | pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { | 351 | pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { |
| 350 | const list = &br.storage.buffer; | 352 | const storage = &br.storage; |
| 351 | const buffer = list.items; | 353 | const buffer = storage.buffer[0..storage.end]; |
| 352 | const seek = br.seek; | 354 | const seek = br.seek; |
| 353 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { | 355 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { |
| 354 | @branchHint(.likely); | 356 | @branchHint(.likely); |
| ... | @@ -357,15 +359,15 @@ pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 | ... | @@ -357,15 +359,15 @@ pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 357 | const remainder = buffer[seek..]; | 359 | const remainder = buffer[seek..]; |
| 358 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 360 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 359 | var i = remainder.len; | 361 | var i = remainder.len; |
| 360 | list.items.len = i; | 362 | storage.end = i; |
| 361 | br.seek = 0; | 363 | br.seek = 0; |
| 362 | while (i < list.capacity) { | 364 | while (i < storage.buffer.len) { |
| 363 | const status = try br.unbuffered_reader.read(&br.storage, .none); | 365 | const status = try br.unbuffered_reader.read(storage, .none); |
| 364 | if (std.mem.indexOfScalarPos(u8, list.items, i, delimiter)) |end| { | 366 | if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { |
| 365 | return list.items[0 .. end + 1]; | 367 | return storage.buffer[0 .. end + 1]; |
| 366 | } | 368 | } |
| 367 | if (status.end) return error.EndOfStream; | 369 | if (status.end) return error.EndOfStream; |
| 368 | i = list.items.len; | 370 | i = storage.end; |
| 369 | } | 371 | } |
| 370 | return error.StreamTooLong; | 372 | return error.StreamTooLong; |
| 371 | } | 373 | } |
| ... | @@ -392,8 +394,8 @@ pub fn takeDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 | ... | @@ -392,8 +394,8 @@ pub fn takeDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 392 | } | 394 | } |
| 393 | 395 | ||
| 394 | pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { | 396 | pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { |
| 395 | const list = &br.storage.buffer; | 397 | const storage = &br.storage; |
| 396 | const buffer = list.items; | 398 | const buffer = storage.buffer[0..storage.end]; |
| 397 | const seek = br.seek; | 399 | const seek = br.seek; |
| 398 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { | 400 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { |
| 399 | @branchHint(.likely); | 401 | @branchHint(.likely); |
| ... | @@ -402,15 +404,15 @@ pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 | ... | @@ -402,15 +404,15 @@ pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 402 | const remainder = buffer[seek..]; | 404 | const remainder = buffer[seek..]; |
| 403 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 405 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 404 | var i = remainder.len; | 406 | var i = remainder.len; |
| 405 | list.items.len = i; | 407 | storage.end = i; |
| 406 | br.seek = 0; | 408 | br.seek = 0; |
| 407 | while (i < list.capacity) { | 409 | while (i < storage.buffer.len) { |
| 408 | const status = try br.unbuffered_reader.read(&br.storage, .none); | 410 | const status = try br.unbuffered_reader.read(storage, .none); |
| 409 | if (std.mem.indexOfScalarPos(u8, list.items, i, delimiter)) |end| { | 411 | if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { |
| 410 | return list.items[0 .. end + 1]; | 412 | return storage.buffer[0 .. end + 1]; |
| 411 | } | 413 | } |
| 412 | if (status.end) return list.items; | 414 | if (status.end) return storage.buffer[0..storage.end]; |
| 413 | i = list.items.len; | 415 | i = storage.end; |
| 414 | } | 416 | } |
| 415 | return error.StreamTooLong; | 417 | return error.StreamTooLong; |
| 416 | } | 418 | } |
| ... | @@ -490,9 +492,9 @@ pub fn discardDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror!vo | ... | @@ -490,9 +492,9 @@ pub fn discardDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror!vo |
| 490 | /// | 492 | /// |
| 491 | /// Asserts buffer capacity is at least `n`. | 493 | /// Asserts buffer capacity is at least `n`. |
| 492 | pub fn fill(br: *BufferedReader, n: usize) anyerror!void { | 494 | pub fn fill(br: *BufferedReader, n: usize) anyerror!void { |
| 493 | assert(n <= br.storage.buffer.capacity); | 495 | const storage = &br.storage; |
| 494 | const list = &br.storage.buffer; | 496 | assert(n <= storage.buffer.len); |
| 495 | const buffer = list.items; | 497 | const buffer = storage.buffer[0..storage.end]; |
| 496 | const seek = br.seek; | 498 | const seek = br.seek; |
| 497 | if (seek + n <= buffer.len) { | 499 | if (seek + n <= buffer.len) { |
| 498 | @branchHint(.likely); | 500 | @branchHint(.likely); |
| ... | @@ -500,18 +502,19 @@ pub fn fill(br: *BufferedReader, n: usize) anyerror!void { | ... | @@ -500,18 +502,19 @@ pub fn fill(br: *BufferedReader, n: usize) anyerror!void { |
| 500 | } | 502 | } |
| 501 | const remainder = buffer[seek..]; | 503 | const remainder = buffer[seek..]; |
| 502 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 504 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 503 | list.items.len = remainder.len; | 505 | storage.end = remainder.len; |
| 504 | br.seek = 0; | 506 | br.seek = 0; |
| 505 | while (true) { | 507 | while (true) { |
| 506 | const status = try br.unbuffered_reader.read(&br.storage, .none); | 508 | const status = try br.unbuffered_reader.read(storage, .none); |
| 507 | if (n <= list.items.len) return; | 509 | if (n <= storage.end) return; |
| 508 | if (status.end) return error.EndOfStream; | 510 | if (status.end) return error.EndOfStream; |
| 509 | } | 511 | } |
| 510 | } | 512 | } |
| 511 | 513 | ||
| 512 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. | 514 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. |
| 513 | pub fn takeByte(br: *BufferedReader) anyerror!u8 { | 515 | pub fn takeByte(br: *BufferedReader) anyerror!u8 { |
| 514 | const buffer = br.storage.buffer.items; | 516 | const storage = &br.storage; |
| 517 | const buffer = storage.buffer[0..storage.end]; | ||
| 515 | const seek = br.seek; | 518 | const seek = br.seek; |
| 516 | if (seek >= buffer.len) { | 519 | if (seek >= buffer.len) { |
| 517 | @branchHint(.unlikely); | 520 | @branchHint(.unlikely); |
lib/std/io/BufferedWriter.zig+94-98| ... | @@ -6,10 +6,6 @@ const Writer = std.io.Writer; | ... | @@ -6,10 +6,6 @@ const Writer = std.io.Writer; |
| 6 | const Allocator = std.mem.Allocator; | 6 | const Allocator = std.mem.Allocator; |
| 7 | const testing = std.testing; | 7 | const testing = std.testing; |
| 8 | 8 | ||
| 9 | /// User-provided storage that must outlive this `BufferedWriter`. | ||
| 10 | /// | ||
| 11 | /// If this has capacity zero, the writer is unbuffered, and `flush` is a no-op. | ||
| 12 | buffer: std.ArrayListUnmanaged(u8), | ||
| 13 | /// Underlying stream to send bytes to. | 9 | /// Underlying stream to send bytes to. |
| 14 | /// | 10 | /// |
| 15 | /// A write will only be sent here if it could not fit into `buffer`, or if it | 11 | /// A write will only be sent here if it could not fit into `buffer`, or if it |
| ... | @@ -19,10 +15,14 @@ buffer: std.ArrayListUnmanaged(u8), | ... | @@ -19,10 +15,14 @@ buffer: std.ArrayListUnmanaged(u8), |
| 19 | /// equals number of bytes provided. This property is exploited by | 15 | /// equals number of bytes provided. This property is exploited by |
| 20 | /// `std.io.AllocatingWriter` for example. | 16 | /// `std.io.AllocatingWriter` for example. |
| 21 | unbuffered_writer: Writer, | 17 | unbuffered_writer: Writer, |
| 18 | /// If this has length zero, the writer is unbuffered, and `flush` is a no-op. | ||
| 19 | buffer: []u8, | ||
| 20 | /// Marks the end of `buffer` - before this are buffered bytes, after this is | ||
| 21 | /// undefined. | ||
| 22 | end: usize = 0, | ||
| 22 | /// Tracks total number of bytes written to this `BufferedWriter`. This value | 23 | /// Tracks total number of bytes written to this `BufferedWriter`. This value |
| 23 | /// only increases. In the case of fixed mode, this value always equals | 24 | /// only increases. In the case of fixed mode, this value always equals `end`. |
| 24 | /// `buffer.items.len`. | 25 | count: usize = 0, |
| 25 | bytes_written: usize = 0, | ||
| 26 | 26 | ||
| 27 | /// Number of slices to store on the stack, when trying to send as many byte | 27 | /// Number of slices to store on the stack, when trying to send as many byte |
| 28 | /// vectors through the underlying write calls as possible. | 28 | /// vectors through the underlying write calls as possible. |
| ... | @@ -46,71 +46,72 @@ const fixed_vtable: Writer.VTable = .{ | ... | @@ -46,71 +46,72 @@ const fixed_vtable: Writer.VTable = .{ |
| 46 | .writeFile = Writer.unimplemented_writeFile, | 46 | .writeFile = Writer.unimplemented_writeFile, |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and | 49 | /// Replaces the `BufferedWriter` with one that writes to `buffer` and returns |
| 50 | /// returns `error.NoSpaceLeft` when it is full. | 50 | /// `error.NoSpaceLeft` when it is full. `end` and `count` will always be |
| 51 | /// equal. | ||
| 51 | pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void { | 52 | pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void { |
| 52 | bw.* = .{ | 53 | bw.* = .{ |
| 53 | .unbuffered_writer = .{ | 54 | .unbuffered_writer = .{ |
| 54 | .context = bw, | 55 | .context = bw, |
| 55 | .vtable = &fixed_vtable, | 56 | .vtable = &fixed_vtable, |
| 56 | }, | 57 | }, |
| 57 | .buffer = .initBuffer(buffer), | 58 | .buffer = buffer, |
| 58 | }; | 59 | }; |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | /// This function is available when using `initFixed`. | 62 | /// This function is available when using `initFixed`. |
| 62 | pub fn getWritten(bw: *const BufferedWriter) []u8 { | 63 | pub fn getWritten(bw: *const BufferedWriter) []u8 { |
| 63 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); | 64 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); |
| 64 | return bw.buffer.items; | 65 | return bw.buffer[0..bw.end]; |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | /// This function is available when using `initFixed`. | 68 | /// This function is available when using `initFixed`. |
| 68 | pub fn reset(bw: *BufferedWriter) void { | 69 | pub fn reset(bw: *BufferedWriter) void { |
| 69 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); | 70 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); |
| 70 | bw.buffer.items.len = 0; | 71 | bw.end = 0; |
| 72 | bw.count = 0; | ||
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | pub fn flush(bw: *BufferedWriter) anyerror!void { | 75 | pub fn flush(bw: *BufferedWriter) anyerror!void { |
| 74 | const list = &bw.buffer; | 76 | const send_buffer = bw.buffer[0..bw.end]; |
| 75 | const send_buffer = list.items; | ||
| 76 | var index: usize = 0; | 77 | var index: usize = 0; |
| 77 | while (index < send_buffer.len) index += try bw.unbuffered_writer.writev(&.{send_buffer[index..]}); | 78 | while (index < send_buffer.len) index += try bw.unbuffered_writer.writev(&.{send_buffer[index..]}); |
| 78 | list.items.len = 0; | 79 | bw.end = 0; |
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | pub fn unusedCapacitySlice(bw: *const BufferedWriter) []u8 { | 82 | pub fn unusedCapacitySlice(bw: *const BufferedWriter) []u8 { |
| 82 | return bw.buffer.unusedCapacitySlice(); | 83 | return bw.buffer[bw.end..]; |
| 83 | } | 84 | } |
| 84 | 85 | ||
| 86 | /// Asserts the provided buffer has total capacity enough for `minimum_length`. | ||
| 85 | pub fn writableSlice(bw: *BufferedWriter, minimum_length: usize) anyerror![]u8 { | 87 | pub fn writableSlice(bw: *BufferedWriter, minimum_length: usize) anyerror![]u8 { |
| 86 | const list = &bw.buffer; | 88 | assert(bw.buffer.len >= minimum_length); |
| 87 | assert(list.capacity >= minimum_length); | 89 | const cap_slice = bw.buffer[bw.end..]; |
| 88 | const cap_slice = list.unusedCapacitySlice(); | ||
| 89 | if (cap_slice.len >= minimum_length) { | 90 | if (cap_slice.len >= minimum_length) { |
| 90 | @branchHint(.likely); | 91 | @branchHint(.likely); |
| 91 | return cap_slice; | 92 | return cap_slice; |
| 92 | } | 93 | } |
| 93 | const buffer = list.items; | 94 | const buffer = bw.buffer[0..bw.end]; |
| 94 | const n = try bw.unbuffered_writer.write(buffer); | 95 | const n = try bw.unbuffered_writer.write(buffer); |
| 95 | if (n == buffer.len) { | 96 | if (n == buffer.len) { |
| 96 | @branchHint(.likely); | 97 | @branchHint(.likely); |
| 97 | list.items.len = 0; | 98 | bw.end = 0; |
| 98 | return list.unusedCapacitySlice(); | 99 | return bw.buffer; |
| 99 | } | 100 | } |
| 100 | if (n > 0) { | 101 | if (n > 0) { |
| 101 | const remainder = buffer[n..]; | 102 | const remainder = buffer[n..]; |
| 102 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 103 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 103 | list.items.len = remainder.len; | 104 | bw.end = remainder.len; |
| 104 | } | 105 | } |
| 105 | return list.unusedCapacitySlice(); | 106 | return bw.buffer[bw.end..]; |
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | /// After calling `writableSlice`, this function tracks how many bytes were written to it. | 109 | /// After calling `writableSlice`, this function tracks how many bytes were written to it. |
| 109 | pub fn advance(bw: *BufferedWriter, n: usize) void { | 110 | pub fn advance(bw: *BufferedWriter, n: usize) void { |
| 110 | const list = &bw.buffer; | 111 | const new_end = bw.end + n; |
| 111 | list.items.len += n; | 112 | assert(new_end <= bw.buffer.len); |
| 112 | assert(list.items.len <= list.capacity); | 113 | bw.end = new_end; |
| 113 | bw.bytes_written += n; | 114 | bw.count += n; |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | /// The `data` parameter is mutable because this function needs to mutate the | 117 | /// The `data` parameter is mutable because this function needs to mutate the |
| ... | @@ -139,9 +140,8 @@ pub fn writev(bw: *BufferedWriter, data: []const []const u8) anyerror!usize { | ... | @@ -139,9 +140,8 @@ pub fn writev(bw: *BufferedWriter, data: []const []const u8) anyerror!usize { |
| 139 | 140 | ||
| 140 | fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | 141 | fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |
| 141 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); | 142 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 142 | const list = &bw.buffer; | 143 | const buffer = bw.buffer; |
| 143 | const buffer = list.allocatedSlice(); | 144 | const start_end = bw.end; |
| 144 | const start_end = list.items.len; | ||
| 145 | 145 | ||
| 146 | var buffers: [max_buffers_len][]const u8 = undefined; | 146 | var buffers: [max_buffers_len][]const u8 = undefined; |
| 147 | var end = start_end; | 147 | var end = start_end; |
| ... | @@ -153,7 +153,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us | ... | @@ -153,7 +153,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 153 | end = new_end; | 153 | end = new_end; |
| 154 | continue; | 154 | continue; |
| 155 | } | 155 | } |
| 156 | if (end == 0) return track(&bw.bytes_written, try bw.unbuffered_writer.writeSplat(data, splat)); | 156 | if (end == 0) return track(&bw.count, try bw.unbuffered_writer.writeSplat(data, splat)); |
| 157 | buffers[0] = buffer[0..end]; | 157 | buffers[0] = buffer[0..end]; |
| 158 | const remaining_data = data[i..]; | 158 | const remaining_data = data[i..]; |
| 159 | const remaining_buffers = buffers[1..]; | 159 | const remaining_buffers = buffers[1..]; |
| ... | @@ -168,22 +168,22 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us | ... | @@ -168,22 +168,22 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 168 | @branchHint(.unlikely); | 168 | @branchHint(.unlikely); |
| 169 | const remainder = buffer[n..end]; | 169 | const remainder = buffer[n..end]; |
| 170 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 170 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 171 | list.items.len = remainder.len; | 171 | bw.end = remainder.len; |
| 172 | return track(&bw.bytes_written, end - start_end); | 172 | return track(&bw.count, end - start_end); |
| 173 | } | 173 | } |
| 174 | list.items.len = 0; | 174 | bw.end = 0; |
| 175 | return track(&bw.bytes_written, n - start_end); | 175 | return track(&bw.count, n - start_end); |
| 176 | } | 176 | } |
| 177 | const n = try bw.unbuffered_writer.writeSplat(send_buffers, 1); | 177 | const n = try bw.unbuffered_writer.writeSplat(send_buffers, 1); |
| 178 | if (n < end) { | 178 | if (n < end) { |
| 179 | @branchHint(.unlikely); | 179 | @branchHint(.unlikely); |
| 180 | const remainder = buffer[n..end]; | 180 | const remainder = buffer[n..end]; |
| 181 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 181 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 182 | list.items.len = remainder.len; | 182 | bw.end = remainder.len; |
| 183 | return track(&bw.bytes_written, end - start_end); | 183 | return track(&bw.count, end - start_end); |
| 184 | } | 184 | } |
| 185 | list.items.len = 0; | 185 | bw.end = 0; |
| 186 | return track(&bw.bytes_written, n - start_end); | 186 | return track(&bw.count, n - start_end); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | const pattern = data[data.len - 1]; | 189 | const pattern = data[data.len - 1]; |
| ... | @@ -192,24 +192,24 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us | ... | @@ -192,24 +192,24 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 192 | @branchHint(.unlikely); | 192 | @branchHint(.unlikely); |
| 193 | // It was added in the loop above; undo it here. | 193 | // It was added in the loop above; undo it here. |
| 194 | end -= pattern.len; | 194 | end -= pattern.len; |
| 195 | list.items.len = end; | 195 | bw.end = end; |
| 196 | return track(&bw.bytes_written, end - start_end); | 196 | return track(&bw.count, end - start_end); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | const remaining_splat = splat - 1; | 199 | const remaining_splat = splat - 1; |
| 200 | 200 | ||
| 201 | switch (pattern.len) { | 201 | switch (pattern.len) { |
| 202 | 0 => { | 202 | 0 => { |
| 203 | list.items.len = end; | 203 | bw.end = end; |
| 204 | return track(&bw.bytes_written, end - start_end); | 204 | return track(&bw.count, end - start_end); |
| 205 | }, | 205 | }, |
| 206 | 1 => { | 206 | 1 => { |
| 207 | const new_end = end + remaining_splat; | 207 | const new_end = end + remaining_splat; |
| 208 | if (new_end <= buffer.len) { | 208 | if (new_end <= buffer.len) { |
| 209 | @branchHint(.likely); | 209 | @branchHint(.likely); |
| 210 | @memset(buffer[end..new_end], pattern[0]); | 210 | @memset(buffer[end..new_end], pattern[0]); |
| 211 | list.items.len = new_end; | 211 | bw.end = new_end; |
| 212 | return track(&bw.bytes_written, new_end - start_end); | 212 | return track(&bw.count, new_end - start_end); |
| 213 | } | 213 | } |
| 214 | buffers[0] = buffer[0..end]; | 214 | buffers[0] = buffer[0..end]; |
| 215 | buffers[1] = pattern; | 215 | buffers[1] = pattern; |
| ... | @@ -218,11 +218,11 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us | ... | @@ -218,11 +218,11 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 218 | @branchHint(.unlikely); | 218 | @branchHint(.unlikely); |
| 219 | const remainder = buffer[n..end]; | 219 | const remainder = buffer[n..end]; |
| 220 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 220 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 221 | list.items.len = remainder.len; | 221 | bw.end = remainder.len; |
| 222 | return track(&bw.bytes_written, end - start_end); | 222 | return track(&bw.count, end - start_end); |
| 223 | } | 223 | } |
| 224 | list.items.len = 0; | 224 | bw.end = 0; |
| 225 | return track(&bw.bytes_written, n - start_end); | 225 | return track(&bw.count, n - start_end); |
| 226 | }, | 226 | }, |
| 227 | else => { | 227 | else => { |
| 228 | const new_end = end + pattern.len * remaining_splat; | 228 | const new_end = end + pattern.len * remaining_splat; |
| ... | @@ -231,8 +231,8 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us | ... | @@ -231,8 +231,8 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 231 | while (end < new_end) : (end += pattern.len) { | 231 | while (end < new_end) : (end += pattern.len) { |
| 232 | @memcpy(buffer[end..][0..pattern.len], pattern); | 232 | @memcpy(buffer[end..][0..pattern.len], pattern); |
| 233 | } | 233 | } |
| 234 | list.items.len = new_end; | 234 | bw.end = new_end; |
| 235 | return track(&bw.bytes_written, new_end - start_end); | 235 | return track(&bw.count, new_end - start_end); |
| 236 | } | 236 | } |
| 237 | buffers[0] = buffer[0..end]; | 237 | buffers[0] = buffer[0..end]; |
| 238 | buffers[1] = pattern; | 238 | buffers[1] = pattern; |
| ... | @@ -241,17 +241,17 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us | ... | @@ -241,17 +241,17 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 241 | @branchHint(.unlikely); | 241 | @branchHint(.unlikely); |
| 242 | const remainder = buffer[n..end]; | 242 | const remainder = buffer[n..end]; |
| 243 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 243 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 244 | list.items.len = remainder.len; | 244 | bw.end = remainder.len; |
| 245 | return track(&bw.bytes_written, end - start_end); | 245 | return track(&bw.count, end - start_end); |
| 246 | } | 246 | } |
| 247 | list.items.len = 0; | 247 | bw.end = 0; |
| 248 | return track(&bw.bytes_written, n - start_end); | 248 | return track(&bw.count, n - start_end); |
| 249 | }, | 249 | }, |
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | fn track(bytes_written: *usize, n: usize) usize { | 253 | fn track(count: *usize, n: usize) usize { |
| 254 | bytes_written.* += n; | 254 | count.* += n; |
| 255 | return n; | 255 | return n; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| ... | @@ -260,31 +260,29 @@ fn track(bytes_written: *usize, n: usize) usize { | ... | @@ -260,31 +260,29 @@ fn track(bytes_written: *usize, n: usize) usize { |
| 260 | /// available buffer has been filled. | 260 | /// available buffer has been filled. |
| 261 | fn fixed_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | 261 | fn fixed_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |
| 262 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); | 262 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 263 | const list = &bw.buffer; | ||
| 264 | for (data) |bytes| { | 263 | for (data) |bytes| { |
| 265 | const dest = list.unusedCapacitySlice(); | 264 | const dest = bw.buffer[bw.end..]; |
| 266 | if (dest.len == 0) return error.NoSpaceLeft; | 265 | if (dest.len == 0) return error.NoSpaceLeft; |
| 267 | const len = @min(bytes.len, dest.len); | 266 | const len = @min(bytes.len, dest.len); |
| 268 | @memcpy(dest[0..len], bytes[0..len]); | 267 | @memcpy(dest[0..len], bytes[0..len]); |
| 269 | list.items.len += len; | 268 | bw.end += len; |
| 270 | bw.bytes_written = list.items.len; | 269 | bw.count = bw.end; |
| 271 | } | 270 | } |
| 272 | const pattern = data[data.len - 1]; | 271 | const pattern = data[data.len - 1]; |
| 273 | const dest = list.unusedCapacitySlice(); | 272 | const dest = bw.buffer[bw.end..]; |
| 274 | switch (pattern.len) { | 273 | switch (pattern.len) { |
| 275 | 0 => unreachable, | 274 | 0 => unreachable, |
| 276 | 1 => @memset(dest, pattern[0]), | 275 | 1 => @memset(dest, pattern[0]), |
| 277 | else => for (0..splat - 1) |i| @memcpy(dest[i * pattern.len ..][0..pattern.len], pattern), | 276 | else => for (0..splat - 1) |i| @memcpy(dest[i * pattern.len ..][0..pattern.len], pattern), |
| 278 | } | 277 | } |
| 279 | list.items.len = list.capacity; | 278 | bw.end = bw.buffer.len; |
| 280 | bw.bytes_written = list.items.len; | 279 | bw.count = bw.end; |
| 281 | return error.NoSpaceLeft; | 280 | return error.NoSpaceLeft; |
| 282 | } | 281 | } |
| 283 | 282 | ||
| 284 | pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { | 283 | pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { |
| 285 | const list = &bw.buffer; | 284 | const buffer = bw.buffer; |
| 286 | const buffer = list.allocatedSlice(); | 285 | const end = bw.end; |
| 287 | const end = list.items.len; | ||
| 288 | const new_end = end + bytes.len; | 286 | const new_end = end + bytes.len; |
| 289 | if (new_end > buffer.len) { | 287 | if (new_end > buffer.len) { |
| 290 | var data: [2][]const u8 = .{ buffer[0..end], bytes }; | 288 | var data: [2][]const u8 = .{ buffer[0..end], bytes }; |
| ... | @@ -293,15 +291,15 @@ pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { | ... | @@ -293,15 +291,15 @@ pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { |
| 293 | @branchHint(.unlikely); | 291 | @branchHint(.unlikely); |
| 294 | const remainder = buffer[n..end]; | 292 | const remainder = buffer[n..end]; |
| 295 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 293 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 296 | list.items.len = remainder.len; | 294 | bw.end = remainder.len; |
| 297 | return 0; | 295 | return 0; |
| 298 | } | 296 | } |
| 299 | list.items.len = 0; | 297 | bw.end = 0; |
| 300 | return track(&bw.bytes_written, n - end); | 298 | return track(&bw.count, n - end); |
| 301 | } | 299 | } |
| 302 | @memcpy(buffer[end..new_end], bytes); | 300 | @memcpy(buffer[end..new_end], bytes); |
| 303 | list.items.len = new_end; | 301 | bw.end = new_end; |
| 304 | return track(&bw.bytes_written, bytes.len); | 302 | return track(&bw.count, bytes.len); |
| 305 | } | 303 | } |
| 306 | 304 | ||
| 307 | /// Calls `write` as many times as necessary such that all of `bytes` are | 305 | /// Calls `write` as many times as necessary such that all of `bytes` are |
| ... | @@ -316,13 +314,12 @@ pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) an | ... | @@ -316,13 +314,12 @@ pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) an |
| 316 | } | 314 | } |
| 317 | 315 | ||
| 318 | pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { | 316 | pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { |
| 319 | const list = &bw.buffer; | 317 | const buffer = bw.buffer[0..bw.end]; |
| 320 | const buffer = list.items; | 318 | if (buffer.len < bw.buffer.len) { |
| 321 | if (buffer.len < list.capacity) { | ||
| 322 | @branchHint(.likely); | 319 | @branchHint(.likely); |
| 323 | buffer.ptr[buffer.len] = byte; | 320 | buffer.ptr[buffer.len] = byte; |
| 324 | list.items.len = buffer.len + 1; | 321 | bw.end = buffer.len + 1; |
| 325 | bw.bytes_written += 1; | 322 | bw.count += 1; |
| 326 | return; | 323 | return; |
| 327 | } | 324 | } |
| 328 | var buffers: [2][]const u8 = .{ buffer, &.{byte} }; | 325 | var buffers: [2][]const u8 = .{ buffer, &.{byte} }; |
| ... | @@ -332,23 +329,23 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { | ... | @@ -332,23 +329,23 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { |
| 332 | @branchHint(.unlikely); | 329 | @branchHint(.unlikely); |
| 333 | continue; | 330 | continue; |
| 334 | } | 331 | } |
| 335 | bw.bytes_written += 1; | 332 | bw.count += 1; |
| 336 | if (n >= buffer.len) { | 333 | if (n >= buffer.len) { |
| 337 | @branchHint(.likely); | 334 | @branchHint(.likely); |
| 338 | if (n > buffer.len) { | 335 | if (n > buffer.len) { |
| 339 | @branchHint(.likely); | 336 | @branchHint(.likely); |
| 340 | list.items.len = 0; | 337 | bw.end = 0; |
| 341 | return; | 338 | return; |
| 342 | } else { | 339 | } else { |
| 343 | buffer[0] = byte; | 340 | buffer[0] = byte; |
| 344 | list.items.len = 1; | 341 | bw.end = 1; |
| 345 | return; | 342 | return; |
| 346 | } | 343 | } |
| 347 | } | 344 | } |
| 348 | const remainder = buffer[n..]; | 345 | const remainder = buffer[n..]; |
| 349 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 346 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 350 | buffer[remainder.len] = byte; | 347 | buffer[remainder.len] = byte; |
| 351 | list.items.len = remainder.len + 1; | 348 | bw.end = remainder.len + 1; |
| 352 | return; | 349 | return; |
| 353 | } | 350 | } |
| 354 | } | 351 | } |
| ... | @@ -430,13 +427,12 @@ fn passthru_writeFile( | ... | @@ -430,13 +427,12 @@ fn passthru_writeFile( |
| 430 | headers_len: usize, | 427 | headers_len: usize, |
| 431 | ) anyerror!usize { | 428 | ) anyerror!usize { |
| 432 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); | 429 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 433 | const list = &bw.buffer; | 430 | const buffer = bw.buffer; |
| 434 | const buffer = list.allocatedSlice(); | ||
| 435 | if (buffer.len == 0) return track( | 431 | if (buffer.len == 0) return track( |
| 436 | &bw.bytes_written, | 432 | &bw.count, |
| 437 | try bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len), | 433 | try bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len), |
| 438 | ); | 434 | ); |
| 439 | const start_end = list.items.len; | 435 | const start_end = bw.end; |
| 440 | const headers = headers_and_trailers[0..headers_len]; | 436 | const headers = headers_and_trailers[0..headers_len]; |
| 441 | const trailers = headers_and_trailers[headers_len..]; | 437 | const trailers = headers_and_trailers[headers_len..]; |
| 442 | var buffers: [max_buffers_len][]const u8 = undefined; | 438 | var buffers: [max_buffers_len][]const u8 = undefined; |
| ... | @@ -466,11 +462,11 @@ fn passthru_writeFile( | ... | @@ -466,11 +462,11 @@ fn passthru_writeFile( |
| 466 | @branchHint(.unlikely); | 462 | @branchHint(.unlikely); |
| 467 | const remainder = buffer[n..end]; | 463 | const remainder = buffer[n..end]; |
| 468 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 464 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 469 | list.items.len = remainder.len; | 465 | bw.end = remainder.len; |
| 470 | return track(&bw.bytes_written, end - start_end); | 466 | return track(&bw.count, end - start_end); |
| 471 | } | 467 | } |
| 472 | list.items.len = 0; | 468 | bw.end = 0; |
| 473 | return track(&bw.bytes_written, n - start_end); | 469 | return track(&bw.count, n - start_end); |
| 474 | } | 470 | } |
| 475 | // Have not made it past the headers yet; must call `writev`. | 471 | // Have not made it past the headers yet; must call `writev`. |
| 476 | const n = try bw.unbuffered_writer.writev(buffers[0 .. buffers_len + 1]); | 472 | const n = try bw.unbuffered_writer.writev(buffers[0 .. buffers_len + 1]); |
| ... | @@ -478,11 +474,11 @@ fn passthru_writeFile( | ... | @@ -478,11 +474,11 @@ fn passthru_writeFile( |
| 478 | @branchHint(.unlikely); | 474 | @branchHint(.unlikely); |
| 479 | const remainder = buffer[n..end]; | 475 | const remainder = buffer[n..end]; |
| 480 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 476 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 481 | list.items.len = remainder.len; | 477 | bw.end = remainder.len; |
| 482 | return track(&bw.bytes_written, end - start_end); | 478 | return track(&bw.count, end - start_end); |
| 483 | } | 479 | } |
| 484 | list.items.len = 0; | 480 | bw.end = 0; |
| 485 | return track(&bw.bytes_written, n - start_end); | 481 | return track(&bw.count, n - start_end); |
| 486 | } | 482 | } |
| 487 | // All headers written to buffer. | 483 | // All headers written to buffer. |
| 488 | buffers[0] = buffer[0..end]; | 484 | buffers[0] = buffer[0..end]; |
| ... | @@ -496,11 +492,11 @@ fn passthru_writeFile( | ... | @@ -496,11 +492,11 @@ fn passthru_writeFile( |
| 496 | @branchHint(.unlikely); | 492 | @branchHint(.unlikely); |
| 497 | const remainder = buffer[n..end]; | 493 | const remainder = buffer[n..end]; |
| 498 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); | 494 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 499 | list.items.len = remainder.len; | 495 | bw.end = remainder.len; |
| 500 | return track(&bw.bytes_written, end - start_end); | 496 | return track(&bw.count, end - start_end); |
| 501 | } | 497 | } |
| 502 | list.items.len = 0; | 498 | bw.end = 0; |
| 503 | return track(&bw.bytes_written, n - start_end); | 499 | return track(&bw.count, n - start_end); |
| 504 | } | 500 | } |
| 505 | 501 | ||
| 506 | pub const WriteFileOptions = struct { | 502 | pub const WriteFileOptions = struct { |
lib/std/io/Writer.zig+1-1| ... | @@ -112,7 +112,7 @@ pub fn unimplemented_writeFile( | ... | @@ -112,7 +112,7 @@ pub fn unimplemented_writeFile( |
| 112 | 112 | ||
| 113 | pub fn buffered(w: Writer, buffer: []u8) std.io.BufferedWriter { | 113 | pub fn buffered(w: Writer, buffer: []u8) std.io.BufferedWriter { |
| 114 | return .{ | 114 | return .{ |
| 115 | .buffer = .initBuffer(buffer), | 115 | .buffer = buffer, |
| 116 | .unbuffered_writer = w, | 116 | .unbuffered_writer = w, |
| 117 | }; | 117 | }; |
| 118 | } | 118 | } |
lib/std/tar/Writer.zig+4-2| ... | @@ -420,7 +420,8 @@ test "write files" { | ... | @@ -420,7 +420,8 @@ test "write files" { |
| 420 | const root = "root"; | 420 | const root = "root"; |
| 421 | 421 | ||
| 422 | var output: std.io.AllocatingWriter = undefined; | 422 | var output: std.io.AllocatingWriter = undefined; |
| 423 | var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) }; | 423 | output.init(testing.allocator); |
| 424 | var wrt: Writer = .{ .underlying_writer = &output.buffered_writer }; | ||
| 424 | defer output.deinit(); | 425 | defer output.deinit(); |
| 425 | try wrt.setRoot(root); | 426 | try wrt.setRoot(root); |
| 426 | for (files) |file| | 427 | for (files) |file| |
| ... | @@ -456,7 +457,8 @@ test "write files" { | ... | @@ -456,7 +457,8 @@ test "write files" { |
| 456 | // without root | 457 | // without root |
| 457 | { | 458 | { |
| 458 | var output: std.io.AllocatingWriter = undefined; | 459 | var output: std.io.AllocatingWriter = undefined; |
| 459 | var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) }; | 460 | output.init(testing.allocator); |
| 461 | var wrt: Writer = .{ .underlying_writer = &output.buffered_writer }; | ||
| 460 | defer output.deinit(); | 462 | defer output.deinit(); |
| 461 | for (files) |file| { | 463 | for (files) |file| { |
| 462 | var content = std.io.fixedBufferStream(file.content); | 464 | var content = std.io.fixedBufferStream(file.content); |
lib/std/zon/parse.zig+14-12| ... | @@ -638,10 +638,12 @@ const Parser = struct { | ... | @@ -638,10 +638,12 @@ const Parser = struct { |
| 638 | const pointer = @typeInfo(T).pointer; | 638 | const pointer = @typeInfo(T).pointer; |
| 639 | var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node); | 639 | var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node); |
| 640 | if (pointer.sentinel() != null) size_hint += 1; | 640 | if (pointer.sentinel() != null) size_hint += 1; |
| 641 | const gpa = self.gpa; | ||
| 641 | 642 | ||
| 642 | var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, size_hint); | 643 | var aw: std.io.AllocatingWriter = undefined; |
| 643 | defer buf.deinit(self.gpa); | 644 | try aw.initCapacity(gpa, size_hint); |
| 644 | switch (try ZonGen.parseStrLit(self.ast, ast_node, buf.writer(self.gpa))) { | 645 | defer aw.deinit(); |
| 646 | switch (try ZonGen.parseStrLit(self.ast, ast_node, &aw.buffered_writer)) { | ||
| 645 | .success => {}, | 647 | .success => {}, |
| 646 | .failure => |err| { | 648 | .failure => |err| { |
| 647 | const token = self.ast.nodeMainToken(ast_node); | 649 | const token = self.ast.nodeMainToken(ast_node); |
| ... | @@ -660,9 +662,9 @@ const Parser = struct { | ... | @@ -660,9 +662,9 @@ const Parser = struct { |
| 660 | } | 662 | } |
| 661 | 663 | ||
| 662 | if (pointer.sentinel() != null) { | 664 | if (pointer.sentinel() != null) { |
| 663 | return buf.toOwnedSliceSentinel(self.gpa, 0); | 665 | return aw.toOwnedSliceSentinel(gpa, 0); |
| 664 | } else { | 666 | } else { |
| 665 | return buf.toOwnedSlice(self.gpa); | 667 | return aw.toOwnedSlice(gpa); |
| 666 | } | 668 | } |
| 667 | } | 669 | } |
| 668 | 670 | ||
| ... | @@ -1064,6 +1066,7 @@ const Parser = struct { | ... | @@ -1064,6 +1066,7 @@ const Parser = struct { |
| 1064 | name: []const u8, | 1066 | name: []const u8, |
| 1065 | ) error{ OutOfMemory, ParseZon } { | 1067 | ) error{ OutOfMemory, ParseZon } { |
| 1066 | @branchHint(.cold); | 1068 | @branchHint(.cold); |
| 1069 | const gpa = self.gpa; | ||
| 1067 | const token = if (field) |f| b: { | 1070 | const token = if (field) |f| b: { |
| 1068 | var buf: [2]Ast.Node.Index = undefined; | 1071 | var buf: [2]Ast.Node.Index = undefined; |
| 1069 | const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?; | 1072 | const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?; |
| ... | @@ -1081,18 +1084,17 @@ const Parser = struct { | ... | @@ -1081,18 +1084,17 @@ const Parser = struct { |
| 1081 | }; | 1084 | }; |
| 1082 | } else b: { | 1085 | } else b: { |
| 1083 | const msg = "supported: "; | 1086 | const msg = "supported: "; |
| 1084 | var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, 64); | 1087 | var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(gpa, 64); |
| 1085 | defer buf.deinit(self.gpa); | 1088 | defer buf.deinit(gpa); |
| 1086 | const writer = buf.writer(self.gpa); | 1089 | try buf.appendSlice(gpa, msg); |
| 1087 | try writer.writeAll(msg); | ||
| 1088 | inline for (info.fields, 0..) |field_info, i| { | 1090 | inline for (info.fields, 0..) |field_info, i| { |
| 1089 | if (i != 0) try writer.writeAll(", "); | 1091 | if (i != 0) try buf.appendSlice(gpa, ", "); |
| 1090 | try writer.print("'{p_}'", .{std.zig.fmtId(field_info.name)}); | 1092 | try buf.print(gpa, "'{p_}'", .{std.zig.fmtId(field_info.name)}); |
| 1091 | } | 1093 | } |
| 1092 | break :b .{ | 1094 | break :b .{ |
| 1093 | .token = token, | 1095 | .token = token, |
| 1094 | .offset = 0, | 1096 | .offset = 0, |
| 1095 | .msg = try buf.toOwnedSlice(self.gpa), | 1097 | .msg = try buf.toOwnedSlice(gpa), |
| 1096 | .owned = true, | 1098 | .owned = true, |
| 1097 | }; | 1099 | }; |
| 1098 | }; | 1100 | }; |