From 939fcce5ef415142631e246a91473317a8d3fa90 Mon Sep 17 00:00:00 2001 From: poypoyan Date: Mon, 29 Jul 2024 11:26:36 +0800 Subject: [PATCH] std.mem.readVarInt: fix for 8-bits and below (Reloaded) (#20513) --- lib/std/mem.zig | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 4cd5ee841d..984f1198ac 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1594,7 +1594,10 @@ test containsAtLeast { /// T specifies the return type, which must be large enough to store /// the result. pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) ReturnType { - var result: ReturnType = 0; + const bits = @typeInfo(ReturnType).Int.bits; + const signedness = @typeInfo(ReturnType).Int.signedness; + const WorkType = std.meta.Int(signedness, @max(16, bits)); + var result: WorkType = 0; switch (endian) { .big => { for (bytes) |b| { @@ -1602,13 +1605,36 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) } }, .little => { - const ShiftType = math.Log2Int(ReturnType); + const ShiftType = math.Log2Int(WorkType); for (bytes, 0..) |b, index| { - result = result | (@as(ReturnType, b) << @as(ShiftType, @intCast(index * 8))); + result = result | (@as(WorkType, b) << @as(ShiftType, @intCast(index * 8))); } }, } - return result; + return @as(ReturnType, @truncate(result)); +} + +test readVarInt { + try testing.expect(readVarInt(u0, &[_]u8{}, .big) == 0x0); + try testing.expect(readVarInt(u0, &[_]u8{}, .little) == 0x0); + try testing.expect(readVarInt(u8, &[_]u8{0x12}, .big) == 0x12); + try testing.expect(readVarInt(u8, &[_]u8{0xde}, .little) == 0xde); + try testing.expect(readVarInt(u16, &[_]u8{ 0x12, 0x34 }, .big) == 0x1234); + try testing.expect(readVarInt(u16, &[_]u8{ 0x12, 0x34 }, .little) == 0x3412); + + try testing.expect(readVarInt(i8, &[_]u8{0xff}, .big) == -1); + try testing.expect(readVarInt(i8, &[_]u8{0xfe}, .little) == -2); + try testing.expect(readVarInt(i16, &[_]u8{ 0xff, 0xfd }, .big) == -3); + try testing.expect(readVarInt(i16, &[_]u8{ 0xfc, 0xff }, .little) == -4); + + // Return type can be oversized (bytes.len * 8 < @typeInfo(ReturnType).Int.bits) + try testing.expect(readVarInt(u9, &[_]u8{0x12}, .little) == 0x12); + try testing.expect(readVarInt(u9, &[_]u8{0xde}, .big) == 0xde); + try testing.expect(readVarInt(u80, &[_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }, .big) == 0x123456789abcdef024); + try testing.expect(readVarInt(u80, &[_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }, .little) == 0xfedcba9876543210ec); + + try testing.expect(readVarInt(i9, &[_]u8{0xff}, .big) == 0xff); + try testing.expect(readVarInt(i9, &[_]u8{0xfe}, .little) == 0xfe); } /// Loads an integer from packed memory with provided bit_count, bit_offset, and signedness.