Skip to content

Instantly share code, notes, and snippets.

@0e4ef622
Created December 7, 2019 09:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0e4ef622/61a57bc4bf137d0655ec7aa47c920291 to your computer and use it in GitHub Desktop.
Save 0e4ef622/61a57bc4bf137d0655ec7aa47c920291 to your computer and use it in GitHub Desktop.
intcode vm from aoc 2019
use std::collections::VecDeque;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Status {
Ready,
WaitingForInput,
Finished,
}
#[derive(Clone, Debug)]
pub struct Icvm {
program: Vec<isize>,
input: VecDeque<isize>,
output: VecDeque<isize>,
pc: usize,
status: Status,
}
impl Icvm {
pub fn new(program: Vec<isize>) -> Self {
Self {
program,
input: VecDeque::new(),
output: VecDeque::new(),
pc: 0,
status: Status::Ready,
}
}
pub fn run(&mut self) {
while self.status == Status::Ready {
self.step();
}
}
pub fn step(&mut self) {
OPS[self.program[self.pc] as usize]((
&mut self.program,
&mut self.pc,
&mut self.input,
&mut self.output,
&mut self.status,
));
}
pub unsafe fn run_unchecked(&mut self) {
while self.status == Status::Ready {
self.step_unchecked();
}
}
pub unsafe fn step_unchecked(&mut self) {
OPS.get_unchecked(*self.program.get_unchecked(self.pc) as usize)((
&mut self.program,
&mut self.pc,
&mut self.input,
&mut self.output,
&mut self.status,
));
}
pub fn pc(&self) -> usize {
self.pc
}
pub fn status(&self) -> Status {
self.status
}
pub fn program(&self) -> &[isize] {
&self.program
}
pub fn push_input(&mut self, i: isize) {
self.input.push_back(i);
if self.status == Status::WaitingForInput {
self.status = Status::Ready;
}
}
pub fn push_inputs<I>(&mut self, i: I)
where
I: IntoIterator<Item = isize>
{
self.input.extend(i);
if self.status == Status::WaitingForInput && !self.input.is_empty() {
self.status = Status::Ready;
}
}
pub fn pop_output(&mut self) -> Option<isize> {
self.output.pop_front()
}
pub fn outputs(&mut self) -> impl Iterator<Item = isize> + '_ {
self.output.drain(..)
}
}
type Op = fn((&mut [isize], &mut usize, &mut VecDeque<isize>, &mut VecDeque<isize>, &mut Status));
static OPS: [Op; 1109] = {
let mut ops: [Op; 1109] = [|(..)| unreachable!(); 1109];
ops[ 1] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[p[*c+1] as usize] + p[p[*c+2] as usize]; *c += 4; }) as Op;
ops[ 101] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[*c+1] + p[p[*c+2] as usize]; *c += 4; }) as Op;
ops[1001] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[p[*c+1] as usize] + p[*c+2]; *c += 4; }) as Op;
ops[1101] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[*c+1] + p[*c+2]; *c += 4; }) as Op;
ops[ 2] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[p[*c+1] as usize] * p[p[*c+2] as usize]; *c += 4; }) as Op;
ops[ 102] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[*c+1] * p[p[*c+2] as usize]; *c += 4; }) as Op;
ops[1002] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[p[*c+1] as usize] * p[*c+2]; *c += 4; }) as Op;
ops[1102] = (|(p, c, ..)| { p[p[*c+3] as usize] = p[*c+1] * p[*c+2]; *c += 4; }) as Op;
ops[ 3] = (|(p, c, i, _, s)| if let Some(x) = i.pop_front() { p[p[*c+1] as usize] = x; *c += 2; } else { *s = Status::WaitingForInput; }) as Op;
ops[ 4] = (|(p, c, _, o, _)| { o.push_back(p[p[*c+1] as usize]); *c += 2; }) as Op;
ops[ 104] = (|(p, c, _, o, _)| { o.push_back( p[*c+1] ); *c += 2; }) as Op;
ops[ 5] = (|(p, c, ..)| if p[p[*c+1] as usize] != 0 { *c = p[p[*c+2] as usize] as usize; } else { *c += 3; }) as Op;
ops[ 105] = (|(p, c, ..)| if p[*c+1] != 0 { *c = p[p[*c+2] as usize] as usize; } else { *c += 3; }) as Op;
ops[1005] = (|(p, c, ..)| if p[p[*c+1] as usize] != 0 { *c = p[*c+2] as usize; } else { *c += 3; }) as Op;
ops[1105] = (|(p, c, ..)| if p[*c+1] != 0 { *c = p[*c+2] as usize; } else { *c += 3; }) as Op;
ops[ 6] = (|(p, c, ..)| if p[p[*c+1] as usize] == 0 { *c = p[p[*c+2] as usize] as usize; } else { *c += 3; }) as Op;
ops[ 106] = (|(p, c, ..)| if p[*c+1] == 0 { *c = p[p[*c+2] as usize] as usize; } else { *c += 3; }) as Op;
ops[1006] = (|(p, c, ..)| if p[p[*c+1] as usize] == 0 { *c = p[*c+2] as usize; } else { *c += 3; }) as Op;
ops[1106] = (|(p, c, ..)| if p[*c+1] == 0 { *c = p[*c+2] as usize; } else { *c += 3; }) as Op;
ops[ 7] = (|(p, c, ..)| { p[p[*c+3] as usize] = (p[p[*c+1] as usize] < p[p[*c+2] as usize]) as isize; *c += 4; }) as Op;
ops[ 107] = (|(p, c, ..)| { p[p[*c+3] as usize] = ( p[*c+1] < p[p[*c+2] as usize]) as isize; *c += 4; }) as Op;
ops[1007] = (|(p, c, ..)| { p[p[*c+3] as usize] = (p[p[*c+1] as usize] < p[*c+2] ) as isize; *c += 4; }) as Op;
ops[1107] = (|(p, c, ..)| { p[p[*c+3] as usize] = ( p[*c+1] < p[*c+2] ) as isize; *c += 4; }) as Op;
ops[ 8] = (|(p, c, ..)| { p[p[*c+3] as usize] = (p[p[*c+1] as usize] == p[p[*c+2] as usize]) as isize; *c += 4; }) as Op;
ops[ 108] = (|(p, c, ..)| { p[p[*c+3] as usize] = ( p[*c+1] == p[p[*c+2] as usize]) as isize; *c += 4; }) as Op;
ops[1008] = (|(p, c, ..)| { p[p[*c+3] as usize] = (p[p[*c+1] as usize] == p[*c+2] ) as isize; *c += 4; }) as Op;
ops[1108] = (|(p, c, ..)| { p[p[*c+3] as usize] = ( p[*c+1] == p[*c+2] ) as isize; *c += 4; }) as Op;
ops[ 99] = (|(.., s)| { *s = Status::Finished; }) as Op;
ops
};
static UNSAFE_OPS: [Op; 1109] = {
let mut ops: [Op; 1109] = [|(..)| unreachable!(); 1109];
ops[ 1] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*p.get_unchecked(*c+1) as usize) + *p.get_unchecked(*p.get_unchecked(*c+2) as usize); *c += 4; }) as Op;
ops[ 101] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*c+1) + *p.get_unchecked(*p.get_unchecked(*c+2) as usize); *c += 4; }) as Op;
ops[1001] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*p.get_unchecked(*c+1) as usize) + *p.get_unchecked(*c+2); *c += 4; }) as Op;
ops[1101] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*c+1) + *p.get_unchecked(*c+2); *c += 4; }) as Op;
ops[ 2] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*p.get_unchecked(*c+1) as usize) * *p.get_unchecked(*p.get_unchecked(*c+2) as usize); *c += 4; }) as Op;
ops[ 102] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*c+1) * *p.get_unchecked(*p.get_unchecked(*c+2) as usize); *c += 4; }) as Op;
ops[1002] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*p.get_unchecked(*c+1) as usize) * *p.get_unchecked(*c+2); *c += 4; }) as Op;
ops[1102] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = *p.get_unchecked(*c+1) * *p.get_unchecked(*c+2); *c += 4; }) as Op;
ops[ 3] = (|(p, c, i, _, s)| unsafe { if let Some(x) = i.pop_front() { *p.get_unchecked_mut(*p.get_unchecked(*c+1) as usize) = x; *c += 2; } else { *s = Status::WaitingForInput; }}) as Op;
ops[ 4] = (|(p, c, _, o, _)| unsafe { o.push_back(*p.get_unchecked(*p.get_unchecked(*c+1) as usize)); *c += 2; }) as Op;
ops[ 104] = (|(p, c, _, o, _)| unsafe { o.push_back( *p.get_unchecked(*c+1) ); *c += 2; }) as Op;
ops[ 5] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*p.get_unchecked(*c+1) as usize) != 0 { *c = *p.get_unchecked(*p.get_unchecked(*c+2) as usize) as usize; } else { *c += 3; }}) as Op;
ops[ 105] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*c+1) != 0 { *c = *p.get_unchecked(*p.get_unchecked(*c+2) as usize) as usize; } else { *c += 3; }}) as Op;
ops[1005] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*p.get_unchecked(*c+1) as usize) != 0 { *c = *p.get_unchecked(*c+2) as usize; } else { *c += 3; }}) as Op;
ops[1105] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*c+1) != 0 { *c = *p.get_unchecked(*c+2) as usize; } else { *c += 3; }}) as Op;
ops[ 6] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*p.get_unchecked(*c+1) as usize) == 0 { *c = *p.get_unchecked(*p.get_unchecked(*c+2) as usize) as usize; } else { *c += 3; }}) as Op;
ops[ 106] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*c+1) == 0 { *c = *p.get_unchecked(*p.get_unchecked(*c+2) as usize) as usize; } else { *c += 3; }}) as Op;
ops[1006] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*p.get_unchecked(*c+1) as usize) == 0 { *c = *p.get_unchecked(*c+2) as usize; } else { *c += 3; }}) as Op;
ops[1106] = (|(p, c, ..)| unsafe { if *p.get_unchecked(*c+1) == 0 { *c = *p.get_unchecked(*c+2) as usize; } else { *c += 3; }}) as Op;
ops[ 7] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = (*p.get_unchecked(*p.get_unchecked(*c+1) as usize) < *p.get_unchecked(*p.get_unchecked(*c+2) as usize)) as isize; *c += 4; }) as Op;
ops[ 107] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = ( *p.get_unchecked(*c+1) < *p.get_unchecked(*p.get_unchecked(*c+2) as usize)) as isize; *c += 4; }) as Op;
ops[1007] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = (*p.get_unchecked(*p.get_unchecked(*c+1) as usize) < *p.get_unchecked(*c+2) ) as isize; *c += 4; }) as Op;
ops[1107] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = ( *p.get_unchecked(*c+1) < *p.get_unchecked(*c+2) ) as isize; *c += 4; }) as Op;
ops[ 8] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = (*p.get_unchecked(*p.get_unchecked(*c+1) as usize) == *p.get_unchecked(*p.get_unchecked(*c+2) as usize)) as isize; *c += 4; }) as Op;
ops[ 108] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = ( *p.get_unchecked(*c+1) == *p.get_unchecked(*p.get_unchecked(*c+2) as usize)) as isize; *c += 4; }) as Op;
ops[1008] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = (*p.get_unchecked(*p.get_unchecked(*c+1) as usize) == *p.get_unchecked(*c+2) ) as isize; *c += 4; }) as Op;
ops[1108] = (|(p, c, ..)| unsafe { *p.get_unchecked_mut(*p.get_unchecked(*c+3) as usize) = ( *p.get_unchecked(*c+1) == *p.get_unchecked(*c+2) ) as isize; *c += 4; }) as Op;
ops[ 99] = (|(.., s)| { *s = Status::Finished; }) as Op;
ops
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment