base4/lib.rs
1use std::{collections::VecDeque, ops::Index};
2type Base4Blocks = VecDeque<Base4>;
3
4/// A big integer represented in base-4 across multiple 64-digit blocks.
5/// Internally stores a deque of [Base4] blocks, each up to 64 digits long.
6///
7/// This can hold large sets of base4 integers.
8///
9/// # Example
10/// ```rust
11/// use base4::Base4Int;
12///
13/// let mut big_int = Base4Int::new();
14/// big_int.push_all(&[0_u64, 1, 2, 3, 2, 1, 0]);
15///
16/// assert!(big_int.total_len() == 7);
17/// ```
18#[derive(Debug)]
19pub struct Base4Int(Base4Blocks);
20
21impl Default for Base4Int {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl Base4Int {
28 /// Creates a new empty instance of `Base4Int` type.
29 pub fn new() -> Self {
30 Self(Base4Blocks::new())
31 }
32
33 /// Pushes a slice of integers into Base4Int. Slice can be
34 /// of any number type which can be caseted to u128.
35 ///
36 /// This may panic if any of the integer is not within base4
37 /// bounds.
38 pub fn push_all<T>(&mut self, ints: &[T])
39 where
40 T: Into<u128> + Copy,
41 {
42 for integer in ints {
43 self.push(*integer);
44 }
45 }
46
47 /// Pushes a single integer into Base4Int. Integer can be
48 /// of any number type which can be caseted to u128.
49 ///
50 /// This may panic if the integer is not within base4 bounds.
51 pub fn push<T>(&mut self, integer: T)
52 where
53 T: Into<u128> + Copy,
54 {
55 assert!(
56 integer.into() < 4,
57 "Base4Int only accepts value bounded within 0..=3"
58 );
59 let codec = self.get_codec();
60 codec.push(integer);
61 }
62
63 /// Pops a single element out of the last block first.
64 ///
65 /// It returns None if the block is empty.
66 pub fn pop(&mut self) -> Option<u8> {
67 let (out, empty) = match self.0.back_mut() {
68 Some(codec) => {
69 let out = codec.pop();
70 (out, codec.size == 0)
71 }
72 // SAFE: In most cases this would not happen since we do
73 // not keep empty containers.
74 None => panic!("Attempt to pop an empty Base4-Integer"),
75 };
76
77 // Remove and drop the empty container.
78 if empty {
79 let _ = self.0.pop_back();
80 }
81 out
82 }
83
84 /// Pops all the elements stored inside each base4 block in
85 /// first-in-first-out order preserving the original ordering
86 /// in whicch all elements were inserted.
87 ///
88 /// This may return an empty vector if no elements are there.
89 pub fn pop_all<T>(&mut self) -> Vec<T>
90 where
91 T: From<u8> + Copy,
92 {
93 if self.total_len() == 0 {
94 return vec![];
95 }
96
97 let optimal_cap = self.0.iter().map(|block| block.size).sum();
98 let mut ints = Vec::with_capacity(optimal_cap);
99
100 while let Some(mut codec) = self.0.pop_front() {
101 ints.extend(codec.pop_all::<T>());
102 }
103
104 ints
105 }
106
107 /// Gets the last [Base4] block if its not full, or else
108 /// allocate a new one.
109 pub fn get_codec(&mut self) -> &mut Base4 {
110 if let Some(codec) = self.0.back() {
111 if codec.size < 64 {
112 return self.0.back_mut().unwrap();
113 }
114 }
115 self.0.push_back(Base4::new());
116 self.0.back_mut().unwrap()
117 }
118
119 /// Peeks at a specific element by index according to the
120 /// original list from which the element were inseted without
121 /// popping the value out of `Base4Int`.
122 ///
123 /// # Example
124 /// ```
125 /// use base4::Base4Int;
126 ///
127 /// let mut big_int = Base4Int::new();
128 /// big_int.push_all(&[0_u64, 1, 2, 3, 2, 1, 0]);
129 ///
130 /// assert!(2 == big_int.peek_at(2));
131 /// assert!(0 == big_int.peek_at(6));
132 /// ```
133 /// # Panics
134 ///
135 /// This method may panic if the porvided index is out of
136 /// bounds according to the original slice.
137 pub fn peek_at<T>(&self, index: usize) -> T
138 where
139 T: From<u8> + Copy,
140 {
141 assert!(
142 index < self.total_len(),
143 "peek_at: index {} out of bounds (size={})",
144 index,
145 self.total_len()
146 );
147
148 let codec_index = index / 64;
149 let peek_index = index % 64;
150
151 self[codec_index].peek_at::<T>(peek_index)
152 }
153
154 /// Returns the list of all the elements packed inside the
155 /// `Base4Int` without popping.
156 ///
157 /// List will be received in the original order in which it
158 /// was packed.
159 pub fn peek_all<T>(&self) -> Vec<T>
160 where
161 T: From<u8> + Copy,
162 {
163 let mut ints = Vec::with_capacity(self.total_len());
164 for codec_idx in 0..self.total_blocks() {
165 ints.extend_from_slice(&self[codec_idx].peek_all());
166 }
167
168 ints
169 }
170
171 /// Returns the number of all the elements packed inside.
172 pub fn total_len(&self) -> usize {
173 self.0.iter().map(|block| block.size).sum()
174 }
175
176 /// Returns the number of [Base4] blocks.
177 pub fn total_blocks(&self) -> usize {
178 self.0.len()
179 }
180}
181
182impl Index<usize> for Base4Int {
183 type Output = Base4;
184 fn index(&self, index: usize) -> &Self::Output {
185 &self.0[index]
186 }
187}
188
189/// Core base4 codec, which can pack upto maximum 64 elements
190/// into a single 128-bit integer.
191///
192/// This acts as a core block-encoder behind [Base4Int] type.
193///
194/// # Example
195/// ```
196/// use base4::Base4;
197///
198/// let mut codec = Base4::new();
199/// codec.push_all(&[1_u8,2,3,0,1]);
200/// ```
201///
202/// Base4 and Base4Int shares the similar API patterns, the only
203/// difference between these two types is that Base4 can never pack
204/// slices larger than 64 elements. So if you want to store recursively
205/// large arrays of base4, then use [Base4Int].
206#[derive(Debug)]
207pub struct Base4 {
208 /// Keeps the current size of block in terms of
209 /// number of elements.
210 size: usize,
211
212 /// Buffer to contain packed elements.
213 packed: u128,
214}
215
216impl Default for Base4 {
217 fn default() -> Self {
218 Self::new()
219 }
220}
221
222impl Base4 {
223 /// Creates a new instance of [Base4] block with default
224 /// size and container.
225 pub fn new() -> Self {
226 Base4 { size: 0, packed: 0 }
227 }
228
229 /// Packs a single element at the back. This may fail if
230 /// the integer is not within base4 bounds.
231 ///
232 /// # Example
233 ///
234 /// ```
235 /// use base4::Base4;
236 ///
237 /// let mut codec = Base4::new();
238 ///
239 /// assert!(codec.push(1u8));
240 /// assert!(!codec.push(4u8));
241 /// ```
242 /// Returns `true` if the element is inserted else false.
243 pub fn push<T>(&mut self, integer: T) -> bool
244 where
245 T: Into<u128> + Copy,
246 {
247 if integer.into() >= 4 || self.size == 64 {
248 return false;
249 }
250 self.size += 1;
251 self.packed = (self.packed << 2) | integer.into();
252
253 true
254 }
255
256 /// Packs a slice of integers.
257 ///
258 /// This may fail if the slice is larger than 64 or if any
259 /// integer in the slice is greater than the base4 bounds.
260 ///
261 /// # Example
262 ///
263 /// ```rust
264 /// use base4::Base4;
265 ///
266 /// let mut codec = Base4::new();
267 ///
268 /// let integers = vec![3_u8;64];
269 ///
270 /// assert!(codec.push_all(&integers));
271 /// assert!(!codec.push(4_u8));
272 /// assert!(!codec.push(2_u8));
273 /// ```
274 /// Returns `true` if it packs every element of slice.
275 pub fn push_all<T>(&mut self, ints: &[T]) -> bool
276 where
277 T: Into<u128> + Copy,
278 {
279 if ints.len() > 64 {
280 return false;
281 }
282
283 for integer in ints {
284 if !self.push(*integer) {
285 self.size = 0;
286 self.packed = 0;
287
288 return false;
289 }
290 }
291 true
292 }
293
294 /// Pops the last element out.
295 ///
296 /// # Example
297 ///
298 /// ```rust
299 /// use base4::Base4;
300 ///
301 /// let mut codec = Base4::new();
302 ///
303 /// let integers: Vec<u32> = vec![0, 1, 2, 3];
304 ///
305 /// assert!(codec.push_all(&integers));
306 /// assert!(codec.pop() == Some(3));
307 /// assert!(codec.pop() == Some(2));
308 /// assert!(codec.pop() == Some(1));
309 /// assert!(codec.pop() == Some(0));
310 /// assert!(codec.pop() == None);
311 /// ```
312 /// Returns none if the block is already empty.
313 pub fn pop(&mut self) -> Option<u8> {
314 if self.size <= 0 {
315 return None;
316 }
317
318 let int = self.packed & 0b11;
319 self.packed >>= 2;
320 self.size -= 1;
321
322 Some(int as u8)
323 }
324
325 /// Pops all the elements out, leaving the block empty
326 /// as in default state.
327 ///
328 /// Elements are received in vector in the original order
329 /// as they were inserted.
330 ///
331 /// # Example
332 ///
333 /// ```rust
334 /// use base4::Base4;
335 ///
336 /// let mut codec = Base4::new();
337 ///
338 /// let integers: Vec<u32> = vec![0, 1, 2, 3];
339 /// codec.push_all(&integers);
340 ///
341 /// assert!(codec.pop_all::<u32>() == integers);
342 /// ```
343 ///
344 /// An empty codec returns empty `Vec`
345 pub fn pop_all<T>(&mut self) -> Vec<T>
346 where
347 T: From<u8> + Copy,
348 {
349 if self.size <= 0 {
350 return vec![];
351 }
352
353 let mut ints = Vec::with_capacity(self.size);
354 while let Some(value) = self.pop() {
355 ints.push(T::from(value));
356 }
357 ints.reverse();
358 ints
359 }
360
361 /// Peeks at a specific element by index according to the
362 /// original list from which the element were inserted without
363 /// popping the value out of `Base4` buffer.
364 ///
365 /// # Example
366 /// ```
367 /// use base4::Base4;
368 ///
369 /// let mut codec = Base4::new();
370 /// let integers: Vec<u32> = vec![0, 1, 2, 3, 2, 1, 0];
371 ///
372 /// codec.push_all(&integers);
373 ///
374 /// assert!(2 == codec.peek_at(2));
375 /// assert!(0 == codec.peek_at(6));
376 /// ```
377 /// # Panics
378 ///
379 /// This method may panic if the porvided index is out of
380 /// bounds according to the original slice.
381 pub fn peek_at<T>(&self, index: usize) -> T
382 where
383 T: From<u8> + Copy,
384 {
385 assert!(
386 index < self.size,
387 "peek_at: index {} out of bounds (size={})",
388 index,
389 self.size
390 );
391
392 let shift_pos = 2 * (self.size - index - 1);
393 T::from(((self.packed >> shift_pos) & 0b11) as u8)
394 }
395
396 /// Returns the list of all the elements packed inside the
397 /// [Base4] without popping.
398 ///
399 /// List will be received in the original order in which it
400 /// was packed.
401 ///
402 /// # Example
403 ///
404 /// ```rust
405 /// use base4::Base4;
406 ///
407 /// let mut codec = Base4::new();
408 /// let integers: Vec<u32> = vec![0, 1, 2, 3];
409 ///
410 /// codec.push_all(&integers);
411 ///
412 /// assert!(codec.peek_all::<u32>() == integers);
413 ///
414 /// // Codec still holds the elements
415 /// assert!(codec.peek_at::<u32>(3) == 3);
416 /// ```
417 pub fn peek_all<T>(&self) -> Vec<T>
418 where
419 T: From<u8> + Copy,
420 {
421 let mut ints = Vec::with_capacity(self.size);
422 for index in 0..self.size {
423 ints.push(self.peek_at(index));
424 }
425
426 ints
427 }
428}