| ... | @@ -269,36 +269,43 @@ fn writeSplatHeaderLimitFinish( | ... | @@ -269,36 +269,43 @@ fn writeSplatHeaderLimitFinish( |
| 269 | limit: usize, | 269 | limit: usize, |
| 270 | ) Error!usize { | 270 | ) Error!usize { |
| 271 | var remaining = limit; | 271 | var remaining = limit; |
| | 272 | var total: usize = 0; |
| 272 | var vecs: [8][]const u8 = undefined; | 273 | var vecs: [8][]const u8 = undefined; |
| 273 | var i: usize = 0; | 274 | var i: usize = 0; |
| 274 | v: { | 275 | if (header.len != 0) { |
| 275 | if (header.len != 0) { | 276 | const copy_len = @min(header.len, remaining); |
| 276 | const copy_len = @min(header.len, remaining); | 277 | vecs[i] = header[0..copy_len]; |
| 277 | vecs[i] = header[0..copy_len]; | 278 | i += 1; |
| 278 | i += 1; | 279 | remaining -= copy_len; |
| 279 | remaining -= copy_len; | 280 | if (remaining == 0) { |
| 280 | if (remaining == 0) break :v; | 281 | return w.vtable.drain(w, (&vecs)[0..i], 1); |
| 281 | } | 282 | } |
| 282 | for (data[0 .. data.len - 1]) |buf| { | 283 | } |
| 283 | if (buf.len == 0) continue; | 284 | for (data[0 .. data.len - 1]) |buf| { |
| 284 | const copy_len = @min(buf.len, remaining); | 285 | if (buf.len == 0) continue; |
| 285 | vecs[i] = buf[0..copy_len]; | 286 | const copy_len = @min(buf.len, remaining); |
| 286 | i += 1; | 287 | vecs[i] = buf[0..copy_len]; |
| 287 | remaining -= copy_len; | 288 | i += 1; |
| 288 | if (remaining == 0) break :v; | 289 | remaining -= copy_len; |
| 289 | if (vecs.len - i == 0) break :v; | 290 | if (remaining == 0) { |
| | 291 | return w.vtable.drain(w, (&vecs)[0..i], 1); |
| 290 | } | 292 | } |
| 291 | const pattern = data[data.len - 1]; | 293 | if (i == vecs.len) { |
| 292 | if (splat == 1 or remaining < pattern.len) { | 294 | total += try w.vtable.drain(w, &vecs, 1); |
| 293 | vecs[i] = pattern[0..@min(remaining, pattern.len)]; | 295 | i = 0; |
| 294 | i += 1; | | |
| 295 | break :v; | | |
| 296 | } | 296 | } |
| 297 | vecs[i] = pattern; | 297 | } |
| | 298 | const pattern = data[data.len - 1]; |
| | 299 | if (splat == 1 or remaining < pattern.len) { |
| | 300 | vecs[i] = pattern[0..@min(remaining, pattern.len)]; |
| 298 | i += 1; | 301 | i += 1; |
| 299 | return w.vtable.drain(w, (&vecs)[0..i], @min(remaining / pattern.len, splat)); | 302 | total += try w.vtable.drain(w, (&vecs)[0..i], 1); |
| | 303 | return total; |
| 300 | } | 304 | } |
| 301 | return w.vtable.drain(w, (&vecs)[0..i], 1); | 305 | vecs[i] = pattern; |
| | 306 | i += 1; |
| | 307 | total += try w.vtable.drain(w, (&vecs)[0..i], @min(remaining / pattern.len, splat)); |
| | 308 | return total; |
| 302 | } | 309 | } |
| 303 | | 310 | |
| 304 | const SplatHeaderTestCase = struct { | 311 | const SplatHeaderTestCase = struct { |
| ... | @@ -357,6 +364,8 @@ test "fixed writer writeSplatHeaderLimit" { | ... | @@ -357,6 +364,8 @@ test "fixed writer writeSplatHeaderLimit" { |
| 357 | | 364 | |
| 358 | // allocating writer that needs to expand capacity during splat | 365 | // allocating writer that needs to expand capacity during splat |
| 359 | try testWriteSplatHeaderLimit(.{ .writer_type = .allocating, .buf_len = 8, .header = "hhhh", .data = &.{"PP"}, .splat = 3, .limit = 100, .expected_res = .{ .written = 10 }, .expected_buf_content = "hhhhPPPPPP" }); | 366 | try testWriteSplatHeaderLimit(.{ .writer_type = .allocating, .buf_len = 8, .header = "hhhh", .data = &.{"PP"}, .splat = 3, .limit = 100, .expected_res = .{ .written = 10 }, .expected_buf_content = "hhhhPPPPPP" }); |
| | 367 | try testWriteSplatHeaderLimit(.{ .writer_type = .allocating, .buf_len = 2, .header = "", .data = &.{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "X", "Y", "ZZ" }, .splat = 2, .limit = 100, .expected_res = .{ .written = 16 }, .expected_buf_content = "0123456789XYZZZZ" }); |
| | 368 | try testWriteSplatHeaderLimit(.{ .writer_type = .allocating, .buf_len = 2, .header = "", .data = &.{ "0", "1", "2", "", "", "3", "4" }, .splat = 2, .limit = 4, .expected_res = .{ .written = 4 }, .expected_buf_content = "0123" }); |
| 360 | } | 369 | } |
| 361 | | 370 | |
| 362 | test "writeSplatHeader splatting avoids buffer aliasing temptation" { | 371 | test "writeSplatHeader splatting avoids buffer aliasing temptation" { |
| ... | @@ -367,9 +376,9 @@ test "writeSplatHeader splatting avoids buffer aliasing temptation" { | ... | @@ -367,9 +376,9 @@ test "writeSplatHeader splatting avoids buffer aliasing temptation" { |
| 367 | const n = try aw.writer.writeSplatHeader("header which is longer than buf ", &.{ | 376 | const n = try aw.writer.writeSplatHeader("header which is longer than buf ", &.{ |
| 368 | "1", "2", "3", "4", "5", "6", "foo", "bar", "foo", | 377 | "1", "2", "3", "4", "5", "6", "foo", "bar", "foo", |
| 369 | }, 3); | 378 | }, 3); |
| 370 | try testing.expectEqual(41, n); | 379 | try testing.expectEqual(53, n); |
| 371 | try testing.expectEqualStrings( | 380 | try testing.expectEqualStrings( |
| 372 | "header which is longer than buf 123456foo", | 381 | "header which is longer than buf 123456foobarfoofoofoo", |
| 373 | aw.writer.buffered(), | 382 | aw.writer.buffered(), |
| 374 | ); | 383 | ); |
| 375 | } | 384 | } |