use std::ops::Add;
#[derive(Clone, Debug)]
pub struct FixedSet<T> {
items: Vec<Option<T>>,
}
impl<T: Clone + PartialEq + Default> FixedSet<T> {
pub fn new(n: usize) -> FixedSet<T> {
FixedSet { items: vec![None; n] }
}
pub fn size(&self) -> usize {
self.items.len()
}
pub fn set_item(&mut self, index: usize, val: T) -> bool {
if index >= self.items.len() {
return false;
}
self.items[index] = Some(val);
true
}
pub fn get_item(&self, index: usize) -> Option<&T> {
match self.items.get(index) {
None => None,
Some(option) => option.as_ref(),
}
}
pub fn clear_item(&mut self, index: usize) {
if index < self.items.len() {
self.items[index] = None;
}
}
pub fn is_full(&self) -> bool {
self.items.iter().all(Option::is_some)
}
pub fn search(&self, val: &T) -> Option<usize> {
self.items
.iter()
.position(|item| item.as_ref().map(|i| i == val).unwrap_or(false))
}
pub fn sum(&self) -> Option<T>
where for<'a> &'a T: Add<&'a T, Output = T> {
if self.size() == 0 {
return Some(T::default());
}
if !self.is_full() {
return None;
}
let mut iter = self.items.iter().filter_map(Option::as_ref);
let mut sum = iter.next().unwrap().clone();
for v in iter {
sum = &sum + v;
}
Some(sum)
}
pub fn into_vec(self) -> Vec<T> {
self.items.into_iter().flatten().collect()
}
pub fn iter(&self) -> impl Iterator<Item = Option<&T>> + '_ {
self.items.iter().map(|e| e.as_ref())
}
}
#[cfg(test)]
mod test {
use super::FixedSet;
#[derive(Eq, PartialEq, Clone, Debug, Default)]
struct Foo {
baz: String,
}
#[test]
fn zero_sized_fixed_set() {
let mut s = FixedSet::<usize>::new(0);
assert!(s.is_full(), "Set should be full");
assert!(!s.set_item(1, 1), "Should not be able to set item");
assert_eq!(s.get_item(0), None, "Should not return a value");
assert_eq!(s.sum(), Some(0));
}
fn data(s: &str) -> Foo {
match s {
"patrician" => Foo {
baz: "The Patrician".into(),
},
"rincewind" => Foo {
baz: "Rincewind".into(),
},
"vimes" => Foo {
baz: "Commander Vimes".into(),
},
"librarian" => Foo {
baz: "The Librarian".into(),
},
"carrot" => Foo {
baz: "Captain Carrot".into(),
},
_ => Foo { baz: "None".into() },
}
}
#[test]
fn small_set() {
let mut s = FixedSet::<Foo>::new(3);
assert!(!s.is_full());
assert!(s.set_item(1, data("patrician")));
assert!(!s.is_full());
assert!(s.set_item(0, data("vimes")));
assert!(!s.is_full());
assert!(s.set_item(1, data("rincewind")));
assert!(!s.is_full());
assert!(s.set_item(2, data("carrot")));
assert!(s.is_full());
assert!(!s.set_item(3, data("librarian")));
assert!(s.is_full());
s.clear_item(1);
assert!(!s.is_full());
assert_eq!(s.get_item(0).unwrap().baz, "Commander Vimes");
assert!(s.get_item(1).is_none());
assert_eq!(s.get_item(2).unwrap().baz, "Captain Carrot");
assert_eq!(s.size(), 3);
assert_eq!(s.search(&data("carrot")), Some(2));
assert_eq!(s.search(&data("vimes")), Some(0));
assert_eq!(s.search(&data("librarian")), None);
assert_eq!(s.search(&data("random")), None);
}
#[test]
fn sum_values() {
let mut s = FixedSet::<usize>::new(4);
s.set_item(0, 5);
assert_eq!(s.sum(), None);
s.set_item(1, 4);
assert_eq!(s.sum(), None);
s.set_item(2, 3);
assert_eq!(s.sum(), None);
s.set_item(3, 2);
assert_eq!(s.sum(), Some(14));
s.set_item(1, 0);
assert_eq!(s.sum(), Some(10));
}
#[test]
fn iterator() {
let mut s = FixedSet::<usize>::new(5);
s.set_item(0, 3);
s.set_item(3, 2);
s.set_item(1, 1);
let elems = s.iter().collect::<Vec<_>>();
assert_eq!(elems, vec![Some(&3), Some(&1), None, Some(&2), None]);
}
#[test]
fn into_vec() {
let mut s = FixedSet::<usize>::new(5);
s.set_item(1, 5);
s.set_item(3, 3);
assert_eq!(s.into_vec(), vec![5, 3]);
}
}