parent
af3a4deb62
commit
19da63e47f
@ -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…
Reference in new issue