fixed_typed_arena/
arena.rs

1/*
2 * Copyright (C) 2021-2022 taylor.fish <contact@taylor.fish>
3 *
4 * This file is part of fixed-typed-arena.
5 *
6 * fixed-typed-arena is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * fixed-typed-arena is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with fixed-typed-arena. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20//! A typed arena that allocates items in non-amortized constant time.
21
22use super::iter::{IntoIter, Iter, IterMut, Position};
23use super::manually_drop::ManuallyDropArena;
24use super::ArenaOptions;
25use core::cell::UnsafeCell;
26use core::mem::ManuallyDrop;
27use integral_constant::Bool;
28
29/// An arena that allocates items of type `T` in non-amortized O(1) (constant)
30/// time.
31///
32/// The arena allocates fixed-size chunks of memory, each able to hold up to
33/// [`Options::ChunkSize`] items. All items are allocated on the heap.
34///
35/// # Panics
36///
37/// The arena may panic when created or used if [`mem::size_of::<T>()`][size]
38/// times [`Options::ChunkSize`] is greater than [`usize::MAX`].
39///
40/// [`Options::ChunkSize`]: ArenaOptions::ChunkSize
41/// [size]: core::mem::size_of
42pub struct Arena<T, Options: ArenaOptions<T> = super::Options>(
43    ManuallyDrop<UnsafeCell<ManuallyDropArena<T, Options>>>,
44);
45
46impl<T, Options: ArenaOptions<T>> Default for Arena<T, Options> {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52impl<T, Options: ArenaOptions<T>> Arena<T, Options> {
53    /// Creates a new [`Arena`].
54    pub fn new() -> Self {
55        Self(Default::default())
56    }
57
58    fn inner(&self) -> &ManuallyDropArena<T, Options> {
59        // SAFETY: No `&self` methods of `ManuallyDropArena` can possibly call
60        // any methods of `Self`, which ensures we do not concurrently mutably
61        // borrow the data in the `UnsafeCell`.
62        unsafe { &*self.0.get() }
63    }
64
65    /// Returns the total number of items that have been allocated.
66    pub fn len(&self) -> usize {
67        self.inner().len()
68    }
69
70    /// Checks whether the arena is empty.
71    pub fn is_empty(&self) -> bool {
72        self.len() == 0
73    }
74
75    /// Allocates a new item in the arena and initializes it with `value`.
76    /// Returns a reference to the allocated item.
77    ///
78    /// This method calls [`handle_alloc_error`] if memory allocation fails;
79    /// for a version that returns [`None`] instead, see [`Self::try_alloc`].
80    ///
81    /// [`handle_alloc_error`]: alloc::alloc::handle_alloc_error
82    #[allow(clippy::mut_from_ref)]
83    pub fn alloc(&self, value: T) -> &mut T
84    where
85        Options: ArenaOptions<T, Mutable = Bool<true>>,
86    {
87        // SAFETY: `ManuallyDropArena::alloc` does not run any code that could
88        // possibly call any methods of `Self`, which ensures that we do not
89        // borrow the data in the `UnsafeCell` multiple times concurrently.
90        //
91        // Additionally, the memory pointed to by the mutable reference we
92        // return is guaranteed by the implementation of `ManuallyDropArena`
93        // not to change (except through the reference itself) or be reused
94        // until either the arena is dropped, or until `Self::iter_mut` is
95        // called, both of which require mutable access to the arena, which
96        // require no live item references to exist.
97        unsafe { &mut *self.0.get() }.alloc(value)
98    }
99
100    /// Like [`Self::alloc`], but returns [`None`] if memory allocation fails.
101    #[allow(clippy::mut_from_ref)]
102    pub fn try_alloc(&self, value: T) -> Option<&mut T>
103    where
104        Options: ArenaOptions<T, Mutable = Bool<true>>,
105    {
106        // SAFETY: See `Self::alloc`.
107        unsafe { &mut *self.0.get() }.try_alloc(value)
108    }
109
110    /// Allocates a new item in the arena and initializes it with `value`.
111    /// Returns a shared/immutable reference to the allocated item.
112    ///
113    /// This method calls [`handle_alloc_error`] if memory allocation fails;
114    /// for a version that returns [`None`] instead, see [`Self::try_alloc`].
115    ///
116    /// [`handle_alloc_error`]: alloc::alloc::handle_alloc_error
117    pub fn alloc_shared(&self, value: T) -> &T {
118        // SAFETY: See `Self::alloc`.
119        unsafe { &mut *self.0.get() }.alloc_shared(value)
120    }
121
122    /// Like [`Self::alloc_shared`], but returns [`None`] if memory allocation
123    /// fails.
124    pub fn try_alloc_shared(&self, value: T) -> Option<&T> {
125        // SAFETY: See `Self::alloc_shared`.
126        unsafe { &mut *self.0.get() }.try_alloc_shared(value)
127    }
128
129    /// Returns an iterator over the items in this arena.
130    pub fn iter(&self) -> Iter<'_, T, Options>
131    where
132        Options: ArenaOptions<T, Mutable = Bool<false>>,
133    {
134        self.inner().iter()
135    }
136
137    /// Returns an iterator over the items in this arena.
138    ///
139    /// # Safety
140    ///
141    /// There must be no mutable references (or references derived from mutable
142    /// references) to items (or parts of items) in this arena or instances of
143    /// [`IterMut`] for this arena.
144    pub unsafe fn iter_unchecked(&self) -> Iter<'_, T, Options> {
145        // SAFETY: Checked by caller.
146        unsafe { self.inner().iter_unchecked() }
147    }
148
149    /// Returns a mutable iterator over the items in this arena.
150    pub fn iter_mut(&mut self) -> IterMut<'_, T, Options> {
151        // SAFETY: This type's design guarantees no references to items exist.
152        unsafe { self.0.get_mut().iter_mut_unchecked() }
153    }
154}
155
156impl<T, Options> Arena<T, Options>
157where
158    Options: ArenaOptions<T, SupportsPositions = Bool<true>>,
159{
160    /// Returns an iterator starting at the specified position.
161    ///
162    /// # Panics
163    ///
164    /// May panic if `position` does not refer to a position in this arena.
165    pub fn iter_at(&self, position: &Position) -> Iter<'_, T, Options>
166    where
167        Options: ArenaOptions<T, Mutable = Bool<false>>,
168    {
169        self.inner().iter_at(position)
170    }
171
172    /// Returns an iterator starting at the specified position.
173    ///
174    /// # Panics
175    ///
176    /// May panic if `position` does not refer to a position in this arena.
177    ///
178    /// # Safety
179    ///
180    /// Same requirements as [`Self::iter_unchecked`].
181    pub unsafe fn iter_at_unchecked(
182        &self,
183        position: &Position,
184    ) -> Iter<'_, T, Options> {
185        // SAFETY: Checked by caller.
186        unsafe { self.inner().iter_at_unchecked(position) }
187    }
188
189    /// Returns a mutable iterator starting at the specified position.
190    ///
191    /// # Panics
192    ///
193    /// May panic if `position` does not refer to a position in this arena.
194    pub fn iter_mut_at(
195        &mut self,
196        position: &Position,
197    ) -> IterMut<'_, T, Options> {
198        // SAFETY: This type's design guarantees no references to items exist.
199        unsafe { self.0.get_mut().iter_mut_at_unchecked(position) }
200    }
201}
202
203// SAFETY: `Arena` owns its items and provides access using standard borrow
204// rules, so it can be `Send` as long as `T` is `Send`.
205unsafe impl<T, Options> Send for Arena<T, Options>
206where
207    T: Send,
208    Options: ArenaOptions<T>,
209{
210}
211
212// SAFETY: This `Drop` impl does not directly or indirectly access any data in
213// any `T` or `Array`, except for calling their destructors (see [1]), and
214// `Self` (via `ManuallyDropArena`) contains a `PhantomData<Box<T>>` so dropck
215// knows that `T` may be dropped (see [2]).
216//
217// [1]: https://doc.rust-lang.org/nomicon/dropck.html
218// [2]: https://forge.rust-lang.org/libs/maintaining-std.html
219//      #is-there-a-manual-drop-implementation
220#[cfg_attr(feature = "dropck_eyepatch", add_syntax::prepend(unsafe))]
221impl<
222    #[cfg_attr(feature = "dropck_eyepatch", may_dangle)] T,
223    #[cfg_attr(feature = "dropck_eyepatch", may_dangle)] Options,
224> Drop for Arena<T, Options>
225where
226    Options: ArenaOptions<T>,
227{
228    fn drop(&mut self) {
229        // SAFETY: `Arena` doesn't hand out references or iterators
230        // that live longer than itself.
231        unsafe {
232            self.0.get_mut().drop();
233        }
234    }
235}
236
237impl<'a, T, Options> IntoIterator for &'a Arena<T, Options>
238where
239    Options: ArenaOptions<T, Mutable = Bool<false>>,
240{
241    type IntoIter = Iter<'a, T, Options>;
242    type Item = &'a T;
243
244    fn into_iter(self) -> Self::IntoIter {
245        self.iter()
246    }
247}
248
249impl<'a, T, Options> IntoIterator for &'a mut Arena<T, Options>
250where
251    Options: ArenaOptions<T>,
252{
253    type IntoIter = IterMut<'a, T, Options>;
254    type Item = &'a mut T;
255
256    fn into_iter(self) -> Self::IntoIter {
257        self.iter_mut()
258    }
259}
260
261impl<T, Options: ArenaOptions<T>> IntoIterator for Arena<T, Options> {
262    type IntoIter = IntoIter<T, Options>;
263    type Item = T;
264
265    fn into_iter(self) -> Self::IntoIter {
266        let mut this = ManuallyDrop::new(self);
267
268        // SAFETY: This `ManuallyDrop` won't be used again because we moved
269        // `self` into a `ManuallyDrop` (so its destructor won't run).
270        let inner = unsafe { ManuallyDrop::take(&mut this.0) };
271
272        // SAFETY: This type's design guarantees no references to items exist.
273        unsafe { inner.into_inner().into_iter_unchecked() }
274    }
275}