| ... | @@ -211,16 +211,37 @@ pub fn writeSplatHeader( | ... | @@ -211,16 +211,37 @@ pub fn writeSplatHeader( |
| 211 | var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size. | 211 | var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size. |
| 212 | var i: usize = 1; | 212 | var i: usize = 1; |
| 213 | vecs[0] = header; | 213 | vecs[0] = header; |
| 214 | for (data) |buf| { | 214 | for (data[0 .. data.len - 1]) |buf| { |
| 215 | if (buf.len == 0) continue; | 215 | if (buf.len == 0) continue; |
| 216 | vecs[i] = buf; | 216 | vecs[i] = buf; |
| 217 | i += 1; | 217 | i += 1; |
| 218 | if (vecs.len - i == 0) break; | 218 | if (vecs.len - i == 0) break; |
| 219 | } | 219 | } |
| 220 | const new_splat = if (vecs[i - 1].ptr == data[data.len - 1].ptr) splat else 1; | 220 | const pattern = data[data.len - 1]; |
| | 221 | const new_splat = s: { |
| | 222 | if (pattern.len == 0 or vecs.len - i == 0) break :s 1; |
| | 223 | vecs[i] = pattern; |
| | 224 | i += 1; |
| | 225 | break :s splat; |
| | 226 | }; |
| 221 | return w.vtable.drain(w, vecs[0..i], new_splat); | 227 | return w.vtable.drain(w, vecs[0..i], new_splat); |
| 222 | } | 228 | } |
| 223 | | 229 | |
| | 230 | test "writeSplatHeader splatting avoids buffer aliasing temptation" { |
| | 231 | const initial_buf = try testing.allocator.alloc(u8, 8); |
| | 232 | var aw: std.io.Writer.Allocating = .initOwnedSlice(testing.allocator, initial_buf); |
| | 233 | defer aw.deinit(); |
| | 234 | // This test assumes 8 vector buffer in this function. |
| | 235 | const n = try aw.writer.writeSplatHeader("header which is longer than buf ", &.{ |
| | 236 | "1", "2", "3", "4", "5", "6", "foo", "bar", "foo", |
| | 237 | }, 3); |
| | 238 | try testing.expectEqual(41, n); |
| | 239 | try testing.expectEqualStrings( |
| | 240 | "header which is longer than buf 123456foo", |
| | 241 | aw.writer.buffered(), |
| | 242 | ); |
| | 243 | } |
| | 244 | |
| 224 | /// Equivalent to `writeSplatHeader` but writes at most `limit` bytes. | 245 | /// Equivalent to `writeSplatHeader` but writes at most `limit` bytes. |
| 225 | pub fn writeSplatHeaderLimit( | 246 | pub fn writeSplatHeaderLimit( |
| 226 | w: *Writer, | 247 | w: *Writer, |
| ... | @@ -2037,8 +2058,8 @@ test "printFloat with comptime_float" { | ... | @@ -2037,8 +2058,8 @@ test "printFloat with comptime_float" { |
| 2037 | var buf: [20]u8 = undefined; | 2058 | var buf: [20]u8 = undefined; |
| 2038 | var w: Writer = .fixed(&buf); | 2059 | var w: Writer = .fixed(&buf); |
| 2039 | try w.printFloat(@as(comptime_float, 1.0), std.fmt.Options.toNumber(.{}, .scientific, .lower)); | 2060 | try w.printFloat(@as(comptime_float, 1.0), std.fmt.Options.toNumber(.{}, .scientific, .lower)); |
| 2040 | try std.testing.expectEqualStrings(w.buffered(), "1e0"); | 2061 | try testing.expectEqualStrings(w.buffered(), "1e0"); |
| 2041 | try std.testing.expectFmt("1", "{}", .{1.0}); | 2062 | try testing.expectFmt("1", "{}", .{1.0}); |
| 2042 | } | 2063 | } |
| 2043 | | 2064 | |
| 2044 | fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void { | 2065 | fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void { |
| ... | @@ -2065,12 +2086,12 @@ test printByteSize { | ... | @@ -2065,12 +2086,12 @@ test printByteSize { |
| 2065 | | 2086 | |
| 2066 | test "bytes.hex" { | 2087 | test "bytes.hex" { |
| 2067 | const some_bytes = "\xCA\xFE\xBA\xBE"; | 2088 | const some_bytes = "\xCA\xFE\xBA\xBE"; |
| 2068 | try std.testing.expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes}); | 2089 | try testing.expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes}); |
| 2069 | try std.testing.expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes}); | 2090 | try testing.expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes}); |
| 2070 | try std.testing.expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]}); | 2091 | try testing.expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]}); |
| 2071 | try std.testing.expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]}); | 2092 | try testing.expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]}); |
| 2072 | const bytes_with_zeros = "\x00\x0E\xBA\xBE"; | 2093 | const bytes_with_zeros = "\x00\x0E\xBA\xBE"; |
| 2073 | try std.testing.expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros}); | 2094 | try testing.expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros}); |
| 2074 | } | 2095 | } |
| 2075 | | 2096 | |
| 2076 | test fixed { | 2097 | test fixed { |
| ... | @@ -2479,7 +2500,7 @@ pub const Allocating = struct { | ... | @@ -2479,7 +2500,7 @@ pub const Allocating = struct { |
| 2479 | } | 2500 | } |
| 2480 | | 2501 | |
| 2481 | test Allocating { | 2502 | test Allocating { |
| 2482 | var a: Allocating = .init(std.testing.allocator); | 2503 | var a: Allocating = .init(testing.allocator); |
| 2483 | defer a.deinit(); | 2504 | defer a.deinit(); |
| 2484 | const w = &a.writer; | 2505 | const w = &a.writer; |
| 2485 | | 2506 | |