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