From a7e7b26c3d676e5c9f3b89ba16888dac87f4a0f1 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 14:51:49 -0500 Subject: [PATCH 01/19] Add FixedQueue: A Fixed Size Queue Implementation A new data structure, `FixedQueue`, which is a fixed-size queue implemented using a static ring buffer. * Both push and pop operations should be constant time. * Elements should be stored contiguously in memory. * Unit tests should cover all methods and functionality. I recognize that Rust already has `VecDeque`, but it's growable and has a more general implementation. Please correct me if I'm wrong, but I believe this might offer a more efficient solution for scenarios where a fixed-size queue is sufficient. I want to learn and am open to any suggestions or critiques. Example Usage: ```rust use std::collections::FixedQueue; let mut fque = FixedQueue::::new(); fque.push(1); fque.push(2); fque.push(3); assert_eq!(fque.pop(), Some(1)); assert_eq!(fque.pop(), Some(2)); fque.push(4); assert_eq!(fque.to_vec(), vec![3, 4]); ``` --- library/alloc/src/collections/fixed_queue.rs | 533 +++++++++++++++++++ 1 file changed, 533 insertions(+) create mode 100644 library/alloc/src/collections/fixed_queue.rs diff --git a/library/alloc/src/collections/fixed_queue.rs b/library/alloc/src/collections/fixed_queue.rs new file mode 100644 index 0000000000000..d36730d9ae85c --- /dev/null +++ b/library/alloc/src/collections/fixed_queue.rs @@ -0,0 +1,533 @@ +use core::{ + fmt::{Debug, Display}, + ops::{Index, Range}, +}; + +/// Fixed Size Queue: +/// A linear queue implemented with a static ring buffer of owned nodes. +/// +/// The `FixedQueue` allows pushing and popping elements in constant time. +/// +/// The "default" usage of this type is to use [`push`] to add to +/// the queue, and [`pop`] to remove from the queue. Iterating over +/// `FixedQueue` goes front to back. +/// +/// A `FixedQueue` with a known list of items can be initialized from an array: +/// ``` +/// use std::collections::FixedQueue; +/// +/// let fque = FixedQueue::from([1, 2, 3]); +/// ``` +/// +/// Since `FixedQueue` is an array ring buffer, its elements are contiguous +/// in memory. +/// +/// [`push`]: FixedQueue::push +/// [`pop`]: FixedQueue::pop +#[derive(Debug)] +pub struct FixedQueue { + buffer: [Option; N], + head: usize, + tail: usize, + len: usize, +} + +impl FixedQueue { + /// Create a new FixedQueue with given fields. + #[inline] + const fn with( + buffer: [Option; N], + head: usize, + tail: usize, + len: usize, + ) -> FixedQueue { + FixedQueue { + buffer, + head, + tail, + len, + } + } + + /// Create a new FixedQueue with a given capacity. + pub const fn new() -> FixedQueue + where + Option: Copy, + { + FixedQueue::with([None; N], 0, 0, 0) + } + + /// Return the max capacity of the FixedQueue. + #[inline] + pub const fn capacity(&self) -> usize { + N + } + + /// Returns the number of elements in the FixedQueue. + #[inline] + pub const fn len(&self) -> usize { + self.len + } + + /// Check if the queue is empty. + #[inline] + pub const fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Check if the queue is full. + #[inline] + pub const fn is_full(&self) -> bool { + self.len == N + } + + /// Removes all elements from the queue. + pub fn clear(&mut self) { + for i in 0..N { + drop(self.buffer[i].take()); + } + self.head = 0; + self.tail = 0; + self.len = 0; + } + + /// Fills the queue with an element. + pub fn fill(&mut self, item: T) + where + Option: Copy, + { + self.buffer = [Some(item); N]; + self.head = 0; + self.tail = 0; + self.len = N; + } + + /// Add an element to the queue. If queue is full, the first element + /// is popped and returned. + pub fn push(&mut self, item: T) -> Option { + // 'pop' first + let overwritten = self.buffer[self.tail].take(); + // overwrite head/tail element + self.buffer[self.tail] = Some(item); + // shift tail with 'push' + self.tail = (self.tail + 1) % N; + if overwritten.is_some() { + // shift head ptr on collision + self.head = (self.head + 1) % N; + } else { + // increase len if no collision + self.len += 1; + } + return overwritten; + } + + /// Removes and returns the oldest element from the queue. + #[inline] + pub fn pop(&mut self) -> Option + where + Option: Copy, + { + if self.len == 0 { + return None; + } + let popped = self.buffer[self.head].take(); + self.head = (self.head + 1) % N; + self.len -= 1; + popped + } + + /// Converts the queue into its array equivalent. + pub fn to_option_array(self) -> [Option; N] + where + Option: Copy, + { + let mut arr: [Option; N] = [None; N]; + for i in 0..N { + arr[i] = self.buffer[(self.head + i) % N]; + } + arr + } + + /// Converts the queue into its vec equivalent. + pub fn to_vec(self) -> Vec + where + T: Copy, + { + let mut vec: Vec = Vec::new(); + for i in 0..N { + if let Some(e) = self.buffer[(self.head + i) % N] { + vec.push(e); + } + } + vec + } +} + +impl From<[T; N]> for FixedQueue { + /// Creates a FixedQueue from a fixed size array. + fn from(array: [T; N]) -> Self { + FixedQueue::with(array.map(Some), 0, 0, N) + } +} + +impl From<&[T; N]> for FixedQueue { + /// Creates a FixedQueue from a fixed size slice. + fn from(array: &[T; N]) -> Self { + FixedQueue::with(array.map(Some), 0, 0, N) + } +} + +impl From<&[T]> for FixedQueue { + /// Creates a FixedQueue from an unsized slice. Copies a maximum of N + /// elements of the slice, and a minimum of the slice length into the + /// queue. {[0, 0], 0} - [0, 0] + fn from(array: &[T]) -> Self { + let mut buf: [Option; N] = [None; N]; + let length = N.min(array.len()); + for i in 0..length { + buf[i] = Some(array[i]); + } + FixedQueue::with(buf, 0, array.len() - 1, length) + } +} + +impl PartialEq for FixedQueue { + /// This method tests if a FixedQueue is equal to another FixedQueue. + fn eq(&self, other: &FixedQueue) -> bool { + if other.len != self.len { + return false; + } + (0..N).all(|x| self.buffer[(self.head + x) % N] == other.buffer[(other.head + x) % N]) + } +} + +impl PartialEq<[T; M]> for FixedQueue { + /// This method tests if a FixedQueue is equal to a fixed size array. + fn eq(&self, other: &[T; M]) -> bool { + if M != self.len { + return false; + } + (0..M).all(|x| self.buffer[(self.head + x) % N].as_ref() == Some(&other[x])) + } +} + +impl Index for FixedQueue { + type Output = Option; + + fn index(&self, index: usize) -> &Self::Output { + if index >= N { + panic!("Index out of bounds"); + } + &self.buffer[(self.head + index) % N] + } +} + +impl Index> for FixedQueue +where + T: Copy + Default, +{ + type Output = [T]; + + fn index(&self, range: Range) -> &Self::Output { + let start = range.start; + let end = range.end; + + // check bounds + assert!(start <= end && end <= self.len, "Index out of bounds"); + + // create temporary array to store the results + let mut temp = Vec::with_capacity(end - start); + + for i in start..end { + let idx = (self.head + i) % N; + if let Some(value) = self.buffer[idx] { + temp.push(value); + } + } + + // Return a slice from the temporary array + // SAFETY: This is safe because temp will live long enough within this function call. + let result = unsafe { std::slice::from_raw_parts(temp.as_ptr(), temp.len()) }; + std::mem::forget(temp); + result + } +} + +impl Display for FixedQueue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.len == 0 { + return write!(f, "{{}}"); + } + write!(f, "{{")?; + for x in 0..(self.len - 1) { + write!( + f, + "{}, ", + self.buffer[(self.head + x) % N].as_ref().unwrap() + )?; + } + write!( + f, + "{}}}", + self.buffer[(self.head + self.len - 1) % N] + .as_ref() + .unwrap() + ) + } +} + +#[cfg(test)] +mod test { + use super::FixedQueue; + + #[test] + fn with() { + let x = FixedQueue::::with([None; 3], 789, 456, 123); + let y = FixedQueue:: { + buffer: [None; 3], + head: 789, + tail: 456, + len: 123, + }; + assert_eq!(x, y); + } + + #[test] + fn partial_eq_self() { + let x = FixedQueue::::new(); + let mut y = FixedQueue::with([None; 3], 0, 0, 0); + assert_eq!(x, y); + y.push(1); + assert_ne!(x, y); + y.push(2); + assert_ne!(x, y); + y.push(3); + assert_ne!(x, y); + y.clear(); + assert_eq!(x, y); + let w = FixedQueue::::with([None; 3], 0, 0, 0); + let z = FixedQueue::::with([None; 3], 1, 1, 0); + assert_eq!(w, z); + let u = FixedQueue::::with([Some(20), None, None], 0, 1, 1); + let v = FixedQueue::::with([None, Some(20), None], 1, 2, 1); + assert_eq!(u, v); + } + + #[test] + fn partial_eq_array() { + let x = FixedQueue::::from([1, 2, 3]); + assert_eq!(x, [1, 2, 3]); + assert_ne!(x, [20, 2, 3]); + let y = FixedQueue::::from([80]); + assert_eq!(y, [80]); + let z = FixedQueue::::with([Some(1), Some(2), Some(3)], 1, 1, 3); + assert_eq!(z, [2, 3, 1]); + let w = FixedQueue::::with([Some(20), None, None], 0, 1, 1); + assert_eq!(w, [20]); + let u = FixedQueue::::with([None, Some(20), None], 1, 2, 1); + assert_eq!(u, [20]); + } + + #[test] + fn new() { + let x = FixedQueue::::new(); + let y = FixedQueue::::with([None; 3], 0, 0, 0); + assert_eq!(x, y); + } + + #[test] + fn from_array() { + let x = FixedQueue::from([1i32, 2i32, 3i32]); + let y = FixedQueue::::with([Some(1i32), Some(2i32), Some(3i32)], 0, 0, 3); + assert_eq!(x, y); + let z = FixedQueue::from([true, false, true]); + let w = FixedQueue::::with([Some(true), Some(false), Some(true)], 0, 0, 3); + assert_eq!(z, w); + } + + #[test] + fn from_sized_slice() { + let x = FixedQueue::from(&[3i32, 2i32, 1i32]); + let y = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); + assert_eq!(x, y); + } + + #[test] + fn from_slice() { + let array = [3i32, 2i32, 1i32]; + let x = FixedQueue::::from(&array[0..1]); + let y = FixedQueue::::with([Some(3i32)], 0, 0, 1); + assert_eq!(x, y); + let w = FixedQueue::::from(&array[0..2]); + let z = FixedQueue::::with([Some(3i32), Some(2i32)], 0, 0, 2); + assert_eq!(w, z); + let u = FixedQueue::::from(&array[0..3]); + let v = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); + assert_eq!(u, v); + let s = FixedQueue::::from(&array[..]); + let t = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); + assert_eq!(s, t); + } + + #[test] + fn index() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert_eq!(x[0], Some("a")); + assert_eq!(x[1], Some("b")); + assert_eq!(x[2], Some("c")); + } + + #[test] + fn index_range() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert!(x[0..0].is_empty()); + assert_eq!(x[0..1], ["a"]); + assert_eq!(x[0..2], ["a", "b"]); + assert_eq!(x[0..3], ["a", "b", "c"]); + } + + #[test] + fn display() { + let mut x = FixedQueue::::new(); + assert_eq!(format!("{}", x), String::from("{}")); + x.push(10); + assert_eq!(format!("{}", x), String::from("{10}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{}")); + x.push(20); + assert_eq!(format!("{}", x), String::from("{20}")); + x.push(30); + assert_eq!(format!("{}", x), String::from("{20, 30}")); + x.push(40); + assert_eq!(format!("{}", x), String::from("{20, 30, 40}")); + x.push(50); + assert_eq!(format!("{}", x), String::from("{30, 40, 50}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{40, 50}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{50}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{}")); + } + + #[test] + fn capacity() { + let x = FixedQueue::::new(); + assert_eq!(x.capacity(), 1); + let y = FixedQueue::::new(); + assert_eq!(y.capacity(), 2); + let z = FixedQueue::::new(); + assert_eq!(z.capacity(), 3); + } + + #[test] + fn len() { + let mut x = FixedQueue::::new(); + assert_eq!(x.len(), 0); + x.push(true); + assert_eq!(x.len(), 1); + x.push(false); + assert_eq!(x.len(), 2); + x.push(true); + assert_eq!(x.len(), 3); + x.pop(); + assert_eq!(x.len(), 2); + x.pop(); + assert_eq!(x.len(), 1); + x.pop(); + assert_eq!(x.len(), 0); + } + + #[test] + fn is_empty() { + let mut x = FixedQueue::::new(); + assert!(x.is_empty()); + x.push(1); + assert!(!x.is_empty()); + } + + #[test] + fn is_full() { + let mut x = FixedQueue::::new(); + assert!(!x.is_full()); + x.push(1); + assert!(!x.is_full()); + x.push(1); + assert!(!x.is_full()); + x.push(1); + assert!(x.is_full()); + } + + #[test] + fn clear() { + let mut x = FixedQueue::from([1, 2, 3]); + assert!(!x.is_empty()); + x.clear(); + assert!(x.is_empty()); + } + + #[test] + fn fill() { + let mut x = FixedQueue::::new(); + assert!(!x.is_full()); + x.fill(10); + assert!(x.is_full()); + } + + #[test] + fn push() { + let mut x = FixedQueue::::from([(); 2].map(|_| String::new())); + assert!(x.is_full()); + x.clear(); + assert!(x.is_empty()); + x.push(String::from("a")); + assert_eq!(x.len(), 1); + assert_eq!(x, [String::from("a")]); + x.push(String::from("b")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("a"), String::from("b")]); + x.push(String::from("c")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("b"), String::from("c")]); + x.push(String::from("d")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("c"), String::from("d")]); + x.push(String::from("e")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("d"), String::from("e")]); + } + + #[test] + fn pop() { + let mut u = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert!(!u.is_empty()); + let w = u.pop(); + assert_eq!(w, Some("a")); + assert_eq!(u, ["b", "c"]); + let x = u.pop(); + assert_eq!(x, Some("b")); + assert_eq!(u, ["c"]); + let y = u.pop(); + assert_eq!(y, Some("c")); + assert_eq!(u, []); + let z = u.pop(); + assert_eq!(z, None); + assert_eq!(u, []); + } + + #[test] + fn to_option_array() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert_eq!(x.to_option_array(), [Some("a"), Some("b"), Some("c")]); + let mut y = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + y.pop(); + assert_eq!(y.to_option_array(), [Some("b"), Some("c"), None]) + } + + #[test] + fn to_vec() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + let y = Vec::from(["a", "b", "c"]); + assert_eq!(x.to_vec(), y); + } +} From 1fab98c62d280cd3b45a0d219697b9288975407a Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 15:08:47 -0500 Subject: [PATCH 02/19] Update fixed_queue.rs mingw-check-tidy formatting errors fix --- library/alloc/src/collections/fixed_queue.rs | 28 +++----------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/collections/fixed_queue.rs b/library/alloc/src/collections/fixed_queue.rs index d36730d9ae85c..70034d6210e07 100644 --- a/library/alloc/src/collections/fixed_queue.rs +++ b/library/alloc/src/collections/fixed_queue.rs @@ -41,12 +41,7 @@ impl FixedQueue { tail: usize, len: usize, ) -> FixedQueue { - FixedQueue { - buffer, - head, - tail, - len, - } + FixedQueue { buffer, head, tail, len } } /// Create a new FixedQueue with a given capacity. @@ -260,19 +255,9 @@ impl Display for FixedQueue { } write!(f, "{{")?; for x in 0..(self.len - 1) { - write!( - f, - "{}, ", - self.buffer[(self.head + x) % N].as_ref().unwrap() - )?; + write!(f, "{}, ", self.buffer[(self.head + x) % N].as_ref().unwrap())?; } - write!( - f, - "{}}}", - self.buffer[(self.head + self.len - 1) % N] - .as_ref() - .unwrap() - ) + write!(f, "{}}}", self.buffer[(self.head + self.len - 1) % N].as_ref().unwrap()) } } @@ -283,12 +268,7 @@ mod test { #[test] fn with() { let x = FixedQueue::::with([None; 3], 789, 456, 123); - let y = FixedQueue:: { - buffer: [None; 3], - head: 789, - tail: 456, - len: 123, - }; + let y = FixedQueue:: { buffer: [None; 3], head: 789, tail: 456, len: 123 }; assert_eq!(x, y); } From f5f4eae4b6c2cb498b064cf850d7d92064a4ce36 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 15:30:41 -0500 Subject: [PATCH 03/19] Create mod.rs Fixing file formatting errors --- .../alloc/src/collections/fixed_queue/mod.rs | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 library/alloc/src/collections/fixed_queue/mod.rs diff --git a/library/alloc/src/collections/fixed_queue/mod.rs b/library/alloc/src/collections/fixed_queue/mod.rs new file mode 100644 index 0000000000000..4c0f6a80209ec --- /dev/null +++ b/library/alloc/src/collections/fixed_queue/mod.rs @@ -0,0 +1,262 @@ +use core::{ + fmt::{Debug, Display}, + ops::{Index, Range}, +}; + +/// Fixed Size Queue: +/// A linear queue implemented with a static ring buffer of owned nodes. +/// +/// The `FixedQueue` allows pushing and popping elements in constant time. +/// +/// The "default" usage of this type is to use [`push`] to add to +/// the queue, and [`pop`] to remove from the queue. Iterating over +/// `FixedQueue` goes front to back. +/// +/// A `FixedQueue` with a known list of items can be initialized from an array: +/// ``` +/// use std::collections::FixedQueue; +/// +/// let fque = FixedQueue::from([1, 2, 3]); +/// ``` +/// +/// Since `FixedQueue` is an array ring buffer, its elements are contiguous +/// in memory. +/// +/// [`push`]: FixedQueue::push +/// [`pop`]: FixedQueue::pop +#[derive(Debug)] +pub struct FixedQueue { + buffer: [Option; N], + head: usize, + tail: usize, + len: usize, +} + +impl FixedQueue { + /// Create a new FixedQueue with given fields. + #[inline] + const fn with( + buffer: [Option; N], + head: usize, + tail: usize, + len: usize, + ) -> FixedQueue { + FixedQueue { buffer, head, tail, len } + } + + /// Create a new FixedQueue with a given capacity. + pub const fn new() -> FixedQueue + where + Option: Copy, + { + FixedQueue::with([None; N], 0, 0, 0) + } + + /// Return the max capacity of the FixedQueue. + #[inline] + pub const fn capacity(&self) -> usize { + N + } + + /// Returns the number of elements in the FixedQueue. + #[inline] + pub const fn len(&self) -> usize { + self.len + } + + /// Check if the queue is empty. + #[inline] + pub const fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Check if the queue is full. + #[inline] + pub const fn is_full(&self) -> bool { + self.len == N + } + + /// Removes all elements from the queue. + pub fn clear(&mut self) { + for i in 0..N { + drop(self.buffer[i].take()); + } + self.head = 0; + self.tail = 0; + self.len = 0; + } + + /// Fills the queue with an element. + pub fn fill(&mut self, item: T) + where + Option: Copy, + { + self.buffer = [Some(item); N]; + self.head = 0; + self.tail = 0; + self.len = N; + } + + /// Add an element to the queue. If queue is full, the first element + /// is popped and returned. + pub fn push(&mut self, item: T) -> Option { + // 'pop' first + let overwritten = self.buffer[self.tail].take(); + // overwrite head/tail element + self.buffer[self.tail] = Some(item); + // shift tail with 'push' + self.tail = (self.tail + 1) % N; + if overwritten.is_some() { + // shift head ptr on collision + self.head = (self.head + 1) % N; + } else { + // increase len if no collision + self.len += 1; + } + return overwritten; + } + + /// Removes and returns the oldest element from the queue. + #[inline] + pub fn pop(&mut self) -> Option + where + Option: Copy, + { + if self.len == 0 { + return None; + } + let popped = self.buffer[self.head].take(); + self.head = (self.head + 1) % N; + self.len -= 1; + popped + } + + /// Converts the queue into its array equivalent. + pub fn to_option_array(self) -> [Option; N] + where + Option: Copy, + { + let mut arr: [Option; N] = [None; N]; + for i in 0..N { + arr[i] = self.buffer[(self.head + i) % N]; + } + arr + } + + /// Converts the queue into its vec equivalent. + pub fn to_vec(self) -> Vec + where + T: Copy, + { + let mut vec: Vec = Vec::new(); + for i in 0..N { + if let Some(e) = self.buffer[(self.head + i) % N] { + vec.push(e); + } + } + vec + } +} + +impl From<[T; N]> for FixedQueue { + /// Creates a FixedQueue from a fixed size array. + fn from(array: [T; N]) -> Self { + FixedQueue::with(array.map(Some), 0, 0, N) + } +} + +impl From<&[T; N]> for FixedQueue { + /// Creates a FixedQueue from a fixed size slice. + fn from(array: &[T; N]) -> Self { + FixedQueue::with(array.map(Some), 0, 0, N) + } +} + +impl From<&[T]> for FixedQueue { + /// Creates a FixedQueue from an unsized slice. Copies a maximum of N + /// elements of the slice, and a minimum of the slice length into the + /// queue. {[0, 0], 0} - [0, 0] + fn from(array: &[T]) -> Self { + let mut buf: [Option; N] = [None; N]; + let length = N.min(array.len()); + for i in 0..length { + buf[i] = Some(array[i]); + } + FixedQueue::with(buf, 0, array.len() - 1, length) + } +} + +impl PartialEq for FixedQueue { + /// This method tests if a FixedQueue is equal to another FixedQueue. + fn eq(&self, other: &FixedQueue) -> bool { + if other.len != self.len { + return false; + } + (0..N).all(|x| self.buffer[(self.head + x) % N] == other.buffer[(other.head + x) % N]) + } +} + +impl PartialEq<[T; M]> for FixedQueue { + /// This method tests if a FixedQueue is equal to a fixed size array. + fn eq(&self, other: &[T; M]) -> bool { + if M != self.len { + return false; + } + (0..M).all(|x| self.buffer[(self.head + x) % N].as_ref() == Some(&other[x])) + } +} + +impl Index for FixedQueue { + type Output = Option; + + fn index(&self, index: usize) -> &Self::Output { + if index >= N { + panic!("Index out of bounds"); + } + &self.buffer[(self.head + index) % N] + } +} + +impl Index> for FixedQueue +where + T: Copy + Default, +{ + type Output = [T]; + + fn index(&self, range: Range) -> &Self::Output { + let start = range.start; + let end = range.end; + + // check bounds + assert!(start <= end && end <= self.len, "Index out of bounds"); + + // create temporary array to store the results + let mut temp = Vec::with_capacity(end - start); + + for i in start..end { + let idx = (self.head + i) % N; + if let Some(value) = self.buffer[idx] { + temp.push(value); + } + } + + // Return a slice from the temporary array + // SAFETY: This is safe because temp will live long enough within this function call. + let result = unsafe { std::slice::from_raw_parts(temp.as_ptr(), temp.len()) }; + std::mem::forget(temp); + result + } +} + +impl Display for FixedQueue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.len == 0 { + return write!(f, "{{}}"); + } + write!(f, "{{")?; + for x in 0..(self.len - 1) { + write!(f, "{}, ", self.buffer[(self.head + x) % N].as_ref().unwrap())?; + } + write!(f, "{}}}", self.buffer[(self.head + self.len - 1) % N].as_ref().unwrap()) + } +} From 6fa3e09802ac52e9888443b27e2810623b9d2c74 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 15:32:52 -0500 Subject: [PATCH 04/19] Create tests.rs Fixing file fomatting errors --- .../src/collections/fixed_queue/tests.rs | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 library/alloc/src/collections/fixed_queue/tests.rs diff --git a/library/alloc/src/collections/fixed_queue/tests.rs b/library/alloc/src/collections/fixed_queue/tests.rs new file mode 100644 index 0000000000000..12ff26bf20133 --- /dev/null +++ b/library/alloc/src/collections/fixed_queue/tests.rs @@ -0,0 +1,247 @@ +use super::*; + +#[test] +fn with() { + let x = FixedQueue::::with([None; 3], 789, 456, 123); + let y = FixedQueue:: { buffer: [None; 3], head: 789, tail: 456, len: 123 }; + assert_eq!(x, y); +} + +#[test] +fn partial_eq_self() { + let x = FixedQueue::::new(); + let mut y = FixedQueue::with([None; 3], 0, 0, 0); + assert_eq!(x, y); + y.push(1); + assert_ne!(x, y); + y.push(2); + assert_ne!(x, y); + y.push(3); + assert_ne!(x, y); + y.clear(); + assert_eq!(x, y); + let w = FixedQueue::::with([None; 3], 0, 0, 0); + let z = FixedQueue::::with([None; 3], 1, 1, 0); + assert_eq!(w, z); + let u = FixedQueue::::with([Some(20), None, None], 0, 1, 1); + let v = FixedQueue::::with([None, Some(20), None], 1, 2, 1); + assert_eq!(u, v); +} + +#[test] +fn partial_eq_array() { + let x = FixedQueue::::from([1, 2, 3]); + assert_eq!(x, [1, 2, 3]); + assert_ne!(x, [20, 2, 3]); + let y = FixedQueue::::from([80]); + assert_eq!(y, [80]); + let z = FixedQueue::::with([Some(1), Some(2), Some(3)], 1, 1, 3); + assert_eq!(z, [2, 3, 1]); + let w = FixedQueue::::with([Some(20), None, None], 0, 1, 1); + assert_eq!(w, [20]); + let u = FixedQueue::::with([None, Some(20), None], 1, 2, 1); + assert_eq!(u, [20]); +} + +#[test] +fn new() { + let x = FixedQueue::::new(); + let y = FixedQueue::::with([None; 3], 0, 0, 0); + assert_eq!(x, y); +} + +#[test] +fn from_array() { + let x = FixedQueue::from([1i32, 2i32, 3i32]); + let y = FixedQueue::::with([Some(1i32), Some(2i32), Some(3i32)], 0, 0, 3); + assert_eq!(x, y); + let z = FixedQueue::from([true, false, true]); + let w = FixedQueue::::with([Some(true), Some(false), Some(true)], 0, 0, 3); + assert_eq!(z, w); +} + +#[test] +fn from_sized_slice() { + let x = FixedQueue::from(&[3i32, 2i32, 1i32]); + let y = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); + assert_eq!(x, y); +} + +#[test] +fn from_slice() { + let array = [3i32, 2i32, 1i32]; + let x = FixedQueue::::from(&array[0..1]); + let y = FixedQueue::::with([Some(3i32)], 0, 0, 1); + assert_eq!(x, y); + let w = FixedQueue::::from(&array[0..2]); + let z = FixedQueue::::with([Some(3i32), Some(2i32)], 0, 0, 2); + assert_eq!(w, z); + let u = FixedQueue::::from(&array[0..3]); + let v = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); + assert_eq!(u, v); + let s = FixedQueue::::from(&array[..]); + let t = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); + assert_eq!(s, t); +} + +#[test] +fn index() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert_eq!(x[0], Some("a")); + assert_eq!(x[1], Some("b")); + assert_eq!(x[2], Some("c")); +} + +#[test] +fn index_range() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert!(x[0..0].is_empty()); + assert_eq!(x[0..1], ["a"]); + assert_eq!(x[0..2], ["a", "b"]); + assert_eq!(x[0..3], ["a", "b", "c"]); +} + +#[test] +fn display() { + let mut x = FixedQueue::::new(); + assert_eq!(format!("{}", x), String::from("{}")); + x.push(10); + assert_eq!(format!("{}", x), String::from("{10}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{}")); + x.push(20); + assert_eq!(format!("{}", x), String::from("{20}")); + x.push(30); + assert_eq!(format!("{}", x), String::from("{20, 30}")); + x.push(40); + assert_eq!(format!("{}", x), String::from("{20, 30, 40}")); + x.push(50); + assert_eq!(format!("{}", x), String::from("{30, 40, 50}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{40, 50}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{50}")); + x.pop(); + assert_eq!(format!("{}", x), String::from("{}")); +} + +#[test] +fn capacity() { + let x = FixedQueue::::new(); + assert_eq!(x.capacity(), 1); + let y = FixedQueue::::new(); + assert_eq!(y.capacity(), 2); + let z = FixedQueue::::new(); + assert_eq!(z.capacity(), 3); +} + +#[test] +fn len() { + let mut x = FixedQueue::::new(); + assert_eq!(x.len(), 0); + x.push(true); + assert_eq!(x.len(), 1); + x.push(false); + assert_eq!(x.len(), 2); + x.push(true); + assert_eq!(x.len(), 3); + x.pop(); + assert_eq!(x.len(), 2); + x.pop(); + assert_eq!(x.len(), 1); + x.pop(); + assert_eq!(x.len(), 0); +} + +#[test] +fn is_empty() { + let mut x = FixedQueue::::new(); + assert!(x.is_empty()); + x.push(1); + assert!(!x.is_empty()); +} + +#[test] +fn is_full() { + let mut x = FixedQueue::::new(); + assert!(!x.is_full()); + x.push(1); + assert!(!x.is_full()); + x.push(1); + assert!(!x.is_full()); + x.push(1); + assert!(x.is_full()); +} + +#[test] +fn clear() { + let mut x = FixedQueue::from([1, 2, 3]); + assert!(!x.is_empty()); + x.clear(); + assert!(x.is_empty()); +} + +#[test] +fn fill() { + let mut x = FixedQueue::::new(); + assert!(!x.is_full()); + x.fill(10); + assert!(x.is_full()); +} + +#[test] +fn push() { + let mut x = FixedQueue::::from([(); 2].map(|_| String::new())); + assert!(x.is_full()); + x.clear(); + assert!(x.is_empty()); + x.push(String::from("a")); + assert_eq!(x.len(), 1); + assert_eq!(x, [String::from("a")]); + x.push(String::from("b")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("a"), String::from("b")]); + x.push(String::from("c")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("b"), String::from("c")]); + x.push(String::from("d")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("c"), String::from("d")]); + x.push(String::from("e")); + assert_eq!(x.len(), 2); + assert_eq!(x, [String::from("d"), String::from("e")]); +} + +#[test] +fn pop() { + let mut u = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert!(!u.is_empty()); + let w = u.pop(); + assert_eq!(w, Some("a")); + assert_eq!(u, ["b", "c"]); + let x = u.pop(); + assert_eq!(x, Some("b")); + assert_eq!(u, ["c"]); + let y = u.pop(); + assert_eq!(y, Some("c")); + assert_eq!(u, []); + let z = u.pop(); + assert_eq!(z, None); + assert_eq!(u, []); +} + +#[test] +fn to_option_array() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + assert_eq!(x.to_option_array(), [Some("a"), Some("b"), Some("c")]); + let mut y = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + y.pop(); + assert_eq!(y.to_option_array(), [Some("b"), Some("c"), None]) +} + +#[test] +fn to_vec() { + let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); + let y = Vec::from(["a", "b", "c"]); + assert_eq!(x.to_vec(), y); +} From f389904e67883317fb87a38b73881ecfb3f3a917 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 15:33:19 -0500 Subject: [PATCH 05/19] Update mod.rs insert tests --- library/alloc/src/collections/fixed_queue/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/alloc/src/collections/fixed_queue/mod.rs b/library/alloc/src/collections/fixed_queue/mod.rs index 4c0f6a80209ec..0a3637f54e65a 100644 --- a/library/alloc/src/collections/fixed_queue/mod.rs +++ b/library/alloc/src/collections/fixed_queue/mod.rs @@ -3,6 +3,9 @@ use core::{ ops::{Index, Range}, }; +#[cfg(test)] +mod tests; + /// Fixed Size Queue: /// A linear queue implemented with a static ring buffer of owned nodes. /// From d6b179bae74e48c33d2d67f34504f08d9c061f24 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 15:34:52 -0500 Subject: [PATCH 06/19] Delete library/alloc/src/collections/fixed_queue.rs moved fixed queue into seperate folder --- library/alloc/src/collections/fixed_queue.rs | 513 ------------------- 1 file changed, 513 deletions(-) delete mode 100644 library/alloc/src/collections/fixed_queue.rs diff --git a/library/alloc/src/collections/fixed_queue.rs b/library/alloc/src/collections/fixed_queue.rs deleted file mode 100644 index 70034d6210e07..0000000000000 --- a/library/alloc/src/collections/fixed_queue.rs +++ /dev/null @@ -1,513 +0,0 @@ -use core::{ - fmt::{Debug, Display}, - ops::{Index, Range}, -}; - -/// Fixed Size Queue: -/// A linear queue implemented with a static ring buffer of owned nodes. -/// -/// The `FixedQueue` allows pushing and popping elements in constant time. -/// -/// The "default" usage of this type is to use [`push`] to add to -/// the queue, and [`pop`] to remove from the queue. Iterating over -/// `FixedQueue` goes front to back. -/// -/// A `FixedQueue` with a known list of items can be initialized from an array: -/// ``` -/// use std::collections::FixedQueue; -/// -/// let fque = FixedQueue::from([1, 2, 3]); -/// ``` -/// -/// Since `FixedQueue` is an array ring buffer, its elements are contiguous -/// in memory. -/// -/// [`push`]: FixedQueue::push -/// [`pop`]: FixedQueue::pop -#[derive(Debug)] -pub struct FixedQueue { - buffer: [Option; N], - head: usize, - tail: usize, - len: usize, -} - -impl FixedQueue { - /// Create a new FixedQueue with given fields. - #[inline] - const fn with( - buffer: [Option; N], - head: usize, - tail: usize, - len: usize, - ) -> FixedQueue { - FixedQueue { buffer, head, tail, len } - } - - /// Create a new FixedQueue with a given capacity. - pub const fn new() -> FixedQueue - where - Option: Copy, - { - FixedQueue::with([None; N], 0, 0, 0) - } - - /// Return the max capacity of the FixedQueue. - #[inline] - pub const fn capacity(&self) -> usize { - N - } - - /// Returns the number of elements in the FixedQueue. - #[inline] - pub const fn len(&self) -> usize { - self.len - } - - /// Check if the queue is empty. - #[inline] - pub const fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Check if the queue is full. - #[inline] - pub const fn is_full(&self) -> bool { - self.len == N - } - - /// Removes all elements from the queue. - pub fn clear(&mut self) { - for i in 0..N { - drop(self.buffer[i].take()); - } - self.head = 0; - self.tail = 0; - self.len = 0; - } - - /// Fills the queue with an element. - pub fn fill(&mut self, item: T) - where - Option: Copy, - { - self.buffer = [Some(item); N]; - self.head = 0; - self.tail = 0; - self.len = N; - } - - /// Add an element to the queue. If queue is full, the first element - /// is popped and returned. - pub fn push(&mut self, item: T) -> Option { - // 'pop' first - let overwritten = self.buffer[self.tail].take(); - // overwrite head/tail element - self.buffer[self.tail] = Some(item); - // shift tail with 'push' - self.tail = (self.tail + 1) % N; - if overwritten.is_some() { - // shift head ptr on collision - self.head = (self.head + 1) % N; - } else { - // increase len if no collision - self.len += 1; - } - return overwritten; - } - - /// Removes and returns the oldest element from the queue. - #[inline] - pub fn pop(&mut self) -> Option - where - Option: Copy, - { - if self.len == 0 { - return None; - } - let popped = self.buffer[self.head].take(); - self.head = (self.head + 1) % N; - self.len -= 1; - popped - } - - /// Converts the queue into its array equivalent. - pub fn to_option_array(self) -> [Option; N] - where - Option: Copy, - { - let mut arr: [Option; N] = [None; N]; - for i in 0..N { - arr[i] = self.buffer[(self.head + i) % N]; - } - arr - } - - /// Converts the queue into its vec equivalent. - pub fn to_vec(self) -> Vec - where - T: Copy, - { - let mut vec: Vec = Vec::new(); - for i in 0..N { - if let Some(e) = self.buffer[(self.head + i) % N] { - vec.push(e); - } - } - vec - } -} - -impl From<[T; N]> for FixedQueue { - /// Creates a FixedQueue from a fixed size array. - fn from(array: [T; N]) -> Self { - FixedQueue::with(array.map(Some), 0, 0, N) - } -} - -impl From<&[T; N]> for FixedQueue { - /// Creates a FixedQueue from a fixed size slice. - fn from(array: &[T; N]) -> Self { - FixedQueue::with(array.map(Some), 0, 0, N) - } -} - -impl From<&[T]> for FixedQueue { - /// Creates a FixedQueue from an unsized slice. Copies a maximum of N - /// elements of the slice, and a minimum of the slice length into the - /// queue. {[0, 0], 0} - [0, 0] - fn from(array: &[T]) -> Self { - let mut buf: [Option; N] = [None; N]; - let length = N.min(array.len()); - for i in 0..length { - buf[i] = Some(array[i]); - } - FixedQueue::with(buf, 0, array.len() - 1, length) - } -} - -impl PartialEq for FixedQueue { - /// This method tests if a FixedQueue is equal to another FixedQueue. - fn eq(&self, other: &FixedQueue) -> bool { - if other.len != self.len { - return false; - } - (0..N).all(|x| self.buffer[(self.head + x) % N] == other.buffer[(other.head + x) % N]) - } -} - -impl PartialEq<[T; M]> for FixedQueue { - /// This method tests if a FixedQueue is equal to a fixed size array. - fn eq(&self, other: &[T; M]) -> bool { - if M != self.len { - return false; - } - (0..M).all(|x| self.buffer[(self.head + x) % N].as_ref() == Some(&other[x])) - } -} - -impl Index for FixedQueue { - type Output = Option; - - fn index(&self, index: usize) -> &Self::Output { - if index >= N { - panic!("Index out of bounds"); - } - &self.buffer[(self.head + index) % N] - } -} - -impl Index> for FixedQueue -where - T: Copy + Default, -{ - type Output = [T]; - - fn index(&self, range: Range) -> &Self::Output { - let start = range.start; - let end = range.end; - - // check bounds - assert!(start <= end && end <= self.len, "Index out of bounds"); - - // create temporary array to store the results - let mut temp = Vec::with_capacity(end - start); - - for i in start..end { - let idx = (self.head + i) % N; - if let Some(value) = self.buffer[idx] { - temp.push(value); - } - } - - // Return a slice from the temporary array - // SAFETY: This is safe because temp will live long enough within this function call. - let result = unsafe { std::slice::from_raw_parts(temp.as_ptr(), temp.len()) }; - std::mem::forget(temp); - result - } -} - -impl Display for FixedQueue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.len == 0 { - return write!(f, "{{}}"); - } - write!(f, "{{")?; - for x in 0..(self.len - 1) { - write!(f, "{}, ", self.buffer[(self.head + x) % N].as_ref().unwrap())?; - } - write!(f, "{}}}", self.buffer[(self.head + self.len - 1) % N].as_ref().unwrap()) - } -} - -#[cfg(test)] -mod test { - use super::FixedQueue; - - #[test] - fn with() { - let x = FixedQueue::::with([None; 3], 789, 456, 123); - let y = FixedQueue:: { buffer: [None; 3], head: 789, tail: 456, len: 123 }; - assert_eq!(x, y); - } - - #[test] - fn partial_eq_self() { - let x = FixedQueue::::new(); - let mut y = FixedQueue::with([None; 3], 0, 0, 0); - assert_eq!(x, y); - y.push(1); - assert_ne!(x, y); - y.push(2); - assert_ne!(x, y); - y.push(3); - assert_ne!(x, y); - y.clear(); - assert_eq!(x, y); - let w = FixedQueue::::with([None; 3], 0, 0, 0); - let z = FixedQueue::::with([None; 3], 1, 1, 0); - assert_eq!(w, z); - let u = FixedQueue::::with([Some(20), None, None], 0, 1, 1); - let v = FixedQueue::::with([None, Some(20), None], 1, 2, 1); - assert_eq!(u, v); - } - - #[test] - fn partial_eq_array() { - let x = FixedQueue::::from([1, 2, 3]); - assert_eq!(x, [1, 2, 3]); - assert_ne!(x, [20, 2, 3]); - let y = FixedQueue::::from([80]); - assert_eq!(y, [80]); - let z = FixedQueue::::with([Some(1), Some(2), Some(3)], 1, 1, 3); - assert_eq!(z, [2, 3, 1]); - let w = FixedQueue::::with([Some(20), None, None], 0, 1, 1); - assert_eq!(w, [20]); - let u = FixedQueue::::with([None, Some(20), None], 1, 2, 1); - assert_eq!(u, [20]); - } - - #[test] - fn new() { - let x = FixedQueue::::new(); - let y = FixedQueue::::with([None; 3], 0, 0, 0); - assert_eq!(x, y); - } - - #[test] - fn from_array() { - let x = FixedQueue::from([1i32, 2i32, 3i32]); - let y = FixedQueue::::with([Some(1i32), Some(2i32), Some(3i32)], 0, 0, 3); - assert_eq!(x, y); - let z = FixedQueue::from([true, false, true]); - let w = FixedQueue::::with([Some(true), Some(false), Some(true)], 0, 0, 3); - assert_eq!(z, w); - } - - #[test] - fn from_sized_slice() { - let x = FixedQueue::from(&[3i32, 2i32, 1i32]); - let y = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); - assert_eq!(x, y); - } - - #[test] - fn from_slice() { - let array = [3i32, 2i32, 1i32]; - let x = FixedQueue::::from(&array[0..1]); - let y = FixedQueue::::with([Some(3i32)], 0, 0, 1); - assert_eq!(x, y); - let w = FixedQueue::::from(&array[0..2]); - let z = FixedQueue::::with([Some(3i32), Some(2i32)], 0, 0, 2); - assert_eq!(w, z); - let u = FixedQueue::::from(&array[0..3]); - let v = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); - assert_eq!(u, v); - let s = FixedQueue::::from(&array[..]); - let t = FixedQueue::::with([Some(3i32), Some(2i32), Some(1i32)], 0, 0, 3); - assert_eq!(s, t); - } - - #[test] - fn index() { - let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); - assert_eq!(x[0], Some("a")); - assert_eq!(x[1], Some("b")); - assert_eq!(x[2], Some("c")); - } - - #[test] - fn index_range() { - let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); - assert!(x[0..0].is_empty()); - assert_eq!(x[0..1], ["a"]); - assert_eq!(x[0..2], ["a", "b"]); - assert_eq!(x[0..3], ["a", "b", "c"]); - } - - #[test] - fn display() { - let mut x = FixedQueue::::new(); - assert_eq!(format!("{}", x), String::from("{}")); - x.push(10); - assert_eq!(format!("{}", x), String::from("{10}")); - x.pop(); - assert_eq!(format!("{}", x), String::from("{}")); - x.push(20); - assert_eq!(format!("{}", x), String::from("{20}")); - x.push(30); - assert_eq!(format!("{}", x), String::from("{20, 30}")); - x.push(40); - assert_eq!(format!("{}", x), String::from("{20, 30, 40}")); - x.push(50); - assert_eq!(format!("{}", x), String::from("{30, 40, 50}")); - x.pop(); - assert_eq!(format!("{}", x), String::from("{40, 50}")); - x.pop(); - assert_eq!(format!("{}", x), String::from("{50}")); - x.pop(); - assert_eq!(format!("{}", x), String::from("{}")); - } - - #[test] - fn capacity() { - let x = FixedQueue::::new(); - assert_eq!(x.capacity(), 1); - let y = FixedQueue::::new(); - assert_eq!(y.capacity(), 2); - let z = FixedQueue::::new(); - assert_eq!(z.capacity(), 3); - } - - #[test] - fn len() { - let mut x = FixedQueue::::new(); - assert_eq!(x.len(), 0); - x.push(true); - assert_eq!(x.len(), 1); - x.push(false); - assert_eq!(x.len(), 2); - x.push(true); - assert_eq!(x.len(), 3); - x.pop(); - assert_eq!(x.len(), 2); - x.pop(); - assert_eq!(x.len(), 1); - x.pop(); - assert_eq!(x.len(), 0); - } - - #[test] - fn is_empty() { - let mut x = FixedQueue::::new(); - assert!(x.is_empty()); - x.push(1); - assert!(!x.is_empty()); - } - - #[test] - fn is_full() { - let mut x = FixedQueue::::new(); - assert!(!x.is_full()); - x.push(1); - assert!(!x.is_full()); - x.push(1); - assert!(!x.is_full()); - x.push(1); - assert!(x.is_full()); - } - - #[test] - fn clear() { - let mut x = FixedQueue::from([1, 2, 3]); - assert!(!x.is_empty()); - x.clear(); - assert!(x.is_empty()); - } - - #[test] - fn fill() { - let mut x = FixedQueue::::new(); - assert!(!x.is_full()); - x.fill(10); - assert!(x.is_full()); - } - - #[test] - fn push() { - let mut x = FixedQueue::::from([(); 2].map(|_| String::new())); - assert!(x.is_full()); - x.clear(); - assert!(x.is_empty()); - x.push(String::from("a")); - assert_eq!(x.len(), 1); - assert_eq!(x, [String::from("a")]); - x.push(String::from("b")); - assert_eq!(x.len(), 2); - assert_eq!(x, [String::from("a"), String::from("b")]); - x.push(String::from("c")); - assert_eq!(x.len(), 2); - assert_eq!(x, [String::from("b"), String::from("c")]); - x.push(String::from("d")); - assert_eq!(x.len(), 2); - assert_eq!(x, [String::from("c"), String::from("d")]); - x.push(String::from("e")); - assert_eq!(x.len(), 2); - assert_eq!(x, [String::from("d"), String::from("e")]); - } - - #[test] - fn pop() { - let mut u = FixedQueue::<&str, 3>::from(["a", "b", "c"]); - assert!(!u.is_empty()); - let w = u.pop(); - assert_eq!(w, Some("a")); - assert_eq!(u, ["b", "c"]); - let x = u.pop(); - assert_eq!(x, Some("b")); - assert_eq!(u, ["c"]); - let y = u.pop(); - assert_eq!(y, Some("c")); - assert_eq!(u, []); - let z = u.pop(); - assert_eq!(z, None); - assert_eq!(u, []); - } - - #[test] - fn to_option_array() { - let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); - assert_eq!(x.to_option_array(), [Some("a"), Some("b"), Some("c")]); - let mut y = FixedQueue::<&str, 3>::from(["a", "b", "c"]); - y.pop(); - assert_eq!(y.to_option_array(), [Some("b"), Some("c"), None]) - } - - #[test] - fn to_vec() { - let x = FixedQueue::<&str, 3>::from(["a", "b", "c"]); - let y = Vec::from(["a", "b", "c"]); - assert_eq!(x.to_vec(), y); - } -} From 21b4b61907804f8f97485ac892976c86f0158b98 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 15:39:20 -0500 Subject: [PATCH 07/19] Update mod.rs allow fixed queue to be a module --- library/alloc/src/collections/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 705b81535c279..372a66aabd7d9 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -6,6 +6,7 @@ pub mod binary_heap; #[cfg(not(no_global_oom_handling))] mod btree; +pub mod fixed_queue; #[cfg(not(no_global_oom_handling))] pub mod linked_list; #[cfg(not(no_global_oom_handling))] @@ -42,6 +43,8 @@ pub use btree_map::BTreeMap; #[doc(no_inline)] pub use btree_set::BTreeSet; +pub use fixed_queue::FixedQueue; + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] From 11907dc4e3dd6621126df697ee6abff2678a2767 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 19:33:31 -0500 Subject: [PATCH 08/19] Update mod.rs add unstable feature --- .../alloc/src/collections/fixed_queue/mod.rs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/collections/fixed_queue/mod.rs b/library/alloc/src/collections/fixed_queue/mod.rs index 0a3637f54e65a..b824f1054fcae 100644 --- a/library/alloc/src/collections/fixed_queue/mod.rs +++ b/library/alloc/src/collections/fixed_queue/mod.rs @@ -1,6 +1,8 @@ +use crate::vec::Vec; use core::{ - fmt::{Debug, Display}, + fmt, mem, ops::{Index, Range}, + slice, }; #[cfg(test)] @@ -28,6 +30,7 @@ mod tests; /// [`push`]: FixedQueue::push /// [`pop`]: FixedQueue::pop #[derive(Debug)] +#[unstable(feature = "fixed_queue", issue = "126204")] pub struct FixedQueue { buffer: [Option; N], head: usize, @@ -48,6 +51,7 @@ impl FixedQueue { } /// Create a new FixedQueue with a given capacity. + #[unstable(feature = "fixed_queue", issue = "126204")] pub const fn new() -> FixedQueue where Option: Copy, @@ -57,29 +61,34 @@ impl FixedQueue { /// Return the max capacity of the FixedQueue. #[inline] + #[unstable(feature = "fixed_queue", issue = "126204")] pub const fn capacity(&self) -> usize { N } /// Returns the number of elements in the FixedQueue. #[inline] + #[unstable(feature = "fixed_queue", issue = "126204")] pub const fn len(&self) -> usize { self.len } /// Check if the queue is empty. #[inline] + #[unstable(feature = "fixed_queue", issue = "126204")] pub const fn is_empty(&self) -> bool { self.len == 0 } /// Check if the queue is full. #[inline] + #[unstable(feature = "fixed_queue", issue = "126204")] pub const fn is_full(&self) -> bool { self.len == N } /// Removes all elements from the queue. + #[unstable(feature = "fixed_queue", issue = "126204")] pub fn clear(&mut self) { for i in 0..N { drop(self.buffer[i].take()); @@ -90,6 +99,7 @@ impl FixedQueue { } /// Fills the queue with an element. + #[unstable(feature = "fixed_queue", issue = "126204")] pub fn fill(&mut self, item: T) where Option: Copy, @@ -102,6 +112,7 @@ impl FixedQueue { /// Add an element to the queue. If queue is full, the first element /// is popped and returned. + #[unstable(feature = "fixed_queue", issue = "126204")] pub fn push(&mut self, item: T) -> Option { // 'pop' first let overwritten = self.buffer[self.tail].take(); @@ -121,6 +132,7 @@ impl FixedQueue { /// Removes and returns the oldest element from the queue. #[inline] + #[unstable(feature = "fixed_queue", issue = "126204")] pub fn pop(&mut self) -> Option where Option: Copy, @@ -135,6 +147,7 @@ impl FixedQueue { } /// Converts the queue into its array equivalent. + #[unstable(feature = "fixed_queue", issue = "126204")] pub fn to_option_array(self) -> [Option; N] where Option: Copy, @@ -147,6 +160,7 @@ impl FixedQueue { } /// Converts the queue into its vec equivalent. + #[unstable(feature = "fixed_queue", issue = "126204")] pub fn to_vec(self) -> Vec where T: Copy, @@ -161,6 +175,7 @@ impl FixedQueue { } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl From<[T; N]> for FixedQueue { /// Creates a FixedQueue from a fixed size array. fn from(array: [T; N]) -> Self { @@ -168,6 +183,7 @@ impl From<[T; N]> for FixedQueue { } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl From<&[T; N]> for FixedQueue { /// Creates a FixedQueue from a fixed size slice. fn from(array: &[T; N]) -> Self { @@ -175,6 +191,7 @@ impl From<&[T; N]> for FixedQueue { } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl From<&[T]> for FixedQueue { /// Creates a FixedQueue from an unsized slice. Copies a maximum of N /// elements of the slice, and a minimum of the slice length into the @@ -189,6 +206,7 @@ impl From<&[T]> for FixedQueue { } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl PartialEq for FixedQueue { /// This method tests if a FixedQueue is equal to another FixedQueue. fn eq(&self, other: &FixedQueue) -> bool { @@ -199,6 +217,7 @@ impl PartialEq for FixedQueue { } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl PartialEq<[T; M]> for FixedQueue { /// This method tests if a FixedQueue is equal to a fixed size array. fn eq(&self, other: &[T; M]) -> bool { @@ -209,6 +228,7 @@ impl PartialEq<[T; M]> for FixedQu } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl Index for FixedQueue { type Output = Option; @@ -220,6 +240,7 @@ impl Index for FixedQueue { } } +#[unstable(feature = "fixed_queue", issue = "126204")] impl Index> for FixedQueue where T: Copy + Default, @@ -245,14 +266,15 @@ where // Return a slice from the temporary array // SAFETY: This is safe because temp will live long enough within this function call. - let result = unsafe { std::slice::from_raw_parts(temp.as_ptr(), temp.len()) }; - std::mem::forget(temp); + let result = unsafe { slice::from_raw_parts(temp.as_ptr(), temp.len()) }; + mem::forget(temp); result } } -impl Display for FixedQueue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +#[unstable(feature = "fixed_queue", issue = "126204")] +impl fmt::Display for FixedQueue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.len == 0 { return write!(f, "{{}}"); } From 107c392f4b2dec0e710a9b20aaf144f88a328095 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 19:35:22 -0500 Subject: [PATCH 09/19] Update tests.rs include vec and string --- library/alloc/src/collections/fixed_queue/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/collections/fixed_queue/tests.rs b/library/alloc/src/collections/fixed_queue/tests.rs index 12ff26bf20133..c3fc738880329 100644 --- a/library/alloc/src/collections/fixed_queue/tests.rs +++ b/library/alloc/src/collections/fixed_queue/tests.rs @@ -1,4 +1,5 @@ use super::*; +use crate::{string::String, vec::Vec}; #[test] fn with() { From 32746284c2e48c60043eab4ecee8f7494f9b45d5 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 19:39:28 -0500 Subject: [PATCH 10/19] Update lib.rs add feature --- library/alloc/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4749b8880fbc4..2d3f5eccc62c5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -123,6 +123,7 @@ #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] +#![feature(fixed_queue)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(hasher_prefixfree_extras)] From a7fa2b97b18088d5d1b084a599aab19700a05b5a Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 19:41:23 -0500 Subject: [PATCH 11/19] Update mod.rs --- library/alloc/src/collections/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 372a66aabd7d9..de92d68c7a6da 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -6,6 +6,7 @@ pub mod binary_heap; #[cfg(not(no_global_oom_handling))] mod btree; +#[cfg(not(no_global_oom_handling))] pub mod fixed_queue; #[cfg(not(no_global_oom_handling))] pub mod linked_list; @@ -43,6 +44,9 @@ pub use btree_map::BTreeMap; #[doc(no_inline)] pub use btree_set::BTreeSet; +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "fixed_queue", issue = "126204")] +#[doc(no_inline)] pub use fixed_queue::FixedQueue; #[cfg(not(no_global_oom_handling))] From 1cf312e053e26965263e0e5d3cf7eca3432207b9 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 9 Jun 2024 19:52:34 -0500 Subject: [PATCH 12/19] Update unstable.rs --- compiler/rustc_feature/src/unstable.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2410019868a19..1c2e2f43ee264 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -467,6 +467,8 @@ declare_features! ( (unstable, f128, "1.78.0", Some(116909)), /// Allow using 16-bit (half precision) floating point numbers. (unstable, f16, "1.78.0", Some(116909)), + /// New collection + (unstable, fixed_queue, "1.77.1", Some(126204)), /// Allows the use of `#[ffi_const]` on foreign functions. (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. From 579c9c291895064bd3ab8e691a384fb1a79a68ab Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 10:00:39 -0500 Subject: [PATCH 13/19] Update mod.rs unstable tags --- library/alloc/src/collections/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index de92d68c7a6da..6909e8f761687 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -7,6 +7,7 @@ pub mod binary_heap; #[cfg(not(no_global_oom_handling))] mod btree; #[cfg(not(no_global_oom_handling))] +#[unstable(feature = "fixed_queue", issue = "126204")] pub mod fixed_queue; #[cfg(not(no_global_oom_handling))] pub mod linked_list; From fcda44fe3c64a00b934c5e11e92fc7257787a4cd Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 10:05:48 -0500 Subject: [PATCH 14/19] Update mod.rs including docs --- library/alloc/src/collections/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 6909e8f761687..cffa5f7500818 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -8,6 +8,7 @@ pub mod binary_heap; mod btree; #[cfg(not(no_global_oom_handling))] #[unstable(feature = "fixed_queue", issue = "126204")] +/// This module provides a fixed-size queue implementation. pub mod fixed_queue; #[cfg(not(no_global_oom_handling))] pub mod linked_list; From f03b7b4c38a599ee543f947f5aa0c87b108bda25 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 10:15:30 -0500 Subject: [PATCH 15/19] Update symbol.rs add symbol --- compiler/rustc_span/src/symbol.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e245dfb9f5d77..c8f30c0de217f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -859,6 +859,7 @@ symbols! { field, field_init_shorthand, file, + fixed_queue, float, float_to_int_unchecked, floorf128, From 8f0297086e1b68ab6fe31186129ff9976043c932 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 10:26:53 -0500 Subject: [PATCH 16/19] Update unstable.rs sort by alphabetical order --- compiler/rustc_feature/src/unstable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1c2e2f43ee264..30ce3095502d9 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -467,12 +467,12 @@ declare_features! ( (unstable, f128, "1.78.0", Some(116909)), /// Allow using 16-bit (half precision) floating point numbers. (unstable, f16, "1.78.0", Some(116909)), - /// New collection - (unstable, fixed_queue, "1.77.1", Some(126204)), /// Allows the use of `#[ffi_const]` on foreign functions. (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. (unstable, ffi_pure, "1.45.0", Some(58329)), + /// New collection + (unstable, fixed_queue, "1.77.1", Some(126204)), /// Allows using `#[repr(align(...))]` on function items (unstable, fn_align, "1.53.0", Some(82232)), /// Support delegating implementation of functions to other already implemented functions. From a30dc9345c48d31d5cdf2b0f31d7ba02ab5850bb Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 10:46:41 -0500 Subject: [PATCH 17/19] Create feature-gate-fixed-queue.rs feature gate test --- tests/ui/feature-gates/feature-gate-fixed-queue.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-fixed-queue.rs diff --git a/tests/ui/feature-gates/feature-gate-fixed-queue.rs b/tests/ui/feature-gates/feature-gate-fixed-queue.rs new file mode 100644 index 0000000000000..a6db96515912e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-fixed-queue.rs @@ -0,0 +1,7 @@ +// This test ensures that the `fixed_queue` feature gate is required +#![allow(unused)] + +// Attempt to use the feature without enabling it +fn main() { + let _queue = FixedQueue::::new(); //~ ERROR the type `FixedQueue` is unstable +} From e6a7ebd2a24341e5a7913f0e968abeeb9b7ea12d Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 11:05:40 -0500 Subject: [PATCH 18/19] Update mod.rs std to alloc (perhaps wrong place) --- library/alloc/src/collections/fixed_queue/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/fixed_queue/mod.rs b/library/alloc/src/collections/fixed_queue/mod.rs index b824f1054fcae..97b32cff4fe02 100644 --- a/library/alloc/src/collections/fixed_queue/mod.rs +++ b/library/alloc/src/collections/fixed_queue/mod.rs @@ -19,7 +19,7 @@ mod tests; /// /// A `FixedQueue` with a known list of items can be initialized from an array: /// ``` -/// use std::collections::FixedQueue; +/// use alloc::collections::FixedQueue; /// /// let fque = FixedQueue::from([1, 2, 3]); /// ``` From 22b477427e7e1ed7a29c641472c6b3e96a7c52cc Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Jun 2024 11:26:49 -0500 Subject: [PATCH 19/19] Update mod.rs use feature in example --- library/alloc/src/collections/fixed_queue/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/collections/fixed_queue/mod.rs b/library/alloc/src/collections/fixed_queue/mod.rs index 97b32cff4fe02..45712374445fd 100644 --- a/library/alloc/src/collections/fixed_queue/mod.rs +++ b/library/alloc/src/collections/fixed_queue/mod.rs @@ -19,6 +19,7 @@ mod tests; /// /// A `FixedQueue` with a known list of items can be initialized from an array: /// ``` +/// #![feature(fixed_queue)] /// use alloc::collections::FixedQueue; /// /// let fque = FixedQueue::from([1, 2, 3]);