cranelift-entity: more efficient EntitySet implementation (#5978)

* Use usize intead of u8

* Rename 'byte's to appropriate words
This commit is contained in:
uint256_t
2023-03-14 03:43:34 +09:00
committed by GitHub
parent ad0bce3a36
commit b50cf9bb57

View File

@@ -5,6 +5,9 @@ use crate::EntityRef;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::marker::PhantomData; use core::marker::PhantomData;
// How many bits are used to represent a single element in `EntitySet`.
const BITS: usize = core::mem::size_of::<usize>() * 8;
/// A set of `K` for densely indexed entity references. /// A set of `K` for densely indexed entity references.
/// ///
/// The `EntitySet` data structure uses the dense index space to implement a set with a bitvector. /// The `EntitySet` data structure uses the dense index space to implement a set with a bitvector.
@@ -14,7 +17,7 @@ pub struct EntitySet<K>
where where
K: EntityRef, K: EntityRef,
{ {
elems: Vec<u8>, elems: Vec<usize>,
len: usize, len: usize,
unused: PhantomData<K>, unused: PhantomData<K>,
} }
@@ -42,7 +45,7 @@ where
/// Creates a new empty set with the specified capacity. /// Creates a new empty set with the specified capacity.
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self {
Self { Self {
elems: Vec::with_capacity((capacity + 7) / 8), elems: Vec::with_capacity((capacity + (BITS - 1)) / BITS),
..Self::new() ..Self::new()
} }
} }
@@ -51,7 +54,7 @@ where
pub fn contains(&self, k: K) -> bool { pub fn contains(&self, k: K) -> bool {
let index = k.index(); let index = k.index();
if index < self.len { if index < self.len {
(self.elems[index / 8] & (1 << (index % 8))) != 0 (self.elems[index / BITS] & (1 << (index % BITS))) != 0
} else { } else {
false false
} }
@@ -71,11 +74,11 @@ where
/// `clear`ed or created with `new`. /// `clear`ed or created with `new`.
pub fn cardinality(&self) -> usize { pub fn cardinality(&self) -> usize {
let mut n: usize = 0; let mut n: usize = 0;
for byte_ix in 0..self.len / 8 { for idx in 0..self.len / BITS {
n += self.elems[byte_ix].count_ones() as usize; n += self.elems[idx].count_ones() as usize;
} }
for bit_ix in (self.len / 8) * 8..self.len { for bit_ix in (self.len / BITS) * BITS..self.len {
if (self.elems[bit_ix / 8] & (1 << (bit_ix % 8))) != 0 { if (self.elems[bit_ix / BITS] & (1 << (bit_ix % BITS))) != 0 {
n += 1; n += 1;
} }
} }
@@ -95,7 +98,7 @@ where
/// Resize the set to have `n` entries by adding default entries as needed. /// Resize the set to have `n` entries by adding default entries as needed.
pub fn resize(&mut self, n: usize) { pub fn resize(&mut self, n: usize) {
self.elems.resize((n + 7) / 8, 0); self.elems.resize((n + (BITS - 1)) / BITS, 0);
self.len = n self.len = n
} }
@@ -106,7 +109,7 @@ where
self.resize(index + 1) self.resize(index + 1)
} }
let result = !self.contains(k); let result = !self.contains(k);
self.elems[index / 8] |= 1 << (index % 8); self.elems[index / BITS] |= 1 << (index % BITS);
result result
} }
@@ -118,7 +121,7 @@ where
// Clear the last known entity in the list. // Clear the last known entity in the list.
let last_index = self.len - 1; let last_index = self.len - 1;
self.elems[last_index / 8] &= !(1 << (last_index % 8)); self.elems[last_index / BITS] &= !(1 << (last_index % BITS));
// Set the length to the next last stored entity or zero if we pop'ed // Set the length to the next last stored entity or zero if we pop'ed
// the last entity. // the last entity.
@@ -127,12 +130,14 @@ where
.iter() .iter()
.enumerate() .enumerate()
.rev() .rev()
.find(|(_, &byte)| byte != 0) .find(|(_, &elem)| elem != 0)
// Map `i` from byte index to bit level index. // Map `i` from `elem` index to bit level index.
// `(i + 1) * 8` = Last bit in byte. // `(i + 1) * BITS` = Last bit in `elem`.
// `last - byte.leading_zeros()` = last set bit in byte. // `last - elem.leading_zeros()` = last set bit in `elem`.
// `as usize` won't ever truncate as the potential range is `0..=8`. // `as usize` won't ever truncate as the potential range is `0..=8`.
.map_or(0, |(i, byte)| ((i + 1) * 8) - byte.leading_zeros() as usize); .map_or(0, |(i, elem)| {
((i + 1) * BITS) - elem.leading_zeros() as usize
});
Some(K::new(last_index)) Some(K::new(last_index))
} }