| ... | ... | @@ -9,19 +9,12 @@ const Reader = std.io.Reader; |
| 9 | 9 | |
| 10 | 10 | const BufferedReader = @This(); |
| 11 | 11 | |
| 12 | | /// Number of bytes which have been consumed from `storage`. |
| 13 | | seek: usize, |
| 14 | | storage: BufferedWriter, |
| 15 | 12 | unbuffered_reader: Reader, |
| 16 | | |
| 17 | | pub fn init(br: *BufferedReader, r: Reader, buffer: []u8) void { |
| 18 | | br.* = .{ |
| 19 | | .seek = 0, |
| 20 | | .storage = undefined, |
| 21 | | .unbuffered_reader = r, |
| 22 | | }; |
| 23 | | br.storage.initFixed(buffer); |
| 24 | | } |
| 13 | buffer: []u8, |
| 14 | /// In `buffer` before this are buffered bytes, after this is `undefined`. |
| 15 | end: usize, |
| 16 | /// Number of bytes which have been consumed from `buffer`. |
| 17 | seek: usize, |
| 25 | 18 | |
| 26 | 19 | /// Constructs `br` such that it will read from `buffer` and then end. |
| 27 | 20 | /// |
| ... | ... | @@ -29,25 +22,15 @@ pub fn init(br: *BufferedReader, r: Reader, buffer: []u8) void { |
| 29 | 22 | /// and if they are avoided then `buffer` can be safely used with `@constCast`. |
| 30 | 23 | pub fn initFixed(br: *BufferedReader, buffer: []u8) void { |
| 31 | 24 | br.* = .{ |
| 32 | | .seek = 0, |
| 33 | | .storage = .{ |
| 34 | | .buffer = buffer, |
| 35 | | .unbuffered_writer = .failing, |
| 36 | | }, |
| 37 | 25 | .unbuffered_reader = .ending, |
| 26 | .buffer = buffer, |
| 27 | .end = buffer.len, |
| 28 | .seek = 0, |
| 38 | 29 | }; |
| 39 | 30 | } |
| 40 | 31 | |
| 41 | | pub fn storageBuffer(br: *BufferedReader) []u8 { |
| 42 | | const storage = &br.storage; |
| 43 | | assert(storage.unbuffered_writer.vtable == std.io.Writer.failing.vtable); |
| 44 | | assert(br.unbuffered_reader.vtable == Reader.ending.vtable); |
| 45 | | return storage.buffer; |
| 46 | | } |
| 47 | | |
| 48 | 32 | pub fn bufferContents(br: *BufferedReader) []u8 { |
| 49 | | const storage = &br.storage; |
| 50 | | return storage.buffer[br.seek..storage.end]; |
| 33 | return br.buffer[br.seek..br.end]; |
| 51 | 34 | } |
| 52 | 35 | |
| 53 | 36 | /// Although `BufferedReader` can easily satisfy the `Reader` interface, it's |
| ... | ... | @@ -65,8 +48,7 @@ pub fn reader(br: *BufferedReader) Reader { |
| 65 | 48 | |
| 66 | 49 | fn passthruRead(ctx: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize { |
| 67 | 50 | const br: *BufferedReader = @alignCast(@ptrCast(ctx)); |
| 68 | | const storage = &br.storage; |
| 69 | | const buffer = storage.buffer[0..storage.end]; |
| 51 | const buffer = br.buffer[0..br.end]; |
| 70 | 52 | const buffered = buffer[br.seek..]; |
| 71 | 53 | const limited = buffered[0..limit.min(buffered.len)]; |
| 72 | 54 | if (limited.len > 0) { |
| ... | ... | @@ -89,7 +71,7 @@ pub fn seekBy(br: *BufferedReader, seek_by: i64) !void { |
| 89 | 71 | } |
| 90 | 72 | |
| 91 | 73 | pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) !void { |
| 92 | | if (seek_by > br.storage.end - br.seek) return error.Unseekable; // TODO |
| 74 | if (seek_by > br.end - br.seek) return error.Unseekable; // TODO |
| 93 | 75 | br.seek += @abs(seek_by); |
| 94 | 76 | } |
| 95 | 77 | |
| ... | ... | @@ -115,10 +97,9 @@ pub fn seekForwardBy(br: *BufferedReader, seek_by: u64) !void { |
| 115 | 97 | /// * `tryPeekArray` |
| 116 | 98 | /// * `toss` |
| 117 | 99 | pub fn peek(br: *BufferedReader, n: usize) Reader.Error![]u8 { |
| 118 | | const storage = &br.storage; |
| 119 | | assert(n <= storage.buffer.len); |
| 100 | assert(n <= br.buffer.len); |
| 120 | 101 | try br.fill(n); |
| 121 | | return storage.buffer[br.seek..][0..n]; |
| 102 | return br.buffer[br.seek..][0..n]; |
| 122 | 103 | } |
| 123 | 104 | |
| 124 | 105 | /// Returns all the next buffered bytes from `unbuffered_reader`, after filling |
| ... | ... | @@ -137,10 +118,9 @@ pub fn peek(br: *BufferedReader, n: usize) Reader.Error![]u8 { |
| 137 | 118 | /// * `tryPeekGreedy` |
| 138 | 119 | /// * `toss` |
| 139 | 120 | pub fn peekGreedy(br: *BufferedReader, n: usize) Reader.Error![]u8 { |
| 140 | | const storage = &br.storage; |
| 141 | | assert(n <= storage.buffer.len); |
| 121 | assert(n <= br.buffer.len); |
| 142 | 122 | try br.fill(n); |
| 143 | | return storage.buffer[br.seek..storage.end]; |
| 123 | return br.buffer[br.seek..br.end]; |
| 144 | 124 | } |
| 145 | 125 | |
| 146 | 126 | /// Skips the next `n` bytes from the stream, advancing the seek position. This |
| ... | ... | @@ -153,7 +133,7 @@ pub fn peekGreedy(br: *BufferedReader, n: usize) Reader.Error![]u8 { |
| 153 | 133 | /// * `discard`. |
| 154 | 134 | pub fn toss(br: *BufferedReader, n: usize) void { |
| 155 | 135 | br.seek += n; |
| 156 | | assert(br.seek <= br.storage.end); |
| 136 | assert(br.seek <= br.end); |
| 157 | 137 | } |
| 158 | 138 | |
| 159 | 139 | /// Equivalent to `peek` followed by `toss`. |
| ... | ... | @@ -207,15 +187,14 @@ pub fn discard(br: *BufferedReader, n: usize) Reader.Error!void { |
| 207 | 187 | /// * `toss` |
| 208 | 188 | /// * `discardRemaining` |
| 209 | 189 | pub fn discardShort(br: *BufferedReader, n: usize) Reader.ShortError!usize { |
| 210 | | const storage = &br.storage; |
| 211 | 190 | const proposed_seek = br.seek + n; |
| 212 | | if (proposed_seek <= storage.end) { |
| 191 | if (proposed_seek <= br.end) { |
| 213 | 192 | @branchHint(.likely); |
| 214 | 193 | br.seek = proposed_seek; |
| 215 | 194 | return n; |
| 216 | 195 | } |
| 217 | | var remaining = n - (storage.end - br.seek); |
| 218 | | storage.end = 0; |
| 196 | var remaining = n - (br.end - br.seek); |
| 197 | br.end = 0; |
| 219 | 198 | br.seek = 0; |
| 220 | 199 | while (true) { |
| 221 | 200 | const discard_len = br.unbuffered_reader.discard(.limited(remaining)) catch |err| switch (err) { |
| ... | ... | @@ -230,9 +209,8 @@ pub fn discardShort(br: *BufferedReader, n: usize) Reader.ShortError!usize { |
| 230 | 209 | /// Reads the stream until the end, ignoring all the data. |
| 231 | 210 | /// Returns the number of bytes discarded. |
| 232 | 211 | pub fn discardRemaining(br: *BufferedReader) Reader.ShortError!usize { |
| 233 | | const storage = &br.storage; |
| 234 | | const buffered_len = storage.end; |
| 235 | | storage.end = 0; |
| 212 | const buffered_len = br.end; |
| 213 | br.end = 0; |
| 236 | 214 | return buffered_len + try br.unbuffered_reader.discardRemaining(); |
| 237 | 215 | } |
| 238 | 216 | |
| ... | ... | @@ -247,36 +225,25 @@ pub fn discardRemaining(br: *BufferedReader) Reader.ShortError!usize { |
| 247 | 225 | /// See also: |
| 248 | 226 | /// * `peek` |
| 249 | 227 | pub fn read(br: *BufferedReader, buffer: []u8) Reader.Error!void { |
| 250 | | const storage = &br.storage; |
| 251 | | const in_buffer = storage.buffer[0..storage.end]; |
| 252 | | const seek = br.seek; |
| 253 | | const proposed_seek = seek + in_buffer.len; |
| 254 | | if (proposed_seek <= in_buffer.len) { |
| 255 | | @memcpy(buffer, in_buffer[seek..proposed_seek]); |
| 256 | | br.seek = proposed_seek; |
| 228 | const in_buffer = br.buffer[br.seek..br.end]; |
| 229 | const copy_len = @min(buffer.len, in_buffer.len); |
| 230 | @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]); |
| 231 | if (copy_len == buffer.len) { |
| 232 | br.seek += copy_len; |
| 257 | 233 | return; |
| 258 | 234 | } |
| 259 | | @memcpy(buffer[0..in_buffer.len], in_buffer); |
| 260 | | storage.end = 0; |
| 235 | var i: usize = copy_len; |
| 236 | br.end = 0; |
| 261 | 237 | br.seek = 0; |
| 262 | | var i: usize = in_buffer.len; |
| 263 | 238 | while (true) { |
| 264 | | // TODO if remaining buffer len is greater than storage len, read directly into buffer |
| 265 | | const read_len = br.unbuffered_reader.read(storage, .unlimited) catch |err| switch (err) { |
| 266 | | error.WriteFailed => storage.end, |
| 267 | | else => |e| return e, |
| 268 | | }; |
| 269 | | assert(read_len == storage.end); |
| 270 | | const next_i = i + storage.end; |
| 271 | | if (next_i >= buffer.len) { |
| 272 | | const remaining = buffer[i..]; |
| 273 | | @memcpy(remaining, storage.buffer[0..remaining.len]); |
| 274 | | br.seek = remaining.len; |
| 275 | | return; |
| 239 | const remaining = buffer[i..]; |
| 240 | const n = try br.unbuffered_reader.readVec(&.{ remaining, br.buffer }); |
| 241 | if (n < remaining.len) { |
| 242 | i += n; |
| 243 | continue; |
| 276 | 244 | } |
| 277 | | @memcpy(buffer[i..next_i], storage.buffer[0..storage.end]); |
| 278 | | storage.end = 0; |
| 279 | | i = next_i; |
| 245 | br.end = n - remaining.len; |
| 246 | return; |
| 280 | 247 | } |
| 281 | 248 | } |
| 282 | 249 | |
| ... | ... | @@ -365,8 +332,8 @@ pub const DelimiterExclusiveError = error{ |
| 365 | 332 | pub fn takeDelimiterExclusive(br: *BufferedReader, delimiter: u8) DelimiterExclusiveError![]u8 { |
| 366 | 333 | const result = br.peekDelimiterInclusiveUnlessEnd(delimiter) catch |err| switch (err) { |
| 367 | 334 | error.EndOfStream => { |
| 368 | | br.toss(br.storage.end); |
| 369 | | return br.storage.buffer[0..br.storage.end]; |
| 335 | br.toss(br.end); |
| 336 | return br.buffer[0..br.end]; |
| 370 | 337 | }, |
| 371 | 338 | else => |e| return e, |
| 372 | 339 | }; |
| ... | ... | @@ -376,15 +343,14 @@ pub fn takeDelimiterExclusive(br: *BufferedReader, delimiter: u8) DelimiterExclu |
| 376 | 343 | |
| 377 | 344 | pub fn peekDelimiterExclusive(br: *BufferedReader, delimiter: u8) DelimiterExclusiveError![]u8 { |
| 378 | 345 | const result = br.peekDelimiterInclusiveUnlessEnd(delimiter) catch |err| switch (err) { |
| 379 | | error.EndOfStream => return br.storage.buffer[0..br.storage.end], |
| 346 | error.EndOfStream => return br.buffer[0..br.end], |
| 380 | 347 | else => |e| return e, |
| 381 | 348 | }; |
| 382 | 349 | return result[0 .. result.len - 1]; |
| 383 | 350 | } |
| 384 | 351 | |
| 385 | 352 | fn peekDelimiterInclusiveUnlessEnd(br: *BufferedReader, delimiter: u8) DelimiterInclusiveError!?[]u8 { |
| 386 | | const storage = &br.storage; |
| 387 | | const buffer = storage.buffer[0..storage.end]; |
| 353 | const buffer = br.buffer[0..br.end]; |
| 388 | 354 | const seek = br.seek; |
| 389 | 355 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { |
| 390 | 356 | @branchHint(.likely); |
| ... | ... | @@ -392,24 +358,15 @@ fn peekDelimiterInclusiveUnlessEnd(br: *BufferedReader, delimiter: u8) Delimiter |
| 392 | 358 | } |
| 393 | 359 | const remainder = buffer[seek..]; |
| 394 | 360 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 395 | | var i = remainder.len; |
| 396 | | storage.end = i; |
| 361 | br.end = remainder.len; |
| 397 | 362 | br.seek = 0; |
| 398 | | while (i < storage.buffer.len) { |
| 399 | | const eos = eos: { |
| 400 | | const read_len = br.unbuffered_reader.read(storage, .unlimited) catch |err| switch (err) { |
| 401 | | error.WriteFailed => storage.end - i, |
| 402 | | error.ReadFailed => return error.ReadFailed, |
| 403 | | error.EndOfStream => break :eos true, |
| 404 | | }; |
| 405 | | assert(read_len == storage.end - i); |
| 406 | | break :eos false; |
| 407 | | }; |
| 408 | | if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { |
| 409 | | return storage.buffer[0 .. end + 1]; |
| 363 | while (br.end < br.buffer.len) { |
| 364 | const n = try br.unbuffered_reader.readVec(&.{br.buffer[br.end..]}); |
| 365 | const prev_end = br.end; |
| 366 | br.end = prev_end + n; |
| 367 | if (std.mem.indexOfScalarPos(u8, br.buffer[0..br.end], prev_end, delimiter)) |end| { |
| 368 | return br.buffer[0 .. end + 1]; |
| 410 | 369 | } |
| 411 | | if (eos) return error.EndOfStream; |
| 412 | | i = storage.end; |
| 413 | 370 | } |
| 414 | 371 | return error.StreamTooLong; |
| 415 | 372 | } |
| ... | ... | @@ -494,9 +451,8 @@ pub fn discardDelimiterExclusive(br: *BufferedReader, delimiter: u8) Reader.Shor |
| 494 | 451 | /// |
| 495 | 452 | /// Asserts buffer capacity is at least `n`. |
| 496 | 453 | pub fn fill(br: *BufferedReader, n: usize) Reader.Error!void { |
| 497 | | const storage = &br.storage; |
| 498 | | assert(n <= storage.buffer.len); |
| 499 | | const buffer = storage.buffer[0..storage.end]; |
| 454 | assert(n <= br.buffer.len); |
| 455 | const buffer = br.buffer[0..br.end]; |
| 500 | 456 | const seek = br.seek; |
| 501 | 457 | if (seek + n <= buffer.len) { |
| 502 | 458 | @branchHint(.likely); |
| ... | ... | @@ -504,22 +460,17 @@ pub fn fill(br: *BufferedReader, n: usize) Reader.Error!void { |
| 504 | 460 | } |
| 505 | 461 | const remainder = buffer[seek..]; |
| 506 | 462 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 507 | | storage.end = remainder.len; |
| 463 | br.end = remainder.len; |
| 508 | 464 | br.seek = 0; |
| 509 | 465 | while (true) { |
| 510 | | const read_len = br.unbuffered_reader.read(storage, .unlimited) catch |err| switch (err) { |
| 511 | | error.WriteFailed => storage.end - remainder.len, |
| 512 | | else => |e| return e, |
| 513 | | }; |
| 514 | | assert(storage.end == remainder.len + read_len); |
| 515 | | if (n <= storage.end) return; |
| 466 | br.end += try br.unbuffered_reader.readVec(&.{br.buffer[br.end..]}); |
| 467 | if (n <= br.end) return; |
| 516 | 468 | } |
| 517 | 469 | } |
| 518 | 470 | |
| 519 | 471 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. |
| 520 | 472 | pub fn takeByte(br: *BufferedReader) Reader.Error!u8 { |
| 521 | | const storage = &br.storage; |
| 522 | | const buffer = storage.buffer[0..storage.end]; |
| 473 | const buffer = br.buffer[0..br.end]; |
| 523 | 474 | const seek = br.seek; |
| 524 | 475 | if (seek >= buffer.len) { |
| 525 | 476 | @branchHint(.unlikely); |