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}