/rust/registry/src/index.crates.io-6f17d22bba15001f/nibble_vec-0.1.0/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | #[cfg(test)] |
2 | | mod test; |
3 | | |
4 | | use smallvec::{Array, SmallVec}; |
5 | | |
6 | | use std::convert::{From, Into}; |
7 | | use std::fmt::{self, Debug, Formatter}; |
8 | | use std::iter::FromIterator; |
9 | | |
10 | | /// A `NibbleVec` backed by a `SmallVec` with 64 inline element slots. |
11 | | /// This will not allocate until more than 64 elements are added. |
12 | | pub type Nibblet = NibbleVec<[u8; 64]>; |
13 | | |
14 | | /// A data-structure for storing a sequence of 4-bit values. |
15 | | /// |
16 | | /// Values are stored in a `Vec<u8>`, with two values per byte. |
17 | | /// |
18 | | /// Values at even indices are stored in the most-significant half of their byte, |
19 | | /// while values at odd indices are stored in the least-significant half. |
20 | | /// |
21 | | /// Imagine a vector of [MSB][msb-wiki] first bytes, and you'll be right. |
22 | | /// |
23 | | /// n = [_ _ | _ _ | _ _] |
24 | | /// |
25 | | /// [msb-wiki]: http://en.wikipedia.org/wiki/Most_significant_bit |
26 | | #[derive(Clone, Default)] |
27 | | pub struct NibbleVec<A: Array<Item = u8>> { |
28 | | length: usize, |
29 | | data: SmallVec<A>, |
30 | | } |
31 | | |
32 | | impl<A: Array<Item = u8>> NibbleVec<A> { |
33 | | /// Create an empty nibble vector. |
34 | 0 | pub fn new() -> NibbleVec<A> { |
35 | 0 | NibbleVec { |
36 | 0 | length: 0, |
37 | 0 | data: SmallVec::new(), |
38 | 0 | } |
39 | 0 | } |
40 | | |
41 | | /// Create a nibble vector from a vector of bytes. |
42 | | /// |
43 | | /// Each byte is split into two 4-bit entries (MSB, LSB). |
44 | | #[inline] |
45 | 0 | pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec<A> { |
46 | 0 | let length = 2 * vec.len(); |
47 | 0 | NibbleVec { |
48 | 0 | length, |
49 | 0 | data: SmallVec::from_iter(vec), |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | | /// Returns a byte slice of the nibble vector's contents. |
54 | | #[inline] |
55 | | pub fn as_bytes(&self) -> &[u8] { |
56 | | &self.data[..] |
57 | | } |
58 | | |
59 | | /// Converts a nibble vector into a byte vector. |
60 | | /// |
61 | | /// This consumes the nibble vector, so we do not need to copy its contents. |
62 | | #[inline] |
63 | | pub fn into_bytes(self) -> Vec<u8> { |
64 | | self.data.to_vec() |
65 | | } |
66 | | |
67 | | /// Get the number of elements stored in the vector. |
68 | | #[inline] |
69 | 0 | pub fn len(&self) -> usize { |
70 | 0 | self.length |
71 | 0 | } |
72 | | |
73 | | /// Returns `true` if the nibble vector has a length of 0. |
74 | | #[inline] |
75 | 0 | pub fn is_empty(&self) -> bool { |
76 | 0 | self.data.is_empty() |
77 | 0 | } |
78 | | |
79 | | /// Fetch a single entry from the vector. |
80 | | /// |
81 | | /// Guaranteed to be a value in the interval [0, 15]. |
82 | | /// |
83 | | /// **Panics** if `idx >= self.len()`. |
84 | | #[inline] |
85 | 0 | pub fn get(&self, idx: usize) -> u8 { |
86 | 0 | if idx >= self.length { |
87 | 0 | panic!( |
88 | 0 | "NibbleVec index out of bounds: len is {}, index is {}", |
89 | 0 | self.length, idx |
90 | 0 | ); |
91 | 0 | } |
92 | 0 | let vec_idx = idx / 2; |
93 | 0 | match idx % 2 { |
94 | | // If the index is even, take the first (most significant) half of the stored byte. |
95 | 0 | 0 => self.data[vec_idx] >> 4, |
96 | | // If the index is odd, take the second (least significant) half. |
97 | 0 | _ => self.data[vec_idx] & 0x0F, |
98 | | } |
99 | 0 | } |
100 | | |
101 | | /// Add a single nibble to the vector. |
102 | | /// |
103 | | /// Only the 4 least-significant bits of the value are used. |
104 | | #[inline] |
105 | 0 | pub fn push(&mut self, val: u8) { |
106 | 0 | if self.length % 2 == 0 { |
107 | 0 | self.data.push(val << 4); |
108 | 0 | } else { |
109 | 0 | let vec_len = self.data.len(); |
110 | 0 |
|
111 | 0 | // Zero the second half of the last byte just to be safe. |
112 | 0 | self.data[vec_len - 1] &= 0xF0; |
113 | 0 |
|
114 | 0 | // Write the new value. |
115 | 0 | self.data[vec_len - 1] |= val & 0x0F; |
116 | 0 | } |
117 | 0 | self.length += 1; |
118 | 0 | } |
119 | | |
120 | | /// Split the vector into two parts. |
121 | | /// |
122 | | /// All elements at or following the given index are returned in a new `NibbleVec`, |
123 | | /// with exactly `idx` elements remaining in this vector. |
124 | | /// |
125 | | /// **Panics** if `idx > self.len()`. |
126 | 0 | pub fn split(&mut self, idx: usize) -> NibbleVec<A> { |
127 | 0 | // assert! is a few percent slower surprisingly |
128 | 0 | if idx > self.length { |
129 | 0 | panic!( |
130 | 0 | "attempted to split past vector end. len is {}, index is {}", |
131 | 0 | self.length, idx |
132 | 0 | ); |
133 | 0 | } else if idx == self.length { |
134 | 0 | NibbleVec::new() |
135 | 0 | } else if idx % 2 == 0 { |
136 | 0 | self.split_even(idx) |
137 | | } else { |
138 | 0 | self.split_odd(idx) |
139 | | } |
140 | 0 | } |
141 | | |
142 | | /// Split function for odd *indices*. |
143 | | #[inline] |
144 | 0 | fn split_odd(&mut self, idx: usize) -> NibbleVec<A> { |
145 | 0 | let mut tail = NibbleVec::new(); |
146 | 0 |
|
147 | 0 | // Perform an overlap copy, copying the last nibble of the original vector only if |
148 | 0 | // the length of the new tail is *odd*. |
149 | 0 | let tail_length = self.length - idx; |
150 | 0 | let take_last = tail_length % 2 == 1; |
151 | 0 | self.overlap_copy( |
152 | 0 | idx / 2, |
153 | 0 | self.data.len(), |
154 | 0 | &mut tail.data, |
155 | 0 | &mut tail.length, |
156 | 0 | take_last, |
157 | 0 | ); |
158 | 0 |
|
159 | 0 | // Remove the copied bytes, being careful to skip the idx byte. |
160 | 0 | for _ in (idx / 2 + 1)..self.data.len() { |
161 | 0 | self.data.pop(); |
162 | 0 | } |
163 | | |
164 | | // Zero the second half of the index byte so as to maintain the last-nibble invariant. |
165 | 0 | self.data[idx / 2] &= 0xF0; |
166 | 0 |
|
167 | 0 | // Update the length of the first NibbleVec. |
168 | 0 | self.length = idx; |
169 | 0 |
|
170 | 0 | tail |
171 | 0 | } |
172 | | |
173 | | /// Split function for even *indices*. |
174 | | #[inline] |
175 | 0 | fn split_even(&mut self, idx: usize) -> NibbleVec<A> { |
176 | 0 | // Avoid allocating a temporary vector by copying all the bytes in order, then popping them. |
177 | 0 |
|
178 | 0 | // Possible to prove: l_d - ⌊i / 2⌋ = ⌊(l_v - i + 1) / 2⌋ |
179 | 0 | // where l_d = self.data.len() |
180 | 0 | // l_v = self.length |
181 | 0 |
|
182 | 0 | let half_idx = idx / 2; |
183 | 0 | let mut tail = NibbleVec::new(); |
184 | | |
185 | | // Copy the bytes. |
186 | 0 | for i in half_idx..self.data.len() { |
187 | 0 | tail.data.push(self.data[i]); |
188 | 0 | } |
189 | | |
190 | | // Pop the same bytes. |
191 | 0 | for _ in half_idx..self.data.len() { |
192 | 0 | self.data.pop(); |
193 | 0 | } |
194 | | |
195 | | // Update lengths. |
196 | 0 | tail.length = self.length - idx; |
197 | 0 | self.length = idx; |
198 | 0 |
|
199 | 0 | tail |
200 | 0 | } |
201 | | |
202 | | /// Copy data between the second half of self.data[start] and |
203 | | /// self.data[end - 1]. The second half of the last entry is included |
204 | | /// if include_last is true. |
205 | | #[inline] |
206 | 0 | fn overlap_copy( |
207 | 0 | &self, |
208 | 0 | start: usize, |
209 | 0 | end: usize, |
210 | 0 | vec: &mut SmallVec<A>, |
211 | 0 | length: &mut usize, |
212 | 0 | include_last: bool, |
213 | 0 | ) { |
214 | | // Copy up to the first half of the last byte. |
215 | 0 | for i in start..(end - 1) { |
216 | 0 | // The first half is the second half of the old entry. |
217 | 0 | let first_half = self.data[i] & 0x0f; |
218 | 0 |
|
219 | 0 | // The second half is the first half of the next entry. |
220 | 0 | let second_half = self.data[i + 1] >> 4; |
221 | 0 |
|
222 | 0 | vec.push((first_half << 4) | second_half); |
223 | 0 | *length += 2; |
224 | 0 | } |
225 | | |
226 | 0 | if include_last { |
227 | 0 | let last = self.data[end - 1] & 0x0f; |
228 | 0 | vec.push(last << 4); |
229 | 0 | *length += 1; |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | | /// Append another nibble vector whilst consuming this vector. |
234 | | #[inline] |
235 | 0 | pub fn join(mut self, other: &NibbleVec<A>) -> NibbleVec<A> { |
236 | 0 | // If the length is even, we can append directly. |
237 | 0 | if self.length % 2 == 0 { |
238 | 0 | self.length += other.length; |
239 | 0 | self.data.extend_from_slice(&other.data); |
240 | 0 | return self; |
241 | 0 | } |
242 | 0 |
|
243 | 0 | // If the other vector is empty, bail out. |
244 | 0 | if other.is_empty() { |
245 | 0 | return self; |
246 | 0 | } |
247 | 0 |
|
248 | 0 | // If the length is odd, we have to perform an overlap copy. |
249 | 0 | // Copy the first half of the first element, to make the vector an even length. |
250 | 0 | self.push(other.get(0)); |
251 | 0 |
|
252 | 0 | // Copy the rest of the vector using an overlap copy. |
253 | 0 | let take_last = other.len() % 2 == 0; |
254 | 0 | other.overlap_copy( |
255 | 0 | 0, |
256 | 0 | other.data.len(), |
257 | 0 | &mut self.data, |
258 | 0 | &mut self.length, |
259 | 0 | take_last, |
260 | 0 | ); |
261 | 0 |
|
262 | 0 | self |
263 | 0 | } |
264 | | } |
265 | | |
266 | | impl<A: Array<Item = u8>> PartialEq<NibbleVec<A>> for NibbleVec<A> { |
267 | | #[inline] |
268 | | fn eq(&self, other: &NibbleVec<A>) -> bool { |
269 | | self.length == other.length && self.data == other.data |
270 | | } |
271 | | } |
272 | | |
273 | | impl<A: Array<Item = u8>> Eq for NibbleVec<A> {} |
274 | | |
275 | | /// Compare a `NibbleVec` and a slice of bytes *element-by-element*. |
276 | | /// Bytes are **not** interpreted as two `NibbleVec` entries. |
277 | | impl<A: Array<Item = u8>> PartialEq<[u8]> for NibbleVec<A> { |
278 | | #[inline] |
279 | | fn eq(&self, other: &[u8]) -> bool { |
280 | | if other.len() != self.len() { |
281 | | return false; |
282 | | } |
283 | | |
284 | | for (i, x) in other.iter().enumerate() { |
285 | | if self.get(i) != *x { |
286 | | return false; |
287 | | } |
288 | | } |
289 | | true |
290 | | } |
291 | | } |
292 | | |
293 | | impl<A: Array<Item = u8>> Debug for NibbleVec<A> { |
294 | | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
295 | | write!(fmt, "NibbleVec [")?; |
296 | | |
297 | | if !self.is_empty() { |
298 | | write!(fmt, "{}", self.get(0))?; |
299 | | } |
300 | | |
301 | | for i in 1..self.len() { |
302 | | write!(fmt, ", {}", self.get(i))?; |
303 | | } |
304 | | write!(fmt, "]") |
305 | | } |
306 | | } |
307 | | |
308 | | impl<A: Array<Item = u8>> From<Vec<u8>> for NibbleVec<A> { |
309 | | #[inline] |
310 | | fn from(v: Vec<u8>) -> NibbleVec<A> { |
311 | | NibbleVec::from_byte_vec(v) |
312 | | } |
313 | | } |
314 | | |
315 | | impl<'a, A: Array<Item = u8>> From<&'a [u8]> for NibbleVec<A> { |
316 | | #[inline] |
317 | | fn from(v: &[u8]) -> NibbleVec<A> { |
318 | | NibbleVec::from_byte_vec(v.into()) |
319 | | } |
320 | | } |
321 | | |
322 | | impl<A: Array<Item = u8>> Into<Vec<u8>> for NibbleVec<A> { |
323 | | #[inline] |
324 | | fn into(self) -> Vec<u8> { |
325 | | self.data.to_vec() |
326 | | } |
327 | | } |
328 | | |
329 | | impl<'a, A: Array<Item = u8>> Into<Vec<u8>> for &'a NibbleVec<A> { |
330 | | #[inline] |
331 | | fn into(self) -> Vec<u8> { |
332 | | self.data.to_vec() |
333 | | } |
334 | | } |