zone_alloc/
arena.rs

1#[cfg(not(feature = "std"))]
2extern crate alloc;
3
4#[cfg(feature = "std")]
5extern crate core;
6
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9use core::{
10    cell::{
11        RefCell,
12        RefMut,
13    },
14    cmp,
15    iter,
16    mem,
17    slice,
18    str,
19};
20
21const MIN_CAPACITY: usize = 1;
22const DEFAULT_INITIAL_SIZE: usize = 1024;
23
24/// A container that can be used for arena allocation of values of a given type.
25///
26/// An [`Arena`] guarantees that all references returned are valid for the lifetime of the arena. A
27/// single value can be moved into the arena using [`Arena::alloc`], and multiple values can be
28/// moved into one contiguous block of memory owned by the arena using [`Arena::alloc_extend`].
29///
30/// All items in the arena are deallocated at the same time when the arena goes out of scope. There
31/// is no support for controlled deallocation of certain items in memory, so this arena type is most
32/// useful for designs where several groups of values should be allocated and deallocated together
33/// over the life of a program.
34///
35/// Internally, arena allocation is achieved by allocating contiguous blocks of memory that are
36/// never resized (to ensure values are never moved). All items will be allocated in a single,
37/// contiguous block of memory. When the arena's current memory block is full, the block is
38/// "committed", and a new, larger block of memory is allocated for future items.
39///
40/// This data type is not thread safe. In fact, usage across multiple threads will likely panic.
41pub struct Arena<T> {
42    blocks: RefCell<MemoryBlocks<T>>,
43}
44
45/// Memory blocks for arena allocation, in their own struct to enable interior mutability on the
46/// arena object.
47struct MemoryBlocks<T> {
48    current: Vec<T>,
49    committed: Vec<Vec<T>>,
50}
51
52impl<T> MemoryBlocks<T> {
53    fn remaining_space_in_current_block(&self) -> usize {
54        self.current.capacity() - self.current.len()
55    }
56
57    #[inline(never)]
58    #[cold]
59    fn reserve(&mut self, num: usize) {
60        let double = self
61            .current
62            .capacity()
63            .checked_mul(2)
64            .expect("capacity overflow");
65        let required = num.checked_next_power_of_two().expect("capacity overflow");
66        let new_capacity = cmp::max(double, required);
67        if self.current.is_empty() {
68            // Small optimization: if the current block has not been used, we can just resize it.
69            self.current.reserve(new_capacity);
70        } else {
71            // Commit the current block and replace it with a new block.
72            self.committed.push(mem::replace(
73                &mut self.current,
74                Vec::with_capacity(new_capacity),
75            ));
76        }
77    }
78}
79
80enum IterMutState<'a, T> {
81    Committed {
82        index: usize,
83        iter: slice::IterMut<'a, T>,
84    },
85    Current {
86        iter: slice::IterMut<'a, T>,
87    },
88}
89
90/// Iterator over mutable elements in an [`Arena`].
91pub struct IterMut<'a, T> {
92    blocks: RefMut<'a, MemoryBlocks<T>>,
93    state: IterMutState<'a, T>,
94}
95
96impl<'a, T> Iterator for IterMut<'a, T> {
97    type Item = &'a mut T;
98
99    fn next(&mut self) -> Option<Self::Item> {
100        loop {
101            self.state = match self.state {
102                IterMutState::Committed {
103                    mut index,
104                    ref mut iter,
105                } => match iter.next() {
106                    Some(item) => return Some(item),
107                    None => {
108                        index += 1;
109                        if index < self.blocks.committed.len() {
110                            let iter = self.blocks.committed[index].iter_mut();
111                            let iter = unsafe { mem::transmute(iter) };
112                            IterMutState::Committed { index, iter }
113                        } else {
114                            let iter = self.blocks.current.iter_mut();
115                            let iter = unsafe { mem::transmute(iter) };
116                            IterMutState::Current { iter }
117                        }
118                    }
119                },
120                IterMutState::Current { ref mut iter } => return iter.next(),
121            }
122        }
123    }
124
125    fn size_hint(&self) -> (usize, Option<usize>) {
126        match &self.state {
127            IterMutState::Committed { index, iter } => {
128                let next = index + 1;
129                let known_remainder = self.blocks.current.len()
130                    + if next < self.blocks.committed.len() {
131                        self.blocks.committed[next..]
132                            .iter()
133                            .fold(0, |acc, b| acc + b.len())
134                    } else {
135                        0
136                    };
137                let (min, max) = iter.size_hint();
138                return (known_remainder + min, max.map(|n| n + known_remainder));
139            }
140            IterMutState::Current { iter } => iter.size_hint(),
141        }
142    }
143}
144
145impl<T> Arena<T> {
146    /// Creates a new arena.
147    pub fn new() -> Self {
148        let size = cmp::max(1, mem::size_of::<T>());
149        Self::with_capacity(DEFAULT_INITIAL_SIZE / size)
150    }
151
152    /// Creates a new arena with the given capacity.
153    pub fn with_capacity(size: usize) -> Self {
154        let size = cmp::max(MIN_CAPACITY, size);
155        Self {
156            blocks: RefCell::new(MemoryBlocks {
157                current: Vec::with_capacity(size),
158                committed: Vec::new(),
159            }),
160        }
161    }
162
163    /// Checks if the arena is empty.
164    pub fn is_empty(&self) -> bool {
165        self.len() == 0
166    }
167
168    /// Returns the number of elements allocated in the arena.
169    pub fn len(&self) -> usize {
170        let blocks = self.blocks.borrow();
171        blocks
172            .committed
173            .iter()
174            .fold(blocks.current.len(), |acc, b| acc + b.len())
175    }
176
177    /// Allocates a new value in the arena, returning a mutable reference to that value.
178    pub fn alloc(&self, value: T) -> &mut T {
179        self.alloc_in_current_block(value)
180            .unwrap_or_else(|value| self.alloc_in_new_block(value))
181    }
182
183    #[inline]
184    fn alloc_in_current_block(&self, value: T) -> Result<&mut T, T> {
185        let mut blocks = self.blocks.borrow_mut();
186        let len = blocks.current.len();
187        if blocks.current.len() < blocks.current.capacity() {
188            blocks.current.push(value);
189            Ok(unsafe { &mut *blocks.current.as_mut_ptr().add(len) })
190        } else {
191            // Return the value back out so it can be moved to a new block.
192            Err(value)
193        }
194    }
195
196    fn alloc_in_new_block(&self, value: T) -> &mut T {
197        &mut self.alloc_extend(iter::once(value))[0]
198    }
199
200    /// Allocates the contents of an iterator in the arena into a contiguous block of memory.
201    ///
202    /// Returns a mutable slice containing all allocated values.
203    pub fn alloc_extend<I>(&self, iterable: I) -> &mut [T]
204    where
205        I: IntoIterator<Item = T>,
206    {
207        let mut blocks = self.blocks.borrow_mut();
208        let mut iter = iterable.into_iter();
209        // The index in the current block where our slice starts.
210        let mut slice_start_index = 0;
211        // Iterators can provide a size hint. If an iterator tells us it needs more space than the
212        // current block has, we optimize and just create a new block for the iterator up front.
213        let min_size = iter.size_hint().0;
214        if min_size > blocks.remaining_space_in_current_block() {
215            blocks.reserve(min_size);
216            blocks.current.extend(iter);
217        } else {
218            // We have no size information about the iterator, so we start by adding elements to the
219            // current block. If we run out of space, we just allocate a new block for
220            // the whole iterator.
221            slice_start_index = blocks.current.len();
222            let mut i = 0;
223            while let Some(value) = iter.next() {
224                if blocks.current.len() == blocks.current.capacity() {
225                    // Allocate a new block, because the current block doesn't have enough space.
226                    let blocks = &mut *blocks;
227                    blocks.reserve(i + 1);
228                    // Move the elements we added to the previous block to this new block.
229                    let prev = blocks.committed.last_mut().unwrap();
230                    let prev_len = prev.len();
231                    blocks.current.extend(prev.drain(prev_len - i..));
232                    blocks.current.push(value);
233                    blocks.current.extend(iter);
234                    slice_start_index = 0;
235                    break;
236                }
237                blocks.current.push(value);
238                i += 1;
239            }
240        }
241
242        // Extend the lifetime of added elements to the lifetime of `self`.
243        // This is valid as long as we ensure we never move or deallocate items.
244        unsafe {
245            let slice_len = blocks.current.len() - slice_start_index;
246            slice::from_raw_parts_mut(
247                blocks.current.as_mut_ptr().add(slice_start_index),
248                slice_len,
249            )
250        }
251    }
252
253    /// Ensures there is enough continuous space for at least `additional` values.
254    pub fn reserve(&self, additional: usize) {
255        let mut blocks = self.blocks.borrow_mut();
256
257        if additional > blocks.remaining_space_in_current_block() {
258            blocks.reserve(additional);
259        }
260    }
261
262    /// Converts the [`Arena<T>`] into a [`Vec<T>`].
263    ///
264    /// Items will be in the same order of allocation in the arena.
265    pub fn into_vec(self) -> Vec<T> {
266        let mut blocks = self.blocks.into_inner();
267        let mut out = Vec::with_capacity(
268            blocks
269                .committed
270                .iter()
271                .fold(blocks.current.len(), |acc, b| acc + b.len()),
272        );
273        for mut block in blocks.committed {
274            out.append(&mut block);
275        }
276        out.append(&mut blocks.current);
277        out
278    }
279
280    /// Returns an iterator that provides mutable access to all elements in the arena, in order of
281    /// allocation.
282    ///
283    /// Arenas only allow mutable iteration because the entire arena must be borrowed for the
284    /// duration of the iteration. The mutable borrow to call this method allows Rust's borrow
285    /// checker to enforce this rule.
286    pub fn iter_mut(&mut self) -> IterMut<T> {
287        let mut blocks = self.blocks.borrow_mut();
288        let state = if !blocks.committed.is_empty() {
289            let index = 0;
290            let iter = blocks.committed[index].iter_mut();
291            let iter = unsafe { mem::transmute(iter) };
292            IterMutState::Committed { index, iter }
293        } else {
294            let iter = unsafe { mem::transmute(blocks.current.iter_mut()) };
295            IterMutState::Current { iter }
296        };
297        IterMut { blocks, state }
298    }
299}
300
301impl Arena<u8> {
302    /// Allocates a string slice in the arena, returning a mutable reference to it.
303    pub fn alloc_str(&self, s: &str) -> &mut str {
304        let slice = self.alloc_extend(s.bytes());
305        // Valid because the string came in as utf-8.
306        unsafe { str::from_utf8_unchecked_mut(slice) }
307    }
308}
309
310impl<T> Default for Arena<T> {
311    fn default() -> Self {
312        Self::new()
313    }
314}
315
316impl<A> FromIterator<A> for Arena<A> {
317    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
318        let iter = iter.into_iter();
319        let arena = Self::with_capacity(iter.size_hint().0);
320        arena.alloc_extend(iter);
321        arena
322    }
323}
324
325#[cfg(test)]
326mod arena_test {
327    #[cfg(not(feature = "std"))]
328    extern crate alloc;
329
330    #[cfg(not(feature = "std"))]
331    use alloc::vec;
332    use core::{
333        cell::Cell,
334        mem,
335    };
336    #[cfg(feature = "std")]
337    use std::sync::{
338        Arc,
339        Mutex,
340    };
341
342    use crate::Arena;
343
344    // A shared counter for how many times a value is deallocated.
345    struct DropCounter<'c>(&'c Cell<u32>);
346
347    impl<'c> Drop for DropCounter<'c> {
348        fn drop(&mut self) {
349            self.0.set(self.0.get() + 1);
350        }
351    }
352
353    // A node type, like one used in a list, tree, or graph data structure.
354    //
355    // Helps us verify that arena-allocated values can refer to each other.
356    struct Node<'a, 'd, T> {
357        parent: Option<&'a Node<'a, 'd, T>>,
358        value: T,
359        #[allow(dead_code)]
360        drop_counter: DropCounter<'d>,
361    }
362
363    impl<'a, 'd, T> Node<'a, 'd, T> {
364        pub fn new(
365            parent: Option<&'a Node<'a, 'd, T>>,
366            value: T,
367            drop_counter: DropCounter<'d>,
368        ) -> Self {
369            Self {
370                parent,
371                value,
372                drop_counter,
373            }
374        }
375    }
376
377    fn commited_blocks<T>(arena: &Arena<T>) -> usize {
378        arena.blocks.borrow().committed.len()
379    }
380
381    #[test]
382    #[allow(dropping_references)]
383    fn allocates_and_owns_values() {
384        let drop_counter = Cell::new(0);
385        {
386            let arena = Arena::with_capacity(2);
387            assert!(arena.is_empty());
388
389            // Allocate a chain of nodes that refer to each other.
390            let mut node: &Node<u32> = arena.alloc(Node::new(None, 1, DropCounter(&drop_counter)));
391            assert_eq!(commited_blocks(&arena), 0);
392            assert_eq!(arena.len(), 1);
393            assert!(!arena.is_empty());
394            node = arena.alloc(Node::new(Some(node), 2, DropCounter(&drop_counter)));
395            assert_eq!(commited_blocks(&arena), 0);
396            assert_eq!(arena.len(), 2);
397            node = arena.alloc(Node::new(Some(node), 3, DropCounter(&drop_counter)));
398            assert_eq!(commited_blocks(&arena), 1);
399            assert_eq!(arena.len(), 3);
400            node = arena.alloc(Node::new(Some(node), 4, DropCounter(&drop_counter)));
401            assert_eq!(commited_blocks(&arena), 1);
402            assert_eq!(arena.len(), 4);
403
404            assert_eq!(node.value, 4);
405            assert_eq!(node.parent.unwrap().value, 3);
406            assert_eq!(node.parent.unwrap().parent.unwrap().value, 2);
407            assert_eq!(
408                node.parent.unwrap().parent.unwrap().parent.unwrap().value,
409                1
410            );
411            assert!(node
412                .parent
413                .unwrap()
414                .parent
415                .unwrap()
416                .parent
417                .unwrap()
418                .parent
419                .is_none());
420
421            // Dropping a node doesn't work. It's trivial (since we return references), but this at
422            // least guarantees we don't break our interface.
423            mem::drop(node);
424            assert_eq!(drop_counter.get(), 0);
425
426            node = arena.alloc(Node::new(None, 5, DropCounter(&drop_counter)));
427            assert_eq!(commited_blocks(&arena), 1);
428            node = arena.alloc(Node::new(Some(node), 6, DropCounter(&drop_counter)));
429            assert_eq!(commited_blocks(&arena), 1);
430            node = arena.alloc(Node::new(Some(node), 7, DropCounter(&drop_counter)));
431            assert_eq!(commited_blocks(&arena), 2);
432
433            assert_eq!(node.value, 7);
434            assert_eq!(node.parent.unwrap().value, 6);
435            assert_eq!(node.parent.unwrap().parent.unwrap().value, 5);
436            assert!(node.parent.unwrap().parent.unwrap().parent.is_none());
437
438            assert_eq!(drop_counter.get(), 0);
439        }
440        // All values deallocated at the same time.
441        assert_eq!(drop_counter.get(), 7);
442    }
443
444    #[test]
445    #[cfg(feature = "std")]
446    fn allocates_strings() {
447        let arena = Arena::new();
448        let str = arena.alloc_str("abcd");
449        assert_eq!(str, "abcd");
450        let str = arena.alloc_str("defg");
451        assert_eq!(str, "defg");
452        let str = "hijklmnop".to_owned();
453        let str = arena.alloc_str(&str);
454        assert_eq!(str, "hijklmnop");
455    }
456
457    #[test]
458    fn supports_circular_reference() {
459        struct CircularNode<'a, T> {
460            value: T,
461            other: Cell<Option<&'a CircularNode<'a, T>>>,
462        }
463
464        let arena = Arena::with_capacity(2);
465        let a = arena.alloc(CircularNode {
466            value: 1,
467            other: Cell::new(None),
468        });
469        let b = arena.alloc(CircularNode {
470            value: 2,
471            other: Cell::new(None),
472        });
473        a.other.set(Some(b));
474        b.other.set(Some(a));
475        assert_eq!(a.other.get().unwrap().value, 2);
476        assert_eq!(b.other.get().unwrap().value, 1);
477    }
478
479    #[test]
480    fn alloc_extend_allocates_and_returns_slice() {
481        let arena = Arena::with_capacity(2);
482        for i in 0..15 {
483            let slice = arena.alloc_extend(0..i);
484            for (j, &value) in (0..i).zip(slice.iter()) {
485                assert_eq!(j, value)
486            }
487        }
488    }
489
490    #[test]
491    fn alloc_extend_allocates_and_owns_values() {
492        let drop_counter = Cell::new(0);
493        {
494            let arena = Arena::with_capacity(2);
495            let iter = (0..100).map(|i| Node::new(None, i, DropCounter(&drop_counter)));
496            let root = &arena.alloc_extend(iter)[0];
497            let iter = (0..100).map(|i| Node::new(Some(root), i, DropCounter(&drop_counter)));
498            arena.alloc_extend(iter);
499            assert_eq!(drop_counter.get(), 0);
500        }
501        assert_eq!(drop_counter.get(), 200);
502    }
503
504    #[test]
505    fn alloc_extend_uses_size_hint() {
506        struct Iter<I>(I);
507        impl<I> Iterator for Iter<I>
508        where
509            I: Iterator,
510        {
511            type Item = I::Item;
512
513            fn next(&mut self) -> Option<Self::Item> {
514                self.0.next()
515            }
516
517            fn size_hint(&self) -> (usize, Option<usize>) {
518                (16, None)
519            }
520        }
521
522        let arena = Arena::with_capacity(10);
523        arena.alloc(123);
524        // This iterator provides a size hint larger than the current capacity, forcing it into a
525        // new block.
526        let slice = arena.alloc_extend(Iter(0..4));
527        assert_eq!(commited_blocks(&arena), 1);
528        assert_eq!(slice.len(), 4);
529    }
530
531    #[test]
532    fn alloc_extend_ignores_size_hint() {
533        struct Iter<I>(I);
534        impl<I> Iterator for Iter<I>
535        where
536            I: Iterator,
537        {
538            type Item = I::Item;
539
540            fn next(&mut self) -> Option<Self::Item> {
541                self.0.next()
542            }
543
544            fn size_hint(&self) -> (usize, Option<usize>) {
545                (2, None)
546            }
547        }
548
549        let arena = Arena::with_capacity(50);
550        arena.alloc(123);
551        // This iterator provides a size hint that does not require a new block, but the iterator
552        // will exceeds the current block's capacity.
553        //
554        // Validate that our arena doesn't blindly follow the size hint in this case.
555        let slice = arena.alloc_extend(Iter(0..100));
556        assert_eq!(commited_blocks(&arena), 1);
557        assert_eq!(slice.len(), 100);
558    }
559
560    #[test]
561    fn alloc_respects_initial_capacity() {
562        let arena = Arena::with_capacity(1000);
563        arena.alloc_extend(0..1000);
564        assert_eq!(commited_blocks(&arena), 0);
565    }
566
567    #[test]
568    fn reserve_large_block() {
569        let arena = Arena::with_capacity(2);
570        // Commit the first block and start the next.
571        arena.alloc_extend(0..1);
572        arena.alloc_extend(0..100);
573        // Since the current block has elements in it, a new block is created.
574        arena.reserve(1000);
575        assert_eq!(commited_blocks(&arena), 2);
576        // These should fit in the same block.
577        arena.alloc_extend(0..500);
578        arena.alloc_extend(501..1000);
579        assert_eq!(commited_blocks(&arena), 2);
580    }
581
582    #[test]
583    fn into_vec_reflects_insertion_order() {
584        let arena = Arena::with_capacity(1);
585        for &s in &["a", "b", "c", "d"] {
586            arena.alloc(s);
587        }
588        let vec = arena.into_vec();
589        assert_eq!(vec, vec!["a", "b", "c", "d"])
590    }
591
592    #[test]
593    fn iter_mut_itereates_in_order() {
594        #[derive(Debug, PartialEq, Eq)]
595        struct NoCopy(usize);
596
597        let mut arena = Arena::new();
598        for i in 0..10 {
599            arena.alloc(NoCopy(i));
600        }
601        assert!(arena
602            .iter_mut()
603            .zip((0..10).map(|i| NoCopy(i)))
604            .all(|(a, b)| a == &b));
605    }
606
607    #[test]
608    fn iter_mut_allows_mutable_access() {
609        let mut arena = Arena::new();
610        for i in 0..10 {
611            arena.alloc(i);
612        }
613        for i in arena.iter_mut() {
614            *i += 1
615        }
616        assert!(arena.iter_mut().zip(1..11).all(|(a, b)| a == &b));
617    }
618
619    #[test]
620    fn iter_mut_over_multiple_blocks() {
621        const LENGTH: usize = 1000;
622        const CAPACITY: usize = 4;
623
624        let mut arena = Arena::with_capacity(CAPACITY);
625        for i in 0..LENGTH {
626            arena.alloc(i);
627        }
628
629        assert!(commited_blocks(&arena) > 1);
630        assert_eq!(arena.len(), LENGTH);
631        assert!(arena.iter_mut().zip(0..LENGTH).all(|(a, b)| a == &b));
632    }
633
634    #[test]
635    fn iter_mut_over_one_block() {
636        const LENGTH: usize = 1000;
637        const CAPACITY: usize = 10000;
638
639        let mut arena = Arena::with_capacity(CAPACITY);
640        for i in 0..LENGTH {
641            arena.alloc(i);
642        }
643
644        assert_eq!(commited_blocks(&arena), 0);
645        assert_eq!(arena.len(), LENGTH);
646        assert!(arena.iter_mut().zip(0..LENGTH).all(|(a, b)| a == &b));
647    }
648
649    #[test]
650    fn iter_mut_size_hint_is_always_bounded_correctly() {
651        const LENGTH: usize = 1000;
652
653        let mut arena = Arena::with_capacity(0);
654        for i in 0..LENGTH {
655            arena.alloc(i);
656        }
657        let mut iter = arena.iter_mut().zip((0..LENGTH).rev());
658        while let Some((_, remaining)) = iter.next() {
659            let (min, max) = iter.size_hint();
660            assert!(min <= remaining);
661            if let Some(max) = max {
662                assert!(max >= remaining)
663            }
664        }
665    }
666
667    #[test]
668    fn constructible_from_iterator() {
669        let arena: Arena<i32> = (0..100).collect();
670        assert_eq!(arena.len(), 100);
671    }
672
673    #[test]
674    #[cfg(feature = "std")]
675    fn arena_is_send() {
676        let arena: Arena<i32> = (0..100).collect();
677
678        let arena = Arc::new(Mutex::new(arena));
679
680        let f = |arena: Arc<Mutex<Arena<i32>>>| {
681            move || {
682                arena.lock().unwrap().alloc_extend(100..200);
683            }
684        };
685        std::thread::spawn(f(arena.clone())).join().unwrap();
686
687        assert_eq!(arena.lock().unwrap().len(), 200);
688    }
689}