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}