day10: part2

master
Avril 4 years ago
parent af3a4deb62
commit 19da63e47f
Signed by: flanchan
GPG Key ID: 284488987C31F630

2
.gitignore vendored

@ -9,4 +9,4 @@ target/
*.gcda *.gcda
# Specific days # Specific days
!day10/src/input.rs !day10/src/*.rs

@ -8,10 +8,12 @@ edition = "2018"
[features] [features]
part2=[] part2=["num_cpus", "semaphore"]
test = [] test = []
[dependencies] [dependencies]
ad-hoc-iter = "0.2.2" ad-hoc-iter = "0.2.2"
cfg-if = "1.0.0" cfg-if = "1.0.0"
num_cpus = {version = "1.13.0", optional = true}
semaphore = {version = "0.4.0", optional = true}
smallmap = "1.2.1" smallmap = "1.2.1"

@ -0,0 +1,136 @@
use super::*;
use std::{
sync::{
Arc,
RwLock,
},
thread,
};
use semaphore::Semaphore;
#[derive(Debug)]
pub struct Cache(RwLock<Map<NonZeroU8, usize>>);
impl Cache
{
pub fn new() -> Self
{
Self(RwLock::new(Map::new()))
}
pub fn get_or_insert_with_owned<F>(self: Arc<Self>, key: u8, with: F) -> usize
where F: FnOnce() -> usize
{
match Arc::try_unwrap(self)
{
Ok(this) => {
debug_assert!(key>0);
let key = unsafe {NonZeroU8::new_unchecked(key)};
let map = this.0.into_inner().unwrap();
if let Some(&value) = map.get(&key) {
value
} else {
// No need to insert, the cache will be dropped after this
with()
}
},
Err(this) => this.get_or_insert_with(key, with)
}
}
#[inline] pub fn insert(&self, key: u8, value: usize) -> usize
{
debug_assert!(key>0);
let key = unsafe {NonZeroU8::new_unchecked(key)};
self.0.write().unwrap().insert(key, value);
value
}
pub fn get(&self, key: u8) -> Option<usize>
{
debug_assert!(key>0);
let key = unsafe {NonZeroU8::new_unchecked(key)};
self.0.read().unwrap().get(&key).copied()
}
pub fn get_or_insert_with<F>(&self, key: u8, with: F) -> usize
where F: FnOnce() -> usize
{
debug_assert!(key>0);
let key = unsafe {NonZeroU8::new_unchecked(key)};
{
let read = self.0.read().unwrap();
if let Some(&value) = read.get(&key) {
return value;
}
}
// Insert needed
{
let value = with();
let mut lock = self.0.write().unwrap();
lock.insert(key, value);
value
}
}
}
#[derive(Debug)]
enum Deffered
{
Known(usize),
Yielded(thread::JoinHandle<usize>),
}
impl Deffered
{
#[inline] pub fn into_value(self) -> usize
{
match self {
Self::Known(v) => v,
Self::Yielded(v) => v.join().unwrap(),
}
}
}
fn rec_part2(map: Arc<Adaptors>, cache: Arc<Cache>, lock: Semaphore<()>, max: u8, f: u8) -> usize
{
if f == max {
return 1;
}
debug_assert!(f < max);
match iterate_adaptor_chain(&map, None, f).map(|next| {
if next == max {
Deffered::Known(1)
} else {
match cache.get(next) {
Some(value) => Deffered::Known(value),
None => {
let map = Arc::clone(&map);
let cache = Arc::clone(&cache);
let lock = lock.clone();
if let Ok(_guard) = lock.try_access() {
Deffered::Yielded(thread::spawn(move || {
cache.clone().insert(next, rec_part2(map, cache, lock, max, next))
}))
} else {
Deffered::Known(cache.clone().insert(next, rec_part2(map, cache, lock, max, next)))
}
}
}
}
}).map(Deffered::into_value)
.sum::<usize>() {
#[cold] 0 => panic!("eh"),
x => x,
}
}
fn gensem() -> Semaphore<()>
{
Semaphore::new(num_cpus::get()+1, ())
}
#[inline] pub fn solve(a: Adaptors, max: u8) -> usize
{
rec_part2(Arc::new(a), Arc::new(Cache::new()), gensem(), max, 0)
}
Loading…
Cancel
Save