Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.mem.writeVarPackedInt: handle write_size == 0 #19745

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 33 additions & 29 deletions lib/std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1609,12 +1609,6 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian)

/// 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 @@ -1677,6 +1671,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 @@ -1773,19 +1774,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 @@ -1925,30 +1927,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 @@ -1961,7 +1955,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 @@ -2001,6 +1997,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