use crate::{GetNeighbors, Sim, TakeDiff, TakeMoveNeighbors};
use rayon::iter::IndexedParallelIterator;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
use std::mem::transmute_copy;
use std::mem::ManuallyDrop;
#[derive(Clone, Debug)]
pub struct SquareGrid<'a, S: Sim<'a>> {
pub(crate) cells: Vec<S::Cell>,
diffs: Vec<ManuallyDrop<(S::Diff, S::MoveNeighbors)>>,
width: usize,
height: usize,
}
impl<'a, S: Sim<'a>> TakeMoveNeighbors<usize, ()> for SquareGrid<'a, S> {
#[inline]
unsafe fn take_move_neighbors(&self, _: usize) {}
}
impl<'a, S, D> TakeDiff<usize, D> for SquareGrid<'a, S>
where
S: Sim<'a, Diff = D>,
{
#[inline]
unsafe fn take_diff(&self, ix: usize) -> D {
transmute_copy(self.get_diff(ix))
}
}
impl<'a, S: Sim<'a>> SquareGrid<'a, S> {
pub fn new(width: usize, height: usize) -> Self
where
S::Cell: Default,
{
SquareGrid {
cells: (0..)
.take(width * height)
.map(|_| S::Cell::default())
.collect(),
diffs: Vec::new(),
width,
height,
}
}
pub fn new_default(width: usize, height: usize, default: S::Cell) -> Self
where
S::Cell: Clone,
{
SquareGrid {
cells: ::std::iter::repeat(default).take(width * height).collect(),
diffs: Vec::new(),
width,
height,
}
}
pub fn new_iter<I>(width: usize, height: usize, iter: I) -> Self
where
I: IntoIterator<Item = S::Cell>,
{
let cells: Vec<_> = iter.into_iter().take(width * height).collect();
assert_eq!(
cells.len(),
width * height,
"gridsim::Grid::new_iter: not enough cells provided in iter"
);
SquareGrid {
cells,
diffs: Vec::new(),
width,
height,
}
}
pub fn new_coord_map<F>(width: usize, height: usize, mut coord_map: F) -> Self
where
F: FnMut(isize, isize) -> S::Cell,
{
Self::new_iter(
width,
height,
(0..height)
.flat_map(|y| (0..width).map(move |x| (x, y)))
.map(move |(x, y)| {
coord_map(
x as isize - width as isize / 2,
y as isize - height as isize / 2,
)
}),
)
}
pub fn new_coords<I>(width: usize, height: usize, coords: I) -> Self
where
I: IntoIterator<Item = ((isize, isize), S::Cell)>,
S::Cell: Default,
{
use std::collections::HashMap;
let coords: &mut HashMap<(isize, isize), S::Cell> = &mut coords.into_iter().collect();
Self::new_coord_map(width, height, |x, y| {
coords.remove(&(x, y)).unwrap_or_default()
})
}
pub fn new_true_coords<I>(width: usize, height: usize, coords: I) -> Self
where
I: IntoIterator<Item = (isize, isize)>,
S: Sim<'a, Cell = bool>,
{
Self::new_coords(width, height, coords.into_iter().map(|c| (c, true)))
}
#[inline]
pub fn delta_index(&self, i: usize, delta: (isize, isize)) -> usize {
let x = delta.0;
let y = delta.1;
((i + self.size()) as isize + x + y * self.width as isize) as usize % self.size()
}
#[inline]
pub fn get_cell(&self, i: usize) -> &S::Cell {
&self.cells[i]
}
#[inline]
pub fn get_cell_at(&self, x: usize, y: usize) -> &S::Cell {
&self.cells[y * self.height + x]
}
#[inline]
pub unsafe fn get_cell_unchecked(&self, i: usize) -> &S::Cell {
self.cells.get_unchecked(i)
}
#[inline]
pub fn get_cell_mut(&mut self, i: usize) -> &mut S::Cell {
&mut self.cells[i]
}
#[inline]
pub fn get_cell_at_mut(&mut self, x: usize, y: usize) -> &mut S::Cell {
&mut self.cells[y * self.height + x]
}
#[inline]
pub unsafe fn get_move_neighbors(&self, i: usize) -> &S::MoveNeighbors {
&self.diffs.get_unchecked(i).1
}
#[inline]
pub unsafe fn get_diff(&self, i: usize) -> &S::Diff {
&self.diffs.get_unchecked(i).0
}
#[inline]
pub fn get_cells(&self) -> &[S::Cell] {
&self.cells[..]
}
#[inline]
pub fn get_cells_mut(&mut self) -> &mut [S::Cell] {
&mut self.cells[..]
}
#[inline]
pub fn get_width(&self) -> usize {
self.width
}
#[inline]
pub fn get_height(&self) -> usize {
self.height
}
#[inline]
pub fn size(&self) -> usize {
self.width * self.height
}
}
impl<'a, S, C, D, M, N, MN> SquareGrid<'a, S>
where
S: Sim<'a, Cell = C, Diff = D, Move = M, Neighbors = N, MoveNeighbors = MN> + 'a,
S::Cell: Sync + Send,
S::Diff: Sync + Send,
S::Move: Sync + Send,
S::Neighbors: Sync + Send,
S::MoveNeighbors: Sync + Send,
Self: GetNeighbors<'a, usize, N>,
Self: TakeMoveNeighbors<usize, MN>,
{
pub fn cycle(&mut self) {
self.step();
self.update();
}
pub(crate) fn step(&mut self) {
self.diffs = self.cells[..]
.par_iter()
.enumerate()
.map(|(ix, c)| self.single_step(ix, c))
.map(ManuallyDrop::new)
.collect();
}
#[inline]
fn single_step(&self, ix: usize, c: &C) -> (S::Diff, S::MoveNeighbors) {
let grid = unsafe { &*(self as *const Self) };
S::step(c, grid.get_neighbors(ix))
}
pub(crate) fn update(&mut self) {
self.cells[..]
.par_iter()
.enumerate()
.for_each(|(ix, cell)| unsafe {
S::update(
&mut *(cell as *const C as *mut C),
self.take_diff(ix),
(self as &Self).take_move_neighbors(ix),
);
});
self.diffs.clear();
}
}