@@ -9,16 +9,13 @@ const VARINT_MAX_BYTES: usize = 10;
9
9
/// A `BitReader` allows for efficiently reading bits from a byte buffer, up to a byte at a time.
10
10
///
11
11
/// It works by always storing at least the next 8 bits in `bits`, which lets us conveniently
12
- /// and efficiently read bits that cross a byte boundary. It's filled with the bits from `next_byte`
13
- /// after every read operation, which is in turn replaced by the next byte from `bytes` as soon
14
- /// as the next read might read bits from `next_byte`.
12
+ /// and efficiently read bits that cross a byte boundary.
15
13
pub struct BitReader < ' a > {
16
14
/// The bytes that have not been read from yet.
17
15
bytes : & ' a [ u8 ] ,
18
- /// The next byte from `bytes` to be added to `bits`.
19
- next_byte : u8 ,
20
16
/// The next bits to be read.
21
- bits : u16 ,
17
+ bits : u64 ,
18
+
22
19
/// The number of bits in `bits` from bytes that came before `next_byte` (at least 8, at most 15).
23
20
num_bits : u32 ,
24
21
}
@@ -31,51 +28,60 @@ impl<'a> BitReader<'a> {
31
28
if bytes. last ( ) == Some ( & 0 ) {
32
29
return Err ( Error :: NotMinimal ) ;
33
30
}
31
+ let mut bits = 0u64 ;
32
+ for i in 0 ..2 {
33
+ let byte = bytes. get ( i) . unwrap_or ( & 0 ) ;
34
+ bits |= ( * byte as u64 ) << ( 8 * i) ;
35
+ }
34
36
35
- let & byte1 = bytes. get ( 0 ) . unwrap_or ( & 0 ) ;
36
- let & byte2 = bytes. get ( 1 ) . unwrap_or ( & 0 ) ;
37
- let bytes = if bytes. len ( ) > 2 { & bytes[ 2 ..] } else { & [ ] } ;
37
+ let bytes = bytes. get ( 2 ..) . unwrap_or ( & [ ] ) ;
38
38
39
39
Ok ( Self {
40
40
bytes,
41
- bits : byte1 as u16 ,
42
- next_byte : byte2,
43
- num_bits : 8 ,
41
+ bits,
42
+ num_bits : 16 ,
44
43
} )
45
44
}
46
45
47
- /// Reads a given number of bits from the buffer. Will keep returning 0 once
46
+ /// Peeks a given number of bits from the buffer.Will keep returning 0 once
48
47
/// the buffer has been exhausted.
49
- pub fn read ( & mut self , num_bits : u32 ) -> u8 {
48
+ pub fn peek ( & self , num_bits : u32 ) -> u8 {
50
49
debug_assert ! ( num_bits <= 8 ) ;
51
50
52
51
// creates a mask with a `num_bits` number of 1s in order
53
52
// to get only the bits we need from `self.bits`
54
53
let mask = ( 1 << num_bits) - 1 ;
55
- let res = ( self . bits & mask) as u8 ;
54
+ ( self . bits & mask) as u8
55
+ }
56
56
57
- // removes the bits we've just read from local storage
58
- // because we don't need them anymore
57
+ /// Drops a number of bits from the buffer
58
+ pub fn drop ( & mut self , num_bits : u32 ) {
59
+ debug_assert ! ( num_bits <= 8 ) ;
60
+
61
+ // removes the bits
59
62
self . bits >>= num_bits;
60
63
self . num_bits -= num_bits;
61
64
62
- // this unconditionally adds the next byte to `bits`,
63
- // regardless of whether there's enough space or not. the
64
- // point is to make sure that `bits` always contains
65
- // at least the next 8 bits to be read
66
- self . bits |= ( self . next_byte as u16 ) << self . num_bits ;
67
65
68
- // if fewer than 8 bits remain, we increment `self.num_bits`
69
- // to include the bits from `next_byte` (which is already
70
- // contained in `bits`) and we update `next_byte` with the
71
- // data to be read after that
66
+ // not sure why this being outside of the if improves the performance
67
+ // bit it does, probably related to keeping caches warm
68
+ let byte = self . bytes . get ( 0 ) . unwrap_or ( & 0 ) ;
69
+ self . bits |= ( * byte as u64 ) << self . num_bits ;
70
+
71
+ // if fewer than 8 bits remain, we skip to loading the next byte
72
72
if self . num_bits < 8 {
73
73
self . num_bits += 8 ;
74
-
75
- let ( & next_byte, bytes) = self . bytes . split_first ( ) . unwrap_or ( ( & 0 , & [ ] ) ) ;
76
- self . next_byte = next_byte;
77
- self . bytes = bytes;
74
+ self . bytes = self . bytes . get ( 1 ..) . unwrap_or ( & [ ] ) ;
78
75
}
76
+ }
77
+
78
+ /// Reads a given number of bits from the buffer. Will keep returning 0 once
79
+ /// the buffer has been exhausted.
80
+ pub fn read ( & mut self , num_bits : u32 ) -> u8 {
81
+ debug_assert ! ( num_bits <= 8 ) ;
82
+
83
+ let res = self . peek ( num_bits) ;
84
+ self . drop ( num_bits) ;
79
85
80
86
res
81
87
}
@@ -114,22 +120,24 @@ impl<'a> BitReader<'a> {
114
120
return Ok ( None ) ;
115
121
}
116
122
117
- let prefix_0 = self . read ( 1 ) ;
118
- let len = if prefix_0 == 1 {
123
+ let peek6 = self . peek ( 6 ) ;
124
+
125
+ let len = if peek6 & 0b1 != 0 {
119
126
// Block Single (prefix 1)
127
+ self . drop ( 1 ) ;
120
128
1
121
129
} else {
122
- let prefix_1 = self . read ( 1 ) ;
123
-
124
- if prefix_1 == 1 {
130
+ if peek6 & 0b10 != 0 {
125
131
// Block Short (prefix 01)
126
- let val = self . read ( 4 ) as u64 ;
132
+ let val = ( ( peek6 >> 2 ) & 0x0f ) as u64 ;
133
+ self . drop ( 6 ) ;
127
134
if val < 2 {
128
135
return Err ( Error :: NotMinimal ) ;
129
136
}
130
137
val
131
138
} else {
132
139
// Block Long (prefix 00)
140
+ self . drop ( 2 ) ;
133
141
let val = self . read_varint ( ) ?;
134
142
if val < 16 {
135
143
return Err ( Error :: NotMinimal ) ;
@@ -143,7 +151,7 @@ impl<'a> BitReader<'a> {
143
151
144
152
/// Returns true if there are more non-zero bits to be read.
145
153
pub fn has_more ( & self ) -> bool {
146
- self . bits > 0 || self . next_byte > 0 || !self . bytes . is_empty ( )
154
+ self . bits != 0 || !self . bytes . is_empty ( )
147
155
}
148
156
}
149
157
0 commit comments