@@ -1901,35 +1901,199 @@ pub fn writeSleb128(w: *Writer, value: anytype) Error!void {
19011901
19021902/// Write a single integer as LEB128 to the given writer.
19031903pub fn writeLeb128 (w : * Writer , value : anytype ) Error ! void {
1904- const value_info = @typeInfo (@TypeOf (value )).int ;
1905- try w .writeMultipleOf7Leb128 (@as (@Type (.{ .int = .{
1906- .signedness = value_info .signedness ,
1907- .bits = @max (std .mem .alignForwardAnyAlign (u16 , value_info .bits , 7 ), 7 ),
1908- } }), value ));
1909- }
1904+ const T = @TypeOf (value );
1905+ const info = switch (@typeInfo (T )) {
1906+ .int = > | info | info ,
1907+ else = > @compileError (@tagName (T ) ++ " not supported" ),
1908+ };
19101909
1911- fn writeMultipleOf7Leb128 (w : * Writer , value : anytype ) Error ! void {
1912- const value_info = @typeInfo (@TypeOf (value )).int ;
1913- const Byte = packed struct (u8 ) { bits : u7 , more : bool };
1914- var bytes : [@divExact (value_info.bits , 7 )]Byte = undefined ;
1915- var remaining = value ;
1916- for (& bytes , 1.. ) | * byte , len | {
1917- const more = switch (value_info .signedness ) {
1918- .signed = > remaining >> 6 != remaining >> (value_info .bits - 1 ),
1919- .unsigned = > remaining > std .math .maxInt (u7 ),
1910+ const BoundInt = @Type (.{ .int = .{ .bits = 7 , .signedness = info .signedness } });
1911+ if (info .bits <= 7 or (value >= std .math .minInt (BoundInt ) and value <= std .math .maxInt (BoundInt ))) {
1912+ const Byte = @Type (.{ .int = .{ .bits = 8 , .signedness = info .signedness } });
1913+ const byte = switch (info .signedness ) {
1914+ .signed = > @as (Byte , @intCast (value )) & 0x7F ,
1915+ .unsigned = > @as (Byte , @intCast (value )),
19201916 };
1917+ try w .writeByte (@bitCast (byte ));
1918+ return ;
1919+ }
1920+
1921+ const Byte = packed struct { bits : u7 , more : bool };
1922+ const Int = std .math .ByteAlignedInt (T );
1923+
1924+ const max_bytes = @divFloor (info .bits - 1 , 7 ) + 1 ;
1925+ const bytes : []Byte = @ptrCast (try w .writableSliceGreedy (max_bytes ));
1926+
1927+ var val : Int = value ;
1928+ for (bytes , 1.. ) | * byte , len | {
1929+ const more = switch (info .signedness ) {
1930+ .signed = > val >> 6 != val >> (info .bits - 1 ),
1931+ .unsigned = > val > std .math .maxInt (u7 ),
1932+ };
1933+
19211934 byte .* = .{
1922- .bits = @bitCast (@as (@Type (.{ .int = .{
1923- .signedness = value_info .signedness ,
1924- .bits = 7 ,
1925- } }), @truncate (remaining ))),
1935+ .bits = @intCast (val & 0x7F ),
19261936 .more = more ,
19271937 };
1928- if (value_info .bits > 7 ) remaining >>= 7 ;
1929- if (! more ) return w .writeAll (@ptrCast (bytes [0.. len ]));
1938+
1939+ if (! more ) {
1940+ w .advance (len );
1941+ return ;
1942+ }
1943+
1944+ val >>= 7 ;
19301945 } else unreachable ;
19311946}
19321947
1948+ test "serialize signed LEB128" {
1949+ // Encode byte boundaries
1950+ try testLeb128Encoding (i7 , std .math .maxInt (i7 ), "\x3F " );
1951+ try testLeb128Encoding (i8 , std .math .maxInt (i7 ) + 1 , "\xC0\x00 " );
1952+ try testLeb128Encoding (i14 , std .math .maxInt (i14 ), "\xFF\x3F " );
1953+ try testLeb128Encoding (i15 , std .math .maxInt (i14 ) + 1 , "\x80\xC0\x00 " );
1954+ try testLeb128Encoding (i21 , std .math .maxInt (i21 ), "\xFF\xFF\x3F " );
1955+ try testLeb128Encoding (i22 , std .math .maxInt (i21 ) + 1 , "\x80\x80\xC0\x00 " );
1956+ try testLeb128Encoding (i28 , std .math .maxInt (i28 ), "\xFF\xFF\xFF\x3F " );
1957+ try testLeb128Encoding (i29 , std .math .maxInt (i28 ) + 1 , "\x80\x80\x80\xC0\x00 " );
1958+ try testLeb128Encoding (i35 , std .math .maxInt (i35 ), "\xFF\xFF\xFF\xFF\x3F " );
1959+ try testLeb128Encoding (i36 , std .math .maxInt (i35 ) + 1 , "\x80\x80\x80\x80\xC0\x00 " );
1960+ try testLeb128Encoding (i42 , std .math .maxInt (i42 ), "\xFF\xFF\xFF\xFF\xFF\x3F " );
1961+ try testLeb128Encoding (i43 , std .math .maxInt (i42 ) + 1 , "\x80\x80\x80\x80\x80\xC0\x00 " );
1962+ try testLeb128Encoding (i49 , std .math .maxInt (i49 ), "\xFF\xFF\xFF\xFF\xFF\xFF\x3F " );
1963+ try testLeb128Encoding (i50 , std .math .maxInt (i49 ) + 1 , "\x80\x80\x80\x80\x80\x80\xC0\x00 " );
1964+ try testLeb128Encoding (i56 , std .math .maxInt (i56 ), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F " );
1965+ try testLeb128Encoding (i57 , std .math .maxInt (i56 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\xC0\x00 " );
1966+ try testLeb128Encoding (i63 , std .math .maxInt (i63 ), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F " );
1967+ try testLeb128Encoding (i64 , std .math .maxInt (i63 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\x80\xC0\x00 " );
1968+ try testLeb128Encoding (i64 , std .math .maxInt (i64 ), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00 " );
1969+ try testLeb128Encoding (i65 , std .math .maxInt (i64 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01 " );
1970+
1971+ try testLeb128Encoding (i7 , std .math .minInt (i7 ), "\x40 " );
1972+ try testLeb128Encoding (i8 , std .math .minInt (i7 ) - 1 , "\xBF\x7F " );
1973+ try testLeb128Encoding (i14 , std .math .minInt (i14 ), "\x80\x40 " );
1974+ try testLeb128Encoding (i15 , std .math .minInt (i14 ) - 1 , "\xFF\xBF\x7F " );
1975+ try testLeb128Encoding (i21 , std .math .minInt (i21 ), "\x80\x80\x40 " );
1976+ try testLeb128Encoding (i22 , std .math .minInt (i21 ) - 1 , "\xFF\xFF\xBF\x7F " );
1977+ try testLeb128Encoding (i28 , std .math .minInt (i28 ), "\x80\x80\x80\x40 " );
1978+ try testLeb128Encoding (i29 , std .math .minInt (i28 ) - 1 , "\xFF\xFF\xFF\xBF\x7F " );
1979+ try testLeb128Encoding (i35 , std .math .minInt (i35 ), "\x80\x80\x80\x80\x40 " );
1980+ try testLeb128Encoding (i36 , std .math .minInt (i35 ) - 1 , "\xFF\xFF\xFF\xFF\xBF\x7F " );
1981+ try testLeb128Encoding (i42 , std .math .minInt (i42 ), "\x80\x80\x80\x80\x80\x40 " );
1982+ try testLeb128Encoding (i43 , std .math .minInt (i42 ) - 1 , "\xFF\xFF\xFF\xFF\xFF\xBF\x7F " );
1983+ try testLeb128Encoding (i49 , std .math .minInt (i49 ), "\x80\x80\x80\x80\x80\x80\x40 " );
1984+ try testLeb128Encoding (i50 , std .math .minInt (i49 ) - 1 , "\xFF\xFF\xFF\xFF\xFF\xFF\xBF\x7F " );
1985+ try testLeb128Encoding (i56 , std .math .minInt (i56 ), "\x80\x80\x80\x80\x80\x80\x80\x40 " );
1986+ try testLeb128Encoding (i57 , std .math .minInt (i56 ) - 1 , "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBF\x7F " );
1987+ try testLeb128Encoding (i63 , std .math .minInt (i63 ), "\x80\x80\x80\x80\x80\x80\x80\x80\x40 " );
1988+ try testLeb128Encoding (i64 , std .math .minInt (i63 ) - 1 , "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBF\x7F " );
1989+ try testLeb128Encoding (i64 , std .math .minInt (i64 ), "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x7F " );
1990+ try testLeb128Encoding (i65 , std .math .minInt (i64 ) - 1 , "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7E " );
1991+
1992+ // Random values
1993+ try testLeb128Encoding (i0 , 0 , "\x00 " );
1994+ try testLeb128Encoding (i1 , 0 , "\x00 " );
1995+
1996+ try testLeb128Encoding (i1 , -1 , "\x7F " );
1997+ try testLeb128Encoding (i7 , -42 , "\x56 " );
1998+ try testLeb128Encoding (i7 , -60 , "\x44 " );
1999+ try testLeb128Encoding (i7 , 28 , "\x1C " );
2000+ try testLeb128Encoding (i7 , 48 , "\x30 " );
2001+ try testLeb128Encoding (i7 , 7 , "\x07 " );
2002+
2003+ try testLeb128Encoding (i8 , 75 , "\xCB\x00 " );
2004+ try testLeb128Encoding (i8 , -16 , "\x70 " );
2005+ try testLeb128Encoding (i16 , 8568 , "\xF8\xC2\x00 " );
2006+ try testLeb128Encoding (i16 , -22129 , "\x8F\xD3\x7E " );
2007+ try testLeb128Encoding (i32 , 706871907 , "\xE3\x84\x88\xD1\x02 " );
2008+ try testLeb128Encoding (i32 , -1086310367 , "\xA1\xF0\x80\xFA\x7B " );
2009+ try testLeb128Encoding (i64 , 3191772538352771995 , "\x9B\xC7\xF4\x82\xE8\x86\xDD\xA5\x2C " );
2010+ try testLeb128Encoding (i64 , 6244662871897637219 , "\xE3\x82\x9E\xEC\xBD\xF9\xDF\xD4\xD6\x00 " );
2011+ try testLeb128Encoding (i64 , -7689149645688732033 , "\xFF\x8C\x9C\xBF\xAD\xE4\xA9\xA5\x95\x7F " );
2012+ try testLeb128Encoding (i64 , -2013874151389131036 , "\xE4\x9D\xF0\xC0\x91\x84\xD2\x86\x64 " );
2013+
2014+ // Ensure basic properties for every relevant type
2015+ inline for (0.. 128 + 1 ) | bits | {
2016+ const T = @Type (.{ .int = .{ .bits = bits , .signedness = .signed } });
2017+
2018+ try testLeb128Encoding (T , 0 , "\x00 " );
2019+ if (bits > 0 ) {
2020+ try testLeb128Encoding (T , -1 , "\x7F " );
2021+ }
2022+ if (bits > 1 ) {
2023+ try testLeb128Encoding (T , 1 , "\x01 " );
2024+ }
2025+ }
2026+ }
2027+
2028+ test "serialize unsigned LEB128" {
2029+ // Encode byte boundaries
2030+ try testLeb128Encoding (u7 , std .math .maxInt (u7 ), "\x7F " );
2031+ try testLeb128Encoding (u8 , std .math .maxInt (u7 ) + 1 , "\x80\x01 " );
2032+ try testLeb128Encoding (u14 , std .math .maxInt (u14 ), "\xFF\x7F " );
2033+ try testLeb128Encoding (u15 , std .math .maxInt (u14 ) + 1 , "\x80\x80\x01 " );
2034+ try testLeb128Encoding (u21 , std .math .maxInt (u21 ), "\xFF\xFF\x7F " );
2035+ try testLeb128Encoding (u22 , std .math .maxInt (u21 ) + 1 , "\x80\x80\x80\x01 " );
2036+ try testLeb128Encoding (u28 , std .math .maxInt (u28 ), "\xFF\xFF\xFF\x7F " );
2037+ try testLeb128Encoding (u29 , std .math .maxInt (u28 ) + 1 , "\x80\x80\x80\x80\x01 " );
2038+ try testLeb128Encoding (u35 , std .math .maxInt (u35 ), "\xFF\xFF\xFF\xFF\x7F " );
2039+ try testLeb128Encoding (u36 , std .math .maxInt (u35 ) + 1 , "\x80\x80\x80\x80\x80\x01 " );
2040+ try testLeb128Encoding (u42 , std .math .maxInt (u42 ), "\xFF\xFF\xFF\xFF\xFF\x7F " );
2041+ try testLeb128Encoding (u43 , std .math .maxInt (u42 ) + 1 , "\x80\x80\x80\x80\x80\x80\x01 " );
2042+ try testLeb128Encoding (u49 , std .math .maxInt (u49 ), "\xFF\xFF\xFF\xFF\xFF\xFF\x7F " );
2043+ try testLeb128Encoding (u50 , std .math .maxInt (u49 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\x01 " );
2044+ try testLeb128Encoding (u56 , std .math .maxInt (u56 ), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F " );
2045+ try testLeb128Encoding (u57 , std .math .maxInt (u56 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\x80\x01 " );
2046+ try testLeb128Encoding (u63 , std .math .maxInt (u63 ), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F " );
2047+ try testLeb128Encoding (u64 , std .math .maxInt (u63 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01 " );
2048+ try testLeb128Encoding (u64 , std .math .maxInt (u64 ), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01 " );
2049+ try testLeb128Encoding (u64 , std .math .maxInt (u7 ) + 1 , "\x80\x01 " );
2050+ try testLeb128Encoding (u64 , std .math .maxInt (u7 ), "\x7F " );
2051+ try testLeb128Encoding (u65 , std .math .maxInt (u64 ) + 1 , "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02 " );
2052+
2053+ // Random values
2054+ try testLeb128Encoding (u0 , 0 , "\x00 " );
2055+ try testLeb128Encoding (u1 , 0 , "\x00 " );
2056+
2057+ try testLeb128Encoding (u1 , 1 , "\x01 " );
2058+ try testLeb128Encoding (u7 , 10 , "\x0A " );
2059+ try testLeb128Encoding (u7 , 12 , "\x0C " );
2060+ try testLeb128Encoding (u7 , 32 , "\x20 " );
2061+ try testLeb128Encoding (u7 , 52 , "\x34 " );
2062+ try testLeb128Encoding (u7 , 98 , "\x62 " );
2063+
2064+ try testLeb128Encoding (u8 , 34 , "\x22 " );
2065+ try testLeb128Encoding (u8 , 133 , "\x85\x01 " );
2066+ try testLeb128Encoding (u16 , 64282 , "\x9A\xF6\x03 " );
2067+ try testLeb128Encoding (u16 , 43357 , "\xDD\xD2\x02 " );
2068+ try testLeb128Encoding (u32 , 677110117 , "\xE5\xC2\xEF\xC2\x02 " );
2069+ try testLeb128Encoding (u32 , 3777136920 , "\x98\x92\x8A\x89\x0E " );
2070+ try testLeb128Encoding (u64 , 10540460130307935799 , "\xB7\x9C\xB0\xE1\xC8\x94\xCF\xA3\x92\x01 " );
2071+ try testLeb128Encoding (u64 , 13430772867946637439 , "\xFF\xD0\xA7\xE7\xB9\x98\xEC\xB1\xBA\x01 " );
2072+ try testLeb128Encoding (u64 , 3059925747106684405 , "\xF5\xBB\xF6\xDA\x93\xC8\xC2\xBB\x2A " );
2073+ try testLeb128Encoding (u64 , 9843945664624830445 , "\xED\xCF\xD6\x81\xD3\x8D\xAE\xCE\x88\x01 " );
2074+
2075+ // Ensure basic properties for every relevant type
2076+ inline for (0.. 128 + 1 ) | bits | {
2077+ const T = @Type (.{ .int = .{ .bits = bits , .signedness = .unsigned } });
2078+
2079+ try testLeb128Encoding (T , 0 , "\x00 " );
2080+ if (bits > 0 ) {
2081+ try testLeb128Encoding (T , 1 , "\x01 " );
2082+ }
2083+ }
2084+ }
2085+
2086+ fn testLeb128Encoding (comptime T : type , value : T , encoding : []const u8 ) ! void {
2087+ const info = @typeInfo (T ).int ;
2088+ const max_bytes = @divFloor (info .bits - | 1 , 7 ) + 1 ;
2089+ var bytes : [max_bytes ]u8 = undefined ;
2090+
2091+ var fw : Writer = .fixed (& bytes );
2092+ try writeLeb128 (& fw , value );
2093+
2094+ try std .testing .expectEqualSlices (u8 , encoding , fw .buffered ());
2095+ }
2096+
19332097test "printValue max_depth" {
19342098 const Vec2 = struct {
19352099 const SelfType = @This ();
0 commit comments