Skip to main content

csc_7b_fc/
circularqueue.rs

1/// A circular queue using a vector of options underneath.  Can't use an array
2/// because the size of the array is part of its type in Rust.  The
3/// unused portions of the vector will hold value None.  Look at the
4/// source code for details.  This program was based on a
5/// roughly equivalent **[C++ Version](https://github.com/chuckcscccl/csc_7b_fc/blob/main/src/circularqueue.cpp)**.
6pub struct CircularQueue<T, const INITCAP: usize = 64> {
7    q: Vec<Option<T>>,
8    front: usize,
9    size: usize,
10}
11
12impl<T, const INITCAP: usize> CircularQueue<T, INITCAP> {
13    /// number of values in queue.  This function can be called from a const
14    /// context, which means it can be evaluated by the compiler, although
15    /// this is unlikely since vectors are heap-allocated.
16    pub const fn len(&self) -> usize {
17        self.size
18    }
19
20    /// current capacity of queue
21    pub fn capacity(&self) -> usize {
22        self.q.len()
23    }
24
25    /// creates an empty queue with default initial capacity defined by
26    /// const generic INITCAP
27    pub fn new() -> Self {
28        //constructor Self = CircularQueue
29        let mut v = Vec::with_capacity(INITCAP);
30        // let mut vec = [None;INITCAP]  won't compile : can't copy/clone
31        v.resize_with(INITCAP, || None); // loop underneath
32                                         //assert_eq!(INITCAP, v.len());
33        CircularQueue {
34            front: 0,
35            size: 0,
36            q: v,
37        }
38    } //new
39
40    fn index(&self, i: usize) -> usize {
41        (self.front + i) % self.q.len()
42    } // converts logical index into actual index
43
44    fn resize(&mut self) {
45        // double capacity, moves queue
46        let newcap = self.q.len() * 2;
47        let mut newq = Vec::with_capacity(newcap);
48        newq.resize_with(newcap, || None);
49        let size = self.size;
50        for i in 0..size {
51            let k = self.index(i);
52            std::mem::swap(&mut self.q[k], &mut newq[i]);
53        }
54        self.q = newq; // always move
55        self.front = 0;
56    } //resize
57
58    /// inserts a value at the back of the queue, wrapping around to the right
59    /// if necessary.  Increases capacity if necessary.
60    pub fn push_back(&mut self, x: T) {
61        if self.size >= self.q.len() {
62            self.resize();
63        }
64        let back = self.index(self.size);
65        self.q[back] = Some(x); // move into vector is ok
66        self.size += 1;
67    }
68
69    /// inserts a value at the front of the queue, wrapping around to the left
70    /// if necessary. Increases capacity if necessary.
71    pub fn push_front(&mut self, x: T) {
72        if self.size >= self.q.len() {
73            self.resize();
74        }
75        let newfront = self.index(self.q.len() - 1);
76        self.q[newfront] = Some(x);
77        self.front = newfront;
78        self.size += 1;
79    }
80
81    /// returns (moves) value at back of the queue, if it exists.
82    pub fn pop_back(&mut self) -> Option<T> {
83        if self.size == 0 {
84            return None;
85        }
86        let mut answer = None;
87        let last = self.index(self.size - 1);
88        std::mem::swap(&mut answer, &mut self.q[last]);
89        self.size -= 1;
90        answer
91    }
92
93    /// returns (moves) value at front of the queue, if it exists.
94    pub fn pop_front(&mut self) -> Option<T> {
95        if self.size == 0 {
96            return None;
97        }
98        let mut answer = None;
99        let first = self.index(0);
100        std::mem::swap(&mut answer, &mut self.q[first]);
101        self.front = self.index(1);
102        self.size -= 1;
103        answer
104    }
105
106    /// Maps mutable closure f over each value of the queue.  The
107    /// closure has the ability to mutate each value as well as
108    /// mutate its environment (see the source for the `test_main` function).
109    pub fn mapfun<F: FnMut(&mut T)>(&mut self, mut f: F) {
110        for i in 0..self.size {
111            let k = self.index(i);
112            f(self.q[k].as_mut().unwrap());
113        }
114    }
115
116    /// returns an immutable iterator, allows `for x in queue.iter()`
117    pub fn iter<'lt>(&'lt self) -> Cqiter<'lt, T, INITCAP> {
118        Cqiter { cq: self, index: 0 }
119    } //iter
120} // impl circularqueue
121
122// overloading [i] only possible by implementing a trait:
123use std::ops::{Index, IndexMut};
124
125impl<T, const C: usize> Index<usize> for CircularQueue<T, C> {
126    type Output = T;
127    fn index(&self, i: usize) -> &Self::Output {
128        let k = self.index(i);
129        self.q[k].as_ref().unwrap()
130    }
131}
132
133impl<T, const C: usize> IndexMut<usize> for CircularQueue<T, C> {
134    fn index_mut(&mut self, i: usize) -> &mut Self::Output {
135        let k = self.index(i);
136        self.q[k].as_mut().unwrap()
137    }
138}
139
140/// Iterator type for circular queues. This is the structure that we will
141/// implement the [Iterator] trait for.
142pub struct Cqiter<'lt, T, const C: usize> {
143    cq: &'lt CircularQueue<T, C>,
144    index: usize, // current index
145}
146impl<'lt, T, const C: usize> Iterator for Cqiter<'lt, T, C> {
147    type Item = &'lt T;
148    fn next(&mut self) -> Option<Self::Item> {
149        if self.index >= self.cq.len() {
150            None
151        } else {
152            let answer = Some(&self.cq[self.index]);
153            self.index += 1;
154            answer
155        }
156    } //next
157} // Iterator
158
159/// Implementing this trait means we can say `for x in &queue`, which is
160/// equivalent to `for x in queue.iter()`.
161impl<'lt, T, const C: usize> IntoIterator for &'lt CircularQueue<T, C> {
162    type Item = &'lt T;
163    type IntoIter = Cqiter<'lt, T, C>;
164    fn into_iter(self) -> Self::IntoIter {
165        // but this self is a &'lt Circ..
166        self.iter()
167    }
168} //IntoIterator
169
170/// function to test circular queue.
171pub fn main() {
172    let mut cq = CircularQueue::<usize>::new();
173    for i in 0..100 {
174        cq.push_back(i * 2);
175        cq.push_front(i * 2 + 1);
176    }
177    cq.mapfun(|x| *x = *x + 1);
178    for _ in 0..50 {
179        cq.pop_front();
180        cq.pop_back();
181    }
182    //cq.mapfun(|x|print!("{} ",&x));
183    for x in &cq {
184        print!("{} ", x);
185    }
186    println!("\nsize: {}, capacity {}", cq.len(), cq.capacity());
187    println!("cq[5] : {}", cq[5]);
188    cq[5] = 99999;
189    println!("cq[5] : {}", cq[5]);
190    let mut sum = 0;
191    cq.mapfun(|x| sum += *x);
192    println!("sum = {}", sum);
193} //main