atomic_arena/
lib.rs

1/*!
2`atomic_arena` provides a generational [`Arena`] that you can reserve
3a [`Key`] for ahead of time using a [`Controller`]. [`Controller`]s
4are backed by atomics, so they can be cloned and used across threads
5and still have consistent state.
6
7This is useful when you want to insert an item into an [`Arena`] on
8a different thread, but you want to have a valid [`Key`] for that
9item immediately on the current thread.
10*/
11
12#![warn(missing_docs)]
13
14mod controller;
15pub mod error;
16pub mod iter;
17mod slot;
18
19#[cfg(test)]
20mod test;
21
22pub use controller::Controller;
23
24use error::{ArenaFull, InsertWithKeyError};
25use iter::{DrainFilter, Iter, IterMut};
26use slot::{ArenaSlot, ArenaSlotState};
27
28/// A unique identifier for an item in an [`Arena`].
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub struct Key {
31	index: usize,
32	generation: usize,
33}
34
35/// A container of items that can be accessed via a [`Key`].
36#[derive(Debug)]
37pub struct Arena<T> {
38	controller: Controller,
39	slots: Vec<ArenaSlot<T>>,
40	first_occupied_slot_index: Option<usize>,
41}
42
43impl<T> Arena<T> {
44	/// Creates a new [`Arena`] with enough space for `capacity`
45	/// number of items.
46	pub fn new(capacity: usize) -> Self {
47		Self {
48			controller: Controller::new(capacity),
49			slots: (0..capacity).map(|_| ArenaSlot::new()).collect(),
50			first_occupied_slot_index: None,
51		}
52	}
53
54	/// Returns a [`Controller`] for this [`Arena`].
55	pub fn controller(&self) -> Controller {
56		self.controller.clone()
57	}
58
59	/// Returns the total capacity for this [`Arena`].
60	pub fn capacity(&self) -> usize {
61		self.slots.len()
62	}
63
64	/// Returns the number of items currently in the [`Arena`].
65	pub fn len(&self) -> usize {
66		self.slots
67			.iter()
68			.filter(|slot| matches!(&slot.state, ArenaSlotState::Occupied { .. }))
69			.count()
70	}
71
72	/// Returns `true` if the [`Arena`] is currently empty.
73	pub fn is_empty(&self) -> bool {
74		self.len() == 0
75	}
76
77	/// Tries to insert an item into the [`Arena`] with a previously
78	/// reserved [`Key`].
79	pub fn insert_with_key(&mut self, key: Key, data: T) -> Result<(), InsertWithKeyError> {
80		// make sure the key is valid and reserved
81		if let Some(slot) = self.slots.get(key.index) {
82			if slot.generation != key.generation {
83				return Err(InsertWithKeyError::InvalidKey);
84			}
85			if let ArenaSlotState::Occupied { .. } = &slot.state {
86				return Err(InsertWithKeyError::KeyNotReserved);
87			}
88		} else {
89			return Err(InsertWithKeyError::InvalidKey);
90		}
91
92		// update the previous head to point to the new head
93		// as the previous occupied slot
94		if let Some(head_index) = self.first_occupied_slot_index {
95			self.slots[head_index].set_previous_occupied_slot_index(Some(key.index));
96		}
97
98		// insert the new data
99		self.slots[key.index].state = ArenaSlotState::Occupied {
100			data,
101			previous_occupied_slot_index: None,
102			next_occupied_slot_index: self.first_occupied_slot_index,
103		};
104
105		// update the head
106		self.first_occupied_slot_index = Some(key.index);
107
108		Ok(())
109	}
110
111	/// Tries to reserve a [`Key`], and, if successful, inserts
112	/// an item into the [`Arena`] with that [`Key`] and
113	/// returns the [`Key`].
114	pub fn insert(&mut self, data: T) -> Result<Key, ArenaFull> {
115		let key = self.controller.try_reserve()?;
116		self.insert_with_key(key, data).unwrap();
117		Ok(key)
118	}
119
120	fn remove_from_slot(&mut self, index: usize) -> Option<T> {
121		let slot = &mut self.slots[index];
122		let state = std::mem::replace(&mut slot.state, ArenaSlotState::Free);
123		match state {
124			ArenaSlotState::Free => None,
125			ArenaSlotState::Occupied {
126				data,
127				previous_occupied_slot_index,
128				next_occupied_slot_index,
129			} => {
130				slot.generation += 1;
131				self.controller.free(index);
132
133				// update the pointers of the previous and next slots
134				if let Some(previous_index) = previous_occupied_slot_index {
135					self.slots[previous_index]
136						.set_next_occupied_slot_index(next_occupied_slot_index);
137				}
138				if let Some(next_index) = next_occupied_slot_index {
139					self.slots[next_index]
140						.set_previous_occupied_slot_index(previous_occupied_slot_index);
141				}
142
143				// update the head if needed.
144				//
145				// `first_occupied_slot_index` should always be `Some` in this case,
146				// because this branch of the `match` is only taken if the slot is
147				// occupied, and if any slots are occupied, `first_occupied_slot_index`
148				// should be `Some`. if not, there's a major bug that needs addressing.
149				if self.first_occupied_slot_index.unwrap() == index {
150					self.first_occupied_slot_index = next_occupied_slot_index;
151				}
152
153				Some(data)
154			}
155		}
156	}
157
158	/// If the [`Arena`] contains an item with the given [`Key`],
159	/// removes it from the [`Arena`] and returns `Some(item)`.
160	/// Otherwise, returns `None`.
161	pub fn remove(&mut self, key: Key) -> Option<T> {
162		// TODO: answer the following questions:
163		// - if you reserve a key, then try to remove the key
164		// without having inserted anything, should the slot
165		// be unreserved? the current answer is no
166		// - what should happen if you try to remove a slot
167		// with the wrong generation? currently the answer is
168		// it just returns None like normal
169		let slot = &mut self.slots[key.index];
170		if slot.generation != key.generation {
171			return None;
172		}
173		self.remove_from_slot(key.index)
174	}
175
176	/// Returns a shared reference to the item in the [`Arena`] with
177	/// the given [`Key`] if it exists. Otherwise, returns `None`.
178	pub fn get(&self, key: Key) -> Option<&T> {
179		let slot = &self.slots[key.index];
180		if slot.generation != key.generation {
181			return None;
182		}
183		match &slot.state {
184			ArenaSlotState::Free => None,
185			ArenaSlotState::Occupied { data, .. } => Some(data),
186		}
187	}
188
189	/// Returns a mutable reference to the item in the [`Arena`] with
190	/// the given [`Key`] if it exists. Otherwise, returns `None`.
191	pub fn get_mut(&mut self, key: Key) -> Option<&mut T> {
192		let slot = &mut self.slots[key.index];
193		if slot.generation != key.generation {
194			return None;
195		}
196		match &mut slot.state {
197			ArenaSlotState::Free => None,
198			ArenaSlotState::Occupied { data, .. } => Some(data),
199		}
200	}
201
202	/// Retains only the elements specified by the predicate.
203	///
204	/// In other words, remove all elements e such that f(&e) returns false.
205	pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
206		let mut index = match self.first_occupied_slot_index {
207			Some(index) => index,
208			None => return,
209		};
210		loop {
211			if let ArenaSlotState::Occupied {
212				data,
213				next_occupied_slot_index,
214				..
215			} = &self.slots[index].state
216			{
217				let next_occupied_slot_index = next_occupied_slot_index.as_ref().copied();
218				if !f(data) {
219					self.remove_from_slot(index);
220				}
221				index = match next_occupied_slot_index {
222					Some(index) => index,
223					None => return,
224				}
225			} else {
226				panic!("expected the slot pointed to by first_occupied_slot_index/next_occupied_slot_index to be occupied")
227			}
228		}
229	}
230
231	/// Returns an iterator over shared references to the items in
232	/// the [`Arena`].
233	///
234	/// The most recently added items will be visited first.
235	pub fn iter(&self) -> Iter<T> {
236		Iter::new(self)
237	}
238
239	/// Returns an iterator over mutable references to the items in
240	/// the [`Arena`].
241	///
242	/// The most recently added items will be visited first.
243	pub fn iter_mut(&mut self) -> IterMut<T> {
244		IterMut::new(self)
245	}
246
247	/// Returns an iterator that removes and yields all elements
248	/// for which `filter(&element)` returns `true`.
249	pub fn drain_filter<F: FnMut(&T) -> bool>(&mut self, filter: F) -> DrainFilter<T, F> {
250		DrainFilter::new(self, filter)
251	}
252}
253
254impl<T> std::ops::Index<Key> for Arena<T> {
255	type Output = T;
256
257	fn index(&self, key: Key) -> &Self::Output {
258		self.get(key).expect("No item associated with this key")
259	}
260}
261
262impl<T> std::ops::IndexMut<Key> for Arena<T> {
263	fn index_mut(&mut self, key: Key) -> &mut Self::Output {
264		self.get_mut(key).expect("No item associated with this key")
265	}
266}
267
268impl<'a, T> IntoIterator for &'a Arena<T> {
269	type Item = (Key, &'a T);
270
271	type IntoIter = Iter<'a, T>;
272
273	fn into_iter(self) -> Self::IntoIter {
274		self.iter()
275	}
276}
277
278impl<'a, T> IntoIterator for &'a mut Arena<T> {
279	type Item = (Key, &'a mut T);
280
281	type IntoIter = IterMut<'a, T>;
282
283	fn into_iter(self) -> Self::IntoIter {
284		self.iter_mut()
285	}
286}