master
1const builtin = @import("builtin");
2const std = @import("std");
3const testing = std.testing;
4
5/// This is an "advanced" function. It allows one to use a fixed amount of memory to store a
6/// ULEB128. This defeats the entire purpose of using this data encoding; it will no longer use
7/// fewer bytes to store smaller numbers. The advantage of using a fixed width is that it makes
8/// fields have a predictable size and so depending on the use case this tradeoff can be worthwhile.
9/// An example use case of this is in emitting DWARF info where one wants to make a ULEB128 field
10/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a
11/// different value without shifting all the following code.
12pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.unsigned, l * 7)) void {
13 writeUnsignedExtended(ptr, int);
14}
15
16/// Same as `writeUnsignedFixed` but with a runtime-known length.
17/// Asserts `slice.len > 0`.
18pub fn writeUnsignedExtended(slice: []u8, arg: anytype) void {
19 const Arg = @TypeOf(arg);
20 const Int = switch (Arg) {
21 comptime_int => std.math.IntFittingRange(arg, arg),
22 else => Arg,
23 };
24 const Value = if (@typeInfo(Int).int.bits < 8) u8 else Int;
25 var value: Value = arg;
26
27 for (slice[0 .. slice.len - 1]) |*byte| {
28 byte.* = @truncate(0x80 | value);
29 value >>= 7;
30 }
31 slice[slice.len - 1] = @as(u7, @intCast(value));
32}
33
34test writeUnsignedFixed {
35 {
36 var buf: [4]u8 = undefined;
37 writeUnsignedFixed(4, &buf, 0);
38 var reader: std.Io.Reader = .fixed(&buf);
39 try testing.expectEqual(0, try reader.takeLeb128(u64));
40 }
41 {
42 var buf: [4]u8 = undefined;
43 writeUnsignedFixed(4, &buf, 1);
44 var reader: std.Io.Reader = .fixed(&buf);
45 try testing.expectEqual(1, try reader.takeLeb128(u64));
46 }
47 {
48 var buf: [4]u8 = undefined;
49 writeUnsignedFixed(4, &buf, 1000);
50 var reader: std.Io.Reader = .fixed(&buf);
51 try testing.expectEqual(1000, try reader.takeLeb128(u64));
52 }
53 {
54 var buf: [4]u8 = undefined;
55 writeUnsignedFixed(4, &buf, 10000000);
56 var reader: std.Io.Reader = .fixed(&buf);
57 try testing.expectEqual(10000000, try reader.takeLeb128(u64));
58 }
59}
60
61/// This is an "advanced" function. It allows one to use a fixed amount of memory to store an
62/// ILEB128. This defeats the entire purpose of using this data encoding; it will no longer use
63/// fewer bytes to store smaller numbers. The advantage of using a fixed width is that it makes
64/// fields have a predictable size and so depending on the use case this tradeoff can be worthwhile.
65/// An example use case of this is in emitting DWARF info where one wants to make a ILEB128 field
66/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a
67/// different value without shifting all the following code.
68pub fn writeSignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.signed, l * 7)) void {
69 const T = @TypeOf(int);
70 const U = if (@typeInfo(T).int.bits < 8) u8 else T;
71 var value: U = @intCast(int);
72
73 comptime var i = 0;
74 inline while (i < (l - 1)) : (i += 1) {
75 const byte: u8 = @bitCast(@as(i8, @truncate(value)) | -0b1000_0000);
76 value >>= 7;
77 ptr[i] = byte;
78 }
79 ptr[i] = @as(u7, @bitCast(@as(i7, @truncate(value))));
80}
81
82test writeSignedFixed {
83 {
84 var buf: [4]u8 = undefined;
85 writeSignedFixed(4, &buf, 0);
86 var reader: std.Io.Reader = .fixed(&buf);
87 try testing.expectEqual(0, try reader.takeLeb128(i64));
88 }
89 {
90 var buf: [4]u8 = undefined;
91 writeSignedFixed(4, &buf, 1);
92 var reader: std.Io.Reader = .fixed(&buf);
93 try testing.expectEqual(1, try reader.takeLeb128(i64));
94 }
95 {
96 var buf: [4]u8 = undefined;
97 writeSignedFixed(4, &buf, -1);
98 var reader: std.Io.Reader = .fixed(&buf);
99 try testing.expectEqual(-1, try reader.takeLeb128(i64));
100 }
101 {
102 var buf: [4]u8 = undefined;
103 writeSignedFixed(4, &buf, 1000);
104 var reader: std.Io.Reader = .fixed(&buf);
105 try testing.expectEqual(1000, try reader.takeLeb128(i64));
106 }
107 {
108 var buf: [4]u8 = undefined;
109 writeSignedFixed(4, &buf, -1000);
110 var reader: std.Io.Reader = .fixed(&buf);
111 try testing.expectEqual(-1000, try reader.takeLeb128(i64));
112 }
113 {
114 var buf: [4]u8 = undefined;
115 writeSignedFixed(4, &buf, -10000000);
116 var reader: std.Io.Reader = .fixed(&buf);
117 try testing.expectEqual(-10000000, try reader.takeLeb128(i64));
118 }
119 {
120 var buf: [4]u8 = undefined;
121 writeSignedFixed(4, &buf, 10000000);
122 var reader: std.Io.Reader = .fixed(&buf);
123 try testing.expectEqual(10000000, try reader.takeLeb128(i64));
124 }
125}