diff --git a/bucket_map/src/index_entry.rs b/bucket_map/src/index_entry.rs index caeb200616..6b56c3b793 100644 --- a/bucket_map/src/index_entry.rs +++ b/bucket_map/src/index_entry.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] + use { crate::{ bucket::Bucket, @@ -57,8 +58,18 @@ impl IndexEntry { .expect("New storage offset must fit into 7 bytes!") } + /// return closest bucket index fit for the slot slice. + /// Since bucket size is 2^index, the return value is + /// min index, such that 2^index >= num_slots + /// index = ceiling(log2(num_slots)) + /// special case, when slot slice empty, return 0th index. pub fn data_bucket_from_num_slots(num_slots: Slot) -> u64 { - (num_slots as f64).log2().ceil() as u64 // use int log here? + // Compute the ceiling of log2 for integer + if num_slots == 0 { + 0 + } else { + (Slot::BITS - (num_slots - 1).leading_zeros()) as u64 + } } pub fn data_bucket_ix(&self) -> u64 { @@ -153,4 +164,23 @@ mod tests { let mut index = IndexEntry::new(Pubkey::new_unique()); index.set_storage_offset(too_big); } + + #[test] + fn test_data_bucket_from_num_slots() { + for n in 0..512 { + assert_eq!( + IndexEntry::data_bucket_from_num_slots(n), + (n as f64).log2().ceil() as u64 + ); + } + assert_eq!(IndexEntry::data_bucket_from_num_slots(u32::MAX as u64), 32); + assert_eq!( + IndexEntry::data_bucket_from_num_slots(u32::MAX as u64 + 1), + 32 + ); + assert_eq!( + IndexEntry::data_bucket_from_num_slots(u32::MAX as u64 + 2), + 33 + ); + } }