irox_tools/buf/
unlimited.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5extern crate alloc;
6use crate::buf::{Buffer, RoundBuffer};
7use alloc::collections::LinkedList;
8use irox_bits::Bits;
9use irox_bits::{Error, MutBits};
10
11const PAGE_SIZE: usize = 0x1000; // 4096
12const PAGE_SHIFT: usize = 12;
13const DATA_MASK: usize = 0x0FFF;
14
15///
16/// Zero re-allocation linked-page buffer.  Faster than a Vec for large datasets
17/// because it does not require pre-allocation of memory to achieve zero-reallocation.
18/// However, wastes memory for very small data sets since the minimum size quanta
19/// that allocates is 4k * sizeof(T).  IE, a `u8` page will be 4k wide, but a
20/// `u128` page will be 64k wide and a `Box<T>` page will either be 32k (standard
21/// types) or 64k wide (`dyn` types)
22#[derive(Default, Clone)]
23pub struct UnlimitedBuffer<T: Clone> {
24    #[allow(clippy::linkedlist)]
25    data: LinkedList<RoundBuffer<PAGE_SIZE, T>>,
26    len: u64,
27}
28
29impl<T: Clone> UnlimitedBuffer<T> {
30    pub fn new() -> UnlimitedBuffer<T> {
31        UnlimitedBuffer {
32            data: LinkedList::new(),
33            len: 0,
34        }
35    }
36
37    pub fn get(&self, index: usize) -> Option<&T> {
38        let offset = index >> PAGE_SHIFT;
39        if let Some(block) = self.data.iter().nth(offset) {
40            let idx = index & DATA_MASK;
41            return block.get(idx);
42        }
43        None
44    }
45
46    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
47        let offset = index >> PAGE_SHIFT;
48        if let Some(block) = self.data.iter_mut().nth(offset) {
49            let idx = index & DATA_MASK;
50            return block.get_mut(idx);
51        }
52        None
53    }
54
55    #[allow(clippy::unused_self)]
56    pub fn capacity(&self) -> usize {
57        usize::MAX
58    }
59    pub fn is_empty(&self) -> bool {
60        self.len == 0
61    }
62    pub fn len(&self) -> u64 {
63        self.len
64    }
65
66    pub fn clear(&mut self) {
67        self.data.clear();
68        self.len = 0;
69    }
70
71    pub fn front(&self) -> Option<&T> {
72        self.data.front().and_then(|v| v.front())
73    }
74
75    pub fn front_mut(&mut self) -> Option<&mut T> {
76        self.data.front_mut().and_then(|v| v.front_mut())
77    }
78
79    pub fn back(&self) -> Option<&T> {
80        self.data.back().and_then(|v| v.back())
81    }
82
83    pub fn back_mut(&mut self) -> Option<&mut T> {
84        self.data.back_mut().and_then(|v| v.back_mut())
85    }
86
87    ///
88    /// Retrieves and returns the front value
89    pub fn pop_front(&mut self) -> Option<T> {
90        while let Some(front) = self.data.front_mut() {
91            if front.is_empty() {
92                let _ = self.data.pop_front();
93                continue;
94            }
95            return if let Some(fr) = front.pop_front() {
96                self.len -= 1;
97                Some(fr)
98            } else {
99                None
100            };
101        }
102        None
103    }
104
105    ///
106    /// Retrieves and returns the last value
107    pub fn pop_back(&mut self) -> Option<T> {
108        while let Some(back) = self.data.back_mut() {
109            if back.is_empty() {
110                let _ = self.data.pop_back();
111                continue;
112            }
113            return if let Some(back) = back.pop_back() {
114                self.len -= 1;
115                Some(back)
116            } else {
117                None
118            };
119        }
120        None
121    }
122
123    ///
124    /// Appends all elements of the slice to the back.
125    pub fn append_slice(&mut self, slice: &[T]) {
126        for v in slice {
127            self.push_back(v.clone());
128        }
129    }
130
131    ///
132    /// Push a value to the front
133    pub fn push_front(&mut self, value: T) {
134        let mut buf = RoundBuffer::default();
135        let _ = buf.push_back(value);
136        self.data.push_front(buf);
137        self.len += 1;
138    }
139
140    ///
141    /// Push a value to the end
142    pub fn push_back(&mut self, value: T) {
143        if let Some(back) = self.data.back_mut() {
144            if let Err(e) = back.push_back(value) {
145                let mut buf = RoundBuffer::new();
146                let _ = buf.push_back(e);
147                self.data.push_back(buf);
148            }
149        } else {
150            let mut buf = RoundBuffer::new();
151            let _ = buf.push_back(value);
152            self.data.push_back(buf);
153        }
154        self.len += 1;
155    }
156
157    ///
158    /// Iterate over each block of data stored
159    pub fn iter_blocks<F: FnMut(&[Option<T>])>(&mut self, mut f: F) {
160        self.data.iter().for_each(|v| {
161            v.raw_buf(&mut f)
162        })
163    }
164}
165
166impl MutBits for UnlimitedBuffer<u8> {
167    fn write_u8(&mut self, val: u8) -> Result<(), Error> {
168        self.push_back(val);
169        Ok(())
170    }
171}
172
173impl Bits for UnlimitedBuffer<u8> {
174    fn next_u8(&mut self) -> Result<Option<u8>, Error> {
175        Ok(self.pop_front())
176    }
177}
178
179impl<T: Clone> Iterator for UnlimitedBuffer<T> {
180    type Item = T;
181
182    fn next(&mut self) -> Option<Self::Item> {
183        self.pop_front()
184    }
185}