Review feedback: bitvec: struct-like enum variants, and factor out one-item cache.

This commit is contained in:
Chris Fallin
2021-08-12 14:33:35 -07:00
parent 7652b4b109
commit 82b7e6ba7b

View File

@@ -21,35 +21,37 @@ const SMALL_ELEMS: usize = 12;
/// cache to allow fast access when streaming through. /// cache to allow fast access when streaming through.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum AdaptiveMap { enum AdaptiveMap {
Small( Small {
u32, len: u32,
[u32; SMALL_ELEMS], keys: [u32; SMALL_ELEMS],
[u64; SMALL_ELEMS], values: [u64; SMALL_ELEMS],
Cell<(u32, u64)>, },
), Large(FxHashMap<u32, u64>),
Large(FxHashMap<u32, u64>, Cell<(u32, u64)>),
} }
const INVALID: u32 = 0xffff_ffff; const INVALID: u32 = 0xffff_ffff;
impl AdaptiveMap { impl AdaptiveMap {
fn new() -> Self { fn new() -> Self {
Self::Small( Self::Small {
0, len: 0,
[INVALID; SMALL_ELEMS], keys: [INVALID; SMALL_ELEMS],
[0; SMALL_ELEMS], values: [0; SMALL_ELEMS],
Cell::new((INVALID, 0)), }
)
} }
#[inline(never)] #[inline(never)]
fn expand(&mut self) { fn expand(&mut self) {
match self { match self {
&mut Self::Small(len, ref keys, ref values, ref cache) => { &mut Self::Small {
len,
ref keys,
ref values,
} => {
let mut map = FxHashMap::default(); let mut map = FxHashMap::default();
for i in 0..len { for i in 0..len {
map.insert(keys[i as usize], values[i as usize]); map.insert(keys[i as usize], values[i as usize]);
} }
*self = Self::Large(map, cache.clone()); *self = Self::Large(map);
} }
_ => {} _ => {}
} }
@@ -57,7 +59,7 @@ impl AdaptiveMap {
#[inline(always)] #[inline(always)]
fn get_or_insert<'a>(&'a mut self, key: u32) -> &'a mut u64 { fn get_or_insert<'a>(&'a mut self, key: u32) -> &'a mut u64 {
let needs_expand = match self { let needs_expand = match self {
&mut Self::Small(len, ref keys, ..) => { &mut Self::Small { len, ref keys, .. } => {
len == SMALL_ELEMS as u32 && !keys.iter().any(|k| *k == key) len == SMALL_ELEMS as u32 && !keys.iter().any(|k| *k == key)
} }
_ => false, _ => false,
@@ -67,10 +69,11 @@ impl AdaptiveMap {
} }
match self { match self {
&mut Self::Small(ref mut len, ref mut keys, ref mut values, ref cached) => { &mut Self::Small {
if cached.get().0 == key { ref mut len,
cached.set((INVALID, 0)); ref mut keys,
} ref mut values,
} => {
for i in 0..*len { for i in 0..*len {
if keys[i as usize] == key { if keys[i as usize] == key {
return &mut values[i as usize]; return &mut values[i as usize];
@@ -83,21 +86,17 @@ impl AdaptiveMap {
values[idx as usize] = 0; values[idx as usize] = 0;
&mut values[idx as usize] &mut values[idx as usize]
} }
&mut Self::Large(ref mut map, ref cached) => { &mut Self::Large(ref mut map) => map.entry(key).or_insert(0),
if cached.get().0 == key {
cached.set((INVALID, 0));
}
map.entry(key).or_insert(0)
}
} }
} }
#[inline(always)] #[inline(always)]
fn get_mut(&mut self, key: u32) -> Option<&mut u64> { fn get_mut(&mut self, key: u32) -> Option<&mut u64> {
match self { match self {
&mut Self::Small(len, ref keys, ref mut values, ref cached) => { &mut Self::Small {
if cached.get().0 == key { len,
cached.set((INVALID, 0)); ref keys,
} ref mut values,
} => {
for i in 0..len { for i in 0..len {
if keys[i as usize] == key { if keys[i as usize] == key {
return Some(&mut values[i as usize]); return Some(&mut values[i as usize]);
@@ -105,48 +104,39 @@ impl AdaptiveMap {
} }
None None
} }
&mut Self::Large(ref mut map, ref cached) => { &mut Self::Large(ref mut map) => map.get_mut(&key),
if cached.get().0 == key {
cached.set((INVALID, 0));
}
map.get_mut(&key)
}
} }
} }
#[inline(always)] #[inline(always)]
fn get(&self, key: u32) -> Option<u64> { fn get(&self, key: u32) -> Option<u64> {
match self { match self {
&Self::Small(len, ref keys, ref values, ref cached) => { &Self::Small {
if cached.get().0 == key { len,
return Some(cached.get().1); ref keys,
} ref values,
} => {
for i in 0..len { for i in 0..len {
if keys[i as usize] == key { if keys[i as usize] == key {
let value = values[i as usize]; let value = values[i as usize];
cached.set((key, value));
return Some(value); return Some(value);
} }
} }
None None
} }
&Self::Large(ref map, ref cached) => { &Self::Large(ref map) => {
if cached.get().0 == key {
return Some(cached.get().1);
}
let value = map.get(&key).cloned(); let value = map.get(&key).cloned();
if let Some(value) = value {
cached.set((key, value));
}
value value
} }
} }
} }
fn iter<'a>(&'a self) -> AdaptiveMapIter<'a> { fn iter<'a>(&'a self) -> AdaptiveMapIter<'a> {
match self { match self {
&Self::Small(len, ref keys, ref values, ..) => { &Self::Small {
AdaptiveMapIter::Small(&keys[0..len as usize], &values[0..len as usize]) len,
} ref keys,
&Self::Large(ref map, ..) => AdaptiveMapIter::Large(map.iter()), ref values,
} => AdaptiveMapIter::Small(&keys[0..len as usize], &values[0..len as usize]),
&Self::Large(ref map) => AdaptiveMapIter::Large(map.iter()),
} }
} }
} }
@@ -180,6 +170,7 @@ impl<'a> std::iter::Iterator for AdaptiveMapIter<'a> {
#[derive(Clone)] #[derive(Clone)]
pub struct BitVec { pub struct BitVec {
elems: AdaptiveMap, elems: AdaptiveMap,
cache: Cell<(u32, u64)>,
} }
const BITS_PER_WORD: usize = 64; const BITS_PER_WORD: usize = 64;
@@ -188,25 +179,36 @@ impl BitVec {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
elems: AdaptiveMap::new(), elems: AdaptiveMap::new(),
cache: Cell::new((INVALID, 0)),
} }
} }
#[inline(always)] #[inline(always)]
fn elem(&mut self, bit_index: usize) -> &mut u64 { fn elem(&mut self, bit_index: usize) -> &mut u64 {
let word_index = (bit_index / BITS_PER_WORD) as u32; let word_index = (bit_index / BITS_PER_WORD) as u32;
if self.cache.get().0 == word_index {
self.cache.set((INVALID, 0));
}
self.elems.get_or_insert(word_index) self.elems.get_or_insert(word_index)
} }
#[inline(always)] #[inline(always)]
fn maybe_elem_mut(&mut self, bit_index: usize) -> Option<&mut u64> { fn maybe_elem_mut(&mut self, bit_index: usize) -> Option<&mut u64> {
let word_index = (bit_index / BITS_PER_WORD) as u32; let word_index = (bit_index / BITS_PER_WORD) as u32;
if self.cache.get().0 == word_index {
self.cache.set((INVALID, 0));
}
self.elems.get_mut(word_index) self.elems.get_mut(word_index)
} }
#[inline(always)] #[inline(always)]
fn maybe_elem(&self, bit_index: usize) -> Option<u64> { fn maybe_elem(&self, bit_index: usize) -> Option<u64> {
let word_index = (bit_index / BITS_PER_WORD) as u32; let word_index = (bit_index / BITS_PER_WORD) as u32;
self.elems.get(word_index) if self.cache.get().0 == word_index {
Some(self.cache.get().1)
} else {
self.elems.get(word_index)
}
} }
#[inline(always)] #[inline(always)]
@@ -221,6 +223,7 @@ impl BitVec {
pub fn assign(&mut self, other: &Self) { pub fn assign(&mut self, other: &Self) {
self.elems = other.elems.clone(); self.elems = other.elems.clone();
self.cache = other.cache.clone();
} }
#[inline(always)] #[inline(always)]