|
|
@ -44,6 +44,43 @@ pub use entry::Entry;
|
|
|
|
|
|
|
|
|
|
|
|
mod init;
|
|
|
|
mod init;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A helper macro for creating `Map` instances with or without pre-set entries.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Create empty map
|
|
|
|
|
|
|
|
/// With no parameters this just calls `Map::new()`.
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # use smallmap::*;
|
|
|
|
|
|
|
|
/// let map: Map<i32, i32> = smallmap!();
|
|
|
|
|
|
|
|
/// let map2: Map<i32, i32> = Map::new();
|
|
|
|
|
|
|
|
/// assert_eq!(map, map2);
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # Create with key-value pairs
|
|
|
|
|
|
|
|
/// You can specify some entries to pre-insert in the format `{key => value}`.
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # use smallmap::*;
|
|
|
|
|
|
|
|
/// let map = smallmap! {
|
|
|
|
|
|
|
|
/// {"Key" => 1},
|
|
|
|
|
|
|
|
/// {"Key two" => 2},
|
|
|
|
|
|
|
|
/// {"Key three" => 3},
|
|
|
|
|
|
|
|
/// {"Key four" => 4},
|
|
|
|
|
|
|
|
/// };
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
#[macro_export ]macro_rules! smallmap {
|
|
|
|
|
|
|
|
() => {
|
|
|
|
|
|
|
|
$crate::Map::new()
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
($({$key:expr => $value:expr}),* $(,)?) => {
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let mut map = $crate::Map::new();
|
|
|
|
|
|
|
|
$(
|
|
|
|
|
|
|
|
map.insert($key, $value);
|
|
|
|
|
|
|
|
)*
|
|
|
|
|
|
|
|
map
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Trait for types that can be used as `Map` keys.
|
|
|
|
/// Trait for types that can be used as `Map` keys.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Implementors should try to minimise collisions by making `collapse` return a relatively unique value if possible.
|
|
|
|
/// Implementors should try to minimise collisions by making `collapse` return a relatively unique value if possible.
|
|
|
@ -143,7 +180,7 @@ where K: Collapse
|
|
|
|
|
|
|
|
|
|
|
|
/// A small hashtable-like map with byte sized key indecies.
|
|
|
|
/// A small hashtable-like map with byte sized key indecies.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
|
|
|
#[cfg_attr(feature="serde", derive(serde::Serialize))]
|
|
|
|
#[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
pub struct Map<TKey, TValue>(Vec<Page<TKey,TValue>>);
|
|
|
|
pub struct Map<TKey, TValue>(Vec<Page<TKey,TValue>>);
|
|
|
|
|
|
|
|
|
|
|
|
impl<K,V> Map<K,V>
|
|
|
|
impl<K,V> Map<K,V>
|
|
|
@ -172,6 +209,8 @@ where K: Collapse
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get an `Entry` for the `key` that lets you get or insert the value
|
|
|
|
pub fn entry(&mut self, key: K) -> Entry<'_, K, V>
|
|
|
|
pub fn entry(&mut self, key: K) -> Entry<'_, K, V>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// somehow this is faster than using index, even though here we search twice????? i don't know why but there you go
|
|
|
|
// somehow this is faster than using index, even though here we search twice????? i don't know why but there you go
|
|
|
@ -207,6 +246,11 @@ where K: Collapse
|
|
|
|
{
|
|
|
|
{
|
|
|
|
self.pages().map(Page::len).sum()
|
|
|
|
self.pages().map(Page::len).sum()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Is this map empty
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.0[0].iter().next().is_none()
|
|
|
|
|
|
|
|
}
|
|
|
|
/// The number of pages currently in this map
|
|
|
|
/// The number of pages currently in this map
|
|
|
|
pub fn num_pages(&self) -> usize
|
|
|
|
pub fn num_pages(&self) -> usize
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -250,8 +294,13 @@ where K: Collapse
|
|
|
|
/// Create a new empty `Map` with a specific number of pages pre-allocated
|
|
|
|
/// Create a new empty `Map` with a specific number of pages pre-allocated
|
|
|
|
pub fn with_capacity(pages: usize) -> Self
|
|
|
|
pub fn with_capacity(pages: usize) -> Self
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
#[cold] fn cap_too_low() -> !
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
panic!("Got 0 capacity, this is invalid.")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if pages == 0 {
|
|
|
|
if pages == 0 {
|
|
|
|
panic!("Got 0 capacity, this is invalid.");
|
|
|
|
cap_too_low()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut p = Vec::with_capacity(pages);
|
|
|
|
let mut p = Vec::with_capacity(pages);
|
|
|
|
p.push(Page::new());
|
|
|
|
p.push(Page::new());
|
|
|
@ -354,6 +403,17 @@ impl<K: Collapse, V> IntoIterator for Map<K,V>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<K: Collapse, V> std::iter::Extend<(K,V)> for Map<K,V>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fn extend<T: IntoIterator<Item = (K,V)>>(&mut self, iter: T) {
|
|
|
|
|
|
|
|
// we can probably optimise this better, right?
|
|
|
|
|
|
|
|
for (key, value) in iter.into_iter()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.insert(key,value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
use std::hash::{Hash, Hasher,};
|
|
|
|
use std::hash::{Hash, Hasher,};
|
|
|
|
impl<T: Hash+ Eq> Collapse for T
|
|
|
|
impl<T: Hash+ Eq> Collapse for T
|
|
|
|
{
|
|
|
|
{
|
|
|
|