use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap};
thread_local! {
static HOLES: RefCell<HashMap<String, BTreeSet<usize>>> = RefCell::new(HashMap::new());
}
pub fn clear(name: &str) {
HOLES.with(|h| {
h.borrow_mut().remove(name);
});
}
pub fn note_subscript_set(name: &str, old_len: usize, i: usize) {
HOLES.with(|h| {
let mut map = h.borrow_mut();
let set = map.entry(name.to_string()).or_default();
if i >= old_len {
for k in old_len..i {
set.insert(k);
}
}
set.remove(&i);
if set.is_empty() {
map.remove(name);
}
});
}
pub fn note_unset(name: &str, i: usize) {
HOLES.with(|h| {
h.borrow_mut().entry(name.to_string()).or_default().insert(i);
});
}
pub fn truncate(name: &str, new_len: usize) {
HOLES.with(|h| {
let mut map = h.borrow_mut();
if let Some(set) = map.get_mut(name) {
set.retain(|&k| k < new_len);
if set.is_empty() {
map.remove(name);
}
}
});
}
pub fn holes(name: &str) -> BTreeSet<usize> {
HOLES.with(|h| h.borrow().get(name).cloned().unwrap_or_default())
}
pub fn has_holes(name: &str) -> bool {
HOLES.with(|h| h.borrow().get(name).map_or(false, |s| !s.is_empty()))
}
pub fn live_indices(name: &str, len: usize) -> Vec<usize> {
let hs = holes(name);
(0..len).filter(|k| !hs.contains(k)).collect()
}
pub fn live_len(name: &str, dense_len: usize) -> usize {
HOLES.with(|h| match h.borrow().get(name) {
Some(set) => dense_len - set.iter().filter(|&&k| k < dense_len).count(),
None => dense_len,
})
}
pub fn compact(name: &str, dense: Vec<String>) -> Vec<String> {
let hs = holes(name);
if hs.is_empty() {
return dense;
}
dense
.into_iter()
.enumerate()
.filter(|(k, _)| !hs.contains(k))
.map(|(_, v)| v)
.collect()
}