use crate::{Index, competitor::Competitor, drift::Drift, time::Time}; /// Dense Vec-backed store for competitor state in History. /// /// Indexed directly by Index.0, eliminating HashMap hashing in the /// forward/backward sweep. Uses `Vec>>` so slots can be /// absent without an explicit present mask. #[derive(Debug)] pub struct CompetitorStore = crate::drift::ConstantDrift> { competitors: Vec>>, n_present: usize, } impl> Default for CompetitorStore { fn default() -> Self { Self { competitors: Vec::new(), n_present: 0, } } } impl> CompetitorStore { pub fn new() -> Self { Self::default() } fn ensure_capacity(&mut self, idx: usize) { if idx >= self.competitors.len() { self.competitors.resize_with(idx + 1, || None); } } pub fn insert(&mut self, idx: Index, competitor: Competitor) { self.ensure_capacity(idx.0); if self.competitors[idx.0].is_none() { self.n_present += 1; } self.competitors[idx.0] = Some(competitor); } pub fn get(&self, idx: Index) -> Option<&Competitor> { self.competitors.get(idx.0).and_then(|slot| slot.as_ref()) } pub fn get_mut(&mut self, idx: Index) -> Option<&mut Competitor> { self.competitors .get_mut(idx.0) .and_then(|slot| slot.as_mut()) } pub fn contains(&self, idx: Index) -> bool { self.get(idx).is_some() } pub fn len(&self) -> usize { self.n_present } pub fn is_empty(&self) -> bool { self.n_present == 0 } pub fn iter(&self) -> impl Iterator)> { self.competitors .iter() .enumerate() .filter_map(|(i, slot)| slot.as_ref().map(|a| (Index(i), a))) } pub fn iter_mut(&mut self) -> impl Iterator)> { self.competitors .iter_mut() .enumerate() .filter_map(|(i, slot)| slot.as_mut().map(|a| (Index(i), a))) } pub fn values_mut(&mut self) -> impl Iterator> { self.competitors.iter_mut().filter_map(|s| s.as_mut()) } } impl> std::ops::Index for CompetitorStore { type Output = Competitor; fn index(&self, idx: Index) -> &Competitor { self.get(idx).expect("competitor not found at index") } } impl> std::ops::IndexMut for CompetitorStore { fn index_mut(&mut self, idx: Index) -> &mut Competitor { self.get_mut(idx).expect("competitor not found at index") } } #[cfg(test)] mod tests { use super::*; use crate::{competitor::Competitor, drift::ConstantDrift}; #[test] fn insert_then_get() { let mut store: CompetitorStore = CompetitorStore::new(); let idx = Index(7); store.insert(idx, Competitor::default()); assert!(store.contains(idx)); assert_eq!(store.len(), 1); assert!(store.get(idx).is_some()); } #[test] fn iter_in_index_order() { let mut store: CompetitorStore = CompetitorStore::new(); store.insert(Index(2), Competitor::default()); store.insert(Index(0), Competitor::default()); store.insert(Index(5), Competitor::default()); let keys: Vec = store.iter().map(|(i, _)| i).collect(); assert_eq!(keys, vec![Index(0), Index(2), Index(5)]); } #[test] fn index_operator_works() { let mut store: CompetitorStore = CompetitorStore::new(); store.insert(Index(3), Competitor::default()); let _ = &store[Index(3)]; } }