limited_queue/lib.rs
1//! # LimitedQueue
2//!
3//! `LimitedQueue<T>` is a limited queue that
4//! overrides the oldest data if trying to
5//! push a data when the queue is full.
6//!
7//! All operations are of `O(1)` complexity,
8//! except the constructor with `O(Vec::with_capacity)`.
9
10use std::mem::{replace, take};
11
12/// A circular queue that overrides the oldest data
13/// if trying to push data when queue is full.
14///
15/// All operations are of `O(1)` complexity,
16/// except the constructor with `O(Vec::with_capacity)`.
17///
18/// # Example
19///
20/// ```
21/// let mut q = limited_queue::LimitedQueue::with_capacity(5);
22/// // push_ret: [None x 5, 0, 1, ..., 4]
23/// let push_ret = [[None; 5], core::array::from_fn(|i| Some(i))].concat();
24/// for (i, pr) in (0..10).zip(push_ret) {
25/// assert_eq!(q.push(i), pr);
26/// }
27/// for (n, element) in q.iter().enumerate() {
28/// assert_eq!(element.clone(), q[n]); // 5, 6, 7, 8, 9
29/// assert_eq!(element.clone(), n + 5); // 5, 6, 7, 8, 9
30/// }
31/// ```
32///
33/// # Error
34///
35/// For indexing, no bound check will occur, so please check
36/// the size of the queue with `len` method before subscription.
37///
38/// If you need boundary check, please use `get` method.
39#[derive(Debug)]
40pub struct LimitedQueue<T> {
41 q: Vec<T>,
42 front: usize,
43 rear: usize,
44 sz: usize,
45}
46
47impl<T> LimitedQueue<T> {
48 /// Vec-like constructor
49 ///
50 /// ```
51 /// use limited_queue::LimitedQueue;
52 ///
53 /// let mut q = LimitedQueue::with_capacity(2);
54 ///
55 /// assert_eq!(q.push(1), None);
56 /// assert_eq!(q.push(2), None);
57 ///
58 /// // first element popped since the capacity is 2
59 /// assert_eq!(q.push(3), Some(1));
60 ///
61 /// assert_eq!(q.peek(), Some(&2));
62 /// assert_eq!(q.pop(), Some(2));
63 /// assert_eq!(q.peek(), Some(&3));
64 /// assert_eq!(q.pop(), Some(3));
65 /// ```
66 ///
67 /// @param `cap` Capacity (limit size) of the queue
68 #[inline]
69 pub fn with_capacity(cap: usize) -> LimitedQueue<T> {
70 LimitedQueue {
71 q: Vec::with_capacity(cap),
72 front: 0usize,
73 rear: 0usize,
74 sz: 0usize,
75 }
76 }
77
78 /// Get the element at position `idx`,
79 /// a.k.a. the position from the start of queue
80 ///
81 /// ```
82 /// use limited_queue::LimitedQueue;
83 ///
84 /// let mut q = LimitedQueue::with_capacity(2);
85 /// q.push(1);
86 /// assert_eq!(q.get(100), None);
87 /// ```
88 #[inline]
89 pub fn get(&self, idx: usize) -> Option<&T> {
90 if idx >= self.front {
91 None
92 } else {
93 Some(&self[idx])
94 }
95 }
96
97 /// Peek the oldest element at the front of the queue
98 ///
99 /// ```
100 /// use limited_queue::LimitedQueue;
101 ///
102 /// let mut q = LimitedQueue::with_capacity(1);
103 ///
104 /// q.push(1234);
105 /// assert_eq!(q.peek(), Some(&1234));
106 /// assert_eq!(q.pop(), Some(1234));
107 /// assert_eq!(q.peek(), None);
108 /// ```
109 #[inline]
110 pub fn peek(&self) -> Option<&T> {
111 if self.is_empty() {
112 None
113 } else {
114 Some(&self.q[self.front])
115 }
116 }
117
118 /// Push a new element into queue,
119 /// removing the oldest element if the queue is full
120 #[inline]
121 pub fn push(&mut self, ele: T) -> Option<T> {
122 let mut popped = None;
123 if self.is_full() {
124 // popped = self.pop();
125 // use `replace` so no implicit `Default` will be called
126 popped = Some(replace(&mut self.q[self.rear], ele));
127 // and move forth the front idx to simulate `pop` operation
128 self.front = self.next_idx(self.front);
129 } else {
130 if self.q.len() == self.rear && self.q.len() < self.q.capacity() {
131 // if the vector is shorter than capacity
132 self.q.push(ele);
133 } else if self.q.len() > self.rear {
134 self.q[self.rear] = ele;
135 } else {
136 panic!("[limited-queue::push] Error, bad push position");
137 }
138 self.sz += 1;
139 }
140 self.rear = self.next_idx(self.rear);
141 popped
142 }
143
144 /// Inner method: next index of the inner vector
145 #[inline]
146 fn next_idx(&self, idx: usize) -> usize {
147 (idx + 1) % self.q.capacity()
148 }
149
150 #[inline]
151 pub fn is_empty(&self) -> bool {
152 self.sz == 0
153 }
154
155 #[inline]
156 pub fn is_full(&self) -> bool {
157 self.sz == self.q.capacity()
158 }
159
160 /// Get queue length
161 ///
162 /// ```
163 /// use limited_queue::LimitedQueue;
164 ///
165 /// let mut q = LimitedQueue::with_capacity(3);
166 ///
167 /// q.push(1234);
168 /// assert_eq!(q.len(), 1);
169 /// q.push(1234);
170 /// assert_eq!(q.len(), 2);
171 /// q.push(1234);
172 /// assert_eq!(q.len(), 3);
173 /// q.push(1234);
174 /// assert_eq!(q.len(), 3);
175 /// ```
176 #[inline]
177 pub fn len(&self) -> usize {
178 self.sz
179 }
180
181 /// To traverse all the elements in
182 /// `LimitedQueue`, for example:
183 ///
184 /// ```
185 /// use limited_queue::LimitedQueue;
186 ///
187 /// let mut q = LimitedQueue::with_capacity(5);
188 /// for i in 0..10 {
189 /// q.push(i);
190 /// }
191 /// for (&n, element) in q.iter().zip(5usize..=9) {
192 /// // will be 5, 6, 7, 8, 9 since 0 ~ 4
193 /// // are popped because the queue is full
194 /// assert_eq!(element.clone(), n);
195 /// }
196 /// ```
197 #[inline]
198 pub fn iter(&self) -> LimitedQueueIterator<T> {
199 LimitedQueueIterator { lq: self, idx: 0 }
200 }
201
202 // #[inline]
203 // pub fn iter_mut(&self) -> LimitedQueueIterator<T> {
204 // LimitedQueueIterator {
205 // lq: self,
206 // idx: self.front,
207 // }
208 // }
209
210 /// `O(1)` method to (lazily) clear all the elements
211 ///
212 /// ```
213 /// use limited_queue::LimitedQueue;
214 ///
215 /// let mut q = LimitedQueue::with_capacity(5);
216 /// for i in 0..10 {
217 /// q.push(i);
218 /// }
219 /// q.clear();
220 /// assert_eq!(q.peek(), None);
221 /// assert_eq!(q.is_empty(), true);
222 /// ```
223 #[inline]
224 pub fn clear(&mut self) {
225 self.front = 0;
226 self.rear = 0;
227 self.sz = 0;
228 }
229
230 /// private method of boundary check and indexing
231 #[inline]
232 fn indexing(&self, idx: usize) -> usize {
233 if idx >= self.sz {
234 panic!("Invalid subscription index: {}", idx)
235 }
236 (idx + self.front) % self.q.capacity()
237 }
238}
239
240/// Optionally provide `pop` method for
241/// types that implements `Default` trait
242impl<T: Default> LimitedQueue<T> {
243 /// Pop the first element from queue,
244 /// will replace the element in queue with
245 /// the `Default` value of the element
246 ///
247 /// ```
248 /// use limited_queue::LimitedQueue;
249 ///
250 /// let mut q = LimitedQueue::with_capacity(1);
251 ///
252 /// q.push(1234);
253 /// assert_eq!(q.pop(), Some(1234));
254 /// assert_eq!(q.pop(), None);
255 /// ```
256 #[inline]
257 pub fn pop(&mut self) -> Option<T> {
258 if self.is_empty() {
259 None
260 } else {
261 let ret = take(&mut self.q[self.front]);
262 self.front = self.next_idx(self.front);
263 self.sz -= 1;
264 Some(ret)
265 }
266 }
267}
268
269impl<T> std::ops::Index<usize> for LimitedQueue<T> {
270 type Output = T;
271
272 #[inline]
273 fn index(&self, idx: usize) -> &Self::Output {
274 let real_idx = self.indexing(idx);
275 &self.q[real_idx]
276 }
277}
278
279impl<T> std::ops::IndexMut<usize> for LimitedQueue<T> {
280 #[inline]
281 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
282 let real_idx = self.indexing(idx);
283 &mut self.q[real_idx]
284 }
285}
286
287pub struct LimitedQueueIterator<'a, T> {
288 lq: &'a LimitedQueue<T>,
289 idx: usize,
290}
291
292impl<'a, T> Iterator for LimitedQueueIterator<'a, T> {
293 type Item = &'a T;
294
295 fn next(&mut self) -> Option<Self::Item> {
296 let cur_idx = self.idx;
297 if cur_idx == self.lq.len() {
298 None
299 } else {
300 self.idx += 1;
301 Some(&self.lq[cur_idx])
302 }
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use std::panic;
309
310 use rand::Rng;
311
312 use crate::LimitedQueue;
313
314 #[test]
315 fn test_iter() {
316 let mut q = crate::LimitedQueue::with_capacity(5);
317 // push_ret: [None x 5, 0, 1, ..., 4]
318 let push_ret = [[None; 5], core::array::from_fn(|i| Some(i))].concat();
319 for (i, pr) in (0..10).zip(push_ret) {
320 assert_eq!(q.push(i), pr);
321 }
322 assert_eq!(q.len(), 5);
323 for (n, element) in q.iter().enumerate() {
324 assert_eq!(element.clone(), q[n]); // 5, 6, 7, 8, 9
325 assert_eq!(element.clone(), n + 5); // 5, 6, 7, 8, 9
326 }
327 }
328
329 #[test]
330 fn test_change_size() {
331 const MAX_SZ: usize = 25;
332 let mut q: LimitedQueue<i32> = crate::LimitedQueue::with_capacity(MAX_SZ);
333 let mut sz = 0;
334 let mut rng = rand::thread_rng();
335
336 for _ in 0..1000 {
337 let op = rng.gen_range(0..=2);
338 match op {
339 0 => {
340 if q.push(rng.gen()).is_none() {
341 sz += 1
342 };
343 }
344 1 => {
345 if q.pop().is_some() {
346 sz -= 1
347 };
348 }
349 _ => {
350 assert!(match sz {
351 0 => q.is_empty() && q.pop().is_none() && q.peek().is_none(),
352 MAX_SZ => q.is_full(),
353 _ => sz == q.len() && sz < MAX_SZ,
354 });
355 }
356 };
357 }
358 }
359
360 #[test]
361 #[should_panic]
362 fn test_zero_len_invalid_indexing() {
363 LimitedQueue::with_capacity(0)[0]
364 }
365
366 #[test]
367 fn test_invalid_indexing() {
368 // shadow out panic message for unwind in the loop
369 let old_hook = panic::take_hook();
370 panic::set_hook(Box::new(|_info| {}));
371
372 let mut q = LimitedQueue::with_capacity(5);
373 q.push(1);
374 for i in 5..100 {
375 let invalid_access = || q[i];
376 let should_be_false = panic::catch_unwind(invalid_access).is_err();
377 if !should_be_false {
378 // reset panic hook to show error message
379 panic::set_hook(old_hook);
380 // panic with reason
381 panic!("Indexing with idx: {} cannot trigger panic.", i);
382 }
383 }
384
385 panic::set_hook(old_hook);
386 }
387
388 #[test]
389 fn test_clear() {
390 let mut q = LimitedQueue::with_capacity(10);
391 for _ in 0..3 {
392 q.push(1);
393 }
394 assert_eq!(q.len(), 3);
395 assert_eq!(q.pop(), Some(1));
396 assert_eq!(q.len(), 2);
397 q.clear();
398 assert_eq!(q.len(), 0);
399 for _ in 0..3 {
400 q.push(1);
401 }
402 assert_eq!(q.len(), 3);
403 assert_eq!(q.pop(), Some(1));
404 assert_eq!(q.len(), 2);
405 q.clear();
406 assert_eq!(q.len(), 0);
407 }
408}