clarify that RollingBitField max is exclusive (#22947)

This commit is contained in:
Jeff Washington (jwash) 2022-02-07 13:40:31 -06:00 committed by GitHub
parent a160fc30f2
commit b2e475b5c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 29 deletions

View File

@ -368,7 +368,7 @@ impl<T: IndexValue> PreAllocatedAccountMapEntry<T> {
pub struct RollingBitField { pub struct RollingBitField {
max_width: u64, max_width: u64,
min: u64, min: u64,
max: u64, // exclusive max_exclusive: u64,
bits: BitVec, bits: BitVec,
count: usize, count: usize,
// These are items that are true and lower than min. // These are items that are true and lower than min.
@ -406,7 +406,7 @@ impl RollingBitField {
bits, bits,
count: 0, count: 0,
min: 0, min: 0,
max: 0, max_exclusive: 0,
excess: HashSet::new(), excess: HashSet::new(),
} }
} }
@ -418,7 +418,7 @@ impl RollingBitField {
pub fn range_width(&self) -> u64 { pub fn range_width(&self) -> u64 {
// note that max isn't updated on remove, so it can be above the current max // note that max isn't updated on remove, so it can be above the current max
self.max - self.min self.max_exclusive - self.min
} }
pub fn min(&self) -> Option<u64> { pub fn min(&self) -> Option<u64> {
@ -449,7 +449,7 @@ impl RollingBitField {
self.count += 1; self.count += 1;
} }
false false
} else if key < self.max { } else if key < self.max_exclusive {
true // fits current bit field range true // fits current bit field range
} else { } else {
// key is >= max // key is >= max
@ -487,15 +487,15 @@ impl RollingBitField {
self.bits.set(address, true); self.bits.set(address, true);
if bits_empty { if bits_empty {
self.min = key; self.min = key;
self.max = key + 1; self.max_exclusive = key + 1;
} else { } else {
self.min = std::cmp::min(self.min, key); self.min = std::cmp::min(self.min, key);
self.max = std::cmp::max(self.max, key + 1); self.max_exclusive = std::cmp::max(self.max_exclusive, key + 1);
assert!( assert!(
self.min + self.max_width >= self.max, self.min + self.max_width >= self.max_exclusive,
"min: {}, max: {}, max_width: {}", "min: {}, max: {}, max_width: {}",
self.min, self.min,
self.max, self.max_exclusive,
self.max_width self.max_width
); );
} }
@ -508,7 +508,7 @@ impl RollingBitField {
pub fn remove(&mut self, key: &u64) -> bool { pub fn remove(&mut self, key: &u64) -> bool {
if key >= &self.min { if key >= &self.min {
// if asked to remove something bigger than max, then no-op // if asked to remove something bigger than max, then no-op
if key < &self.max { if key < &self.max_exclusive {
let address = self.get_address(key); let address = self.get_address(key);
let get = self.bits.get(address); let get = self.bits.get(address);
if get { if get {
@ -539,7 +539,7 @@ impl RollingBitField {
if self.count > 0 && !self.all_items_in_excess() { if self.count > 0 && !self.all_items_in_excess() {
if key == &self.min { if key == &self.min {
let start = self.min + 1; // min just got removed let start = self.min + 1; // min just got removed
for key in start..self.max { for key in start..self.max_exclusive {
if self.contains_assume_in_range(&key) { if self.contains_assume_in_range(&key) {
self.min = key; self.min = key;
break; break;
@ -558,7 +558,7 @@ impl RollingBitField {
// Otherwise, we look in excess since the request is < min. // Otherwise, we look in excess since the request is < min.
// So, resetting min like this after a remove results in the correct behavior for the model. // So, resetting min like this after a remove results in the correct behavior for the model.
// Later, if we insert and there are 0 items total (excess + bitfield), then we reset min/max to reflect the new item only. // Later, if we insert and there are 0 items total (excess + bitfield), then we reset min/max to reflect the new item only.
self.min = self.max; self.min = self.max_exclusive;
} }
} }
@ -571,7 +571,7 @@ impl RollingBitField {
// This is the 99% use case. // This is the 99% use case.
// This needs be fast for the most common case of asking for key >= min. // This needs be fast for the most common case of asking for key >= min.
pub fn contains(&self, key: &u64) -> bool { pub fn contains(&self, key: &u64) -> bool {
if key < &self.max { if key < &self.max_exclusive {
if key >= &self.min { if key >= &self.min {
// in the bitfield range // in the bitfield range
self.contains_assume_in_range(key) self.contains_assume_in_range(key)
@ -596,14 +596,14 @@ impl RollingBitField {
std::mem::swap(&mut n, self); std::mem::swap(&mut n, self);
} }
pub fn max(&self) -> u64 { pub fn max_exclusive(&self) -> u64 {
self.max self.max_exclusive
} }
pub fn get_all(&self) -> Vec<u64> { pub fn get_all(&self) -> Vec<u64> {
let mut all = Vec::with_capacity(self.count); let mut all = Vec::with_capacity(self.count);
self.excess.iter().for_each(|slot| all.push(*slot)); self.excess.iter().for_each(|slot| all.push(*slot));
for key in self.min..self.max { for key in self.min..self.max_exclusive {
if self.contains_assume_in_range(&key) { if self.contains_assume_in_range(&key) {
all.push(key); all.push(key);
} }
@ -2136,12 +2136,12 @@ pub mod tests {
assert_eq!(bitfield.excess.len(), 1); assert_eq!(bitfield.excess.len(), 1);
assert_eq!(bitfield.min, too_big); assert_eq!(bitfield.min, too_big);
assert_eq!(bitfield.min(), Some(0)); assert_eq!(bitfield.min(), Some(0));
assert_eq!(bitfield.max, too_big + 1); assert_eq!(bitfield.max_exclusive, too_big + 1);
// delete the thing that is NOT in excess // delete the thing that is NOT in excess
bitfield.remove(&too_big); bitfield.remove(&too_big);
assert_eq!(bitfield.min, too_big + 1); assert_eq!(bitfield.min, too_big + 1);
assert_eq!(bitfield.max, too_big + 1); assert_eq!(bitfield.max_exclusive, too_big + 1);
let too_big_times_2 = too_big * 2; let too_big_times_2 = too_big * 2;
bitfield.insert(too_big_times_2); bitfield.insert(too_big_times_2);
assert!(bitfield.contains(&0)); assert!(bitfield.contains(&0));
@ -2150,7 +2150,7 @@ pub mod tests {
assert_eq!(bitfield.excess.len(), 1); assert_eq!(bitfield.excess.len(), 1);
assert_eq!(bitfield.min(), bitfield.excess.iter().min().copied()); assert_eq!(bitfield.min(), bitfield.excess.iter().min().copied());
assert_eq!(bitfield.min, too_big_times_2); assert_eq!(bitfield.min, too_big_times_2);
assert_eq!(bitfield.max, too_big_times_2 + 1); assert_eq!(bitfield.max_exclusive, too_big_times_2 + 1);
bitfield.remove(&0); bitfield.remove(&0);
bitfield.remove(&too_big_times_2); bitfield.remove(&too_big_times_2);
@ -2160,7 +2160,7 @@ pub mod tests {
assert!(bitfield.contains(&other)); assert!(bitfield.contains(&other));
assert!(bitfield.excess.is_empty()); assert!(bitfield.excess.is_empty());
assert_eq!(bitfield.min, other); assert_eq!(bitfield.min, other);
assert_eq!(bitfield.max, other + 1); assert_eq!(bitfield.max_exclusive, other + 1);
} }
#[test] #[test]
@ -2178,13 +2178,13 @@ pub mod tests {
assert_eq!(bitfield.excess.len(), 1); assert_eq!(bitfield.excess.len(), 1);
assert!(bitfield.excess.contains(&0)); assert!(bitfield.excess.contains(&0));
assert_eq!(bitfield.min, too_big); assert_eq!(bitfield.min, too_big);
assert_eq!(bitfield.max, too_big + 1); assert_eq!(bitfield.max_exclusive, too_big + 1);
// delete the thing that IS in excess // delete the thing that IS in excess
// this does NOT affect min/max // this does NOT affect min/max
bitfield.remove(&0); bitfield.remove(&0);
assert_eq!(bitfield.min, too_big); assert_eq!(bitfield.min, too_big);
assert_eq!(bitfield.max, too_big + 1); assert_eq!(bitfield.max_exclusive, too_big + 1);
// re-add to excess // re-add to excess
bitfield.insert(0); bitfield.insert(0);
assert!(bitfield.contains(&0)); assert!(bitfield.contains(&0));
@ -2192,7 +2192,7 @@ pub mod tests {
assert_eq!(bitfield.len(), 2); assert_eq!(bitfield.len(), 2);
assert_eq!(bitfield.excess.len(), 1); assert_eq!(bitfield.excess.len(), 1);
assert_eq!(bitfield.min, too_big); assert_eq!(bitfield.min, too_big);
assert_eq!(bitfield.max, too_big + 1); assert_eq!(bitfield.max_exclusive, too_big + 1);
} }
#[test] #[test]
@ -2620,12 +2620,12 @@ pub mod tests {
} else { } else {
( (
std::cmp::min(bitfield.min, slot), std::cmp::min(bitfield.min, slot),
std::cmp::max(bitfield.max, slot + 1), std::cmp::max(bitfield.max_exclusive, slot + 1),
) )
}; };
bitfield.insert(slot); bitfield.insert(slot);
assert_eq!(bitfield.min, new_min); assert_eq!(bitfield.min, new_min);
assert_eq!(bitfield.max, new_max); assert_eq!(bitfield.max_exclusive, new_max);
assert_eq!(bitfield.len(), len + 1); assert_eq!(bitfield.len(), len + 1);
assert!(!bitfield.is_empty()); assert!(!bitfield.is_empty());
assert!(bitfield.contains(&slot)); assert!(bitfield.contains(&slot));
@ -2672,24 +2672,24 @@ pub mod tests {
assert!(bitfield.remove(&0)); assert!(bitfield.remove(&0));
assert!(!bitfield.remove(&0)); assert!(!bitfield.remove(&0));
assert_eq!(bitfield.min, 2); assert_eq!(bitfield.min, 2);
assert_eq!(bitfield.max, 4); assert_eq!(bitfield.max_exclusive, 4);
assert_eq!(bitfield.len(), 2); assert_eq!(bitfield.len(), 2);
assert!(!bitfield.remove(&0)); // redundant remove assert!(!bitfield.remove(&0)); // redundant remove
assert_eq!(bitfield.len(), 2); assert_eq!(bitfield.len(), 2);
assert_eq!(bitfield.get_all(), vec![2, 3]); assert_eq!(bitfield.get_all(), vec![2, 3]);
bitfield.insert(4); // wrapped around value - same bit as '0' bitfield.insert(4); // wrapped around value - same bit as '0'
assert_eq!(bitfield.min, 2); assert_eq!(bitfield.min, 2);
assert_eq!(bitfield.max, 5); assert_eq!(bitfield.max_exclusive, 5);
assert_eq!(bitfield.len(), 3); assert_eq!(bitfield.len(), 3);
assert_eq!(bitfield.get_all(), vec![2, 3, 4]); assert_eq!(bitfield.get_all(), vec![2, 3, 4]);
assert!(bitfield.remove(&2)); assert!(bitfield.remove(&2));
assert_eq!(bitfield.min, 3); assert_eq!(bitfield.min, 3);
assert_eq!(bitfield.max, 5); assert_eq!(bitfield.max_exclusive, 5);
assert_eq!(bitfield.len(), 2); assert_eq!(bitfield.len(), 2);
assert_eq!(bitfield.get_all(), vec![3, 4]); assert_eq!(bitfield.get_all(), vec![3, 4]);
assert!(bitfield.remove(&3)); assert!(bitfield.remove(&3));
assert_eq!(bitfield.min, 4); assert_eq!(bitfield.min, 4);
assert_eq!(bitfield.max, 5); assert_eq!(bitfield.max_exclusive, 5);
assert_eq!(bitfield.len(), 1); assert_eq!(bitfield.len(), 1);
assert_eq!(bitfield.get_all(), vec![4]); assert_eq!(bitfield.get_all(), vec![4]);
assert!(bitfield.remove(&4)); assert!(bitfield.remove(&4));

View File

@ -86,7 +86,7 @@ impl Ancestors {
} }
pub fn max_slot(&self) -> Slot { pub fn max_slot(&self) -> Slot {
self.ancestors.max() - 1 self.ancestors.max_exclusive().saturating_sub(1)
} }
} }
#[cfg(test)] #[cfg(test)]