smallmap/
lib.rs

1//! # smallmap
2//! A small table map with a byte sized key index.
3//!
4//! With a key type which all invariants can be represented as unique bytes, searching this map is a single index dereference.
5//! With only a few bytes it is still very efficient.
6//!
7//! ## Usage
8//! The API is a similar subset to `HashMap`, containing the same `insert`, `get`, and `entry` functions:
9//!
10//! ```
11//! # use smallmap::Map;
12//! fn max_char(chars: &str) -> (char, usize)
13//! {
14//!     let mut map = Map::new();
15//!     for x in chars.chars() {
16//! 	    *map.entry(x).or_insert(0usize) += 1;	
17//!     }
18//! 
19//!     map.into_iter().max_by_key(|&(_, v)| v).unwrap_or_default()
20//! }
21//! ```
22//!
23//! ## Use cases
24//! Designed for instances where you want a small map with small key types.
25//! Performance greately outpaces complex hash-based maps in these cases.
26//!
27//! ###  When not to use
28//! Generally don't use this if your key would have a lot of collisions being represents in 8 bits, otherwise it might be a faster alternative to hash-based maps. You should check yourself before sticking with this crate instead of `std`'s vectorised map implementations.
29#![cfg_attr(any(not(test), not(feature = "std")), no_std)]
30#![cfg_attr(nightly, feature(test))] 
31#![cfg_attr(nightly, feature(never_type))] 
32
33#[cfg(all(nightly, test))] extern crate test;
34extern crate alloc;
35
36const MAX: usize = 256;
37
38use alloc::vec;
39use alloc::vec::Vec;
40use core::borrow::Borrow;
41
42pub mod iter;
43use iter::*;
44pub mod entry;
45pub use entry::Entry;
46
47pub mod space;
48
49pub mod primitive;
50pub use primitive::Primitive;
51
52mod init;
53
54mod private {
55    pub trait Sealed{}
56}
57
58/// A smallmap set.
59///
60/// Can be used to quickly insert or remove a key only, with no value; and can be used to see if this key is present.
61///
62/// Any map type with a zero-sized value is essentially a set.
63pub type Set<T> = Map<T,()>;
64
65/// A helper macro for creating `Map` instances with or without pre-set entries.
66///
67/// # Create empty map
68/// With no parameters this just calls `Map::new()`.
69/// ```
70/// # use smallmap::*;
71/// let map: Map<i32, i32> = smallmap!();
72/// let map2: Map<i32, i32> = Map::new();
73/// assert_eq!(map, map2);
74/// ```
75/// # Create with key-value pairs
76/// You can specify some entries to pre-insert in the format `{key => value}`.
77/// ```
78/// # use smallmap::*;
79/// let map = smallmap! {
80///   {"Key" => 1},
81///   {"Key two" => 2},
82///   {"Key three" => 3},
83///   {"Key four" => 4},
84/// };
85/// ```
86#[macro_export ]macro_rules! smallmap {
87    () => {
88	$crate::Map::new()
89    };
90    ($({$key:expr => $value:expr}),* $(,)?) => {
91	{
92	    let mut map = $crate::Map::new();
93	    $(
94		map.insert($key, $value);
95	    )*
96		map
97	}
98    }
99}
100
101
102/// Trait for types that can be used as `Map` keys.
103///
104/// Implementors should try to minimise collisions by making `collapse` return a relatively unique value if possible.
105/// But it is not required.
106/// It is automatically implemented for types implementing the `Hash` trait.
107/// A simple folding implementation is provided for byte slices here [`collapse_iter()`](collapse_iter).
108///
109/// The default implementation has integer types implement this through the modulo of itself over 256, whereas byte slice types implement it through an XOR fold over itself. It doesn't matter though, the programmer is free to implement it how she chooses.
110pub trait Collapse: Eq
111{
112    /// Create the index key for this instance. This is similar in use to `Hash::hash()`.
113    fn collapse(&self) -> u8;
114}
115
116/// A single page in a `Map`. Contains up to 256 key-value entries.
117#[repr(transparent)]
118pub struct Page<TKey,TValue>([Option<(TKey, TValue)>; MAX]);
119
120mod page_impls;
121
122impl<K,V> Page<K,V>
123where K: Collapse
124{
125    /// Create a new blank page
126    #[cfg(nightly)] 
127    pub const fn new() -> Self
128    {
129	Self(init::blank_page())
130    }
131    /// Create a new blank page
132    #[cfg(not(nightly))]
133    pub fn new() -> Self
134    {
135	Self(init::blank_page())
136    }
137    
138    /// The number of entries currently in this page
139    ///
140    /// This is a count that iterates over all slots, if possible store it in a temporary instead of re-calling it many times.
141    pub fn len(&self) -> usize
142    {
143	self.0.iter().map(Option::as_ref).filter_map(core::convert::identity).count()
144    }
145
146    /// An iterator over all entries currently in this page
147    pub fn iter(&self) -> PageElements<'_, K,V>
148    {
149	PageElements(self.0.iter())
150    }
151
152    /// A mutable iterator over all entries currently in this page
153    pub fn iter_mut(&mut self) -> PageElementsMut<'_, K,V>
154    {
155	PageElementsMut(self.0.iter_mut())
156    }
157    
158    fn search<Q: ?Sized>(&self, key: &Q) -> &Option<(K,V)>
159    where Q: Collapse
160    {
161	&self.0[usize::from(key.collapse())]
162    }
163    fn search_mut<Q: ?Sized>(&mut self, key: &Q) -> &mut Option<(K,V)>
164    where Q: Collapse
165    {
166	&mut self.0[usize::from(key.collapse())]
167    }
168
169    fn replace(&mut self, k: K, v: V) -> Option<(K,V)>
170    {
171	core::mem::replace(&mut self.0[usize::from(k.collapse())], Some((k,v)))
172    }
173}
174
175impl<K: Collapse, V> core::iter::FromIterator<(K, V)> for Map<K,V>
176{
177    fn from_iter<I: IntoIterator<Item=(K, V)>>(iter: I) -> Self
178    {
179	//TODO: Optimise this
180	let mut this = Self::new();
181	for (key, value) in iter.into_iter()
182	{
183	    this.insert(key, value);
184	}
185	this
186    }
187}
188
189impl<K,V> IntoIterator for Page<K,V>
190where K: Collapse
191{
192    type Item= (K,V);
193    type IntoIter = IntoPageElements<K,V>;
194
195    /// Consume this `Page` into an iterator of all values currently in it.
196    fn into_iter(self) -> Self::IntoIter
197    {
198	IntoPageElements(self.0, 0)
199    }
200}
201
202
203impl<K,V> Default for Page<K,V>
204where K: Collapse
205{
206    #[inline]
207    fn default() -> Self
208    {
209	Self::new()
210    }
211}
212
213/// A small hashtable-like map with byte sized key indecies.
214#[derive(Debug, Clone, PartialEq, Eq, Hash)]
215// TODO: Replace with `SmallVec<[Page<TKey, TValue>; 1]>` when feature that adds `smallvec` is enabled (this will allocate the first page on the stack, and the rest on the heap.
216pub struct Map<TKey, TValue>(Vec<Page<TKey,TValue>>);
217
218#[cfg(feature = "serde")]
219struct MapVisitor<TKey, TValue> {
220	_pd: core::marker::PhantomData<(TKey, TValue)>,
221}
222
223#[cfg(feature = "serde")]
224impl<'de, TKey, TValue> serde::de::Deserialize<'de> for Map<TKey, TValue> where TKey: Collapse + serde::Deserialize<'de>, TValue: serde::Deserialize<'de> {
225	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
226		deserializer.deserialize_map(MapVisitor { _pd: core::marker::PhantomData::default() })
227	}
228}
229
230/// Just taken from [serde.rs' examples](https://serde.rs/deserialize-map.html)
231#[cfg(feature = "serde")]
232impl<'de, TKey, TValue> serde::de::Visitor<'de> for MapVisitor<TKey, TValue> where TKey: Collapse + serde::Deserialize<'de>, TValue: serde::Deserialize<'de> {
233	type Value = Map<TKey, TValue>;
234
235	fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
236		formatter.write_str("A map")
237	}
238
239	fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error> where A: serde::de::MapAccess<'de> {
240		let mut map = Map::with_capacity(access.size_hint().unwrap_or(1));
241		while let Some((key, value)) = access.next_entry()? {
242			map.insert(key, value);
243		}
244		Ok(map)
245	}
246}
247
248#[cfg(feature = "serde")]
249impl<TKey, TValue> serde::Serialize for Map<TKey, TValue> where TKey: Collapse + serde::Serialize, TValue: serde::Serialize {
250	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
251		let mut m = serializer.serialize_map(Some(self.len()))?;
252		for (k, v) in self.iter() {
253			m.serialize_entry(k, v)?;
254		}
255		m.end()
256	}
257}
258
259impl<K,V> Map<K,V>
260{
261    /// Returns the currently allocated size of the map in bytes (including currently unused reserved space.)
262    #[inline(always)]
263    #[allow(dead_code)] // Used in test cases, but compiler still warns about it
264    pub(crate) fn internal_size_bytes(&self) -> usize
265    {
266	self.0.capacity() * core::mem::size_of::<Page<K,V>>()
267	//self.0.iter().map(core::mem::size_of_val).sum::<usize>()
268    }
269}
270
271impl<K,V> Map<K,V>
272where K: Collapse
273{
274    fn new_page(&mut self) -> &mut Page<K,V>
275    {
276	let len = self.0.len();
277	self.0.push(Page::new());
278	&mut self.0[len]
279    }
280    #[inline(always)] fn fuck_entry(&mut self, key: K) -> Option<Entry<'_, K, V>>
281    {
282	for page in self.0.iter_mut()
283	{
284	    let re = page.search_mut(&key);
285	    match  re {
286		Some((ref ok, _)) if key.eq(ok.borrow()) => {
287		    return Some(Entry::Occupied(entry::OccupiedEntry(re)));
288		},
289		None => {
290		    return Some(Entry::Vacant(entry::VacantEntry(re, key)));
291		},
292		_ => (),
293	    }
294	}
295	None
296    }
297
298    /// Get an `Entry` for the `key` that lets you get or insert the value
299    pub fn entry(&mut self, key: K) -> Entry<'_, K, V>
300    {
301	// somehow this is faster than using index, even though here we search twice????? i don't know why but there you go
302	if let None =  self.0.iter()
303	    .filter(|x| x.search(&key).as_ref().and_then(|(k, v)| if k==&key {None} else {Some((k,v))}).is_none())
304	    .next() {
305		self.new_page();
306	    }
307	self.fuck_entry(key).unwrap()
308    }
309    /// Remove all empty pages from this instance.
310    pub fn clean(&mut self)
311    {
312	self.0.retain(|x| x.len() >= 1);
313    }
314
315    /// The number of entries currently in this map
316    ///
317    /// This is an iterating count over all slots in all current pages, if possible store it in a temporary instead of re-calling it.
318    pub fn len(&self) -> usize
319    {
320	self.pages().map(Page::len).sum()
321    }
322    /// Is this map empty
323    pub fn is_empty(&self) -> bool
324    {
325	self.0[0].iter().next().is_none()
326    }
327    /// The number of pages currently in this map
328    pub fn num_pages(&self) -> usize
329    {
330	self.0.len()
331    }
332    /// Consume the instance, returning all pages.
333    pub fn into_pages(self) -> Vec<Page<K,V>>
334    {
335	self.0
336    }
337    /// An iterator over all pages
338    pub fn pages(&self) -> Pages<'_, K, V>
339    {
340	iter::Pages(self.0.iter())
341    }
342
343    /// A mutable iterator over all pages
344    pub fn pages_mut(&mut self) -> PagesMut<'_, K, V>
345    {
346	iter::PagesMut(self.0.iter_mut())
347    }
348
349    /// An iterator over all elements in the map
350    pub fn iter(&self) -> Iter<'_, K, V>
351    {
352	Iter(None, self.pages())
353    }
354
355	/// An iterator over all the keys in the map
356	pub fn keys(&self) -> impl Iterator<Item = &K> {
357		self.iter().map(|(k, _)| k)
358	}
359
360	/// An iterator over all the values in the map
361	pub fn values(&self) -> impl Iterator<Item = &V> {
362		self.iter().map(|(_, v)| v)
363	}
364
365	/// A mutable iterator over all the values in the map
366	pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
367		self.iter_mut().map(|(_, v)| v)
368	}
369
370    /// A mutable iterator over all elements in the map
371    pub fn iter_mut(&mut self) -> IterMut<'_, K, V>
372    {
373	IterMut(None, self.pages_mut())
374    }
375
376    /// Create a new empty `Map`
377    pub fn new() -> Self
378    {
379	Self(vec![Page::new()])
380    }
381
382    /// Create a new empty `Map` with a specific number of pages pre-allocated
383    pub fn with_capacity(pages: usize) -> Self
384    {
385	#[cold] fn cap_too_low() -> !
386	{
387	    panic!("Got 0 capacity, this is invalid.")
388	}
389	
390	if pages == 0 {
391	    cap_too_low()
392	}
393	let mut p = Vec::with_capacity(pages);
394	p.push(Page::new());
395	Self(p)
396    }
397
398    /// Get a mutable reference of the value corresponding to this key if it is in the map.
399    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
400    where K: Borrow<Q>,
401	  Q: Collapse + Eq
402    {
403	for page in self.0.iter_mut()
404	{
405	    match page.search_mut(key) {
406		Some((ref ok, ov)) if key.eq(ok.borrow()) => {
407		    return Some(ov);
408		},
409		_ => (),
410	    }
411	}
412	None
413    }
414
415    /// Search the map for entry corresponding to this key
416    #[inline] pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
417    where K: Borrow<Q>,
418	  Q: Collapse + Eq
419    {
420	self.get(key).is_some()
421    }
422
423    /// Get a reference of the value corresponding to this key if it is in the map.
424    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
425    where K: Borrow<Q>,
426	  Q: Collapse + Eq
427    {
428	for page in self.0.iter()
429	{
430	    match page.search(key) {
431		Some((ref ok, ov)) if key.eq(ok.borrow()) => {
432		    return Some(ov);
433		},
434		_ => (),
435	    }
436	}
437	None
438    }
439
440    /// Remove the entry corresponding to this key in the map, returning the value if it was present
441    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
442    where K: Borrow<Q>,
443	  Q: Collapse + Eq
444    {
445	for page in self.0.iter_mut()
446	{
447	    let v = page.search_mut(key);
448	    match v {
449		Some((ref ok, _)) if key.eq(ok.borrow()) => {
450		    return v.take().map(|(_, v)| v);
451		},
452		_ => (),
453	    }
454	}
455	None
456    }
457
458    /// Insert a new key-value entry into this map, returning the pervious value if it was present
459    pub fn insert(&mut self, key: K, value: V) -> Option<V>
460    {
461	for page in self.0.iter_mut()
462	{
463	    match page.search_mut(&key) {
464		Some((ref ok, ov)) if ok.eq(&key) => {
465		    return Some(core::mem::replace(ov, value));
466		},
467		empty @ None => {
468		    return empty.replace((key, value))
469			.map(|(_, v)| v);
470		},
471		_ => (),
472	    }
473	}
474
475	let mut page = Page::new();
476	page.replace(key, value);
477	self.0.push(page);
478	None
479    }
480    
481    /// Consume this `Map` by swapping its keys and values around.
482    pub fn reverse(self) -> Map<V,K>
483    where V: Collapse
484    {
485	let mut output = Map::with_capacity(self.num_pages());
486
487	for (k,v) in self.into_iter()
488	{
489	    output.insert(v, k);
490	}
491
492	output
493    }
494}
495
496impl<K: Collapse, V> Default for Map<K,V>
497{
498    #[inline]
499    fn default() -> Self
500    {
501        Self::new()
502    }
503}
504
505impl<K: Collapse, V> IntoIterator for Map<K,V>
506{
507    type Item= (K,V);
508    type IntoIter = IntoIter<K,V>;
509
510    /// Consume this map into an iterator over all currently inserted entries
511    fn into_iter(self) -> Self::IntoIter
512    {
513	IntoIter(None, self.0.into_iter())
514    }
515}
516
517impl<K: Collapse, V> core::iter::Extend<(K,V)> for Map<K,V>
518{
519    fn extend<T: IntoIterator<Item = (K,V)>>(&mut self, iter: T) {
520	// we can probably optimise this better, right?
521	for (key, value) in iter.into_iter()
522	{
523	    self.insert(key,value);
524	}
525    }
526}
527
528use core::hash::{Hash, Hasher,};
529use core::ops::{Index, IndexMut};
530#[cfg(feature = "serde")]
531use serde::ser::SerializeMap;
532
533impl<T: ?Sized + Hash + Eq> Collapse for T
534{
535    fn collapse(&self) -> u8 {
536	struct CollapseHasher(u8);
537	macro_rules! hash_type {
538	    
539	    ($nm:ident, u8) => {
540		#[inline(always)] fn $nm(&mut self, i: u8)
541		{
542		    self.0 ^= i;
543		}
544	    };
545	    
546	    ($nm:ident, i8) => {
547		#[inline(always)] fn $nm(&mut self, i: i8)
548		{
549		    self.0 ^= i as u8;
550		}
551	    };
552	    
553	    ($nm:ident, $ty:tt) => {
554		#[inline] fn $nm(&mut self, i: $ty)
555		{
556		    self.0 ^= (i % MAX as $ty) as u8;
557		}
558	    };
559	}
560	impl Hasher for CollapseHasher
561	{
562	    #[inline] fn finish(&self) -> u64
563	    {
564		self.0 as u64
565	    }
566	    #[inline] fn write(&mut self, buffer: &[u8])
567	    {
568		self.0 ^= collapse(buffer);
569	    }
570	    hash_type!(write_u8, u8);
571	    hash_type!(write_i8, i8);
572	    hash_type!(write_i16, i16);
573	    hash_type!(write_u16, u16);
574	    hash_type!(write_i32, i32);
575	    hash_type!(write_u32, u32);
576	    hash_type!(write_i64, i64);
577	    hash_type!(write_u64, u64);
578	    hash_type!(write_u128, u128);
579	    
580	    hash_type!(write_isize, isize);
581	    hash_type!(write_usize, usize);
582	}
583
584	let mut h = CollapseHasher(0);
585	self.hash(&mut h);
586	h.0
587    }
588}
589
590impl<K, Q, V> Index<&Q> for Map<K, V>
591	where
592		K: Collapse + Borrow<Q>,
593		Q: ?Sized + Collapse + Eq,
594{
595	type Output = V;
596
597	fn index(&self, key: &Q) -> &Self::Output {
598		self.get(key).expect("Key not found")
599	}
600}
601
602impl<K, Q, V> IndexMut<&Q> for Map<K, V>
603	where
604		K: Collapse + Borrow<Q>,
605		Q: ?Sized + Collapse + Eq,
606{
607	fn index_mut(&mut self, key: &Q) -> &mut Self::Output {
608		self.get_mut(key).expect("Key not found")
609	}
610}
611
612#[cfg(test)]
613mod tests;
614
615/// Collapse a slice of bytes with an XOR fold
616#[inline] pub fn collapse<T: AsRef<[u8]>>(bytes: T) -> u8
617{
618    bytes.as_ref().iter().copied().fold(0, |a, b| a ^ b)
619}
620
621/// Collapse an iterator of bytes with an XOR fold
622#[inline] pub fn collapse_iter<T: IntoIterator<Item=u8>>(bytes: T) -> u8
623{
624    bytes.into_iter().fold(0, |a, b| a ^ b)
625}