Use a single HashMap with the entry API and a KeyedJobTask enum for KeyedJobs.

This commit is contained in:
Avi Weinstock 2021-05-31 12:04:18 -04:00
parent 6d3dcc3835
commit 8b21ed540c

View File

@ -48,7 +48,7 @@ use conrod_core::{
}; };
use core::{convert::TryInto, f32, f64, ops::Range}; use core::{convert::TryInto, f32, f64, ops::Range};
use graphic::TexId; use graphic::TexId;
use hashbrown::{hash_map::Entry, HashMap, HashSet}; use hashbrown::{hash_map::Entry, HashMap};
use std::{hash::Hash, time::Duration}; use std::{hash::Hash, time::Duration};
use tracing::{error, warn}; use tracing::{error, warn};
use vek::*; use vek::*;
@ -1055,11 +1055,15 @@ fn default_scissor(renderer: &Renderer) -> Aabr<u16> {
} }
} }
enum KeyedJobTask<V> {
Pending,
Completed(V),
}
pub struct KeyedJobs<K, V> { pub struct KeyedJobs<K, V> {
tx: crossbeam_channel::Sender<(K, V)>, tx: crossbeam_channel::Sender<(K, V)>,
rx: crossbeam_channel::Receiver<(K, V)>, rx: crossbeam_channel::Receiver<(K, V)>,
completed: HashMap<K, V>, tasks: HashMap<K, KeyedJobTask<V>>,
pending: HashSet<K>,
} }
impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> KeyedJobs<K, V> { impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> KeyedJobs<K, V> {
@ -1069,8 +1073,7 @@ impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> Key
Self { Self {
tx, tx,
rx, rx,
completed: HashMap::new(), tasks: HashMap::new(),
pending: HashSet::new(),
} }
} }
@ -1081,26 +1084,35 @@ impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> Key
f: impl FnOnce(&K) -> V + Send + Sync + 'static, f: impl FnOnce(&K) -> V + Send + Sync + 'static,
) -> Option<(K, V)> { ) -> Option<(K, V)> {
if let Some(pool) = pool { if let Some(pool) = pool {
if let Some(v) = self.completed.remove(&k) { while let Ok((k2, v)) = self.rx.try_recv() {
Some((k, v)) if k == k2 {
} else { return Some((k, v));
while let Ok((k2, v)) = self.rx.try_recv() { } else {
self.pending.remove(&k2); self.tasks.insert(k2, KeyedJobTask::Completed(v));
if k == k2 {
return Some((k, v));
} else {
self.completed.insert(k2, v);
}
} }
if !self.pending.contains(&k) { }
self.pending.insert(k.clone()); match self.tasks.entry(k.clone()) {
Entry::Occupied(e) => {
let mut ret = None;
e.replace_entry_with(|_, v| {
if let KeyedJobTask::Completed(v) = v {
ret = Some((k, v));
None
} else {
Some(v)
}
});
ret
},
Entry::Vacant(e) => {
let tx = self.tx.clone(); let tx = self.tx.clone();
pool.spawn("IMAGE_PROCESSING", move || { pool.spawn("IMAGE_PROCESSING", move || {
let v = f(&k); let v = f(&k);
let _ = tx.send((k, v)); let _ = tx.send((k, v));
}); });
} e.insert(KeyedJobTask::Pending);
None None
},
} }
} else { } else {
let v = f(&k); let v = f(&k);