cretonne_entity/
list.rs

1//! Small lists of entity references.
2use std::marker::PhantomData;
3use std::mem;
4use std::vec::Vec;
5use EntityRef;
6
7/// A small list of entity references allocated from a pool.
8///
9/// An `EntityList<T>` type provides similar functionality to `Vec<T>`, but with some important
10/// differences in the implementation:
11///
12/// 1. Memory is allocated from a `ListPool<T>` instead of the global heap.
13/// 2. The footprint of an entity list is 4 bytes, compared with the 24 bytes for `Vec<T>`.
14/// 3. An entity list doesn't implement `Drop`, leaving it to the pool to manage memory.
15///
16/// The list pool is intended to be used as a LIFO allocator. After building up a larger data
17/// structure with many list references, the whole thing can be discarded quickly by clearing the
18/// pool.
19///
20/// # Safety
21///
22/// Entity lists are not as safe to use as `Vec<T>`, but they never jeopardize Rust's memory safety
23/// guarantees. These are the problems to be aware of:
24///
25/// - If you lose track of an entity list, its memory won't be recycled until the pool is cleared.
26///   This can cause the pool to grow very large with leaked lists.
27/// - If entity lists are used after their pool is cleared, they may contain garbage data, and
28///   modifying them may corrupt other lists in the pool.
29/// - If an entity list is used with two different pool instances, both pools are likely to become
30///   corrupted.
31///
32/// Entity lists can be cloned, but that operation should only be used as part of cloning the whole
33/// function they belong to. *Cloning an entity list does not allocate new memory for the clone*.
34/// It creates an alias of the same memory.
35///
36/// Entity lists cannot be hashed and compared for equality because it's not possible to compare the
37/// contents of the list without the pool reference.
38///
39/// # Implementation
40///
41/// The `EntityList` itself is designed to have the smallest possible footprint. This is important
42/// because it is used inside very compact data structures like `InstructionData`. The list
43/// contains only a 32-bit index into the pool's memory vector, pointing to the first element of
44/// the list.
45///
46/// The pool is just a single `Vec<T>` containing all of the allocated lists. Each list is
47/// represented as three contiguous parts:
48///
49/// 1. The number of elements in the list.
50/// 2. The list elements.
51/// 3. Excess capacity elements.
52///
53/// The total size of the three parts is always a power of two, and the excess capacity is always
54/// as small as possible. This means that shrinking a list may cause the excess capacity to shrink
55/// if a smaller power-of-two size becomes available.
56///
57/// Both growing and shrinking a list may cause it to be reallocated in the pool vector.
58///
59/// The index stored in an `EntityList` points to part 2, the list elements. The value 0 is
60/// reserved for the empty list which isn't allocated in the vector.
61#[derive(Clone, Debug)]
62pub struct EntityList<T: EntityRef> {
63    index: u32,
64    unused: PhantomData<T>,
65}
66
67/// Create an empty list.
68impl<T: EntityRef> Default for EntityList<T> {
69    fn default() -> Self {
70        Self {
71            index: 0,
72            unused: PhantomData,
73        }
74    }
75}
76
77/// A memory pool for storing lists of `T`.
78#[derive(Clone, Debug)]
79pub struct ListPool<T: EntityRef> {
80    // The main array containing the lists.
81    data: Vec<T>,
82
83    // Heads of the free lists, one for each size class.
84    free: Vec<usize>,
85}
86
87/// Lists are allocated in sizes that are powers of two, starting from 4.
88/// Each power of two is assigned a size class number, so the size is `4 << SizeClass`.
89type SizeClass = u8;
90
91/// Get the size of a given size class. The size includes the length field, so the maximum list
92/// length is one less than the class size.
93fn sclass_size(sclass: SizeClass) -> usize {
94    4 << sclass
95}
96
97/// Get the size class to use for a given list length.
98/// This always leaves room for the length element in addition to the list elements.
99fn sclass_for_length(len: usize) -> SizeClass {
100    30 - (len as u32 | 3).leading_zeros() as SizeClass
101}
102
103/// Is `len` the minimum length in its size class?
104fn is_sclass_min_length(len: usize) -> bool {
105    len > 3 && len.is_power_of_two()
106}
107
108impl<T: EntityRef> ListPool<T> {
109    /// Create a new list pool.
110    pub fn new() -> Self {
111        Self {
112            data: Vec::new(),
113            free: Vec::new(),
114        }
115    }
116
117    /// Clear the pool, forgetting about all lists that use it.
118    ///
119    /// This invalidates any existing entity lists that used this pool to allocate memory.
120    ///
121    /// The pool's memory is not released to the operating system, but kept around for faster
122    /// allocation in the future.
123    pub fn clear(&mut self) {
124        self.data.clear();
125        self.free.clear();
126    }
127
128    /// Read the length of a list field, if it exists.
129    fn len_of(&self, list: &EntityList<T>) -> Option<usize> {
130        let idx = list.index as usize;
131        // `idx` points at the list elements. The list length is encoded in the element immediately
132        // before the list elements.
133        //
134        // The `wrapping_sub` handles the special case 0, which is the empty list. This way, the
135        // cost of the bounds check that we have to pay anyway is co-opted to handle the special
136        // case of the empty list.
137        self.data.get(idx.wrapping_sub(1)).map(|len| len.index())
138    }
139
140    /// Allocate a storage block with a size given by `sclass`.
141    ///
142    /// Returns the first index of an available segment of `self.data` containing
143    /// `sclass_size(sclass)` elements.
144    fn alloc(&mut self, sclass: SizeClass) -> usize {
145        // First try the free list for this size class.
146        match self.free.get(sclass as usize).cloned() {
147            Some(head) if head > 0 => {
148                // The free list pointers are offset by 1, using 0 to terminate the list.
149                // A block on the free list has two entries: `[ 0, next ]`.
150                // The 0 is where the length field would be stored for a block in use.
151                // The free list heads and the next pointer point at the `next` field.
152                self.free[sclass as usize] = self.data[head].index();
153                head - 1
154            }
155            _ => {
156                // Nothing on the free list. Allocate more memory.
157                let offset = self.data.len();
158                // We don't want to mess around with uninitialized data.
159                // Just fill it up with nulls.
160                self.data.resize(offset + sclass_size(sclass), T::new(0));
161                offset
162            }
163        }
164    }
165
166    /// Free a storage block with a size given by `sclass`.
167    ///
168    /// This must be a block that was previously allocated by `alloc()` with the same size class.
169    fn free(&mut self, block: usize, sclass: SizeClass) {
170        let sclass = sclass as usize;
171
172        // Make sure we have a free-list head for `sclass`.
173        if self.free.len() <= sclass {
174            self.free.resize(sclass + 1, 0);
175        }
176
177        // Make sure the length field is cleared.
178        self.data[block] = T::new(0);
179        // Insert the block on the free list which is a single linked list.
180        self.data[block + 1] = T::new(self.free[sclass]);
181        self.free[sclass] = block + 1
182    }
183
184    /// Returns two mutable slices representing the two requested blocks.
185    ///
186    /// The two returned slices can be longer than the blocks. Each block is located at the front
187    /// of the respective slice.
188    fn mut_slices(&mut self, block0: usize, block1: usize) -> (&mut [T], &mut [T]) {
189        if block0 < block1 {
190            let (s0, s1) = self.data.split_at_mut(block1);
191            (&mut s0[block0..], s1)
192        } else {
193            let (s1, s0) = self.data.split_at_mut(block0);
194            (s0, &mut s1[block1..])
195        }
196    }
197
198    /// Reallocate a block to a different size class.
199    ///
200    /// Copy `elems_to_copy` elements from the old to the new block.
201    fn realloc(
202        &mut self,
203        block: usize,
204        from_sclass: SizeClass,
205        to_sclass: SizeClass,
206        elems_to_copy: usize,
207    ) -> usize {
208        debug_assert!(elems_to_copy <= sclass_size(from_sclass));
209        debug_assert!(elems_to_copy <= sclass_size(to_sclass));
210        let new_block = self.alloc(to_sclass);
211
212        if elems_to_copy > 0 {
213            let (old, new) = self.mut_slices(block, new_block);
214            (&mut new[0..elems_to_copy]).copy_from_slice(&old[0..elems_to_copy]);
215        }
216
217        self.free(block, from_sclass);
218        new_block
219    }
220}
221
222impl<T: EntityRef> EntityList<T> {
223    /// Create a new empty list.
224    pub fn new() -> Self {
225        Default::default()
226    }
227
228    /// Create a new list with the contents initialized from a slice.
229    pub fn from_slice(slice: &[T], pool: &mut ListPool<T>) -> Self {
230        let len = slice.len();
231        if len == 0 {
232            return EntityList::new();
233        }
234
235        let block = pool.alloc(sclass_for_length(len));
236        pool.data[block] = T::new(len);
237        pool.data[block + 1..block + len + 1].copy_from_slice(slice);
238
239        EntityList {
240            index: (block + 1) as u32,
241            unused: PhantomData,
242        }
243    }
244
245    /// Returns `true` if the list has a length of 0.
246    pub fn is_empty(&self) -> bool {
247        // 0 is a magic value for the empty list. Any list in the pool array must have a positive
248        // length.
249        self.index == 0
250    }
251
252    /// Get the number of elements in the list.
253    pub fn len(&self, pool: &ListPool<T>) -> usize {
254        // Both the empty list and any invalidated old lists will return `None`.
255        pool.len_of(self).unwrap_or(0)
256    }
257
258    /// Returns `true` if the list is valid
259    pub fn is_valid(&self, pool: &ListPool<T>) -> bool {
260        // We consider an empty list to be valid
261        self.is_empty() || pool.len_of(self) != None
262    }
263
264    /// Get the list as a slice.
265    pub fn as_slice<'a>(&'a self, pool: &'a ListPool<T>) -> &'a [T] {
266        let idx = self.index as usize;
267        match pool.len_of(self) {
268            None => &[],
269            Some(len) => &pool.data[idx..idx + len],
270        }
271    }
272
273    /// Get a single element from the list.
274    pub fn get(&self, index: usize, pool: &ListPool<T>) -> Option<T> {
275        self.as_slice(pool).get(index).cloned()
276    }
277
278    /// Get the first element from the list.
279    pub fn first(&self, pool: &ListPool<T>) -> Option<T> {
280        if self.is_empty() {
281            None
282        } else {
283            Some(pool.data[self.index as usize])
284        }
285    }
286
287    /// Get the list as a mutable slice.
288    pub fn as_mut_slice<'a>(&'a mut self, pool: &'a mut ListPool<T>) -> &'a mut [T] {
289        let idx = self.index as usize;
290        match pool.len_of(self) {
291            None => &mut [],
292            Some(len) => &mut pool.data[idx..idx + len],
293        }
294    }
295
296    /// Get a mutable reference to a single element from the list.
297    pub fn get_mut<'a>(&'a mut self, index: usize, pool: &'a mut ListPool<T>) -> Option<&'a mut T> {
298        self.as_mut_slice(pool).get_mut(index)
299    }
300
301    /// Removes all elements from the list.
302    ///
303    /// The memory used by the list is put back in the pool.
304    pub fn clear(&mut self, pool: &mut ListPool<T>) {
305        let idx = self.index as usize;
306        match pool.len_of(self) {
307            None => debug_assert_eq!(idx, 0, "Invalid pool"),
308            Some(len) => pool.free(idx - 1, sclass_for_length(len)),
309        }
310        // Switch back to the empty list representation which has no storage.
311        self.index = 0;
312    }
313
314    /// Take all elements from this list and return them as a new list. Leave this list empty.
315    ///
316    /// This is the equivalent of `Option::take()`.
317    pub fn take(&mut self) -> Self {
318        mem::replace(self, Default::default())
319    }
320
321    /// Appends an element to the back of the list.
322    /// Returns the index where the element was inserted.
323    pub fn push(&mut self, element: T, pool: &mut ListPool<T>) -> usize {
324        let idx = self.index as usize;
325        match pool.len_of(self) {
326            None => {
327                // This is an empty list. Allocate a block and set length=1.
328                debug_assert_eq!(idx, 0, "Invalid pool");
329                let block = pool.alloc(sclass_for_length(1));
330                pool.data[block] = T::new(1);
331                pool.data[block + 1] = element;
332                self.index = (block + 1) as u32;
333                0
334            }
335            Some(len) => {
336                // Do we need to reallocate?
337                let new_len = len + 1;
338                let block;
339                if is_sclass_min_length(new_len) {
340                    // Reallocate, preserving length + all old elements.
341                    let sclass = sclass_for_length(len);
342                    block = pool.realloc(idx - 1, sclass, sclass + 1, len + 1);
343                    self.index = (block + 1) as u32;
344                } else {
345                    block = idx - 1;
346                }
347                pool.data[block + new_len] = element;
348                pool.data[block] = T::new(new_len);
349                len
350            }
351        }
352    }
353
354    /// Grow list by adding `count` uninitialized elements at the end.
355    ///
356    /// Returns a mutable slice representing the whole list.
357    fn grow<'a>(&'a mut self, count: usize, pool: &'a mut ListPool<T>) -> &'a mut [T] {
358        let idx = self.index as usize;
359        let new_len;
360        let block;
361        match pool.len_of(self) {
362            None => {
363                // This is an empty list. Allocate a block.
364                debug_assert_eq!(idx, 0, "Invalid pool");
365                if count == 0 {
366                    return &mut [];
367                }
368                new_len = count;
369                block = pool.alloc(sclass_for_length(new_len));
370                self.index = (block + 1) as u32;
371            }
372            Some(len) => {
373                // Do we need to reallocate?
374                let sclass = sclass_for_length(len);
375                new_len = len + count;
376                let new_sclass = sclass_for_length(new_len);
377                if new_sclass != sclass {
378                    block = pool.realloc(idx - 1, sclass, new_sclass, len + 1);
379                    self.index = (block + 1) as u32;
380                } else {
381                    block = idx - 1;
382                }
383            }
384        }
385        pool.data[block] = T::new(new_len);
386        &mut pool.data[block + 1..block + 1 + new_len]
387    }
388
389    /// Appends multiple elements to the back of the list.
390    pub fn extend<I>(&mut self, elements: I, pool: &mut ListPool<T>)
391    where
392        I: IntoIterator<Item = T>,
393    {
394        // TODO: use `size_hint()` to reduce reallocations.
395        for x in elements {
396            self.push(x, pool);
397        }
398    }
399
400    /// Inserts an element as position `index` in the list, shifting all elements after it to the
401    /// right.
402    pub fn insert(&mut self, index: usize, element: T, pool: &mut ListPool<T>) {
403        // Increase size by 1.
404        self.push(element, pool);
405
406        // Move tail elements.
407        let seq = self.as_mut_slice(pool);
408        if index < seq.len() {
409            let tail = &mut seq[index..];
410            for i in (1..tail.len()).rev() {
411                tail[i] = tail[i - 1];
412            }
413            tail[0] = element;
414        } else {
415            debug_assert_eq!(index, seq.len());
416        }
417    }
418
419    /// Removes the element at position `index` from the list. Potentially linear complexity.
420    pub fn remove(&mut self, index: usize, pool: &mut ListPool<T>) {
421        let len;
422        {
423            let seq = self.as_mut_slice(pool);
424            len = seq.len();
425            debug_assert!(index < len);
426
427            // Copy elements down.
428            for i in index..len - 1 {
429                seq[i] = seq[i + 1];
430            }
431        }
432
433        // Check if we deleted the last element.
434        if len == 1 {
435            self.clear(pool);
436            return;
437        }
438
439        // Do we need to reallocate to a smaller size class?
440        let mut block = self.index as usize - 1;
441        if is_sclass_min_length(len) {
442            let sclass = sclass_for_length(len);
443            block = pool.realloc(block, sclass, sclass - 1, len);
444            self.index = (block + 1) as u32;
445        }
446
447        // Finally adjust the length.
448        pool.data[block] = T::new(len - 1);
449    }
450
451    /// Removes the element at `index` in constant time by switching it with the last element of
452    /// the list.
453    pub fn swap_remove(&mut self, index: usize, pool: &mut ListPool<T>) {
454        let len = self.len(pool);
455        debug_assert!(index < len);
456        if index == len - 1 {
457            self.remove(index, pool);
458        } else {
459            {
460                let seq = self.as_mut_slice(pool);
461                seq.swap(index, len - 1);
462            }
463            self.remove(len - 1, pool);
464        }
465    }
466
467    /// Grow the list by inserting `count` elements at `index`.
468    ///
469    /// The new elements are not initialized, they will contain whatever happened to be in memory.
470    /// Since the memory comes from the pool, this will be either zero entity references or
471    /// whatever where in a previously deallocated list.
472    pub fn grow_at(&mut self, index: usize, count: usize, pool: &mut ListPool<T>) {
473        let data = self.grow(count, pool);
474
475        // Copy elements after `index` up.
476        for i in (index + count..data.len()).rev() {
477            data[i] = data[i - count];
478        }
479    }
480}
481
482#[cfg(test)]
483mod tests {
484    use super::*;
485    use super::{sclass_for_length, sclass_size};
486    use EntityRef;
487
488    /// An opaque reference to an instruction in a function.
489    #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
490    pub struct Inst(u32);
491    entity_impl!(Inst, "inst");
492
493    #[test]
494    fn size_classes() {
495        assert_eq!(sclass_size(0), 4);
496        assert_eq!(sclass_for_length(0), 0);
497        assert_eq!(sclass_for_length(1), 0);
498        assert_eq!(sclass_for_length(2), 0);
499        assert_eq!(sclass_for_length(3), 0);
500        assert_eq!(sclass_for_length(4), 1);
501        assert_eq!(sclass_for_length(7), 1);
502        assert_eq!(sclass_for_length(8), 2);
503        assert_eq!(sclass_size(1), 8);
504        for l in 0..300 {
505            assert!(sclass_size(sclass_for_length(l)) >= l + 1);
506        }
507    }
508
509    #[test]
510    fn block_allocator() {
511        let mut pool = ListPool::<Inst>::new();
512        let b1 = pool.alloc(0);
513        let b2 = pool.alloc(1);
514        let b3 = pool.alloc(0);
515        assert_ne!(b1, b2);
516        assert_ne!(b1, b3);
517        assert_ne!(b2, b3);
518        pool.free(b2, 1);
519        let b2a = pool.alloc(1);
520        let b2b = pool.alloc(1);
521        assert_ne!(b2a, b2b);
522        // One of these should reuse the freed block.
523        assert!(b2a == b2 || b2b == b2);
524
525        // Check the free lists for a size class smaller than the largest seen so far.
526        pool.free(b1, 0);
527        pool.free(b3, 0);
528        let b1a = pool.alloc(0);
529        let b3a = pool.alloc(0);
530        assert_ne!(b1a, b3a);
531        assert!(b1a == b1 || b1a == b3);
532        assert!(b3a == b1 || b3a == b3);
533    }
534
535    #[test]
536    fn empty_list() {
537        let pool = &mut ListPool::<Inst>::new();
538        let mut list = EntityList::<Inst>::default();
539        {
540            let ilist = &list;
541            assert!(ilist.is_empty());
542            assert_eq!(ilist.len(pool), 0);
543            assert_eq!(ilist.as_slice(pool), &[]);
544            assert_eq!(ilist.get(0, pool), None);
545            assert_eq!(ilist.get(100, pool), None);
546        }
547        assert_eq!(list.as_mut_slice(pool), &[]);
548        assert_eq!(list.get_mut(0, pool), None);
549        assert_eq!(list.get_mut(100, pool), None);
550
551        list.clear(pool);
552        assert!(list.is_empty());
553        assert_eq!(list.len(pool), 0);
554        assert_eq!(list.as_slice(pool), &[]);
555        assert_eq!(list.first(pool), None);
556    }
557
558    #[test]
559    fn from_slice() {
560        let pool = &mut ListPool::<Inst>::new();
561
562        let list = EntityList::<Inst>::from_slice(&[Inst(0), Inst(1)], pool);
563        assert!(!list.is_empty());
564        assert_eq!(list.len(pool), 2);
565        assert_eq!(list.as_slice(pool), &[Inst(0), Inst(1)]);
566        assert_eq!(list.get(0, pool), Some(Inst(0)));
567        assert_eq!(list.get(100, pool), None);
568
569        let list = EntityList::<Inst>::from_slice(&[], pool);
570        assert!(list.is_empty());
571        assert_eq!(list.len(pool), 0);
572        assert_eq!(list.as_slice(pool), &[]);
573        assert_eq!(list.get(0, pool), None);
574        assert_eq!(list.get(100, pool), None);
575    }
576
577    #[test]
578    fn push() {
579        let pool = &mut ListPool::<Inst>::new();
580        let mut list = EntityList::<Inst>::default();
581
582        let i1 = Inst::new(1);
583        let i2 = Inst::new(2);
584        let i3 = Inst::new(3);
585        let i4 = Inst::new(4);
586
587        assert_eq!(list.push(i1, pool), 0);
588        assert_eq!(list.len(pool), 1);
589        assert!(!list.is_empty());
590        assert_eq!(list.as_slice(pool), &[i1]);
591        assert_eq!(list.first(pool), Some(i1));
592        assert_eq!(list.get(0, pool), Some(i1));
593        assert_eq!(list.get(1, pool), None);
594
595        assert_eq!(list.push(i2, pool), 1);
596        assert_eq!(list.len(pool), 2);
597        assert!(!list.is_empty());
598        assert_eq!(list.as_slice(pool), &[i1, i2]);
599        assert_eq!(list.first(pool), Some(i1));
600        assert_eq!(list.get(0, pool), Some(i1));
601        assert_eq!(list.get(1, pool), Some(i2));
602        assert_eq!(list.get(2, pool), None);
603
604        assert_eq!(list.push(i3, pool), 2);
605        assert_eq!(list.len(pool), 3);
606        assert!(!list.is_empty());
607        assert_eq!(list.as_slice(pool), &[i1, i2, i3]);
608        assert_eq!(list.first(pool), Some(i1));
609        assert_eq!(list.get(0, pool), Some(i1));
610        assert_eq!(list.get(1, pool), Some(i2));
611        assert_eq!(list.get(2, pool), Some(i3));
612        assert_eq!(list.get(3, pool), None);
613
614        // This triggers a reallocation.
615        assert_eq!(list.push(i4, pool), 3);
616        assert_eq!(list.len(pool), 4);
617        assert!(!list.is_empty());
618        assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4]);
619        assert_eq!(list.first(pool), Some(i1));
620        assert_eq!(list.get(0, pool), Some(i1));
621        assert_eq!(list.get(1, pool), Some(i2));
622        assert_eq!(list.get(2, pool), Some(i3));
623        assert_eq!(list.get(3, pool), Some(i4));
624        assert_eq!(list.get(4, pool), None);
625
626        list.extend([i1, i1, i2, i2, i3, i3, i4, i4].iter().cloned(), pool);
627        assert_eq!(list.len(pool), 12);
628        assert_eq!(
629            list.as_slice(pool),
630            &[i1, i2, i3, i4, i1, i1, i2, i2, i3, i3, i4, i4]
631        );
632    }
633
634    #[test]
635    fn insert_remove() {
636        let pool = &mut ListPool::<Inst>::new();
637        let mut list = EntityList::<Inst>::default();
638
639        let i1 = Inst::new(1);
640        let i2 = Inst::new(2);
641        let i3 = Inst::new(3);
642        let i4 = Inst::new(4);
643
644        list.insert(0, i4, pool);
645        assert_eq!(list.as_slice(pool), &[i4]);
646
647        list.insert(0, i3, pool);
648        assert_eq!(list.as_slice(pool), &[i3, i4]);
649
650        list.insert(2, i2, pool);
651        assert_eq!(list.as_slice(pool), &[i3, i4, i2]);
652
653        list.insert(2, i1, pool);
654        assert_eq!(list.as_slice(pool), &[i3, i4, i1, i2]);
655
656        list.remove(3, pool);
657        assert_eq!(list.as_slice(pool), &[i3, i4, i1]);
658
659        list.remove(2, pool);
660        assert_eq!(list.as_slice(pool), &[i3, i4]);
661
662        list.remove(0, pool);
663        assert_eq!(list.as_slice(pool), &[i4]);
664
665        list.remove(0, pool);
666        assert_eq!(list.as_slice(pool), &[]);
667        assert!(list.is_empty());
668    }
669
670    #[test]
671    fn growing() {
672        let pool = &mut ListPool::<Inst>::new();
673        let mut list = EntityList::<Inst>::default();
674
675        let i1 = Inst::new(1);
676        let i2 = Inst::new(2);
677        let i3 = Inst::new(3);
678        let i4 = Inst::new(4);
679
680        // This is not supposed to change the list.
681        list.grow_at(0, 0, pool);
682        assert_eq!(list.len(pool), 0);
683        assert!(list.is_empty());
684
685        list.grow_at(0, 2, pool);
686        assert_eq!(list.len(pool), 2);
687
688        list.as_mut_slice(pool).copy_from_slice(&[i2, i3]);
689
690        list.grow_at(1, 0, pool);
691        assert_eq!(list.as_slice(pool), &[i2, i3]);
692
693        list.grow_at(1, 1, pool);
694        list.as_mut_slice(pool)[1] = i1;
695        assert_eq!(list.as_slice(pool), &[i2, i1, i3]);
696
697        // Append nothing at the end.
698        list.grow_at(3, 0, pool);
699        assert_eq!(list.as_slice(pool), &[i2, i1, i3]);
700
701        // Append something at the end.
702        list.grow_at(3, 1, pool);
703        list.as_mut_slice(pool)[3] = i4;
704        assert_eq!(list.as_slice(pool), &[i2, i1, i3, i4]);
705    }
706}