cranelift_entity/
list.rs

1//! Small lists of entity references.
2use crate::packed_option::ReservedValue;
3use crate::EntityRef;
4use alloc::vec::Vec;
5use core::marker::PhantomData;
6use core::mem;
7
8#[cfg(feature = "enable-serde")]
9use serde_derive::{Deserialize, Serialize};
10
11/// A small list of entity references allocated from a pool.
12///
13/// An `EntityList<T>` type provides similar functionality to `Vec<T>`, but with some important
14/// differences in the implementation:
15///
16/// 1. Memory is allocated from a `ListPool<T>` instead of the global heap.
17/// 2. The footprint of an entity list is 4 bytes, compared with the 24 bytes for `Vec<T>`.
18/// 3. An entity list doesn't implement `Drop`, leaving it to the pool to manage memory.
19///
20/// The list pool is intended to be used as a LIFO allocator. After building up a larger data
21/// structure with many list references, the whole thing can be discarded quickly by clearing the
22/// pool.
23///
24/// # Safety
25///
26/// Entity lists are not as safe to use as `Vec<T>`, but they never jeopardize Rust's memory safety
27/// guarantees. These are the problems to be aware of:
28///
29/// - If you lose track of an entity list, its memory won't be recycled until the pool is cleared.
30///   This can cause the pool to grow very large with leaked lists.
31/// - If entity lists are used after their pool is cleared, they may contain garbage data, and
32///   modifying them may corrupt other lists in the pool.
33/// - If an entity list is used with two different pool instances, both pools are likely to become
34///   corrupted.
35///
36/// Entity lists can be cloned, but that operation should only be used as part of cloning the whole
37/// function they belong to. *Cloning an entity list does not allocate new memory for the clone*.
38/// It creates an alias of the same memory.
39///
40/// Entity lists cannot be hashed and compared for equality because it's not possible to compare the
41/// contents of the list without the pool reference.
42///
43/// # Implementation
44///
45/// The `EntityList` itself is designed to have the smallest possible footprint. This is important
46/// because it is used inside very compact data structures like `InstructionData`. The list
47/// contains only a 32-bit index into the pool's memory vector, pointing to the first element of
48/// the list. A zero value represents the empty list, which is returned by `EntityList::default`.
49///
50/// The pool is just a single `Vec<T>` containing all of the allocated lists. Each list is
51/// represented as three contiguous parts:
52///
53/// 1. The number of elements in the list.
54/// 2. The list elements.
55/// 3. Excess capacity elements.
56///
57/// The total size of the three parts is always a power of two, and the excess capacity is always
58/// as small as possible. This means that shrinking a list may cause the excess capacity to shrink
59/// if a smaller power-of-two size becomes available.
60///
61/// Both growing and shrinking a list may cause it to be reallocated in the pool vector.
62///
63/// The index stored in an `EntityList` points to part 2, the list elements. The value 0 is
64/// reserved for the empty list which isn't allocated in the vector.
65#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
66#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
67#[repr(C)]
68pub struct EntityList<T: EntityRef + ReservedValue> {
69    index: u32,
70    unused: PhantomData<T>,
71}
72
73/// Create an empty list.
74impl<T: EntityRef + ReservedValue> Default for EntityList<T> {
75    fn default() -> Self {
76        Self {
77            index: 0,
78            unused: PhantomData,
79        }
80    }
81}
82
83/// A memory pool for storing lists of `T`.
84#[derive(Clone, Debug)]
85#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
86pub struct ListPool<T: EntityRef + ReservedValue> {
87    // The main array containing the lists.
88    data: Vec<T>,
89
90    // Heads of the free lists, one for each size class.
91    free: Vec<usize>,
92}
93
94impl<T: EntityRef + ReservedValue> PartialEq for ListPool<T> {
95    fn eq(&self, other: &Self) -> bool {
96        // ignore the free list
97        self.data == other.data
98    }
99}
100
101impl<T: core::hash::Hash + EntityRef + ReservedValue> core::hash::Hash for ListPool<T> {
102    fn hash<H: __core::hash::Hasher>(&self, state: &mut H) {
103        // ignore the free list
104        self.data.hash(state);
105    }
106}
107
108impl<T: EntityRef + ReservedValue> Default for ListPool<T> {
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114/// Lists are allocated in sizes that are powers of two, starting from 4.
115/// Each power of two is assigned a size class number, so the size is `4 << SizeClass`.
116type SizeClass = u8;
117
118/// Get the size of a given size class. The size includes the length field, so the maximum list
119/// length is one less than the class size.
120#[inline]
121fn sclass_size(sclass: SizeClass) -> usize {
122    4 << sclass
123}
124
125/// Get the size class to use for a given list length.
126/// This always leaves room for the length element in addition to the list elements.
127#[inline]
128fn sclass_for_length(len: usize) -> SizeClass {
129    30 - (len as u32 | 3).leading_zeros() as SizeClass
130}
131
132/// Is `len` the minimum length in its size class?
133#[inline]
134fn is_sclass_min_length(len: usize) -> bool {
135    len > 3 && len.is_power_of_two()
136}
137
138impl<T: EntityRef + ReservedValue> ListPool<T> {
139    /// Create a new list pool.
140    pub fn new() -> Self {
141        Self {
142            data: Vec::new(),
143            free: Vec::new(),
144        }
145    }
146
147    /// Create a new list pool with the given capacity for data pre-allocated.
148    pub fn with_capacity(len: usize) -> Self {
149        Self {
150            data: Vec::with_capacity(len),
151            free: Vec::new(),
152        }
153    }
154
155    /// Get the capacity of this pool. This will be somewhat higher
156    /// than the total length of lists that can be stored without
157    /// reallocating, because of internal metadata overheads. It is
158    /// mostly useful to allow another pool to be allocated that is
159    /// likely to hold data transferred from this one without the need
160    /// to grow.
161    pub fn capacity(&self) -> usize {
162        self.data.capacity()
163    }
164
165    /// Clear the pool, forgetting about all lists that use it.
166    ///
167    /// This invalidates any existing entity lists that used this pool to allocate memory.
168    ///
169    /// The pool's memory is not released to the operating system, but kept around for faster
170    /// allocation in the future.
171    pub fn clear(&mut self) {
172        self.data.clear();
173        self.free.clear();
174    }
175
176    /// Read the length of a list field, if it exists.
177    fn len_of(&self, list: &EntityList<T>) -> Option<usize> {
178        let idx = list.index as usize;
179        // `idx` points at the list elements. The list length is encoded in the element immediately
180        // before the list elements.
181        //
182        // The `wrapping_sub` handles the special case 0, which is the empty list. This way, the
183        // cost of the bounds check that we have to pay anyway is co-opted to handle the special
184        // case of the empty list.
185        self.data.get(idx.wrapping_sub(1)).map(|len| len.index())
186    }
187
188    /// Allocate a storage block with a size given by `sclass`.
189    ///
190    /// Returns the first index of an available segment of `self.data` containing
191    /// `sclass_size(sclass)` elements. The allocated memory is filled with reserved
192    /// values.
193    fn alloc(&mut self, sclass: SizeClass) -> usize {
194        // First try the free list for this size class.
195        match self.free.get(sclass as usize).cloned() {
196            Some(head) if head > 0 => {
197                // The free list pointers are offset by 1, using 0 to terminate the list.
198                // A block on the free list has two entries: `[ 0, next ]`.
199                // The 0 is where the length field would be stored for a block in use.
200                // The free list heads and the next pointer point at the `next` field.
201                self.free[sclass as usize] = self.data[head].index();
202                head - 1
203            }
204            _ => {
205                // Nothing on the free list. Allocate more memory.
206                let offset = self.data.len();
207                self.data
208                    .resize(offset + sclass_size(sclass), T::reserved_value());
209                offset
210            }
211        }
212    }
213
214    /// Free a storage block with a size given by `sclass`.
215    ///
216    /// This must be a block that was previously allocated by `alloc()` with the same size class.
217    fn free(&mut self, block: usize, sclass: SizeClass) {
218        let sclass = sclass as usize;
219
220        // Make sure we have a free-list head for `sclass`.
221        if self.free.len() <= sclass {
222            self.free.resize(sclass + 1, 0);
223        }
224
225        // Make sure the length field is cleared.
226        self.data[block] = T::new(0);
227        // Insert the block on the free list which is a single linked list.
228        self.data[block + 1] = T::new(self.free[sclass]);
229        self.free[sclass] = block + 1
230    }
231
232    /// Returns two mutable slices representing the two requested blocks.
233    ///
234    /// The two returned slices can be longer than the blocks. Each block is located at the front
235    /// of the respective slice.
236    fn mut_slices(&mut self, block0: usize, block1: usize) -> (&mut [T], &mut [T]) {
237        if block0 < block1 {
238            let (s0, s1) = self.data.split_at_mut(block1);
239            (&mut s0[block0..], s1)
240        } else {
241            let (s1, s0) = self.data.split_at_mut(block0);
242            (s0, &mut s1[block1..])
243        }
244    }
245
246    /// Reallocate a block to a different size class.
247    ///
248    /// Copy `elems_to_copy` elements from the old to the new block.
249    fn realloc(
250        &mut self,
251        block: usize,
252        from_sclass: SizeClass,
253        to_sclass: SizeClass,
254        elems_to_copy: usize,
255    ) -> usize {
256        debug_assert!(elems_to_copy <= sclass_size(from_sclass));
257        debug_assert!(elems_to_copy <= sclass_size(to_sclass));
258        let new_block = self.alloc(to_sclass);
259
260        if elems_to_copy > 0 {
261            let (old, new) = self.mut_slices(block, new_block);
262            (&mut new[0..elems_to_copy]).copy_from_slice(&old[0..elems_to_copy]);
263        }
264
265        self.free(block, from_sclass);
266        new_block
267    }
268}
269
270impl<T: EntityRef + ReservedValue> EntityList<T> {
271    /// Create a new empty list.
272    pub fn new() -> Self {
273        Default::default()
274    }
275
276    /// Create a new list with the contents initialized from a slice.
277    pub fn from_slice(slice: &[T], pool: &mut ListPool<T>) -> Self {
278        let len = slice.len();
279        if len == 0 {
280            return Self::new();
281        }
282
283        let block = pool.alloc(sclass_for_length(len));
284        pool.data[block] = T::new(len);
285        pool.data[block + 1..=block + len].copy_from_slice(slice);
286
287        Self {
288            index: (block + 1) as u32,
289            unused: PhantomData,
290        }
291    }
292
293    /// Returns `true` if the list has a length of 0.
294    pub fn is_empty(&self) -> bool {
295        // 0 is a magic value for the empty list. Any list in the pool array must have a positive
296        // length.
297        self.index == 0
298    }
299
300    /// Get the number of elements in the list.
301    pub fn len(&self, pool: &ListPool<T>) -> usize {
302        // Both the empty list and any invalidated old lists will return `None`.
303        pool.len_of(self).unwrap_or(0)
304    }
305
306    /// Returns `true` if the list is valid
307    pub fn is_valid(&self, pool: &ListPool<T>) -> bool {
308        // We consider an empty list to be valid
309        self.is_empty() || pool.len_of(self) != None
310    }
311
312    /// Get the list as a slice.
313    pub fn as_slice<'a>(&self, pool: &'a ListPool<T>) -> &'a [T] {
314        let idx = self.index as usize;
315        match pool.len_of(self) {
316            None => &[],
317            Some(len) => &pool.data[idx..idx + len],
318        }
319    }
320
321    /// Get a single element from the list.
322    pub fn get(&self, index: usize, pool: &ListPool<T>) -> Option<T> {
323        self.as_slice(pool).get(index).cloned()
324    }
325
326    /// Get the first element from the list.
327    pub fn first(&self, pool: &ListPool<T>) -> Option<T> {
328        if self.is_empty() {
329            None
330        } else {
331            Some(pool.data[self.index as usize])
332        }
333    }
334
335    /// Get the list as a mutable slice.
336    pub fn as_mut_slice<'a>(&'a mut self, pool: &'a mut ListPool<T>) -> &'a mut [T] {
337        let idx = self.index as usize;
338        match pool.len_of(self) {
339            None => &mut [],
340            Some(len) => &mut pool.data[idx..idx + len],
341        }
342    }
343
344    /// Get a mutable reference to a single element from the list.
345    pub fn get_mut<'a>(&'a mut self, index: usize, pool: &'a mut ListPool<T>) -> Option<&'a mut T> {
346        self.as_mut_slice(pool).get_mut(index)
347    }
348
349    /// Create a deep clone of the list, which does not alias the original list.
350    pub fn deep_clone(&self, pool: &mut ListPool<T>) -> Self {
351        match pool.len_of(self) {
352            None => return Self::new(),
353            Some(len) => {
354                let src = self.index as usize;
355                let block = pool.alloc(sclass_for_length(len));
356                pool.data[block] = T::new(len);
357                pool.data.copy_within(src..src + len, block + 1);
358
359                Self {
360                    index: (block + 1) as u32,
361                    unused: PhantomData,
362                }
363            }
364        }
365    }
366
367    /// Removes all elements from the list.
368    ///
369    /// The memory used by the list is put back in the pool.
370    pub fn clear(&mut self, pool: &mut ListPool<T>) {
371        let idx = self.index as usize;
372        match pool.len_of(self) {
373            None => debug_assert_eq!(idx, 0, "Invalid pool"),
374            Some(len) => pool.free(idx - 1, sclass_for_length(len)),
375        }
376        // Switch back to the empty list representation which has no storage.
377        self.index = 0;
378    }
379
380    /// Take all elements from this list and return them as a new list. Leave this list empty.
381    ///
382    /// This is the equivalent of `Option::take()`.
383    pub fn take(&mut self) -> Self {
384        mem::replace(self, Default::default())
385    }
386
387    /// Appends an element to the back of the list.
388    /// Returns the index where the element was inserted.
389    pub fn push(&mut self, element: T, pool: &mut ListPool<T>) -> usize {
390        let idx = self.index as usize;
391        match pool.len_of(self) {
392            None => {
393                // This is an empty list. Allocate a block and set length=1.
394                debug_assert_eq!(idx, 0, "Invalid pool");
395                let block = pool.alloc(sclass_for_length(1));
396                pool.data[block] = T::new(1);
397                pool.data[block + 1] = element;
398                self.index = (block + 1) as u32;
399                0
400            }
401            Some(len) => {
402                // Do we need to reallocate?
403                let new_len = len + 1;
404                let block;
405                if is_sclass_min_length(new_len) {
406                    // Reallocate, preserving length + all old elements.
407                    let sclass = sclass_for_length(len);
408                    block = pool.realloc(idx - 1, sclass, sclass + 1, len + 1);
409                    self.index = (block + 1) as u32;
410                } else {
411                    block = idx - 1;
412                }
413                pool.data[block + new_len] = element;
414                pool.data[block] = T::new(new_len);
415                len
416            }
417        }
418    }
419
420    /// Grow list by adding `count` reserved-value elements at the end.
421    ///
422    /// Returns a mutable slice representing the whole list.
423    fn grow<'a>(&'a mut self, count: usize, pool: &'a mut ListPool<T>) -> &'a mut [T] {
424        let idx = self.index as usize;
425        let new_len;
426        let block;
427        match pool.len_of(self) {
428            None => {
429                // This is an empty list. Allocate a block.
430                debug_assert_eq!(idx, 0, "Invalid pool");
431                if count == 0 {
432                    return &mut [];
433                }
434                new_len = count;
435                block = pool.alloc(sclass_for_length(new_len));
436                self.index = (block + 1) as u32;
437            }
438            Some(len) => {
439                // Do we need to reallocate?
440                let sclass = sclass_for_length(len);
441                new_len = len + count;
442                let new_sclass = sclass_for_length(new_len);
443                if new_sclass != sclass {
444                    block = pool.realloc(idx - 1, sclass, new_sclass, len + 1);
445                    self.index = (block + 1) as u32;
446                } else {
447                    block = idx - 1;
448                }
449            }
450        }
451        pool.data[block] = T::new(new_len);
452        &mut pool.data[block + 1..block + 1 + new_len]
453    }
454
455    /// Constructs a list from an iterator.
456    pub fn from_iter<I>(elements: I, pool: &mut ListPool<T>) -> Self
457    where
458        I: IntoIterator<Item = T>,
459    {
460        let mut list = Self::new();
461        list.extend(elements, pool);
462        list
463    }
464
465    /// Appends multiple elements to the back of the list.
466    pub fn extend<I>(&mut self, elements: I, pool: &mut ListPool<T>)
467    where
468        I: IntoIterator<Item = T>,
469    {
470        let iterator = elements.into_iter();
471        let (len, upper) = iterator.size_hint();
472        // On most iterators this check is optimized down to `true`.
473        if upper == Some(len) {
474            let data = self.grow(len, pool);
475            let offset = data.len() - len;
476            for (src, dst) in iterator.zip(data[offset..].iter_mut()) {
477                *dst = src;
478            }
479        } else {
480            for x in iterator {
481                self.push(x, pool);
482            }
483        }
484    }
485
486    /// Copies a slice from an entity list in the same pool to a position in this one.
487    ///
488    /// Will panic if `self` is the same list as `other`.
489    pub fn copy_from(
490        &mut self,
491        other: &Self,
492        slice: impl core::ops::RangeBounds<usize>,
493        index: usize,
494        pool: &mut ListPool<T>,
495    ) {
496        assert!(
497            index <= self.len(pool),
498            "attempted to copy a slice out of bounds of `self`"
499        );
500        assert_ne!(
501            self.index, other.index,
502            "cannot copy within one `EntityList`"
503        );
504
505        let (other_index, other_len) = (other.index, other.len(pool));
506
507        let start = match slice.start_bound() {
508            core::ops::Bound::Included(&x) => x,
509            core::ops::Bound::Excluded(&x) => x + 1,
510            core::ops::Bound::Unbounded => 0,
511        } + other_index as usize;
512        let end = match slice.end_bound() {
513            core::ops::Bound::Included(&x) => x + 1,
514            core::ops::Bound::Excluded(&x) => x,
515            core::ops::Bound::Unbounded => other_len,
516        } + other_index as usize;
517        let count = end - start;
518        assert!(
519            count <= other_len,
520            "attempted to copy a slice from out of bounds of `other`"
521        );
522
523        self.grow_at(index, count, pool);
524        pool.data
525            .copy_within(start..end, index + self.index as usize);
526    }
527
528    /// Inserts an element as position `index` in the list, shifting all elements after it to the
529    /// right.
530    pub fn insert(&mut self, index: usize, element: T, pool: &mut ListPool<T>) {
531        // Increase size by 1.
532        self.push(element, pool);
533
534        // Move tail elements.
535        let seq = self.as_mut_slice(pool);
536        if index < seq.len() {
537            let tail = &mut seq[index..];
538            for i in (1..tail.len()).rev() {
539                tail[i] = tail[i - 1];
540            }
541            tail[0] = element;
542        } else {
543            debug_assert_eq!(index, seq.len());
544        }
545    }
546
547    /// Removes the last element from the list.
548    fn remove_last(&mut self, len: usize, pool: &mut ListPool<T>) {
549        // Check if we deleted the last element.
550        if len == 1 {
551            self.clear(pool);
552            return;
553        }
554
555        // Do we need to reallocate to a smaller size class?
556        let mut block = self.index as usize - 1;
557        if is_sclass_min_length(len) {
558            let sclass = sclass_for_length(len);
559            block = pool.realloc(block, sclass, sclass - 1, len);
560            self.index = (block + 1) as u32;
561        }
562
563        // Finally adjust the length.
564        pool.data[block] = T::new(len - 1);
565    }
566
567    /// Removes the element at position `index` from the list. Potentially linear complexity.
568    pub fn remove(&mut self, index: usize, pool: &mut ListPool<T>) {
569        let len;
570        {
571            let seq = self.as_mut_slice(pool);
572            len = seq.len();
573            debug_assert!(index < len);
574
575            // Copy elements down.
576            for i in index..len - 1 {
577                seq[i] = seq[i + 1];
578            }
579        }
580
581        self.remove_last(len, pool);
582    }
583
584    /// Removes the element at `index` in constant time by switching it with the last element of
585    /// the list.
586    pub fn swap_remove(&mut self, index: usize, pool: &mut ListPool<T>) {
587        let seq = self.as_mut_slice(pool);
588        let len = seq.len();
589        debug_assert!(index < len);
590        if index != len - 1 {
591            seq.swap(index, len - 1);
592        }
593
594        self.remove_last(len, pool);
595    }
596
597    /// Shortens the list down to `len` elements.
598    ///
599    /// Does nothing if the list is already shorter than `len`.
600    pub fn truncate(&mut self, new_len: usize, pool: &mut ListPool<T>) {
601        if new_len == 0 {
602            self.clear(pool);
603            return;
604        }
605
606        match pool.len_of(self) {
607            None => return,
608            Some(len) => {
609                if len <= new_len {
610                    return;
611                }
612
613                let block;
614                let idx = self.index as usize;
615                let sclass = sclass_for_length(len);
616                let new_sclass = sclass_for_length(new_len);
617                if sclass != new_sclass {
618                    block = pool.realloc(idx - 1, sclass, new_sclass, new_len + 1);
619                    self.index = (block + 1) as u32;
620                } else {
621                    block = idx - 1;
622                }
623                pool.data[block] = T::new(new_len);
624            }
625        }
626    }
627
628    /// Grow the list by inserting `count` elements at `index`.
629    ///
630    /// The new elements are not initialized, they will contain whatever happened to be in memory.
631    /// Since the memory comes from the pool, this will be either zero entity references or
632    /// whatever where in a previously deallocated list.
633    pub fn grow_at(&mut self, index: usize, count: usize, pool: &mut ListPool<T>) {
634        let data = self.grow(count, pool);
635
636        // Copy elements after `index` up.
637        for i in (index + count..data.len()).rev() {
638            data[i] = data[i - count];
639        }
640    }
641}
642
643#[cfg(test)]
644mod tests {
645    use super::*;
646
647    /// An opaque reference to an instruction in a function.
648    #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
649    pub struct Inst(u32);
650    entity_impl!(Inst, "inst");
651
652    #[test]
653    fn size_classes() {
654        assert_eq!(sclass_size(0), 4);
655        assert_eq!(sclass_for_length(0), 0);
656        assert_eq!(sclass_for_length(1), 0);
657        assert_eq!(sclass_for_length(2), 0);
658        assert_eq!(sclass_for_length(3), 0);
659        assert_eq!(sclass_for_length(4), 1);
660        assert_eq!(sclass_for_length(7), 1);
661        assert_eq!(sclass_for_length(8), 2);
662        assert_eq!(sclass_size(1), 8);
663        for l in 0..300 {
664            assert!(sclass_size(sclass_for_length(l)) >= l + 1);
665        }
666    }
667
668    #[test]
669    fn block_allocator() {
670        let mut pool = ListPool::<Inst>::new();
671        let b1 = pool.alloc(0);
672        let b2 = pool.alloc(1);
673        let b3 = pool.alloc(0);
674        assert_ne!(b1, b2);
675        assert_ne!(b1, b3);
676        assert_ne!(b2, b3);
677        pool.free(b2, 1);
678        let b2a = pool.alloc(1);
679        let b2b = pool.alloc(1);
680        assert_ne!(b2a, b2b);
681        // One of these should reuse the freed block.
682        assert!(b2a == b2 || b2b == b2);
683
684        // Check the free lists for a size class smaller than the largest seen so far.
685        pool.free(b1, 0);
686        pool.free(b3, 0);
687        let b1a = pool.alloc(0);
688        let b3a = pool.alloc(0);
689        assert_ne!(b1a, b3a);
690        assert!(b1a == b1 || b1a == b3);
691        assert!(b3a == b1 || b3a == b3);
692    }
693
694    #[test]
695    fn empty_list() {
696        let pool = &mut ListPool::<Inst>::new();
697        let mut list = EntityList::<Inst>::default();
698        {
699            let ilist = &list;
700            assert!(ilist.is_empty());
701            assert_eq!(ilist.len(pool), 0);
702            assert_eq!(ilist.as_slice(pool), &[]);
703            assert_eq!(ilist.get(0, pool), None);
704            assert_eq!(ilist.get(100, pool), None);
705        }
706        assert_eq!(list.as_mut_slice(pool), &[]);
707        assert_eq!(list.get_mut(0, pool), None);
708        assert_eq!(list.get_mut(100, pool), None);
709
710        list.clear(pool);
711        assert!(list.is_empty());
712        assert_eq!(list.len(pool), 0);
713        assert_eq!(list.as_slice(pool), &[]);
714        assert_eq!(list.first(pool), None);
715    }
716
717    #[test]
718    fn from_slice() {
719        let pool = &mut ListPool::<Inst>::new();
720
721        let list = EntityList::<Inst>::from_slice(&[Inst(0), Inst(1)], pool);
722        assert!(!list.is_empty());
723        assert_eq!(list.len(pool), 2);
724        assert_eq!(list.as_slice(pool), &[Inst(0), Inst(1)]);
725        assert_eq!(list.get(0, pool), Some(Inst(0)));
726        assert_eq!(list.get(100, pool), None);
727
728        let list = EntityList::<Inst>::from_slice(&[], pool);
729        assert!(list.is_empty());
730        assert_eq!(list.len(pool), 0);
731        assert_eq!(list.as_slice(pool), &[]);
732        assert_eq!(list.get(0, pool), None);
733        assert_eq!(list.get(100, pool), None);
734    }
735
736    #[test]
737    fn push() {
738        let pool = &mut ListPool::<Inst>::new();
739        let mut list = EntityList::<Inst>::default();
740
741        let i1 = Inst::new(1);
742        let i2 = Inst::new(2);
743        let i3 = Inst::new(3);
744        let i4 = Inst::new(4);
745
746        assert_eq!(list.push(i1, pool), 0);
747        assert_eq!(list.len(pool), 1);
748        assert!(!list.is_empty());
749        assert_eq!(list.as_slice(pool), &[i1]);
750        assert_eq!(list.first(pool), Some(i1));
751        assert_eq!(list.get(0, pool), Some(i1));
752        assert_eq!(list.get(1, pool), None);
753
754        assert_eq!(list.push(i2, pool), 1);
755        assert_eq!(list.len(pool), 2);
756        assert!(!list.is_empty());
757        assert_eq!(list.as_slice(pool), &[i1, i2]);
758        assert_eq!(list.first(pool), Some(i1));
759        assert_eq!(list.get(0, pool), Some(i1));
760        assert_eq!(list.get(1, pool), Some(i2));
761        assert_eq!(list.get(2, pool), None);
762
763        assert_eq!(list.push(i3, pool), 2);
764        assert_eq!(list.len(pool), 3);
765        assert!(!list.is_empty());
766        assert_eq!(list.as_slice(pool), &[i1, i2, i3]);
767        assert_eq!(list.first(pool), Some(i1));
768        assert_eq!(list.get(0, pool), Some(i1));
769        assert_eq!(list.get(1, pool), Some(i2));
770        assert_eq!(list.get(2, pool), Some(i3));
771        assert_eq!(list.get(3, pool), None);
772
773        // This triggers a reallocation.
774        assert_eq!(list.push(i4, pool), 3);
775        assert_eq!(list.len(pool), 4);
776        assert!(!list.is_empty());
777        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]);
778        assert_eq!(list.first(pool), Some(i1));
779        assert_eq!(list.get(0, pool), Some(i1));
780        assert_eq!(list.get(1, pool), Some(i2));
781        assert_eq!(list.get(2, pool), Some(i3));
782        assert_eq!(list.get(3, pool), Some(i4));
783        assert_eq!(list.get(4, pool), None);
784
785        list.extend([i1, i1, i2, i2, i3, i3, i4, i4].iter().cloned(), pool);
786        assert_eq!(list.len(pool), 12);
787        assert_eq!(
788            list.as_slice(pool),
789            &[i1, i2, i3, i4, i1, i1, i2, i2, i3, i3, i4, i4]
790        );
791
792        let list2 = EntityList::from_iter([i1, i1, i2, i2, i3, i3, i4, i4].iter().cloned(), pool);
793        assert_eq!(list2.len(pool), 8);
794        assert_eq!(list2.as_slice(pool), &[i1, i1, i2, i2, i3, i3, i4, i4]);
795    }
796
797    #[test]
798    fn insert_remove() {
799        let pool = &mut ListPool::<Inst>::new();
800        let mut list = EntityList::<Inst>::default();
801
802        let i1 = Inst::new(1);
803        let i2 = Inst::new(2);
804        let i3 = Inst::new(3);
805        let i4 = Inst::new(4);
806
807        list.insert(0, i4, pool);
808        assert_eq!(list.as_slice(pool), &[i4]);
809
810        list.insert(0, i3, pool);
811        assert_eq!(list.as_slice(pool), &[i3, i4]);
812
813        list.insert(2, i2, pool);
814        assert_eq!(list.as_slice(pool), &[i3, i4, i2]);
815
816        list.insert(2, i1, pool);
817        assert_eq!(list.as_slice(pool), &[i3, i4, i1, i2]);
818
819        list.remove(3, pool);
820        assert_eq!(list.as_slice(pool), &[i3, i4, i1]);
821
822        list.remove(2, pool);
823        assert_eq!(list.as_slice(pool), &[i3, i4]);
824
825        list.remove(0, pool);
826        assert_eq!(list.as_slice(pool), &[i4]);
827
828        list.remove(0, pool);
829        assert_eq!(list.as_slice(pool), &[]);
830        assert!(list.is_empty());
831    }
832
833    #[test]
834    fn growing() {
835        let pool = &mut ListPool::<Inst>::new();
836        let mut list = EntityList::<Inst>::default();
837
838        let i1 = Inst::new(1);
839        let i2 = Inst::new(2);
840        let i3 = Inst::new(3);
841        let i4 = Inst::new(4);
842
843        // This is not supposed to change the list.
844        list.grow_at(0, 0, pool);
845        assert_eq!(list.len(pool), 0);
846        assert!(list.is_empty());
847
848        list.grow_at(0, 2, pool);
849        assert_eq!(list.len(pool), 2);
850
851        list.as_mut_slice(pool).copy_from_slice(&[i2, i3]);
852
853        list.grow_at(1, 0, pool);
854        assert_eq!(list.as_slice(pool), &[i2, i3]);
855
856        list.grow_at(1, 1, pool);
857        list.as_mut_slice(pool)[1] = i1;
858        assert_eq!(list.as_slice(pool), &[i2, i1, i3]);
859
860        // Append nothing at the end.
861        list.grow_at(3, 0, pool);
862        assert_eq!(list.as_slice(pool), &[i2, i1, i3]);
863
864        // Append something at the end.
865        list.grow_at(3, 1, pool);
866        list.as_mut_slice(pool)[3] = i4;
867        assert_eq!(list.as_slice(pool), &[i2, i1, i3, i4]);
868    }
869
870    #[test]
871    fn deep_clone() {
872        let pool = &mut ListPool::<Inst>::new();
873
874        let i1 = Inst::new(1);
875        let i2 = Inst::new(2);
876        let i3 = Inst::new(3);
877        let i4 = Inst::new(4);
878
879        let mut list1 = EntityList::from_slice(&[i1, i2, i3], pool);
880        let list2 = list1.deep_clone(pool);
881        assert_eq!(list1.as_slice(pool), &[i1, i2, i3]);
882        assert_eq!(list2.as_slice(pool), &[i1, i2, i3]);
883
884        list1.as_mut_slice(pool)[0] = i4;
885        assert_eq!(list1.as_slice(pool), &[i4, i2, i3]);
886        assert_eq!(list2.as_slice(pool), &[i1, i2, i3]);
887    }
888
889    #[test]
890    fn truncate() {
891        let pool = &mut ListPool::<Inst>::new();
892
893        let i1 = Inst::new(1);
894        let i2 = Inst::new(2);
895        let i3 = Inst::new(3);
896        let i4 = Inst::new(4);
897
898        let mut list = EntityList::from_slice(&[i1, i2, i3, i4, i1, i2, i3, i4], pool);
899        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2, i3, i4]);
900        list.truncate(6, pool);
901        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]);
902        list.truncate(9, pool);
903        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]);
904        list.truncate(2, pool);
905        assert_eq!(list.as_slice(pool), &[i1, i2]);
906        list.truncate(0, pool);
907        assert!(list.is_empty());
908    }
909
910    #[test]
911    fn copy_from() {
912        let pool = &mut ListPool::<Inst>::new();
913
914        let i1 = Inst::new(1);
915        let i2 = Inst::new(2);
916        let i3 = Inst::new(3);
917        let i4 = Inst::new(4);
918
919        let mut list = EntityList::from_slice(&[i1, i2, i3, i4], pool);
920        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]);
921        let list2 = EntityList::from_slice(&[i4, i3, i2, i1], pool);
922        assert_eq!(list2.as_slice(pool), &[i4, i3, i2, i1]);
923        list.copy_from(&list2, 0..0, 0, pool);
924        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]);
925        list.copy_from(&list2, 0..4, 0, pool);
926        assert_eq!(list.as_slice(pool), &[i4, i3, i2, i1, i1, i2, i3, i4]);
927    }
928
929    #[test]
930    #[should_panic]
931    fn copy_from_self() {
932        let pool = &mut ListPool::<Inst>::new();
933
934        let i1 = Inst::new(1);
935        let i2 = Inst::new(2);
936        let i3 = Inst::new(3);
937        let i4 = Inst::new(4);
938
939        let mut list = EntityList::from_slice(&[i4, i3, i2, i1, i1, i2, i3, i4], pool);
940        let list_again = list;
941        assert_eq!(list.as_slice(pool), &[i4, i3, i2, i1, i1, i2, i3, i4]);
942        // Panic should occur on the line below because `list.index == other.index`
943        list.copy_from(&list_again, 0..=1, 8, pool);
944        assert_eq!(
945            list.as_slice(pool),
946            &[i4, i3, i2, i1, i1, i2, i3, i4, i4, i3]
947        );
948        list.copy_from(&list_again, .., 7, pool);
949        assert_eq!(
950            list.as_slice(pool),
951            &[i4, i3, i2, i1, i1, i2, i4, i3, i2, i1, i1, i2, i3, i4, i4, i3, i3, i4, i4, i3]
952        )
953    }
954}