Review feedback: bitvec: struct-like enum variants, and factor out one-item cache.
This commit is contained in:
109
src/bitvec.rs
109
src/bitvec.rs
@@ -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)]
|
||||||
|
|||||||
Reference in New Issue
Block a user