Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/entity/src/list.rs
1692 views
1
//! Small lists of entity references.
2
use crate::EntityRef;
3
use crate::packed_option::ReservedValue;
4
use alloc::vec::Vec;
5
use core::marker::PhantomData;
6
use core::mem;
7
8
#[cfg(feature = "enable-serde")]
9
use 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)]
68
pub struct EntityList<T: EntityRef + ReservedValue> {
69
index: u32,
70
unused: PhantomData<T>,
71
}
72
73
/// Create an empty list.
74
impl<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))]
86
pub 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
94
impl<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
101
impl<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
108
impl<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`.
116
type 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]
121
fn 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]
128
fn 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]
134
fn is_sclass_min_length(len: usize) -> bool {
135
len > 3 && len.is_power_of_two()
136
}
137
138
impl<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
270
impl<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)]
644
mod 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
&[
952
i4, i3, i2, i1, i1, i2, i4, i3, i2, i1, i1, i2, i3, i4, i4, i3, i3, i4, i4, i3
953
]
954
)
955
}
956
}
957
958