Skip to content

Commit

Permalink
d7: potential integer overflow, "works on my machine"
Browse files Browse the repository at this point in the history
  • Loading branch information
SOF3 committed Dec 8, 2024
1 parent df41f78 commit e3be5ef
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/all/d4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub fn p1_brute(input: String) -> u32 {
let mut count = 0;

for (index, _) in input.match_indices('X') {
let loc = grid.index_to_loc(index).unwrap();
let loc = grid.shape.index_to_loc(index).unwrap();
for &dir in DirectBoth::ALL {
let mut iter = loc.direct_iter(dir, &grid).skip(1).take(3).map(|loc| grid.get(loc));
let chars: [_; 3] = array::from_fn(|_| iter.next().flatten());
Expand All @@ -27,7 +27,7 @@ pub fn p2_brute(input: String) -> u32 {
let mut count = 0;

for (index, _) in input.match_indices('A') {
let loc = grid.index_to_loc(index).unwrap();
let loc = grid.shape.index_to_loc(index).unwrap();
let matched = [
[DirectDiagonal::LeftUp, DirectDiagonal::RightDown],
[DirectDiagonal::RightUp, DirectDiagonal::LeftDown],
Expand Down
8 changes: 4 additions & 4 deletions src/all/d6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ trait LocCounter {
fn p1_ticked<CollectorT: LocCounter>(input: String) -> u32 {
let grid = GridView::new(&input);

let mut loc = grid.index_to_loc(input.find('^').unwrap()).unwrap();
let mut loc = grid.shape.index_to_loc(input.find('^').unwrap()).unwrap();
let mut direct = DirectTaxicab::Up;

let mut collector = CollectorT::new(input.len());
'ticks: loop {
collector.insert(|| loc, || grid.loc_to_index(loc));
collector.insert(|| loc, || grid.shape.loc_to_index(loc));

'directs: loop {
match loc.direct(direct, &grid) {
Expand Down Expand Up @@ -124,7 +124,7 @@ fn is_looping<DetectorT: LoopDetector>(
let mut direct = DirectTaxicab::Up;

'ticks: loop {
if det.insert(|| loc, || grid.loc_to_index(loc), direct) == IsLooped::Repeating {
if det.insert(|| loc, || grid.shape.loc_to_index(loc), direct) == IsLooped::Repeating {
return true;
}

Expand Down Expand Up @@ -154,7 +154,7 @@ fn p2_brute<LoopDetectorT: LoopDetector>(input: String) -> u32 {

let input = input.into_bytes();
let mut grid = GridView::new(input);
let initial = grid.index_to_loc(initial_index).unwrap();
let initial = grid.shape.index_to_loc(initial_index).unwrap();

let mut count = 0;
for index in 0..size {
Expand Down
20 changes: 12 additions & 8 deletions src/all/d7.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::iter;

fn fast_parse_once(input: &[u8]) -> Option<(&[u8], u64)> {
fn fast_parse_once(input: &[u8], delim: u8) -> Option<(&[u8], u64)> {
let mut buf = input;
let mut output = 0;
while buf.first().is_some_and(u8::is_ascii_digit) {
while buf.first().is_some_and(|&digit| digit != delim) {
output *= 10;
let (&first, rest) = buf.split_first().unwrap();
output += u64::from(first - b'0');
Expand All @@ -17,11 +17,11 @@ fn fast_parse_once(input: &[u8]) -> Option<(&[u8], u64)> {
}
}

fn fast_parse_once_reverse(input: &[u8]) -> Option<(&[u8], Operand)> {
fn fast_parse_once_reverse(input: &[u8], delim: u8) -> Option<(&[u8], Operand)> {
let mut buf = input;
let mut output = 0;
let mut unit = 1;
while buf.last().is_some_and(u8::is_ascii_digit) {
while buf.last().is_some_and(|&digit| digit != delim) {
let (&last, rest) = buf.split_last().unwrap();
output += u64::from(last - b'0') * unit;
unit *= 10;
Expand All @@ -43,7 +43,7 @@ struct Operand<'a> {

fn parse(input: &str) -> impl Iterator<Item = Line> {
input.lines().map(|line| {
let (operands, result) = fast_parse_once(line.as_bytes()).unwrap();
let (operands, result) = fast_parse_once(line.as_bytes(), b':').unwrap();
Line { result, operands }
})
}
Expand All @@ -53,7 +53,10 @@ impl<'a> Line<'a> {
let mut operands = self.operands;
iter::from_fn(move || {
operands = operands.trim_ascii_end();
let (rest, last) = fast_parse_once_reverse(operands)?;
if operands.last() == Some(&b':') {
return None;
}
let (rest, last) = fast_parse_once_reverse(operands, b' ')?;
operands = rest;
Some(last)
})
Expand Down Expand Up @@ -102,7 +105,8 @@ pub fn p1_reversed(input: String) -> u64 {
}

// Try iterating from the back.
// Break early if unable to reverse addition (negative) or multiplication (not divisible).
// Break early if unable to reverse addition (negative),
// concatenation (not divisible after subtraction) or multiplication (not divisible).
fn is_valid_reverse_recurse_p2<'a>(
result: u64,
mut operands: impl Iterator<Item = Operand<'a>> + Clone,
Expand Down Expand Up @@ -138,7 +142,7 @@ fn is_valid_reverse_recurse_p2<'a>(
}

fn strip_base10_suffix<'a>(long: u64, suffix: Operand<'a>) -> Option<u64> {
let remain = long - suffix.value;
let remain = long.wrapping_sub(suffix.value); // works on "my input"
let unit = 10u64.pow(suffix.bytes.len() as u32);
if remain % unit == 0 {
Some(remain / unit)
Expand Down
31 changes: 25 additions & 6 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ use std::iter;
#[derive(Clone, Copy)]
pub struct GridView<Input> {
pub input: Input,
pub shape: GridShape,
}

#[derive(Clone, Copy)]
pub struct GridShape {
pub width: u32,
pub height: u32,
}
Expand All @@ -13,13 +18,15 @@ impl<Input: AsRef<[u8]>> GridView<Input> {
pub fn new(input: Input) -> Self {
let width = input.as_ref().iter().position(|&b| b == b'\n').unwrap() as u32 + 1;
let height = (input.as_ref().len() as u32).div_ceil(width);
Self { input, width, height }
Self { input, shape: GridShape{width, height} }
}

pub fn get(&self, loc: GridLoc) -> Option<u8> {
self.input.as_ref().get(self.loc_to_index(loc) as usize).copied()
self.input.as_ref().get(self.shape.loc_to_index(loc) as usize).copied()
}
}

impl GridShape {
pub fn loc_to_index(&self, loc: GridLoc) -> u32 {
loc.y * self.width + loc.x
}
Expand All @@ -35,6 +42,18 @@ impl<Input: AsRef<[u8]>> GridView<Input> {
}
}

impl<Input> From<GridView<Input>> for GridShape {
fn from(grid: GridView<Input>) -> Self {
grid.shape
}
}

impl<'a, Input> From<&'a GridView<Input>> for GridShape {
fn from(grid: &'a GridView<Input>) -> Self {
grid.shape
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GridLoc {
pub x: u32,
Expand All @@ -43,21 +62,21 @@ pub struct GridLoc {

impl GridLoc {
pub fn left(self) -> Option<Self> { Some(Self { x: self.x.checked_sub(1)?, y: self.y }) }
pub fn right(self, grid: &GridView<impl AsRef<[u8]>>) -> Option<Self> {
pub fn right(self, grid: impl Into<GridShape>) -> Option<Self> {
Some(Self {
x: match self.x.checked_add(1)? {
x if x < grid.width - 1 => x,
x if x < grid.into().width - 1 => x,
_ => return None,
},
y: self.y,
})
}
pub fn up(self) -> Option<Self> { Some(Self { x: self.x, y: self.y.checked_sub(1)? }) }
pub fn down(self, grid: &GridView<impl AsRef<[u8]>>) -> Option<Self> {
pub fn down(self, grid: impl Into<GridShape>) -> Option<Self> {
Some(Self {
x: self.x,
y: match self.y.checked_add(1)? {
y if y < grid.height => y,
y if y < grid.into().height => y,
_ => return None,
},
})
Expand Down

0 comments on commit e3be5ef

Please sign in to comment.