typed_arena/
lib.rs

1//! The arena, a fast but limited type of allocator.
2//!
3//! Arenas are a type of allocator that destroy the objects within,
4//! all at once, once the arena itself is destroyed.
5//! They do not support deallocation of individual objects while the arena itself is still alive.
6//! The benefit of an arena is very fast allocation; just a vector push.
7//!
8//! This is an equivalent of the old
9//! [`arena::TypedArena`](https://doc.rust-lang.org/1.1.0/arena/struct.TypedArena.html)
10//! type that was once distributed with nightly rustc but has since been
11//! removed.
12//!
13//! It is slightly less efficient, but simpler internally and uses much less unsafe code.
14//! It is based on a `Vec<Vec<T>>` instead of raw pointers and manual drops.
15//!
16//! ## Example
17//!
18//! ```
19//! use typed_arena::Arena;
20//!
21//! struct Monster {
22//!     level: u32,
23//! }
24//!
25//! let monsters = Arena::new();
26//!
27//! let vegeta = monsters.alloc(Monster { level: 9001 });
28//! assert!(vegeta.level > 9000);
29//! ```
30//!
31//! ## Safe Cycles
32//!
33//! All allocated objects get the same lifetime, so you can safely create cycles
34//! between them. This can be useful for certain data structures, such as graphs
35//! and trees with parent pointers.
36//!
37//! ```
38//! use std::cell::Cell;
39//! use typed_arena::Arena;
40//!
41//! struct CycleParticipant<'a> {
42//!     other: Cell<Option<&'a CycleParticipant<'a>>>,
43//! }
44//!
45//! let arena = Arena::new();
46//!
47//! let a = arena.alloc(CycleParticipant { other: Cell::new(None) });
48//! let b = arena.alloc(CycleParticipant { other: Cell::new(None) });
49//!
50//! a.other.set(Some(b));
51//! b.other.set(Some(a));
52//! ```
53
54// Potential optimizations:
55// 1) add and stabilize a method for in-place reallocation of vecs.
56// 2) add and stabilize placement new.
57// 3) use an iterator. This may add far too much unsafe code.
58
59#![deny(missing_docs)]
60#![cfg_attr(not(any(feature = "std", test)), no_std)]
61#![cfg_attr(not(feature = "std"), feature(alloc))]
62
63#[cfg(not(feature = "std"))]
64extern crate alloc;
65
66#[cfg(any(feature = "std", test))]
67extern crate core;
68
69#[cfg(not(feature = "std"))]
70use alloc::Vec;
71
72use core::cell::RefCell;
73use core::cmp;
74use core::iter;
75use core::mem;
76use core::slice;
77
78#[cfg(test)]
79mod test;
80
81// Initial size in bytes.
82const INITIAL_SIZE: usize = 1024;
83// Minimum capacity. Must be larger than 0.
84const MIN_CAPACITY: usize = 1;
85
86/// An arena of objects of type `T`.
87///
88/// ## Example
89///
90/// ```
91/// use typed_arena::Arena;
92///
93/// struct Monster {
94///     level: u32,
95/// }
96///
97/// let monsters = Arena::new();
98///
99/// let vegeta = monsters.alloc(Monster { level: 9001 });
100/// assert!(vegeta.level > 9000);
101/// ```
102pub struct Arena<T> {
103    chunks: RefCell<ChunkList<T>>,
104}
105
106struct ChunkList<T> {
107    current: Vec<T>,
108    rest: Vec<Vec<T>>,
109}
110
111impl<T> Arena<T> {
112    /// Construct a new arena.
113    ///
114    /// ## Example
115    ///
116    /// ```
117    /// use typed_arena::Arena;
118    ///
119    /// let arena = Arena::new();
120    /// # arena.alloc(1);
121    /// ```
122    pub fn new() -> Arena<T> {
123        let size = cmp::max(1, mem::size_of::<T>());
124        Arena::with_capacity(INITIAL_SIZE / size)
125    }
126
127    /// Construct a new arena with capacity for `n` values pre-allocated.
128    ///
129    /// ## Example
130    ///
131    /// ```
132    /// use typed_arena::Arena;
133    ///
134    /// let arena = Arena::with_capacity(1337);
135    /// # arena.alloc(1);
136    /// ```
137    pub fn with_capacity(n: usize) -> Arena<T> {
138        let n = cmp::max(MIN_CAPACITY, n);
139        Arena {
140            chunks: RefCell::new(ChunkList {
141                current: Vec::with_capacity(n),
142                rest: Vec::new(),
143            }),
144        }
145    }
146
147    /// Allocates a value in the arena, and returns a mutable reference
148    /// to that value.
149    ///
150    /// ## Example
151    ///
152    /// ```
153    /// use typed_arena::Arena;
154    ///
155    /// let arena = Arena::new();
156    /// let x = arena.alloc(42);
157    /// assert_eq!(*x, 42);
158    /// ```
159    pub fn alloc(&self, value: T) -> &mut T {
160        &mut self.alloc_extend(iter::once(value))[0]
161    }
162
163    /// Uses the contents of an iterator to allocate values in the arena.
164    /// Returns a mutable slice that contains these values.
165    ///
166    /// ## Example
167    ///
168    /// ```
169    /// use typed_arena::Arena;
170    ///
171    /// let arena = Arena::new();
172    /// let abc = arena.alloc_extend("abcdefg".chars().take(3));
173    /// assert_eq!(abc, ['a', 'b', 'c']);
174    /// ```
175    pub fn alloc_extend<I>(&self, iterable: I) -> &mut [T]
176        where I: IntoIterator<Item = T>
177    {
178        let mut iter = iterable.into_iter();
179
180        let mut chunks = self.chunks.borrow_mut();
181
182        let iter_min_len = iter.size_hint().0;
183        let mut next_item_index;
184        if chunks.current.len() + iter_min_len > chunks.current.capacity() {
185            chunks.reserve(iter_min_len);
186            chunks.current.extend(iter);
187            next_item_index = 0;
188        } else {
189            next_item_index = chunks.current.len();
190            let mut i = 0;
191            while let Some(elem) = iter.next() {
192                if chunks.current.len() == chunks.current.capacity() {
193                    // The iterator was larger than we could fit into the current chunk.
194                    let chunks = &mut *chunks;
195                    // Create a new chunk into which we can freely push the entire iterator into
196                    chunks.reserve(i + 1);
197                    let previous_chunk = chunks.rest.last_mut().unwrap();
198                    let previous_chunk_len = previous_chunk.len();
199                    // Move any elements we put into the previous chunk into this new chunk
200                    chunks.current.extend(previous_chunk.drain(previous_chunk_len - i..));
201                    chunks.current.push(elem);
202                    // And the remaining elements in the iterator
203                    chunks.current.extend(iter);
204                    next_item_index = 0;
205                    break;
206                } else {
207                    chunks.current.push(elem);
208                }
209                i += 1;
210            }
211        }
212        let new_slice_ref = {
213            let new_slice_ref = &mut chunks.current[next_item_index..];
214
215            // Extend the lifetime from that of `chunks_borrow` to that of `self`.
216            // This is OK because we’re careful to never move items
217            // by never pushing to inner `Vec`s beyond their initial capacity.
218            // The returned reference is unique (`&mut`):
219            // the `Arena` never gives away references to existing items.
220            unsafe { mem::transmute::<&mut [T], &mut [T]>(new_slice_ref) }
221        };
222
223        new_slice_ref
224    }
225
226    /// Allocates space for a given number of values, but doesn't initialize it.
227    ///
228    /// ## Unsafety and Undefined Behavior
229    ///
230    /// The same caveats that apply to
231    /// [`std::mem::uninitialized`](https://doc.rust-lang.org/nightly/std/mem/fn.uninitialized.html)
232    /// apply here:
233    ///
234    /// > **This is incredibly dangerous and should not be done lightly. Deeply
235    /// consider initializing your memory with a default value instead.**
236    ///
237    /// In particular, it is easy to trigger undefined behavior by allocating
238    /// uninitialized values, failing to properly initialize them, and then the
239    /// `Arena` will attempt to drop them when it is dropped. Initializing an
240    /// uninitialized value is trickier than it might seem: a normal assignment
241    /// to a field will attempt to drop the old, uninitialized value, which
242    /// almost certainly also triggers undefined behavior. You must also
243    /// consider all the places where your code might "unexpectedly" drop values
244    /// earlier than it "should" because of unwinding during panics.
245    pub unsafe fn alloc_uninitialized(&self, num: usize) -> *mut [T] {
246        let mut chunks = self.chunks.borrow_mut();
247
248        if chunks.current.len() + num > chunks.current.capacity() {
249            chunks.reserve(num);
250        }
251
252        // At this point, the current chunk must have free capacity.
253        let next_item_index = chunks.current.len();
254        chunks.current.set_len(next_item_index + num);
255        // Extend the lifetime...
256        &mut chunks.current[next_item_index..] as *mut _
257    }
258
259    /// Returns unused space.
260    ///
261    /// *This unused space is still not considered "allocated".* Therefore, it
262    /// won't be dropped unless there are further calls to `alloc`,
263    /// `alloc_uninitialized`, or `alloc_extend` which is why the method is
264    /// safe.
265    pub fn uninitialized_array(&self) -> *mut [T] {
266        let chunks = self.chunks.borrow();
267        let len = chunks.current.capacity() - chunks.current.len();
268        let next_item_index = chunks.current.len();
269        let slice = &chunks.current[next_item_index..];
270        unsafe { slice::from_raw_parts_mut(slice.as_ptr() as *mut T, len) as *mut _ }
271    }
272
273    /// Convert this `Arena` into a `Vec<T>`.
274    ///
275    /// Items in the resulting `Vec<T>` appear in the order that they were
276    /// allocated in.
277    ///
278    /// ## Example
279    ///
280    /// ```
281    /// use typed_arena::Arena;
282    ///
283    /// let arena = Arena::new();
284    ///
285    /// arena.alloc("a");
286    /// arena.alloc("b");
287    /// arena.alloc("c");
288    ///
289    /// let easy_as_123 = arena.into_vec();
290    ///
291    /// assert_eq!(easy_as_123, vec!["a", "b", "c"]);
292    /// ```
293    pub fn into_vec(self) -> Vec<T> {
294        let mut chunks = self.chunks.into_inner();
295        // keep order of allocation in the resulting Vec
296        let n = chunks.rest.iter().fold(chunks.current.len(), |a, v| a + v.len());
297        let mut result = Vec::with_capacity(n);
298        for mut vec in chunks.rest {
299            result.append(&mut vec);
300        }
301        result.append(&mut chunks.current);
302        result
303    }
304}
305
306impl<T> ChunkList<T> {
307    #[inline(never)]
308    #[cold]
309    fn reserve(&mut self, additional: usize) {
310        let double_cap = self.current.capacity().checked_mul(2).expect("capacity overflow");
311        let required_cap = additional.checked_next_power_of_two().expect("capacity overflow");
312        let new_capacity = cmp::max(double_cap, required_cap);
313        let chunk = mem::replace(&mut self.current, Vec::with_capacity(new_capacity));
314        self.rest.push(chunk);
315    }
316}