Optimize EntityList::extend and add EntityList::from_iter

This commit is contained in:
Amanieu d'Antras
2021-01-28 16:06:28 +00:00
committed by Benjamin Bouvier
parent ac60ad6c9a
commit 78f312799e

View File

@@ -91,17 +91,20 @@ type SizeClass = u8;
/// Get the size of a given size class. The size includes the length field, so the maximum list /// Get the size of a given size class. The size includes the length field, so the maximum list
/// length is one less than the class size. /// length is one less than the class size.
#[inline]
fn sclass_size(sclass: SizeClass) -> usize { fn sclass_size(sclass: SizeClass) -> usize {
4 << sclass 4 << sclass
} }
/// Get the size class to use for a given list length. /// Get the size class to use for a given list length.
/// This always leaves room for the length element in addition to the list elements. /// This always leaves room for the length element in addition to the list elements.
#[inline]
fn sclass_for_length(len: usize) -> SizeClass { fn sclass_for_length(len: usize) -> SizeClass {
30 - (len as u32 | 3).leading_zeros() as SizeClass 30 - (len as u32 | 3).leading_zeros() as SizeClass
} }
/// Is `len` the minimum length in its size class? /// Is `len` the minimum length in its size class?
#[inline]
fn is_sclass_min_length(len: usize) -> bool { fn is_sclass_min_length(len: usize) -> bool {
len > 3 && len.is_power_of_two() len > 3 && len.is_power_of_two()
} }
@@ -387,16 +390,36 @@ impl<T: EntityRef + ReservedValue> EntityList<T> {
&mut pool.data[block + 1..block + 1 + new_len] &mut pool.data[block + 1..block + 1 + new_len]
} }
/// Constructs a list from an iterator.
pub fn from_iter<I>(elements: I, pool: &mut ListPool<T>) -> Self
where
I: IntoIterator<Item = T>,
{
let mut list = Self::new();
list.extend(elements, pool);
list
}
/// Appends multiple elements to the back of the list. /// Appends multiple elements to the back of the list.
pub fn extend<I>(&mut self, elements: I, pool: &mut ListPool<T>) pub fn extend<I>(&mut self, elements: I, pool: &mut ListPool<T>)
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
{ {
// TODO: use `size_hint()` to reduce reallocations. let iterator = elements.into_iter();
for x in elements { let (len, upper) = iterator.size_hint();
// On most iterators this check is optimized down to `true`.
if upper == Some(len) {
let data = self.grow(len, pool);
let offset = data.len() - len;
for (src, dst) in iterator.zip(data[offset..].iter_mut()) {
*dst = src;
}
} else {
for x in iterator {
self.push(x, pool); self.push(x, pool);
} }
} }
}
/// Inserts an element as position `index` in the list, shifting all elements after it to the /// Inserts an element as position `index` in the list, shifting all elements after it to the
/// right. /// right.
@@ -630,6 +653,10 @@ mod tests {
list.as_slice(pool), list.as_slice(pool),
&[i1, i2, i3, i4, i1, i1, i2, i2, i3, i3, i4, i4] &[i1, i2, i3, i4, i1, i1, i2, i2, i3, i3, i4, i4]
); );
let list2 = EntityList::from_iter([i1, i1, i2, i2, i3, i3, i4, i4].iter().cloned(), pool);
assert_eq!(list2.len(pool), 8);
assert_eq!(list2.as_slice(pool), &[i1, i1, i2, i2, i3, i3, i4, i4]);
} }
#[test] #[test]