1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
use std::collections::hash_map::Entry; use std::hash::Hash; use N; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct CellCoords(pub i32, pub i32); use fnv::{FnvHashMap}; use util::SmallSet; pub type CellContent<M> = SmallSet<[M; 4]>; pub trait GridShape { fn covered_cell_coords(&self, cell_width: N) -> Vec<CellCoords>; } #[derive(Clone)] pub struct Grid<M: Hash + Eq + Clone> { pub cell_width: N, cells: FnvHashMap<CellCoords, CellContent<M>>, pub min_bounds: CellCoords, pub max_bounds: CellCoords, } impl<M: Hash + Eq + Clone> Grid<M> { pub fn new(cell_width: N) -> Grid<M> { Grid { cell_width, cells: FnvHashMap::default(), min_bounds: CellCoords(0, 0), max_bounds: CellCoords(0, 0), } } pub fn insert_unchecked<S: GridShape>(&mut self, member: M, shape: &S) { for coords in shape.covered_cell_coords(self.cell_width) { match self.cells.entry(coords) { Entry::Vacant(vacant) => { let mut set = SmallSet::new(); set.insert(member.clone()); vacant.insert(set); } Entry::Occupied(mut occupied) => { occupied.into_mut().insert(member.clone()); } } self.min_bounds.0 = self.min_bounds.0.min(coords.0); self.min_bounds.1 = self.min_bounds.0.min(coords.1); self.max_bounds.0 = self.max_bounds.0.max(coords.0); self.max_bounds.1 = self.max_bounds.0.max(coords.1); } } pub fn insert_visiting<S: GridShape, F: FnMut(&CellContent<M>)>( &mut self, member: M, shape: &S, mut visitor: F, ) { for coords in shape.covered_cell_coords(self.cell_width) { match self.cells.entry(coords) { Entry::Vacant(vacant) => { let mut set = SmallSet::new(); set.insert(member.clone()); vacant.insert(set); } Entry::Occupied(mut occupied) => { visitor(occupied.get()); occupied.into_mut().insert(member.clone()); } } self.min_bounds.0 = self.min_bounds.0.min(coords.0); self.min_bounds.1 = self.min_bounds.0.min(coords.1); self.max_bounds.0 = self.max_bounds.0.max(coords.0); self.max_bounds.1 = self.max_bounds.0.max(coords.1); } } pub fn visit<S: GridShape, F: FnMut(&CellContent<M>)>(&self, shape: &S, mut visitor: F) { for coords in shape.covered_cell_coords(self.cell_width) { if let Some(content) = self.cells.get(&coords) { visitor(content); } } } pub fn retain<S: GridShape, F: FnMut(&mut M) -> bool>(&mut self, shape: S, mut predicate: F) { for coords in shape.covered_cell_coords(self.cell_width) { if let Entry::Occupied(mut occupied) = self.cells.entry(coords) { let remove = { let set = occupied.get_mut(); set.retain(&mut predicate); set.is_empty() }; if remove { occupied.remove(); } } } } }