]> git.lizzy.rs Git - rust.git/blob - src/librbml/leb128.rs
Auto merge of #30845 - nagisa:mir-extern-calls, r=dotdash
[rust.git] / src / librbml / leb128.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #[inline]
12 pub fn write_to_vec(vec: &mut Vec<u8>, position: &mut usize, byte: u8) {
13     if *position == vec.len() {
14         vec.push(byte);
15     } else {
16         vec[*position] = byte;
17     }
18
19     *position += 1;
20 }
21
22 pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value: u64) -> usize {
23     let mut position = start_position;
24     loop {
25         let mut byte = (value & 0x7F) as u8;
26         value >>= 7;
27         if value != 0 {
28             byte |= 0x80;
29         }
30
31         write_to_vec(out, &mut position, byte);
32
33         if value == 0 {
34             break;
35         }
36     }
37
38     return position - start_position;
39 }
40
41 pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) {
42     let mut result = 0;
43     let mut shift = 0;
44     let mut position = start_position;
45     loop {
46         let byte = data[position];
47         position += 1;
48         result |= ((byte & 0x7F) as u64) << shift;
49         if (byte & 0x80) == 0 {
50             break;
51         }
52         shift += 7;
53     }
54
55     (result, position - start_position)
56 }
57
58
59 pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value: i64) -> usize {
60     let mut position = start_position;
61
62     loop {
63         let mut byte = (value as u8) & 0x7f;
64         value >>= 7;
65         let more = !((((value == 0) && ((byte & 0x40) == 0)) ||
66                       ((value == -1) && ((byte & 0x40) != 0))));
67         if more {
68             byte |= 0x80; // Mark this byte to show that more bytes will follow.
69         }
70
71         write_to_vec(out, &mut position, byte);
72
73         if !more {
74             break;
75         }
76     }
77
78     return position - start_position;
79 }
80
81 pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) {
82     let mut result = 0;
83     let mut shift = 0;
84     let mut position = start_position;
85     let mut byte;
86
87     loop {
88         byte = data[position];
89         position += 1;
90         result |= ((byte & 0x7F) as i64) << shift;
91         shift += 7;
92
93         if (byte & 0x80) == 0 {
94             break;
95         }
96     }
97
98     if (shift < 64) && ((byte & 0x40) != 0) {
99         // sign extend
100         result |= -(1i64 << shift);
101     }
102
103     (result, position - start_position)
104 }
105
106 #[test]
107 fn test_unsigned_leb128() {
108     let mut stream = Vec::with_capacity(10000);
109
110     for x in 0..62 {
111         let pos = stream.len();
112         let bytes_written = write_unsigned_leb128(&mut stream, pos, 3 << x);
113         assert_eq!(stream.len(), pos + bytes_written);
114     }
115
116     let mut position = 0;
117     for x in 0..62 {
118         let expected = 3 << x;
119         let (actual, bytes_read) = read_unsigned_leb128(&stream, position);
120         assert_eq!(expected, actual);
121         position += bytes_read;
122     }
123     assert_eq!(stream.len(), position);
124 }
125
126 #[test]
127 fn test_signed_leb128() {
128     let mut values = Vec::new();
129
130     let mut i = -500;
131     while i < 500 {
132         values.push(i * 123457i64);
133         i += 1;
134     }
135
136     let mut stream = Vec::new();
137
138     for &x in &values {
139         let pos = stream.len();
140         let bytes_written = write_signed_leb128(&mut stream, pos, x);
141         assert_eq!(stream.len(), pos + bytes_written);
142     }
143
144     let mut pos = 0;
145     for &x in &values {
146         let (value, bytes_read) = read_signed_leb128(&mut stream, pos);
147         pos += bytes_read;
148         assert_eq!(x, value);
149     }
150     assert_eq!(pos, stream.len());
151 }