Optimize EntityList::extend and add EntityList::from_iter
This commit is contained in:
committed by
Benjamin Bouvier
parent
ac60ad6c9a
commit
78f312799e
@@ -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,14 +390,34 @@ 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();
|
||||||
self.push(x, pool);
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user