mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-26 21:30:31 +01:00
Merge owned and non-owned grids
Through the power of generics. Should've been easier if it was possible to be generic over mutable and non-mutable, but AsRef/AsMut is close enough
This commit is contained in:
@@ -244,20 +244,22 @@ impl IndexMut<usize> for Vec2 {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Grid<'a> {
|
||||
#[derive(PartialEq)]
|
||||
pub struct Grid<T: AsRef<[u8]>> {
|
||||
width: usize,
|
||||
data: &'a [u8],
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<'a> Grid<'a> {
|
||||
pub fn new(data: &'a [u8]) -> anyhow::Result<Self> {
|
||||
impl<T: AsRef<[u8]>> Grid<T> {
|
||||
pub fn new(data: T) -> anyhow::Result<Self> {
|
||||
let width = 1 + data
|
||||
.as_ref()
|
||||
.iter()
|
||||
.position(|&c| c == b'\n')
|
||||
.context("Failed to find end of line in grid")?;
|
||||
|
||||
anyhow::ensure!(
|
||||
data.len() % width == 0,
|
||||
data.as_ref().len() % width == 0,
|
||||
"Grid should divide equally into rows"
|
||||
);
|
||||
|
||||
@@ -265,65 +267,7 @@ impl<'a> Grid<'a> {
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
self.data.len() / self.width
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.width - 1
|
||||
}
|
||||
|
||||
pub fn rows(&self) -> impl Iterator<Item = &'a [u8]> {
|
||||
let width = self.width();
|
||||
self.data
|
||||
.chunks_exact(self.width)
|
||||
.map(move |row| &row[..width])
|
||||
}
|
||||
|
||||
pub fn find(&self, c: u8) -> Option<(usize, usize)> {
|
||||
let pos = self.data.iter().position(|&d| d == c)?;
|
||||
|
||||
Some((pos % self.width, pos / self.width))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Index<usize> for Grid<'a> {
|
||||
type Output = [u8];
|
||||
|
||||
fn index(&self, y: usize) -> &Self::Output {
|
||||
let offset = y * self.width;
|
||||
&self.data[offset..(offset + self.width())]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Grid<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", String::from_utf8_lossy(self.data))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: merge OwnedGrid and Grid impls so I don't go insane
|
||||
pub struct OwnedGrid {
|
||||
width: usize,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl OwnedGrid {
|
||||
pub fn new(data: Vec<u8>) -> anyhow::Result<Self> {
|
||||
let width = 1 + data
|
||||
.iter()
|
||||
.position(|&c| c == b'\n')
|
||||
.context("Failed to find end of line in grid")?;
|
||||
|
||||
anyhow::ensure!(
|
||||
data.len() % width == 0,
|
||||
"Grid should divide equally into rows"
|
||||
);
|
||||
|
||||
Ok(Self { width, data })
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
self.data.len() / self.width
|
||||
self.data.as_ref().len() / self.width
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
@@ -333,59 +277,48 @@ impl OwnedGrid {
|
||||
pub fn rows(&self) -> impl Iterator<Item = &[u8]> {
|
||||
let width = self.width();
|
||||
self.data
|
||||
.as_ref()
|
||||
.chunks_exact(self.width)
|
||||
.map(move |row| &row[..width])
|
||||
}
|
||||
|
||||
pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [u8]> {
|
||||
let width = self.width();
|
||||
self.data
|
||||
.chunks_exact_mut(self.width)
|
||||
.map(move |row| &mut row[..width])
|
||||
}
|
||||
|
||||
pub fn find(&self, c: u8) -> Option<(usize, usize)> {
|
||||
let pos = self.data.iter().position(|&d| d == c)?;
|
||||
let pos = self.data.as_ref().iter().position(|&d| d == c)?;
|
||||
|
||||
Some((pos % self.width, pos / self.width))
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for OwnedGrid {
|
||||
impl<T: AsMut<[u8]> + AsRef<[u8]>> Grid<T> {
|
||||
pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [u8]> {
|
||||
let width = self.width();
|
||||
self.data
|
||||
.as_mut()
|
||||
.chunks_exact_mut(self.width)
|
||||
.map(move |row| &mut row[..width])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> Index<usize> for Grid<T> {
|
||||
type Output = [u8];
|
||||
|
||||
fn index(&self, y: usize) -> &Self::Output {
|
||||
let offset = y * self.width;
|
||||
&self.data[offset..(offset + self.width())]
|
||||
&self.data.as_ref()[offset..(offset + self.width())]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for OwnedGrid {
|
||||
fn index_mut(&mut self, y: usize) -> &mut Self::Output {
|
||||
let offset = y * self.width;
|
||||
let width = self.width;
|
||||
&mut self.data[offset..(offset + width)]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for OwnedGrid {
|
||||
impl<T: AsRef<[u8]>> Display for Grid<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", String::from_utf8_lossy(&self.data))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<OwnedGrid> for OwnedGrid {
|
||||
fn eq(&self, other: &OwnedGrid) -> bool {
|
||||
// No need to compare width as width is a function of data
|
||||
self.data == other.data
|
||||
write!(f, "{}", String::from_utf8_lossy(self.data.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Clone impl so we don't allocate in `clone_from`
|
||||
impl Clone for OwnedGrid {
|
||||
impl<T: AsRef<[u8]> + Clone> Clone for Grid<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
width: self.width.clone(),
|
||||
width: self.width,
|
||||
data: self.data.clone(),
|
||||
}
|
||||
}
|
||||
@@ -395,3 +328,11 @@ impl Clone for OwnedGrid {
|
||||
self.data.clone_from(&source.data);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsMut<[u8]> + AsRef<[u8]>> IndexMut<usize> for Grid<T> {
|
||||
fn index_mut(&mut self, y: usize) -> &mut Self::Output {
|
||||
let offset = y * self.width;
|
||||
let width = self.width;
|
||||
&mut self.data.as_mut()[offset..(offset + width)]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user