Skip to main content

omp_core/
sparse_map.rs

1//! Sparse map backed by bitmap occupancy tracking.
2//!
3//! `SparseMap<K, V>` stores key-value pairs where keys map to indices. Uses a
4//! bitmap for presence and a packed vector for values, minimizing memory
5//! overhead for sparse mappings.
6
7use std::{
8	fmt,
9	iter::{self, FusedIterator},
10	marker::PhantomData,
11	ops::{Index, IndexMut},
12	slice,
13};
14
15use serde::{Deserialize, Serialize};
16use smol_bitmap::SmolBitmap;
17
18use crate::{sparse_index::TrySparseIndex, sparse_set::SparseSet};
19
20/// A sparse map from keys convertible to indices to values.
21///
22/// [`SparseMap`] provides an efficient storage mechanism for mappings
23/// where keys can be converted to `usize` indices. It uses a bitmap to track
24/// which indices are occupied and a packed vector to store only the present
25/// values, achieving both memory efficiency and fast lookup times.
26///
27/// The key type `K` must implement [`Into<usize>`] and [`From<usize>`] to
28/// convert between keys and indices. This makes it ideal for enum keys,
29/// small integers, or other types with a natural index representation.
30///
31/// # Examples
32///
33/// ```
34/// use omp_core::{sparse_index::TrySparseIndex, sparse_map::SparseMap};
35///
36/// #[repr(usize)]
37/// #[derive(Copy, Clone, Debug, PartialEq)]
38/// enum Status {
39/// 	Active  = 0,
40/// 	Pending = 1,
41/// 	Closed  = 2,
42/// }
43///
44/// #[derive(Debug)]
45/// struct StatusError(String);
46///
47/// impl std::fmt::Display for StatusError {
48/// 	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49/// 		write!(f, "{}", self.0)
50/// 	}
51/// }
52///
53/// impl std::error::Error for StatusError {}
54///
55/// impl TrySparseIndex for Status {
56/// 	type Error = StatusError;
57///
58/// 	fn index(&self) -> usize {
59/// 		*self as usize
60/// 	}
61///
62/// 	fn try_from_index(index: usize) -> Result<Self, Self::Error> {
63/// 		match index {
64/// 			0 => Ok(Status::Active),
65/// 			1 => Ok(Status::Pending),
66/// 			2 => Ok(Status::Closed),
67/// 			_ => Err(StatusError("Invalid status value".to_string())),
68/// 		}
69/// 	}
70/// }
71///
72/// let mut map = SparseMap::new();
73/// map.insert(Status::Active, "running");
74/// map.insert(Status::Closed, "finished");
75///
76/// assert_eq!(map.get(Status::Active), Some(&"running"));
77/// assert_eq!(map.get(Status::Pending), None);
78/// assert_eq!(map[Status::Active], "running");
79/// ```
80pub struct SparseMap<K, V> {
81	/// Bitmap tracking which indices have values stored
82	bits:     SmolBitmap,
83	/// Packed storage for values at occupied indices
84	values:   Vec<V>,
85	/// Phantom data to maintain type information for keys
86	_phantom: PhantomData<K>,
87}
88
89impl<K, V: Clone> Clone for SparseMap<K, V> {
90	fn clone(&self) -> Self {
91		Self { bits: self.bits.clone(), values: self.values.clone(), _phantom: PhantomData }
92	}
93}
94
95impl<K: TrySparseIndex + fmt::Debug, V: fmt::Debug> fmt::Debug for SparseMap<K, V> {
96	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97		let mut s = f.debug_map();
98		for (index, value) in self {
99			s.entry(&index, &value);
100		}
101		s.finish()
102	}
103}
104impl<K: TrySparseIndex + Serialize, V: Serialize> Serialize for SparseMap<K, V> {
105	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
106	where
107		S: serde::Serializer,
108	{
109		if serializer.is_human_readable() {
110			use serde::ser::SerializeSeq;
111			let mut seq = serializer.serialize_seq(Some(self.len()))?;
112			for (index, value) in self {
113				seq.serialize_element(&(index, value))?;
114			}
115			seq.end()
116		} else {
117			use serde::ser::SerializeTuple;
118			let mut tuple = serializer.serialize_tuple(2)?;
119			tuple.serialize_element(&self.bits)?;
120			tuple.serialize_element(&self.values)?;
121			tuple.end()
122		}
123	}
124}
125
126impl<'de, K: TrySparseIndex + Deserialize<'de>, V: Deserialize<'de>> Deserialize<'de>
127	for SparseMap<K, V>
128{
129	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130	where
131		D: serde::Deserializer<'de>,
132	{
133		if deserializer.is_human_readable() {
134			use std::fmt;
135
136			use serde::de::{SeqAccess, Visitor};
137
138			struct SparseMapVisitor<K, V> {
139				_phantom: PhantomData<(K, V)>,
140			}
141
142			impl<'de, K: TrySparseIndex + Deserialize<'de>, V: Deserialize<'de>> Visitor<'de>
143				for SparseMapVisitor<K, V>
144			{
145				type Value = SparseMap<K, V>;
146
147				fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
148					formatter.write_str("a sequence of (index, value) pairs")
149				}
150
151				fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
152				where
153					A: SeqAccess<'de>,
154				{
155					let mut map = SparseMap::new();
156					if let Some(len) = seq.size_hint() {
157						map.reserve(len);
158					}
159					let mut prev_index = None;
160					while let Some((index, value)) = seq.next_element::<(K, V)>()? {
161						let index = index.index();
162						if prev_index.is_some_and(|prev| prev >= index) {
163							return Err(serde::de::Error::invalid_value(
164								serde::de::Unexpected::Unsigned(index as u64),
165								&"indices must be in ascending order",
166							));
167						}
168						prev_index = Some(index);
169						map.bits.insert(index);
170						map.values.push(value);
171					}
172					Ok(map)
173				}
174			}
175
176			deserializer.deserialize_seq(SparseMapVisitor { _phantom: PhantomData })
177		} else {
178			let (bits, values): (SmolBitmap, Vec<V>) = Deserialize::deserialize(deserializer)?;
179			// Reject occupancy/value mismatches: rank-based lookups misassociate
180			// values (or panic in insert/remove) if the packed vector length does
181			// not equal the number of set bits.
182			if bits.count_ones() != values.len() {
183				return Err(serde::de::Error::invalid_length(
184					values.len(),
185					&"as many values as set bits in the occupancy bitmap",
186				));
187			}
188			K::validate_sorted(bits.iter()).map_err(serde::de::Error::custom)?;
189			Ok(Self { bits, values, _phantom: PhantomData })
190		}
191	}
192}
193
194impl<K, V> Default for SparseMap<K, V> {
195	fn default() -> Self {
196		Self::new()
197	}
198}
199
200impl<K, V: PartialEq> PartialEq for SparseMap<K, V> {
201	fn eq(&self, other: &Self) -> bool {
202		self.bits == other.bits && self.values == other.values
203	}
204}
205
206impl<K, V: Eq> Eq for SparseMap<K, V> {}
207
208impl<K, V> SparseMap<K, V> {
209	/// Creates a sparse index map from a sequence of values.
210	///
211	/// The values are assigned indices starting from 0. This is equivalent to
212	/// inserting each value with its position as the key.
213	///
214	/// # Arguments
215	///
216	/// * `values` - A sequence of values to insert
217	pub fn from_sequence(values: Vec<V>) -> Self {
218		let len = values.len();
219		let mut bits = SmolBitmap::with_capacity(len);
220
221		// Set all bits from 0 to len-1
222		for i in 0..len {
223			bits.insert(i);
224		}
225
226		Self { bits, values, _phantom: PhantomData }
227	}
228
229	/// Creates a new empty sparse index map.
230	pub const fn new() -> Self {
231		Self { bits: SmolBitmap::new(), values: Vec::new(), _phantom: PhantomData }
232	}
233
234	/// Creates a new sparse index map with the specified capacity.
235	///
236	/// # Arguments
237	///
238	/// * `capacity` - The maximum index that might be stored
239	pub fn with_capacity(capacity: usize) -> Self {
240		Self {
241			bits:     SmolBitmap::with_capacity(capacity),
242			values:   Vec::with_capacity(capacity),
243			_phantom: PhantomData,
244		}
245	}
246
247	/// Returns the number of key-value pairs in the map.
248	#[inline]
249	pub const fn len(&self) -> usize {
250		self.values.len()
251	}
252
253	/// Returns `true` if the map contains no elements.
254	#[inline]
255	pub const fn is_empty(&self) -> bool {
256		self.values.is_empty()
257	}
258
259	/// Returns the capacity of the underlying bitmap.
260	#[inline]
261	pub const fn capacity(&self) -> usize {
262		self.bits.capacity()
263	}
264
265	/// Clears the map, removing all key-value pairs.
266	pub fn clear(&mut self) {
267		self.bits.clear();
268		self.values.clear();
269	}
270
271	/// Shrinks the capacity of the map as much as possible.
272	pub fn shrink_to_fit(&mut self) {
273		self.bits.shrink_to_fit();
274		self.values.shrink_to_fit();
275	}
276
277	/// Reserves capacity for at least `additional` more elements to be
278	/// inserted in the map.
279	pub fn reserve(&mut self, additional: usize) {
280		self.bits.reserve(additional);
281		self.values.reserve(additional);
282	}
283
284	/// Returns a set of all keys in the map.
285	pub const fn key_set(&self) -> &SparseSet<K> {
286		// SAFETY: This is safe because SparseSet is repr(transparent)
287		// over SmolBitmap.
288		unsafe { &*(&raw const self.bits).cast::<SparseSet<K>>() }
289	}
290
291	/// Decomposes the map into its raw parts: bitmap and values vector.
292	///
293	/// # Returns
294	///
295	/// A tuple of `(SmolBitmap, Vec<V>)` representing the bitmap and values
296	#[inline]
297	pub fn into_parts(self) -> (SmolBitmap, Vec<V>) {
298		(self.bits, self.values)
299	}
300
301	/// Constructs a sparse map from its raw parts: bitmap and values vector.
302	///
303	/// # Arguments
304	///
305	/// * `bits` - The bitmap tracking which indices have values
306	/// * `values` - The packed vector of values corresponding to set bits
307	///
308	/// # Safety
309	///
310	/// The caller must ensure that the bitmap and values vector are consistent:
311	/// - The number of set bits in the bitmap must equal the length of the
312	///   values vector
313	/// - The values must be in the order corresponding to the set bits in the
314	///   bitmap
315	#[inline]
316	pub fn from_parts(bits: SmolBitmap, values: Vec<V>) -> Self {
317		assert_eq!(bits.count_ones(), values.len(), "bitmap and values length mismatch");
318		Self { bits, values, _phantom: PhantomData }
319	}
320}
321
322impl<K: TrySparseIndex, V> SparseMap<K, V> {
323	/// Gets a reference to the value corresponding to the key.
324	///
325	/// # Arguments
326	///
327	/// * `key` - The key to look up
328	///
329	/// # Returns
330	///
331	/// A reference to the value, or [`None`] if the key is not present
332	#[inline]
333	pub fn get(&self, key: K) -> Option<&V> {
334		let index = key.index();
335		if self.bits.get(index) {
336			self.values.get(self.bits.rank(index))
337		} else {
338			None
339		}
340	}
341
342	/// Gets a mutable reference to the value corresponding to the key.
343	///
344	/// # Arguments
345	///
346	/// * `key` - The key to look up
347	///
348	/// # Returns
349	///
350	/// A mutable reference to the value, or [`None`] if the key is not
351	/// present
352	#[inline]
353	pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
354		let index = key.index();
355		if self.bits.get(index) {
356			let pos = self.bits.rank(index);
357			self.values.get_mut(pos)
358		} else {
359			None
360		}
361	}
362
363	/// Gets the value corresponding to the key, or inserts a default value if
364	/// not present.
365	///
366	/// If the key exists in the map, returns a mutable reference to the existing
367	/// value. If the key does not exist, inserts the provided value and
368	/// returns a mutable reference to it.
369	///
370	/// # Arguments
371	///
372	/// * `key` - The key to look up or insert
373	/// * `value` - The value to insert if the key is not present
374	///
375	/// # Returns
376	///
377	/// A mutable reference to the value (either existing or newly inserted)
378	#[inline]
379	pub fn get_or_insert(&mut self, key: K, value: V) -> &mut V {
380		let index = key.index();
381		let pos = if self.bits.insert(index) {
382			// New entry
383			let pos = self.bits.rank(index);
384			self.values.insert(pos, value);
385			pos
386		} else {
387			// Existing entry
388			self.bits.rank(index)
389		};
390		&mut self.values[pos]
391	}
392
393	/// Gets the value corresponding to the key, or inserts a computed default
394	/// value if not present.
395	///
396	/// If the key exists in the map, returns a mutable reference to the existing
397	/// value. If the key does not exist, calls the provided closure to
398	/// compute a value, inserts it, and returns a mutable reference to it.
399	///
400	/// # Arguments
401	///
402	/// * `key` - The key to look up or insert
403	/// * `f` - A closure that computes the value to insert if the key is not
404	///   present
405	///
406	/// # Returns
407	///
408	/// A mutable reference to the value (either existing or newly inserted)
409	#[inline]
410	pub fn get_or_insert_with<F>(&mut self, key: K, f: F) -> &mut V
411	where
412		F: FnOnce() -> V,
413	{
414		let index = key.index();
415		let pos = if self.bits.insert(index) {
416			// New entry
417			let pos = self.bits.rank(index);
418			self.values.insert(pos, f());
419			pos
420		} else {
421			// Existing entry
422			self.bits.rank(index)
423		};
424		&mut self.values[pos]
425	}
426
427	/// Returns `true` if the map contains a value for the specified key.
428	///
429	/// # Arguments
430	///
431	/// * `key` - The key to check for
432	#[inline]
433	pub fn contains_key(&self, key: K) -> bool {
434		self.bits.get(key.index())
435	}
436
437	/// Inserts a key-value pair into the map.
438	///
439	/// If the map did not have this key present, [`None`] is returned.
440	/// If the map did have this key present, the value is updated and the old
441	/// value is returned.
442	///
443	/// # Arguments
444	///
445	/// * `key` - The key to insert
446	/// * `value` - The value to associate with the key
447	///
448	/// # Returns
449	///
450	/// The previous value associated with the key, if any
451	pub fn insert(&mut self, key: K, value: V) -> Option<V> {
452		let index = key.index();
453		let pos = self.bits.rank(index);
454		if self.bits.insert(index) {
455			// New entry
456			self.values.insert(pos, value);
457			None
458		} else {
459			// Existing entry - replace value
460			Some(std::mem::replace(&mut self.values[pos], value))
461		}
462	}
463
464	/// Removes a key from the map, returning the value at the key if the key
465	/// was previously in the map.
466	///
467	/// # Arguments
468	///
469	/// * `key` - The key to remove
470	///
471	/// # Returns
472	///
473	/// The removed value, or [`None`] if the key was not present
474	pub fn remove(&mut self, key: K) -> Option<V> {
475		let index = key.index();
476		if self.bits.remove(index) {
477			let pos = self.bits.rank(index);
478			Some(self.values.remove(pos))
479		} else {
480			None
481		}
482	}
483
484	/// Retains only the elements specified by the predicate.
485	///
486	/// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)`
487	/// returns `false`.
488	pub fn retain<F>(&mut self, mut f: F)
489	where
490		F: FnMut(K, &mut V) -> bool,
491	{
492		let mut write_idx = 0;
493		let mut read_idx = 0;
494		self.bits.retain(|idx| {
495			let key = K::from_index(idx);
496			let should_retain = f(key, &mut self.values[read_idx]);
497			if should_retain {
498				if write_idx != read_idx {
499					self.values.swap(write_idx, read_idx);
500				}
501				write_idx += 1;
502			}
503			read_idx += 1;
504			should_retain
505		});
506		self.values.truncate(write_idx);
507	}
508
509	/// Returns an iterator over the key-value pairs of the map.
510	///
511	/// The iterator yields pairs in the order of their index values.
512	#[define_opaque(Iter)]
513	pub fn iter(&self) -> Iter<'_, K, V> {
514		iter::zip(self.bits.iter().map(K::from_index), self.values.iter())
515	}
516
517	/// Returns a mutable iterator over the key-value pairs of the map.
518	#[define_opaque(IterMut)]
519	pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
520		iter::zip(self.bits.iter().map(K::from_index), self.values.iter_mut())
521	}
522
523	/// Returns an iterator over the keys of the map.
524	#[define_opaque(KeyIter)]
525	pub fn keys(&self) -> KeyIter<'_, K> {
526		self.bits.iter().map(K::from_index)
527	}
528
529	/// Returns an iterator over the values of the map.
530	#[inline]
531	pub fn values(&self) -> slice::Iter<'_, V> {
532		self.values.iter()
533	}
534
535	/// Returns a mutable iterator over the values of the map.
536	#[inline]
537	pub fn values_mut(&mut self) -> slice::IterMut<'_, V> {
538		self.values.iter_mut()
539	}
540
541	/// Finds the position in the values vector for the given index.
542	///
543	/// This counts the number of set bits before the given index to determine
544	/// where the corresponding value is stored in the packed values vector.
545	#[inline]
546	pub fn rank(&self, key: K) -> usize {
547		self.bits.rank(key.index())
548	}
549
550	/// Returns the first (minimum) key-value pair in the map, or [`None`] if the
551	/// map is empty.
552	pub fn first(&self) -> Option<(K, &V)> {
553		self
554			.bits
555			.first()
556			.and_then(|idx| self.values.first().map(|v| (K::from_index(idx), v)))
557	}
558
559	/// Returns the last (maximum) key-value pair in the map, or [`None`] if the
560	/// map is empty.
561	pub fn last(&self) -> Option<(K, &V)> {
562		self
563			.bits
564			.last()
565			.and_then(|idx| self.values.last().map(|v| (K::from_index(idx), v)))
566	}
567
568	/// Returns `true` if the map has holes (gaps) in its indices.
569	///
570	/// A map is considered sparse if there are missing indices between the
571	/// first and last elements. An empty map or a map with a single element
572	/// is considered non-sparse.
573	pub fn is_sparse(&self) -> bool {
574		match (self.bits.first(), self.bits.last()) {
575			(Some(first), Some(last)) => {
576				// If we have all consecutive indices from first to last,
577				// the count should equal (last - first + 1)
578				self.len() < (last - first + 1)
579			},
580			_ => false, // Empty or single element maps are not sparse
581		}
582	}
583}
584
585/// Iterator over key/value pairs in key order; see [`SparseMap::iter`].
586pub type Iter<'a, K: TrySparseIndex, V: 'a> =
587	impl DoubleEndedIterator<Item = (K, &'a V)> + ExactSizeIterator + FusedIterator + Clone;
588/// Iterator over key/mutable-value pairs in key order; see
589/// [`SparseMap::iter_mut`].
590pub type IterMut<'a, K: TrySparseIndex, V: 'a> =
591	impl DoubleEndedIterator<Item = (K, &'a mut V)> + ExactSizeIterator + FusedIterator;
592/// Iterator over keys in key order; see [`SparseMap::keys`].
593pub type KeyIter<'a, K: TrySparseIndex> =
594	impl DoubleEndedIterator<Item = K> + ExactSizeIterator + FusedIterator + Clone;
595/// Owning iterator over key/value pairs in key order.
596pub type IntoIter<K: TrySparseIndex, V> =
597	impl DoubleEndedIterator<Item = (K, V)> + ExactSizeIterator + FusedIterator;
598
599// Index trait for convenient access
600impl<K: TrySparseIndex, V> Index<K> for SparseMap<K, V> {
601	type Output = V;
602
603	fn index(&self, key: K) -> &Self::Output {
604		self.get(key).expect("key not found in SparseMap")
605	}
606}
607
608impl<K: TrySparseIndex, V> IndexMut<K> for SparseMap<K, V> {
609	fn index_mut(&mut self, key: K) -> &mut Self::Output {
610		self.get_mut(key).expect("key not found in SparseMap")
611	}
612}
613
614impl<'a, K: TrySparseIndex, V> IntoIterator for &'a SparseMap<K, V> {
615	type IntoIter = Iter<'a, K, V>;
616	type Item = (K, &'a V);
617
618	fn into_iter(self) -> Self::IntoIter {
619		self.iter()
620	}
621}
622
623impl<'a, K: TrySparseIndex, V> IntoIterator for &'a mut SparseMap<K, V> {
624	type IntoIter = IterMut<'a, K, V>;
625	type Item = (K, &'a mut V);
626
627	fn into_iter(self) -> Self::IntoIter {
628		self.iter_mut()
629	}
630}
631
632impl<K: TrySparseIndex, V> IntoIterator for SparseMap<K, V> {
633	type IntoIter = IntoIter<K, V>;
634	type Item = (K, V);
635
636	#[define_opaque(IntoIter)]
637	fn into_iter(self) -> Self::IntoIter {
638		let indices = self.bits.into_iter().map(K::from_index);
639		let values = self.values.into_iter();
640		indices.zip(values)
641	}
642}
643
644impl<K: TrySparseIndex, V> FromIterator<(K, V)> for SparseMap<K, V> {
645	fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
646		let iter = iter.into_iter();
647		let mut map = Self::with_capacity(iter.size_hint().0);
648		let mut hi = None;
649
650		for (key, value) in iter {
651			let ix = key.index();
652			match hi {
653				Some(hi) if ix == hi => {
654					*map.values.last_mut().expect("can't have key without value") = value;
655				},
656				Some(hi) if ix < hi => {
657					map.insert(K::from_index(ix), value);
658				},
659				_ => {
660					map.bits.insert(ix);
661					map.values.push(value);
662					hi = Some(ix);
663				},
664			}
665		}
666
667		map
668	}
669}
670
671impl<K: TrySparseIndex, V> Extend<(K, V)> for SparseMap<K, V> {
672	fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
673		let mut hi = self.bits.last();
674		for (key, value) in iter {
675			let ix = key.index();
676			match hi {
677				Some(hi) if ix == hi => {
678					*self
679						.values
680						.last_mut()
681						.expect("can't have key without value") = value;
682				},
683				Some(hi) if ix < hi => {
684					self.insert(K::from_index(ix), value);
685				},
686				_ => {
687					self.bits.insert(ix);
688					self.values.push(value);
689					hi = Some(ix);
690				},
691			}
692		}
693	}
694}