]> git.proxmox.com Git - rustc.git/blame_incremental - compiler/rustc_serialize/src/leb128.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_serialize / src / leb128.rs
... / ...
CommitLineData
1use crate::opaque::MemDecoder;
2use crate::serialize::Decoder;
3
4/// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type
5pub const fn max_leb128_len<T>() -> usize {
6 // The longest LEB128 encoding for an integer uses 7 bits per byte.
7 (std::mem::size_of::<T>() * 8 + 6) / 7
8}
9
10/// Returns the length of the longest LEB128 encoding of all supported integer types.
11pub const fn largest_max_leb128_len() -> usize {
12 max_leb128_len::<u128>()
13}
14
15macro_rules! impl_write_unsigned_leb128 {
16 ($fn_name:ident, $int_ty:ty) => {
17 #[inline]
18 pub fn $fn_name(
19 out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len::<$int_ty>()],
20 mut value: $int_ty,
21 ) -> &[u8] {
22 let mut i = 0;
23
24 loop {
25 if value < 0x80 {
26 unsafe {
27 *out.get_unchecked_mut(i).as_mut_ptr() = value as u8;
28 }
29
30 i += 1;
31 break;
32 } else {
33 unsafe {
34 *out.get_unchecked_mut(i).as_mut_ptr() = ((value & 0x7f) | 0x80) as u8;
35 }
36
37 value >>= 7;
38 i += 1;
39 }
40 }
41
42 unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) }
43 }
44 };
45}
46
47impl_write_unsigned_leb128!(write_u16_leb128, u16);
48impl_write_unsigned_leb128!(write_u32_leb128, u32);
49impl_write_unsigned_leb128!(write_u64_leb128, u64);
50impl_write_unsigned_leb128!(write_u128_leb128, u128);
51impl_write_unsigned_leb128!(write_usize_leb128, usize);
52
53macro_rules! impl_read_unsigned_leb128 {
54 ($fn_name:ident, $int_ty:ty) => {
55 #[inline]
56 pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty {
57 // The first iteration of this loop is unpeeled. This is a
58 // performance win because this code is hot and integer values less
59 // than 128 are very common, typically occurring 50-80% or more of
60 // the time, even for u64 and u128.
61 let byte = decoder.read_u8();
62 if (byte & 0x80) == 0 {
63 return byte as $int_ty;
64 }
65 let mut result = (byte & 0x7F) as $int_ty;
66 let mut shift = 7;
67 loop {
68 let byte = decoder.read_u8();
69 if (byte & 0x80) == 0 {
70 result |= (byte as $int_ty) << shift;
71 return result;
72 } else {
73 result |= ((byte & 0x7F) as $int_ty) << shift;
74 }
75 shift += 7;
76 }
77 }
78 };
79}
80
81impl_read_unsigned_leb128!(read_u16_leb128, u16);
82impl_read_unsigned_leb128!(read_u32_leb128, u32);
83impl_read_unsigned_leb128!(read_u64_leb128, u64);
84impl_read_unsigned_leb128!(read_u128_leb128, u128);
85impl_read_unsigned_leb128!(read_usize_leb128, usize);
86
87macro_rules! impl_write_signed_leb128 {
88 ($fn_name:ident, $int_ty:ty) => {
89 #[inline]
90 pub fn $fn_name(
91 out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len::<$int_ty>()],
92 mut value: $int_ty,
93 ) -> &[u8] {
94 let mut i = 0;
95
96 loop {
97 let mut byte = (value as u8) & 0x7f;
98 value >>= 7;
99 let more = !(((value == 0) && ((byte & 0x40) == 0))
100 || ((value == -1) && ((byte & 0x40) != 0)));
101
102 if more {
103 byte |= 0x80; // Mark this byte to show that more bytes will follow.
104 }
105
106 unsafe {
107 *out.get_unchecked_mut(i).as_mut_ptr() = byte;
108 }
109
110 i += 1;
111
112 if !more {
113 break;
114 }
115 }
116
117 unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) }
118 }
119 };
120}
121
122impl_write_signed_leb128!(write_i16_leb128, i16);
123impl_write_signed_leb128!(write_i32_leb128, i32);
124impl_write_signed_leb128!(write_i64_leb128, i64);
125impl_write_signed_leb128!(write_i128_leb128, i128);
126impl_write_signed_leb128!(write_isize_leb128, isize);
127
128macro_rules! impl_read_signed_leb128 {
129 ($fn_name:ident, $int_ty:ty) => {
130 #[inline]
131 pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty {
132 let mut result = 0;
133 let mut shift = 0;
134 let mut byte;
135
136 loop {
137 byte = decoder.read_u8();
138 result |= <$int_ty>::from(byte & 0x7F) << shift;
139 shift += 7;
140
141 if (byte & 0x80) == 0 {
142 break;
143 }
144 }
145
146 if (shift < <$int_ty>::BITS) && ((byte & 0x40) != 0) {
147 // sign extend
148 result |= (!0 << shift);
149 }
150
151 result
152 }
153 };
154}
155
156impl_read_signed_leb128!(read_i16_leb128, i16);
157impl_read_signed_leb128!(read_i32_leb128, i32);
158impl_read_signed_leb128!(read_i64_leb128, i64);
159impl_read_signed_leb128!(read_i128_leb128, i128);
160impl_read_signed_leb128!(read_isize_leb128, isize);