Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-egraph-0.91.1/src/bumpvec.rs
Line
Count
Source (jump to first uncovered line)
1
//! Vectors allocated in arenas, with small per-vector overhead.
2
3
use std::marker::PhantomData;
4
use std::mem::MaybeUninit;
5
use std::ops::Range;
6
7
/// A vector of `T` stored within a `BumpArena`.
8
///
9
/// This is something like a normal `Vec`, except that all accesses
10
/// and updates require a separate borrow of the `BumpArena`. This, in
11
/// turn, makes the Vec itself very compact: only three `u32`s (12
12
/// bytes). The `BumpSlice` variant is only two `u32`s (8 bytes) and
13
/// is sufficient to reconstruct a slice, but not grow the vector.
14
///
15
/// The `BumpVec` does *not* implement `Clone` or `Copy`; it
16
/// represents unique ownership of a range of indices in the arena. If
17
/// dropped, those indices will be unavailable until the arena is
18
/// freed. This is "fine" (it is normally how arena allocation
19
/// works). To explicitly free and make available for some
20
/// allocations, a very rudimentary reuse mechanism exists via
21
/// `BumpVec::free(arena)`. (The allocation path opportunistically
22
/// checks the first range on the freelist, and can carve off a piece
23
/// of it if larger than needed, but it does not attempt to traverse
24
/// the entire freelist; this is a compromise between bump-allocation
25
/// speed and memory efficiency, which also influences speed through
26
/// cached-memory reuse.)
27
///
28
/// The type `T` should not have a `Drop` implementation. This
29
/// typically means that it does not own any boxed memory,
30
/// sub-collections, or other resources. This is important for the
31
/// efficiency of the data structure (otherwise, to call `Drop` impls,
32
/// the arena needs to track which indices are live or dead; the
33
/// BumpVec itself cannot do the drop because it does not retain a
34
/// reference to the arena). Note that placing a `T` with a `Drop`
35
/// impl in the arena is still *safe*, because leaking (that is, never
36
/// calling `Drop::drop()`) is safe. It is merely less efficient, and
37
/// so should be avoided if possible.
38
#[derive(Debug)]
39
pub struct BumpVec<T> {
40
    base: u32,
41
    len: u32,
42
    cap: u32,
43
    _phantom: PhantomData<T>,
44
}
45
46
/// A slice in an arena: like a `BumpVec`, but has a fixed size that
47
/// cannot grow. The size of this struct is one 32-bit word smaller
48
/// than `BumpVec`. It is copyable/cloneable because it will never be
49
/// freed.
50
#[derive(Debug, Clone, Copy)]
51
pub struct BumpSlice<T> {
52
    base: u32,
53
    len: u32,
54
    _phantom: PhantomData<T>,
55
}
56
57
#[derive(Default)]
58
pub struct BumpArena<T> {
59
    vec: Vec<MaybeUninit<T>>,
60
    freelist: Vec<Range<u32>>,
61
}
62
63
impl<T> BumpArena<T> {
64
    /// Create a new arena into which one can allocate `BumpVec`s.
65
0
    pub fn new() -> Self {
66
0
        Self {
67
0
            vec: vec![],
68
0
            freelist: vec![],
69
0
        }
70
0
    }
71
72
    /// Create a new arena, pre-allocating space for `cap` total `T`
73
    /// elements.
74
0
    pub fn arena_with_capacity(cap: usize) -> Self {
75
0
        Self {
76
0
            vec: Vec::with_capacity(cap),
77
0
            freelist: Vec::with_capacity(cap / 16),
78
0
        }
79
0
    }
80
81
    /// Create a new `BumpVec` with the given pre-allocated capacity
82
    /// and zero length.
83
0
    pub fn vec_with_capacity(&mut self, cap: usize) -> BumpVec<T> {
84
0
        let cap = u32::try_from(cap).unwrap();
85
0
        if let Some(range) = self.maybe_freelist_alloc(cap) {
86
0
            BumpVec {
87
0
                base: range.start,
88
0
                len: 0,
89
0
                cap,
90
0
                _phantom: PhantomData,
91
0
            }
92
        } else {
93
0
            let base = self.vec.len() as u32;
94
0
            for _ in 0..cap {
95
0
                self.vec.push(MaybeUninit::uninit());
96
0
            }
97
0
            BumpVec {
98
0
                base,
99
0
                len: 0,
100
0
                cap,
101
0
                _phantom: PhantomData,
102
0
            }
103
        }
104
0
    }
105
106
    /// Create a new `BumpVec` with a single element. The capacity is
107
    /// also only one element; growing the vector further will require
108
    /// a reallocation.
109
0
    pub fn single(&mut self, t: T) -> BumpVec<T> {
110
0
        let mut vec = self.vec_with_capacity(1);
111
0
        unsafe {
112
0
            self.write_into_index(vec.base, t);
113
0
        }
114
0
        vec.len = 1;
115
0
        vec
116
0
    }
117
118
    /// Create a new `BumpVec` with the sequence from an iterator.
119
0
    pub fn from_iter<I: Iterator<Item = T>>(&mut self, i: I) -> BumpVec<T> {
120
0
        let base = self.vec.len() as u32;
121
0
        self.vec.extend(i.map(|item| MaybeUninit::new(item)));
122
0
        let len = self.vec.len() as u32 - base;
123
0
        BumpVec {
124
0
            base,
125
0
            len,
126
0
            cap: len,
127
0
            _phantom: PhantomData,
128
0
        }
129
0
    }
130
131
    /// Append two `BumpVec`s, returning a new one. Consumes both
132
    /// vectors. This will use the capacity at the end of `a` if
133
    /// possible to move `b`'s elements into place; otherwise it will
134
    /// need to allocate new space.
135
0
    pub fn append(&mut self, a: BumpVec<T>, b: BumpVec<T>) -> BumpVec<T> {
136
0
        if (a.cap - a.len) >= b.len {
137
0
            self.append_into_cap(a, b)
138
        } else {
139
0
            self.append_into_new(a, b)
140
        }
141
0
    }
142
143
    /// Helper: read the `T` out of a given arena index. After
144
    /// reading, that index becomes uninitialized.
145
0
    unsafe fn read_out_of_index(&self, index: u32) -> T {
146
0
        // Note that we don't actually *track* uninitialized status
147
0
        // (and this is fine because we will never `Drop` and we never
148
0
        // allow a `BumpVec` to refer to an uninitialized index, so
149
0
        // the bits are effectively dead). We simply read the bits out
150
0
        // and return them.
151
0
        self.vec[index as usize].as_ptr().read()
152
0
    }
153
154
    /// Helper: write a `T` into the given arena index. Index must
155
    /// have been uninitialized previously.
156
0
    unsafe fn write_into_index(&mut self, index: u32, t: T) {
157
0
        self.vec[index as usize].as_mut_ptr().write(t);
158
0
    }
159
160
    /// Helper: move a `T` from one index to another. Old index
161
    /// becomes uninitialized and new index must have previously been
162
    /// uninitialized.
163
0
    unsafe fn move_item(&mut self, from: u32, to: u32) {
164
0
        let item = self.read_out_of_index(from);
165
0
        self.write_into_index(to, item);
166
0
    }
167
168
    /// Helper: push a `T` onto the end of the arena, growing its
169
    /// storage. The `T` to push is read out of another index, and
170
    /// that index subsequently becomes uninitialized.
171
0
    unsafe fn push_item(&mut self, from: u32) -> u32 {
172
0
        let index = self.vec.len() as u32;
173
0
        let item = self.read_out_of_index(from);
174
0
        self.vec.push(MaybeUninit::new(item));
175
0
        index
176
0
    }
177
178
    /// Helper: append `b` into the capacity at the end of `a`.
179
0
    fn append_into_cap(&mut self, mut a: BumpVec<T>, b: BumpVec<T>) -> BumpVec<T> {
180
0
        debug_assert!(a.cap - a.len >= b.len);
181
0
        for i in 0..b.len {
182
            // Safety: initially, the indices in `b` are initialized;
183
            // the indices in `a`'s cap, beyond its length, are
184
            // uninitialized. We move the initialized contents from
185
            // `b` to the tail beyond `a`, and we consume `b` (so it
186
            // no longer exists), and we update `a`'s length to cover
187
            // the initialized contents in their new location.
188
0
            unsafe {
189
0
                self.move_item(b.base + i, a.base + a.len + i);
190
0
            }
191
        }
192
0
        a.len += b.len;
193
0
        b.free(self);
194
0
        a
195
0
    }
196
197
    /// Helper: return a range of indices that are available
198
    /// (uninitialized) according to the freelist for `len` elements,
199
    /// if possible.
200
0
    fn maybe_freelist_alloc(&mut self, len: u32) -> Option<Range<u32>> {
201
0
        if let Some(entry) = self.freelist.last_mut() {
202
0
            if entry.len() >= len as usize {
203
0
                let base = entry.start;
204
0
                entry.start += len;
205
0
                if entry.start == entry.end {
206
0
                    self.freelist.pop();
207
0
                }
208
0
                return Some(base..(base + len));
209
0
            }
210
0
        }
211
0
        None
212
0
    }
213
214
    /// Helper: append `a` and `b` into a completely new allocation.
215
0
    fn append_into_new(&mut self, a: BumpVec<T>, b: BumpVec<T>) -> BumpVec<T> {
216
0
        // New capacity: round up to a power of two.
217
0
        let len = a.len + b.len;
218
0
        let cap = round_up_power_of_two(len);
219
220
0
        if let Some(range) = self.maybe_freelist_alloc(cap) {
221
0
            for i in 0..a.len {
222
                // Safety: the indices in `a` must be initialized. We read
223
                // out the item and copy it to a new index; the old index
224
                // is no longer covered by a BumpVec, because we consume
225
                // `a`.
226
0
                unsafe {
227
0
                    self.move_item(a.base + i, range.start + i);
228
0
                }
229
            }
230
0
            for i in 0..b.len {
231
                // Safety: the indices in `b` must be initialized. We read
232
                // out the item and copy it to a new index; the old index
233
                // is no longer covered by a BumpVec, because we consume
234
                // `b`.
235
0
                unsafe {
236
0
                    self.move_item(b.base + i, range.start + a.len + i);
237
0
                }
238
            }
239
240
0
            a.free(self);
241
0
            b.free(self);
242
0
243
0
            BumpVec {
244
0
                base: range.start,
245
0
                len,
246
0
                cap,
247
0
                _phantom: PhantomData,
248
0
            }
249
        } else {
250
0
            self.vec.reserve(cap as usize);
251
0
            let base = self.vec.len() as u32;
252
0
            for i in 0..a.len {
253
                // Safety: the indices in `a` must be initialized. We read
254
                // out the item and copy it to a new index; the old index
255
                // is no longer covered by a BumpVec, because we consume
256
                // `a`.
257
0
                unsafe {
258
0
                    self.push_item(a.base + i);
259
0
                }
260
            }
261
0
            for i in 0..b.len {
262
                // Safety: the indices in `b` must be initialized. We read
263
                // out the item and copy it to a new index; the old index
264
                // is no longer covered by a BumpVec, because we consume
265
                // `b`.
266
0
                unsafe {
267
0
                    self.push_item(b.base + i);
268
0
                }
269
            }
270
0
            let len = self.vec.len() as u32 - base;
271
0
272
0
            for _ in len..cap {
273
0
                self.vec.push(MaybeUninit::uninit());
274
0
            }
275
276
0
            a.free(self);
277
0
            b.free(self);
278
0
279
0
            BumpVec {
280
0
                base,
281
0
                len,
282
0
                cap,
283
0
                _phantom: PhantomData,
284
0
            }
285
        }
286
0
    }
287
288
    /// Returns the size of the backing `Vec`.
289
0
    pub fn size(&self) -> usize {
290
0
        self.vec.len()
291
0
    }
292
}
293
294
0
fn round_up_power_of_two(x: u32) -> u32 {
295
0
    debug_assert!(x > 0);
296
0
    debug_assert!(x < 0x8000_0000);
297
0
    let log2 = 32 - (x - 1).leading_zeros();
298
0
    1 << log2
299
0
}
300
301
impl<T> BumpVec<T> {
302
    /// Returns a slice view of this `BumpVec`, given a borrow of the
303
    /// arena.
304
0
    pub fn as_slice<'a>(&'a self, arena: &'a BumpArena<T>) -> &'a [T] {
305
0
        let maybe_uninit_slice =
306
0
            &arena.vec[(self.base as usize)..((self.base + self.len) as usize)];
307
0
        // Safety: the index range we represent must be initialized.
308
0
        unsafe { std::mem::transmute(maybe_uninit_slice) }
309
0
    }
310
311
    /// Returns a mutable slice view of this `BumpVec`, given a
312
    /// mutable borrow of the arena.
313
0
    pub fn as_mut_slice<'a>(&'a mut self, arena: &'a mut BumpArena<T>) -> &'a mut [T] {
314
0
        let maybe_uninit_slice =
315
0
            &mut arena.vec[(self.base as usize)..((self.base + self.len) as usize)];
316
0
        // Safety: the index range we represent must be initialized.
317
0
        unsafe { std::mem::transmute(maybe_uninit_slice) }
318
0
    }
319
320
    /// Returns the length of this vector. Does not require access to
321
    /// the arena.
322
0
    pub fn len(&self) -> usize {
323
0
        self.len as usize
324
0
    }
325
326
    /// Returns the capacity of this vector. Does not require access
327
    /// to the arena.
328
0
    pub fn cap(&self) -> usize {
329
0
        self.cap as usize
330
0
    }
331
332
    /// Reserve `extra_len` capacity at the end of the vector,
333
    /// reallocating if necessary.
334
0
    pub fn reserve(&mut self, extra_len: usize, arena: &mut BumpArena<T>) {
335
0
        let extra_len = u32::try_from(extra_len).unwrap();
336
0
        if self.cap - self.len < extra_len {
337
0
            if self.base + self.cap == arena.vec.len() as u32 {
338
0
                for _ in 0..extra_len {
339
0
                    arena.vec.push(MaybeUninit::uninit());
340
0
                }
341
0
                self.cap += extra_len;
342
            } else {
343
0
                let new_cap = self.cap + extra_len;
344
0
                let new = arena.vec_with_capacity(new_cap as usize);
345
                unsafe {
346
0
                    for i in 0..self.len {
347
0
                        arena.move_item(self.base + i, new.base + i);
348
0
                    }
349
                }
350
0
                self.base = new.base;
351
0
                self.cap = new.cap;
352
            }
353
0
        }
354
0
    }
355
356
    /// Push an item, growing the capacity if needed.
357
0
    pub fn push(&mut self, t: T, arena: &mut BumpArena<T>) {
358
0
        if self.cap > self.len {
359
0
            unsafe {
360
0
                arena.write_into_index(self.base + self.len, t);
361
0
            }
362
0
            self.len += 1;
363
0
        } else if (self.base + self.cap) as usize == arena.vec.len() {
364
0
            arena.vec.push(MaybeUninit::new(t));
365
0
            self.cap += 1;
366
0
            self.len += 1;
367
0
        } else {
368
0
            let new_cap = round_up_power_of_two(self.cap + 1);
369
0
            let extra = new_cap - self.cap;
370
0
            self.reserve(extra as usize, arena);
371
0
            unsafe {
372
0
                arena.write_into_index(self.base + self.len, t);
373
0
            }
374
0
            self.len += 1;
375
0
        }
376
0
    }
377
378
    /// Clone, if `T` is cloneable.
379
0
    pub fn clone(&self, arena: &mut BumpArena<T>) -> BumpVec<T>
380
0
    where
381
0
        T: Clone,
382
0
    {
383
0
        let mut new = arena.vec_with_capacity(self.len as usize);
384
0
        for i in 0..self.len {
385
0
            let item = self.as_slice(arena)[i as usize].clone();
386
0
            new.push(item, arena);
387
0
        }
388
0
        new
389
0
    }
390
391
    /// Truncate the length to a smaller-or-equal length.
392
0
    pub fn truncate(&mut self, len: usize) {
393
0
        let len = len as u32;
394
0
        assert!(len <= self.len);
395
0
        self.len = len;
396
0
    }
397
398
    /// Consume the BumpVec and return its indices to a free pool in
399
    /// the arena.
400
0
    pub fn free(self, arena: &mut BumpArena<T>) {
401
0
        arena.freelist.push(self.base..(self.base + self.cap));
402
0
    }
403
404
    /// Freeze the capacity of this BumpVec, turning it into a slice,
405
    /// for a smaller struct (8 bytes rather than 12). Once this
406
    /// exists, it is copyable, because the slice will never be freed.
407
0
    pub fn freeze(self, arena: &mut BumpArena<T>) -> BumpSlice<T> {
408
0
        if self.cap > self.len {
409
0
            arena
410
0
                .freelist
411
0
                .push((self.base + self.len)..(self.base + self.cap));
412
0
        }
413
0
        BumpSlice {
414
0
            base: self.base,
415
0
            len: self.len,
416
0
            _phantom: PhantomData,
417
0
        }
418
0
    }
419
}
420
421
impl<T> BumpSlice<T> {
422
    /// Returns a slice view of the `BumpSlice`, given a borrow of the
423
    /// arena.
424
0
    pub fn as_slice<'a>(&'a self, arena: &'a BumpArena<T>) -> &'a [T] {
425
0
        let maybe_uninit_slice =
426
0
            &arena.vec[(self.base as usize)..((self.base + self.len) as usize)];
427
0
        // Safety: the index range we represent must be initialized.
428
0
        unsafe { std::mem::transmute(maybe_uninit_slice) }
429
0
    }
430
431
    /// Returns a mutable slice view of the `BumpSlice`, given a
432
    /// mutable borrow of the arena.
433
0
    pub fn as_mut_slice<'a>(&'a mut self, arena: &'a mut BumpArena<T>) -> &'a mut [T] {
434
0
        let maybe_uninit_slice =
435
0
            &mut arena.vec[(self.base as usize)..((self.base + self.len) as usize)];
436
0
        // Safety: the index range we represent must be initialized.
437
0
        unsafe { std::mem::transmute(maybe_uninit_slice) }
438
0
    }
439
440
    /// Returns the length of the `BumpSlice`.
441
0
    pub fn len(&self) -> usize {
442
0
        self.len as usize
443
0
    }
444
}
445
446
impl<T> std::default::Default for BumpVec<T> {
447
0
    fn default() -> Self {
448
0
        BumpVec {
449
0
            base: 0,
450
0
            len: 0,
451
0
            cap: 0,
452
0
            _phantom: PhantomData,
453
0
        }
454
0
    }
455
}
456
457
impl<T> std::default::Default for BumpSlice<T> {
458
0
    fn default() -> Self {
459
0
        BumpSlice {
460
0
            base: 0,
461
0
            len: 0,
462
0
            _phantom: PhantomData,
463
0
        }
464
0
    }
465
}
466
467
#[cfg(test)]
468
mod test {
469
    use super::*;
470
471
    #[test]
472
    fn test_round_up() {
473
        assert_eq!(1, round_up_power_of_two(1));
474
        assert_eq!(2, round_up_power_of_two(2));
475
        assert_eq!(4, round_up_power_of_two(3));
476
        assert_eq!(4, round_up_power_of_two(4));
477
        assert_eq!(32, round_up_power_of_two(24));
478
        assert_eq!(0x8000_0000, round_up_power_of_two(0x7fff_ffff));
479
    }
480
481
    #[test]
482
    fn test_basic() {
483
        let mut arena: BumpArena<u32> = BumpArena::new();
484
485
        let a = arena.single(1);
486
        let b = arena.single(2);
487
        let c = arena.single(3);
488
        let ab = arena.append(a, b);
489
        assert_eq!(ab.as_slice(&arena), &[1, 2]);
490
        assert_eq!(ab.cap(), 2);
491
        let abc = arena.append(ab, c);
492
        assert_eq!(abc.len(), 3);
493
        assert_eq!(abc.cap(), 4);
494
        assert_eq!(abc.as_slice(&arena), &[1, 2, 3]);
495
        assert_eq!(arena.size(), 9);
496
        let mut d = arena.single(4);
497
        // Should have reused the freelist.
498
        assert_eq!(arena.size(), 9);
499
        assert_eq!(d.len(), 1);
500
        assert_eq!(d.cap(), 1);
501
        assert_eq!(d.as_slice(&arena), &[4]);
502
        d.as_mut_slice(&mut arena)[0] = 5;
503
        assert_eq!(d.as_slice(&arena), &[5]);
504
        abc.free(&mut arena);
505
        let d2 = d.clone(&mut arena);
506
        let dd = arena.append(d, d2);
507
        // Should have reused the freelist.
508
        assert_eq!(arena.size(), 9);
509
        assert_eq!(dd.as_slice(&arena), &[5, 5]);
510
        let mut e = arena.from_iter([10, 11, 12].into_iter());
511
        e.push(13, &mut arena);
512
        assert_eq!(arena.size(), 13);
513
        e.reserve(4, &mut arena);
514
        assert_eq!(arena.size(), 17);
515
        let _f = arena.from_iter([1, 2, 3, 4, 5, 6, 7, 8].into_iter());
516
        assert_eq!(arena.size(), 25);
517
        e.reserve(8, &mut arena);
518
        assert_eq!(e.cap(), 16);
519
        assert_eq!(e.as_slice(&arena), &[10, 11, 12, 13]);
520
        // `e` must have been copied now that `f` is at the end of the
521
        // arena.
522
        assert_eq!(arena.size(), 41);
523
    }
524
}