Skip to content

Commit

Permalink
std.mem.writeVarPackedInt: handle write_size == 0 (ziglang#19745)
Browse files Browse the repository at this point in the history
Also move example comments into tests.
  • Loading branch information
clickingbuttons authored and SammyJames committed Aug 15, 2024
1 parent 1a90b26 commit 9b6c23a
Showing 1 changed file with 33 additions and 29 deletions.
62 changes: 33 additions & 29 deletions lib/std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1811,19 +1812,20 @@ 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),
.big => return readPackedIntBig(T, bytes, bit_offset),
}
}

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;
Expand Down Expand Up @@ -1963,30 +1965,22 @@ 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),
.big => writePackedIntBig(T, bytes, bit_offset, value),
}
}

/// 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));
Expand All @@ -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)));
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 9b6c23a

Please sign in to comment.