Commit 939fcce5ef

poypoyan <srazin123@gmail.com>
2024-07-29 05:26:36
std.mem.readVarInt: fix for 8-bits and below (Reloaded) (#20513)
1 parent 08e83fe
Changed files (1)
lib
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.