88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ use std:: cmp;
12+
1113#[ inline]
1214fn write_to_vec ( vec : & mut Vec < u8 > , position : usize , byte : u8 ) {
1315 if position == vec. len ( ) {
@@ -18,56 +20,95 @@ fn write_to_vec(vec: &mut Vec<u8>, position: usize, byte: u8) {
1820}
1921
2022#[ inline]
21- /// encodes an integer using unsigned leb128 encoding and stores
22- /// the result using a callback function.
23- ///
24- /// The callback `write` is called once for each position
25- /// that is to be written to with the byte to be encoded
26- /// at that position.
27- pub fn write_unsigned_leb128_to < W > ( mut value : u128 , mut write : W ) -> usize
28- where W : FnMut ( usize , u8 )
29- {
30- let mut position = 0 ;
31- loop {
32- let mut byte = ( value & 0x7F ) as u8 ;
33- value >>= 7 ;
34- if value != 0 {
35- byte |= 0x80 ;
36- }
37-
38- write ( position, byte) ;
39- position += 1 ;
23+ fn write_slice_to_vec ( output : & mut Vec < u8 > , start_position : usize , input : & [ u8 ] ) {
24+ let input_len = input. len ( ) ;
25+ let capacity = output. len ( ) - start_position;
26+ let first_half = cmp:: min ( capacity, input_len) ;
4027
41- if value == 0 {
42- break ;
43- }
28+ if first_half > 0 {
29+ ( & mut output[ start_position..] ) . copy_from_slice ( & input[ .. first_half] ) ;
4430 }
4531
46- position
32+ if first_half < input_len {
33+ output. extend_from_slice ( & input[ first_half..] ) ;
34+ }
4735}
4836
49- pub fn write_unsigned_leb128 ( out : & mut Vec < u8 > , start_position : usize , value : u128 ) -> usize {
50- write_unsigned_leb128_to ( value, |i, v| write_to_vec ( out, start_position+i, v) )
37+ #[ cfg( target_pointer_width = "32" ) ]
38+ const USIZE_LEB128_SIZE : usize = 5 ;
39+ #[ cfg( target_pointer_width = "64" ) ]
40+ const USIZE_LEB128_SIZE : usize = 10 ;
41+
42+ macro_rules! leb128_size {
43+ ( u16 ) => ( 3 ) ;
44+ ( u32 ) => ( 5 ) ;
45+ ( u64 ) => ( 10 ) ;
46+ ( u128 ) => ( 19 ) ;
47+ ( usize ) => ( USIZE_LEB128_SIZE ) ;
5148}
5249
53- #[ inline]
54- pub fn read_unsigned_leb128 ( data : & [ u8 ] , start_position : usize ) -> ( u128 , usize ) {
55- let mut result = 0 ;
56- let mut shift = 0 ;
57- let mut position = start_position;
58- loop {
59- let byte = data[ position] ;
60- position += 1 ;
61- result |= ( ( byte & 0x7F ) as u128 ) << shift;
62- if ( byte & 0x80 ) == 0 {
63- break ;
50+ macro_rules! impl_write_unsigned_leb128 {
51+ ( $fn_name: ident, $int_ty: ident) => (
52+ #[ inline]
53+ pub fn $fn_name( out: & mut Vec <u8 >, start_position: usize , mut value: $int_ty) -> usize {
54+ let mut encoded = [ 0u8 ; leb128_size!( $int_ty) ] ;
55+
56+ for i in 0 .. leb128_size!( $int_ty) {
57+ encoded[ i] = ( value as u8 ) & 0b0111_1111 ;
58+ value = value >> 7 ;
59+
60+ if value == 0 {
61+ let bytes_written = i + 1 ;
62+ write_slice_to_vec( out, start_position, & encoded[ 0 .. bytes_written] ) ;
63+ return bytes_written
64+ } else {
65+ encoded[ i] |= 0b1000_0000 ;
66+ }
67+ }
68+
69+ unreachable!( )
6470 }
65- shift += 7 ;
66- }
71+ )
72+ }
6773
68- ( result, position - start_position)
74+ impl_write_unsigned_leb128 ! ( write_u16_leb128, u16 ) ;
75+ impl_write_unsigned_leb128 ! ( write_u32_leb128, u32 ) ;
76+ impl_write_unsigned_leb128 ! ( write_u64_leb128, u64 ) ;
77+ impl_write_unsigned_leb128 ! ( write_u128_leb128, u128 ) ;
78+ impl_write_unsigned_leb128 ! ( write_usize_leb128, usize ) ;
79+
80+ macro_rules! impl_read_unsigned_leb128 {
81+ ( $fn_name: ident, $int_ty: ident) => (
82+ #[ inline]
83+ pub fn $fn_name( data: & [ u8 ] , start_position: usize ) -> ( $int_ty, usize ) {
84+ // Copy things into a fixed size buffer so we can skip the bounds check
85+ let mut bytes = [ 0u8 ; leb128_size!( $int_ty) ] ;
86+ let copy_len = cmp:: min( data. len( ) - start_position, leb128_size!( $int_ty) ) ;
87+ ( & mut bytes[ 0 .. copy_len] )
88+ . copy_from_slice( & data[ start_position .. start_position + copy_len] ) ;
89+
90+ let mut result = 0 ;
91+
92+ for i in 0 .. leb128_size!( $int_ty) {
93+ let byte = bytes[ i] ;
94+ result |= ( ( byte & 0b0111_1111 ) as $int_ty) << i * 7 ;
95+
96+ if ( byte & 0b1000_0000 ) == 0 {
97+ return ( result, i + 1 ) ;
98+ }
99+ }
100+
101+ unreachable!( )
102+ }
103+ )
69104}
70105
106+ impl_read_unsigned_leb128 ! ( read_u16_leb128, u16 ) ;
107+ impl_read_unsigned_leb128 ! ( read_u32_leb128, u32 ) ;
108+ impl_read_unsigned_leb128 ! ( read_u64_leb128, u64 ) ;
109+ impl_read_unsigned_leb128 ! ( read_u128_leb128, u128 ) ;
110+ impl_read_unsigned_leb128 ! ( read_usize_leb128, usize ) ;
111+
71112#[ inline]
72113/// encodes an integer using signed leb128 encoding and stores
73114/// the result using a callback function.
@@ -130,26 +171,36 @@ pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) {
130171 ( result, position - start_position)
131172}
132173
133- #[ test]
134- fn test_unsigned_leb128 ( ) {
135- let mut stream = Vec :: with_capacity ( 10000 ) ;
136-
137- for x in 0 ..62 {
138- let pos = stream. len ( ) ;
139- let bytes_written = write_unsigned_leb128 ( & mut stream, pos, 3 << x) ;
140- assert_eq ! ( stream. len( ) , pos + bytes_written) ;
141- }
142-
143- let mut position = 0 ;
144- for x in 0 ..62 {
145- let expected = 3 << x;
146- let ( actual, bytes_read) = read_unsigned_leb128 ( & stream, position) ;
147- assert_eq ! ( expected, actual) ;
148- position += bytes_read;
149- }
150- assert_eq ! ( stream. len( ) , position) ;
174+ macro_rules! impl_test_unsigned_leb128 {
175+ ( $test_name: ident, $write_fn_name: ident, $read_fn_name: ident, $int_ty: ident) => (
176+ #[ test]
177+ fn $test_name( ) {
178+ let mut stream = Vec :: new( ) ;
179+
180+ for x in 0 ..62 {
181+ let pos = stream. len( ) ;
182+ let bytes_written = $write_fn_name( & mut stream, pos, ( 3u64 << x) as $int_ty) ;
183+ assert_eq!( stream. len( ) , pos + bytes_written) ;
184+ }
185+
186+ let mut position = 0 ;
187+ for x in 0 ..62 {
188+ let expected = ( 3u64 << x) as $int_ty;
189+ let ( actual, bytes_read) = $read_fn_name( & stream, position) ;
190+ assert_eq!( expected, actual) ;
191+ position += bytes_read;
192+ }
193+ assert_eq!( stream. len( ) , position) ;
194+ }
195+ )
151196}
152197
198+ impl_test_unsigned_leb128 ! ( test_u16_leb128, write_u16_leb128, read_u16_leb128, u16 ) ;
199+ impl_test_unsigned_leb128 ! ( test_u32_leb128, write_u32_leb128, read_u32_leb128, u32 ) ;
200+ impl_test_unsigned_leb128 ! ( test_u64_leb128, write_u64_leb128, read_u64_leb128, u64 ) ;
201+ impl_test_unsigned_leb128 ! ( test_u128_leb128, write_u128_leb128, read_u128_leb128, u128 ) ;
202+ impl_test_unsigned_leb128 ! ( test_usize_leb128, write_usize_leb128, read_usize_leb128, usize ) ;
203+
153204#[ test]
154205fn test_signed_leb128 ( ) {
155206 let values: Vec < _ > = ( -500 ..500 ) . map ( |i| i * 0x12345789ABCDEF ) . collect ( ) ;
0 commit comments