From da8fbcc2a9134c52474060ecc240c06e4a7df3cd Mon Sep 17 00:00:00 2001 From: clickingbuttons Date: Thu, 15 Aug 2024 02:03:29 -0400 Subject: [PATCH] std.mem.writeVarPackedInt: handle write_size == 0 (#19745) Also move example comments into tests. --- lib/std/mem.zig | 62 ++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 1fd8af950a..685e36feae 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1647,12 +1647,6 @@ test readVarInt { /// Loads an integer from packed memory with provided bit_count, bit_offset, and signedness. /// Asserts that T is large enough to store the read value. -/// -/// Example: -/// const T = packed struct(u16){ a: u3, b: u7, c: u6 }; -/// var st = T{ .a = 1, .b = 2, .c = 4 }; -/// const b_field = readVarPackedInt(u64, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 7, builtin.cpu.arch.endian(), .unsigned); -/// pub fn readVarPackedInt( comptime T: type, bytes: []const u8, @@ -1715,6 +1709,13 @@ pub fn readVarPackedInt( } } +test readVarPackedInt { + const T = packed struct(u16) { a: u3, b: u7, c: u6 }; + var st = T{ .a = 1, .b = 2, .c = 4 }; + const b_field = readVarPackedInt(u64, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 7, builtin.cpu.arch.endian(), .unsigned); + try std.testing.expectEqual(st.b, b_field); +} + /// Reads an integer from memory with bit count specified by T. /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. @@ -1811,12 +1812,6 @@ pub const readPackedIntForeign = switch (native_endian) { /// Loads an integer from packed memory. /// Asserts that buffer contains at least bit_offset + @bitSizeOf(T) bits. -/// -/// Example: -/// const T = packed struct(u16){ a: u3, b: u7, c: u6 }; -/// var st = T{ .a = 1, .b = 2, .c = 4 }; -/// const b_field = readPackedInt(u7, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), builtin.cpu.arch.endian()); -/// pub fn readPackedInt(comptime T: type, bytes: []const u8, bit_offset: usize, endian: Endian) T { switch (endian) { .little => return readPackedIntLittle(T, bytes, bit_offset), @@ -1824,6 +1819,13 @@ pub fn readPackedInt(comptime T: type, bytes: []const u8, bit_offset: usize, end } } +test readPackedInt { + const T = packed struct(u16) { a: u3, b: u7, c: u6 }; + var st = T{ .a = 1, .b = 2, .c = 4 }; + const b_field = readPackedInt(u7, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), builtin.cpu.arch.endian()); + try std.testing.expectEqual(st.b, b_field); +} + test "comptime read/write int" { comptime { var bytes: [2]u8 = undefined; @@ -1963,13 +1965,6 @@ pub const writePackedIntForeign = switch (native_endian) { /// Stores an integer to packed memory. /// Asserts that buffer contains at least bit_offset + @bitSizeOf(T) bits. -/// -/// Example: -/// const T = packed struct(u16){ a: u3, b: u7, c: u6 }; -/// var st = T{ .a = 1, .b = 2, .c = 4 }; -/// // st.b = 0x7f; -/// writePackedInt(u7, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 0x7f, builtin.cpu.arch.endian()); -/// pub fn writePackedInt(comptime T: type, bytes: []u8, bit_offset: usize, value: T, endian: Endian) void { switch (endian) { .little => writePackedIntLittle(T, bytes, bit_offset, value), @@ -1977,16 +1972,15 @@ pub fn writePackedInt(comptime T: type, bytes: []u8, bit_offset: usize, value: T } } -/// Stores an integer to packed memory with provided bit_count, bit_offset, and signedness. +test writePackedInt { + const T = packed struct(u16) { a: u3, b: u7, c: u6 }; + var st = T{ .a = 1, .b = 2, .c = 4 }; + writePackedInt(u7, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 0x7f, builtin.cpu.arch.endian()); + try std.testing.expectEqual(T{ .a = 1, .b = 0x7f, .c = 4 }, st); +} + +/// Stores an integer to packed memory with provided bit_offset, bit_count, and signedness. /// If negative, the written value is sign-extended. -/// -/// Example: -/// const T = packed struct(u16){ a: u3, b: u7, c: u6 }; -/// var st = T{ .a = 1, .b = 2, .c = 4 }; -/// // st.b = 0x7f; -/// var value: u64 = 0x7f; -/// writeVarPackedInt(std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 7, value, builtin.cpu.arch.endian()); -/// pub fn writeVarPackedInt(bytes: []u8, bit_offset: usize, bit_count: usize, value: anytype, endian: std.builtin.Endian) void { const T = @TypeOf(value); const uN = std.meta.Int(.unsigned, @bitSizeOf(T)); @@ -1999,7 +1993,9 @@ pub fn writeVarPackedInt(bytes: []u8, bit_offset: usize, bit_count: usize, value }; const write_bytes = bytes[lowest_byte..][0..write_size]; - if (write_size == 1) { + if (write_size == 0) { + return; + } else if (write_size == 1) { // Single byte writes are handled specially, since we need to mask bits // on both ends of the byte. const mask = (@as(u8, 0xff) >> @as(u3, @intCast(8 - bit_count))); @@ -2039,6 +2035,14 @@ pub fn writeVarPackedInt(bytes: []u8, bit_offset: usize, bit_count: usize, value write_bytes[@as(usize, @intCast(i))] |= @as(u8, @intCast(@as(uN, @bitCast(remaining)) & tail_mask)); } +test writeVarPackedInt { + const T = packed struct(u16) { a: u3, b: u7, c: u6 }; + var st = T{ .a = 1, .b = 2, .c = 4 }; + const value: u64 = 0x7f; + writeVarPackedInt(std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 7, value, builtin.cpu.arch.endian()); + try testing.expectEqual(T{ .a = 1, .b = value, .c = 4 }, st); +} + /// Swap the byte order of all the members of the fields of a struct /// (Changing their endianness) pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {