mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-09-27 12:30:35 +00:00
port IndexMap and IndexSet
This commit is contained in:
parent
0a41f9e6fa
commit
f58f7abfed
@ -22,4 +22,5 @@ version = "0.3.0"
|
||||
scoped_threadpool = "0.1.8"
|
||||
|
||||
[dependencies]
|
||||
generic-array = "0.11.0"
|
||||
generic-array = "0.11.0"
|
||||
hash32 = "0.1.0"
|
||||
|
@ -1,6 +1,8 @@
|
||||
/// Temporary fork of some stuff in `core` that's doesn't have a `const fn` API
|
||||
|
||||
pub mod mem {
|
||||
pub use core::mem::{replace, zeroed};
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
#[allow(unions_with_drop_fields)]
|
||||
|
889
src/indexmap.rs
Normal file
889
src/indexmap.rs
Normal file
@ -0,0 +1,889 @@
|
||||
use core::borrow::Borrow;
|
||||
use core::iter::FromIterator;
|
||||
use core::num::NonZeroU32;
|
||||
use core::{fmt, ops, slice};
|
||||
|
||||
use generic_array::typenum::PowerOfTwo;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher};
|
||||
|
||||
use Vec;
|
||||
use __core::mem;
|
||||
|
||||
/// An `IndexMap` using the default FNV hasher
|
||||
pub type FnvIndexMap<K, V, N> = IndexMap<K, V, N, BuildHasherDefault<FnvHasher>>;
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
struct HashValue(u16);
|
||||
|
||||
impl HashValue {
|
||||
fn desired_pos(&self, mask: usize) -> usize {
|
||||
usize::from(self.0) & mask
|
||||
}
|
||||
|
||||
fn probe_distance(&self, mask: usize, current: usize) -> usize {
|
||||
current.wrapping_sub(self.desired_pos(mask) as usize) & mask
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Bucket<K, V> {
|
||||
hash: HashValue,
|
||||
key: K,
|
||||
value: V,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct Pos {
|
||||
// compact representation of `{ hash_value: u16, index: u16 }`
|
||||
// To get the most from `NonZero` we store the *value minus 1*. This way `None::Option<Pos>`
|
||||
// is equivalent to the very unlikely value of `{ hash_value: 0xffff, index: 0xffff }` instead
|
||||
// the more likely of `{ hash_value: 0x00, index: 0x00 }`
|
||||
nz: NonZeroU32,
|
||||
}
|
||||
|
||||
impl Pos {
|
||||
fn new(index: usize, hash: HashValue) -> Self {
|
||||
Pos {
|
||||
nz: unsafe {
|
||||
NonZeroU32::new_unchecked(
|
||||
((u32::from(hash.0) << 16) + index as u32).wrapping_add(1),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hash(&self) -> HashValue {
|
||||
HashValue((self.nz.get().wrapping_sub(1) >> 16) as u16)
|
||||
}
|
||||
|
||||
fn index(&self) -> usize {
|
||||
self.nz.get().wrapping_sub(1) as u16 as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Inserted<V> {
|
||||
Done,
|
||||
Swapped { prev_value: V },
|
||||
RobinHood { probe: usize, old_pos: Pos },
|
||||
}
|
||||
|
||||
macro_rules! probe_loop {
|
||||
($probe_var: ident < $len: expr, $body: expr) => {
|
||||
loop {
|
||||
if $probe_var < $len {
|
||||
$body
|
||||
$probe_var += 1;
|
||||
} else {
|
||||
$probe_var = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CoreMap<K, V, N>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
entries: Vec<Bucket<K, V>, N>,
|
||||
indices: GenericArray<Option<Pos>, N>,
|
||||
}
|
||||
|
||||
impl<K, V, N> CoreMap<K, V, N>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
// TODO turn into a `const fn`; needs `mem::zeroed` to be a `const fn`
|
||||
fn new() -> Self {
|
||||
CoreMap {
|
||||
entries: Vec::new(),
|
||||
indices: unsafe { mem::zeroed() },
|
||||
}
|
||||
}
|
||||
|
||||
fn capacity() -> usize {
|
||||
N::to_usize()
|
||||
}
|
||||
|
||||
fn mask() -> usize {
|
||||
Self::capacity() - 1
|
||||
}
|
||||
|
||||
fn find<Q>(&self, hash: HashValue, query: &Q) -> Option<(usize, usize)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Eq,
|
||||
{
|
||||
let mut probe = hash.desired_pos(Self::mask());
|
||||
let mut dist = 0;
|
||||
|
||||
probe_loop!(probe < self.indices.len(), {
|
||||
if let Some(pos) = self.indices[probe] {
|
||||
let entry_hash = pos.hash();
|
||||
// NOTE(i) we use unchecked indexing below
|
||||
let i = pos.index();
|
||||
debug_assert!(i < self.entries.len());
|
||||
|
||||
if dist > entry_hash.probe_distance(Self::mask(), probe) {
|
||||
// give up when probe distance is too long
|
||||
return None;
|
||||
} else if entry_hash == hash && unsafe {
|
||||
self.entries.get_unchecked(i).key.borrow() == query
|
||||
} {
|
||||
return Some((probe, i));
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
||||
dist += 1;
|
||||
});
|
||||
}
|
||||
|
||||
// First phase: Look for the preferred location for key.
|
||||
//
|
||||
// We will know if `key` is already in the map, before we need to insert it.
|
||||
// When we insert they key, it might be that we need to continue displacing
|
||||
// entries (robin hood hashing), in which case Inserted::RobinHood is returned
|
||||
fn insert_phase_1(&mut self, hash: HashValue, key: K, value: V) -> Inserted<V> {
|
||||
let mut probe = hash.desired_pos(Self::mask());
|
||||
let mut dist = 0;
|
||||
|
||||
let inserted;
|
||||
probe_loop!(probe < self.indices.len(), {
|
||||
let pos = &mut self.indices[probe];
|
||||
|
||||
if let Some(pos) = *pos {
|
||||
let entry_hash = pos.hash();
|
||||
// NOTE(i) we use unchecked indexing below
|
||||
let i = pos.index();
|
||||
debug_assert!(i < self.entries.len());
|
||||
|
||||
let their_dist = entry_hash.probe_distance(Self::mask(), probe);
|
||||
|
||||
if their_dist < dist {
|
||||
// robin hood: steal the spot if it's better for us
|
||||
let index = self.entries.len();
|
||||
inserted = Inserted::RobinHood {
|
||||
probe: probe,
|
||||
old_pos: Pos::new(index, hash),
|
||||
};
|
||||
break;
|
||||
} else if entry_hash == hash && unsafe { self.entries.get_unchecked(i).key == key }
|
||||
{
|
||||
return Inserted::Swapped {
|
||||
prev_value: mem::replace(
|
||||
unsafe { &mut self.entries.get_unchecked_mut(i).value },
|
||||
value,
|
||||
),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// empty bucket, insert here
|
||||
let index = self.entries.len();
|
||||
*pos = Some(Pos::new(index, hash));
|
||||
inserted = Inserted::Done;
|
||||
break;
|
||||
}
|
||||
dist += 1;
|
||||
});
|
||||
|
||||
// NOTE(unsafe) we already checked (in `insert`) that we aren't exceeding the capacity
|
||||
unsafe { self.entries.push_unchecked(Bucket { hash, key, value }) }
|
||||
inserted
|
||||
}
|
||||
|
||||
// phase 2 is post-insert where we forward-shift `Pos` in the indices.
|
||||
fn insert_phase_2(&mut self, mut probe: usize, mut old_pos: Pos) {
|
||||
probe_loop!(probe < self.indices.len(), {
|
||||
let pos = unsafe { self.indices.get_unchecked_mut(probe) };
|
||||
|
||||
if let Some(pos) = pos.as_mut() {
|
||||
old_pos = mem::replace(pos, old_pos);
|
||||
} else {
|
||||
*pos = Some(old_pos);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn remove_found(&mut self, probe: usize, found: usize) -> (K, V) {
|
||||
// index `probe` and entry `found` is to be removed
|
||||
// use swap_remove, but then we need to update the index that points
|
||||
// to the other entry that has to move
|
||||
self.indices[probe] = None;
|
||||
let entry = unsafe { self.entries.swap_remove_unchecked(found) };
|
||||
|
||||
// correct index that points to the entry that had to swap places
|
||||
if let Some(entry) = self.entries.get(found) {
|
||||
// was not last element
|
||||
// examine new element in `found` and find it in indices
|
||||
let mut probe = entry.hash.desired_pos(Self::mask());
|
||||
|
||||
probe_loop!(probe < self.indices.len(), {
|
||||
if let Some(pos) = self.indices[probe] {
|
||||
if pos.index() >= self.entries.len() {
|
||||
// found it
|
||||
self.indices[probe] = Some(Pos::new(found, entry.hash));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self.backward_shift_after_removal(probe);
|
||||
|
||||
(entry.key, entry.value)
|
||||
}
|
||||
|
||||
fn backward_shift_after_removal(&mut self, probe_at_remove: usize) {
|
||||
// backward shift deletion in self.indices
|
||||
// after probe, shift all non-ideally placed indices backward
|
||||
let mut last_probe = probe_at_remove;
|
||||
let mut probe = probe_at_remove + 1;
|
||||
|
||||
probe_loop!(probe < self.indices.len(), {
|
||||
if let Some(pos) = self.indices[probe] {
|
||||
let entry_hash = pos.hash();
|
||||
|
||||
if entry_hash.probe_distance(Self::mask(), probe) > 0 {
|
||||
unsafe { *self.indices.get_unchecked_mut(last_probe) = self.indices[probe] }
|
||||
self.indices[probe] = None;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
last_probe = probe;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Fixed capacity [`IndexMap`](https://docs.rs/indexmap/1/indexmap/map/struct.IndexMap.html)
|
||||
///
|
||||
/// Note that the capacity of the `IndexMap` must be a power of 2.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// // A hash map with a capacity of 16 key-value pairs
|
||||
/// let mut book_reviews = FnvIndexMap::<_, _, U16>::new();
|
||||
///
|
||||
/// // review some books.
|
||||
/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book.").unwrap();
|
||||
/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece.").unwrap();
|
||||
/// book_reviews.insert("Pride and Prejudice", "Very enjoyable.").unwrap();
|
||||
/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot.").unwrap();
|
||||
///
|
||||
/// // check for a specific one.
|
||||
/// if !book_reviews.contains_key("Les Misérables") {
|
||||
/// println!("We've got {} reviews, but Les Misérables ain't one.",
|
||||
/// book_reviews.len());
|
||||
/// }
|
||||
///
|
||||
/// // oops, this review has a lot of spelling mistakes, let's delete it.
|
||||
/// book_reviews.remove("The Adventures of Sherlock Holmes");
|
||||
///
|
||||
/// // look up the values associated with some keys.
|
||||
/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
|
||||
/// for book in &to_find {
|
||||
/// match book_reviews.get(book) {
|
||||
/// Some(review) => println!("{}: {}", book, review),
|
||||
/// None => println!("{} is unreviewed.", book)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // iterate over everything.
|
||||
/// for (book, review) in &book_reviews {
|
||||
/// println!("{}: \"{}\"", book, review);
|
||||
/// }
|
||||
/// ```
|
||||
pub struct IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
core: CoreMap<K, V, N>,
|
||||
build_hasher: S,
|
||||
}
|
||||
|
||||
impl<K, V, N, S> IndexMap<K, V, N, BuildHasherDefault<S>>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: Default + Hasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>> + PowerOfTwo,
|
||||
{
|
||||
// TODO turn into a `const fn`; needs `mem::zeroed` to be a `const fn`
|
||||
/// Creates an empty `IndexMap`.
|
||||
///
|
||||
/// **NOTE** This constructor will become a `const fn` in the future
|
||||
pub fn new() -> Self {
|
||||
IndexMap {
|
||||
build_hasher: BuildHasherDefault::default(),
|
||||
core: CoreMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, N, S> IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
/* Public API */
|
||||
/// Returns the number of elements the map can hold
|
||||
pub fn capacity(&self) -> usize {
|
||||
N::to_usize()
|
||||
}
|
||||
|
||||
/// Return an iterator over the keys of the map, in their order
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U16>::new();
|
||||
/// map.insert("a", 1).unwrap();
|
||||
/// map.insert("b", 2).unwrap();
|
||||
/// map.insert("c", 3).unwrap();
|
||||
///
|
||||
/// for key in map.keys() {
|
||||
/// println!("{}", key);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn keys(&self) -> impl Iterator<Item = &K> {
|
||||
self.core.entries.iter().map(|bucket| &bucket.key)
|
||||
}
|
||||
|
||||
/// Return an iterator over the values of the map, in their order
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U16>::new();
|
||||
/// map.insert("a", 1).unwrap();
|
||||
/// map.insert("b", 2).unwrap();
|
||||
/// map.insert("c", 3).unwrap();
|
||||
///
|
||||
/// for val in map.values() {
|
||||
/// println!("{}", val);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn values(&self) -> impl Iterator<Item = &V> {
|
||||
self.core.entries.iter().map(|bucket| &bucket.value)
|
||||
}
|
||||
|
||||
/// Return an iterator over mutable references to the the values of the map, in their order
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U16>::new();
|
||||
/// map.insert("a", 1).unwrap();
|
||||
/// map.insert("b", 2).unwrap();
|
||||
/// map.insert("c", 3).unwrap();
|
||||
///
|
||||
/// for val in map.values_mut() {
|
||||
/// *val += 10;
|
||||
/// }
|
||||
///
|
||||
/// for val in map.values() {
|
||||
/// println!("{}", val);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
|
||||
self.core.entries.iter_mut().map(|bucket| &mut bucket.value)
|
||||
}
|
||||
|
||||
/// Return an iterator over the key-value pairs of the map, in their order
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U16>::new();
|
||||
/// map.insert("a", 1).unwrap();
|
||||
/// map.insert("b", 2).unwrap();
|
||||
/// map.insert("c", 3).unwrap();
|
||||
///
|
||||
/// for (key, val) in map.iter() {
|
||||
/// println!("key: {} val: {}", key, val);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter {
|
||||
iter: self.core.entries.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator over the key-value pairs of the map, in their order
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U16>::new();
|
||||
/// map.insert("a", 1).unwrap();
|
||||
/// map.insert("b", 2).unwrap();
|
||||
/// map.insert("c", 3).unwrap();
|
||||
///
|
||||
/// for (_, val) in map.iter_mut() {
|
||||
/// *val = 2;
|
||||
/// }
|
||||
///
|
||||
/// for (key, val) in &map {
|
||||
/// println!("key: {} val: {}", key, val);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
IterMut {
|
||||
iter: self.core.entries.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// pub fn entry(&mut self, key: K) -> Entry<K, V> { .. }
|
||||
|
||||
/// Return the number of key-value pairs in the map.
|
||||
///
|
||||
/// Computes in **O(1)** time.
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a = FnvIndexMap::<_, _, U16>::new();
|
||||
/// assert_eq!(a.len(), 0);
|
||||
/// a.insert(1, "a").unwrap();
|
||||
/// assert_eq!(a.len(), 1);
|
||||
/// ```
|
||||
pub fn len(&self) -> usize {
|
||||
self.core.entries.len()
|
||||
}
|
||||
|
||||
/// Returns true if the map contains no elements.
|
||||
///
|
||||
/// Computes in **O(1)** time.
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a = FnvIndexMap::<_, _, U16>::new();
|
||||
/// assert!(a.is_empty());
|
||||
/// a.insert(1, "a");
|
||||
/// assert!(!a.is_empty());
|
||||
/// ```
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Remove all key-value pairs in the map, while preserving its capacity.
|
||||
///
|
||||
/// Computes in **O(n)** time.
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a = FnvIndexMap::<_, _, U16>::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.clear();
|
||||
/// assert!(a.is_empty());
|
||||
/// ```
|
||||
pub fn clear(&mut self) {
|
||||
self.core.entries.clear();
|
||||
for pos in self.core.indices.iter_mut() {
|
||||
*pos = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the value corresponding to the key.
|
||||
///
|
||||
/// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
|
||||
/// form *must* match those for the key type.
|
||||
///
|
||||
/// Computes in **O(1)** time (average).
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U16>::new();
|
||||
/// map.insert(1, "a").unwrap();
|
||||
/// assert_eq!(map.get(&1), Some(&"a"));
|
||||
/// assert_eq!(map.get(&2), None);
|
||||
/// ```
|
||||
pub fn get<Q>(&self, key: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.find(key)
|
||||
.map(|(_, found)| unsafe { &self.core.entries.get_unchecked(found).value })
|
||||
}
|
||||
|
||||
/// Returns true if the map contains a value for the specified key.
|
||||
///
|
||||
/// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
|
||||
/// form *must* match those for the key type.
|
||||
///
|
||||
/// Computes in **O(1)** time (average).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U8>::new();
|
||||
/// map.insert(1, "a").unwrap();
|
||||
/// assert_eq!(map.contains_key(&1), true);
|
||||
/// assert_eq!(map.contains_key(&2), false);
|
||||
/// ```
|
||||
pub fn contains_key<Q>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Eq + Hash,
|
||||
{
|
||||
self.find(key).is_some()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the value corresponding to the key.
|
||||
///
|
||||
/// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
|
||||
/// form *must* match those for the key type.
|
||||
///
|
||||
/// Computes in **O(1)** time (average).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U8>::new();
|
||||
/// map.insert(1, "a").unwrap();
|
||||
/// if let Some(x) = map.get_mut(&1) {
|
||||
/// *x = "b";
|
||||
/// }
|
||||
/// assert_eq!(map[&1], "b");
|
||||
/// ```
|
||||
pub fn get_mut<'v, Q>(&'v mut self, key: &Q) -> Option<&'v mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
if let Some((_, found)) = self.find(key) {
|
||||
Some(unsafe { &mut self.core.entries.get_unchecked_mut(found).value })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a key-value pair into the map.
|
||||
///
|
||||
/// If an equivalent key already exists in the map: the key remains and retains in its place in
|
||||
/// the order, its corresponding value is updated with `value` and the older value is returned
|
||||
/// inside `Some(_)`.
|
||||
///
|
||||
/// If no equivalent key existed in the map: the new key-value pair is inserted, last in order,
|
||||
/// and `None` is returned.
|
||||
///
|
||||
/// Computes in **O(1)** time (average).
|
||||
///
|
||||
/// See also entry if you you want to insert or modify or if you need to get the index of the
|
||||
/// corresponding key-value pair.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexMap;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut map = FnvIndexMap::<_, _, U8>::new();
|
||||
/// assert_eq!(map.insert(37, "a"), Ok(None));
|
||||
/// assert_eq!(map.is_empty(), false);
|
||||
///
|
||||
/// map.insert(37, "b");
|
||||
/// assert_eq!(map.insert(37, "c"), Ok(Some("b")));
|
||||
/// assert_eq!(map[&37], "c");
|
||||
/// ```
|
||||
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, (K, V)> {
|
||||
if self.core.entries.is_full() {
|
||||
Err((key, value))
|
||||
} else {
|
||||
Ok(match self.insert_phase_1(key, value) {
|
||||
Inserted::Swapped { prev_value } => Some(prev_value),
|
||||
Inserted::Done => None,
|
||||
Inserted::RobinHood { probe, old_pos } => {
|
||||
self.core.insert_phase_2(probe, old_pos);
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [`swap_remove`](struct.IndexMap.html#method.swap_remove)
|
||||
///
|
||||
/// Computes in **O(1)** time (average).
|
||||
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.swap_remove(key)
|
||||
}
|
||||
|
||||
/// Remove the key-value pair equivalent to `key` and return its value.
|
||||
///
|
||||
/// Like `Vec::swap_remove`, the pair is removed by swapping it with the last element of the map
|
||||
/// and popping it off. **This perturbs the postion of what used to be the last element!**
|
||||
///
|
||||
/// Return `None` if `key` is not in map.
|
||||
///
|
||||
/// Computes in **O(1)** time (average).
|
||||
pub fn swap_remove<Q>(&mut self, key: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.find(key)
|
||||
.map(|(probe, found)| self.core.remove_found(probe, found).1)
|
||||
}
|
||||
|
||||
/* Private API */
|
||||
/// Return probe (indices) and position (entries)
|
||||
fn find<Q>(&self, key: &Q) -> Option<(usize, usize)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
if self.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
let h = hash_with(key, &self.build_hasher);
|
||||
self.core.find(h, key)
|
||||
}
|
||||
|
||||
fn insert_phase_1(&mut self, key: K, value: V) -> Inserted<V> {
|
||||
let hash = hash_with(&key, &self.build_hasher);
|
||||
self.core.insert_phase_1(hash, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, Q, V, N, S> ops::Index<&'a Q> for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash + Borrow<Q>,
|
||||
Q: ?Sized + Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
type Output = V;
|
||||
|
||||
fn index(&self, key: &Q) -> &V {
|
||||
self.get(key).expect("key not found")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, Q, V, N, S> ops::IndexMut<&'a Q> for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash + Borrow<Q>,
|
||||
Q: ?Sized + Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn index_mut(&mut self, key: &Q) -> &mut V {
|
||||
self.get_mut(key).expect("key not found")
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, N, S> fmt::Debug for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash + fmt::Debug,
|
||||
V: fmt::Debug,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_map().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, N, S> Default for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
IndexMap {
|
||||
build_hasher: <_>::default(),
|
||||
core: CoreMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, N, S> Extend<(K, V)> for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn extend<I>(&mut self, iterable: I)
|
||||
where
|
||||
I: IntoIterator<Item = (K, V)>,
|
||||
{
|
||||
for (k, v) in iterable {
|
||||
self.insert(k, v).ok().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, N, S> Extend<(&'a K, &'a V)> for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash + Copy,
|
||||
V: Copy,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn extend<I>(&mut self, iterable: I)
|
||||
where
|
||||
I: IntoIterator<Item = (&'a K, &'a V)>,
|
||||
{
|
||||
self.extend(iterable.into_iter().map(|(&key, &value)| (key, value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, N, S> FromIterator<(K, V)> for IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn from_iter<I>(iterable: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = (K, V)>,
|
||||
{
|
||||
let mut map = IndexMap::default();
|
||||
map.extend(iterable);
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, N, S> IntoIterator for &'a IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
type Item = (&'a K, &'a V);
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, N, S> IntoIterator for &'a mut IndexMap<K, V, N, S>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
type Item = (&'a K, &'a mut V);
|
||||
type IntoIter = IterMut<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, K, V>
|
||||
where
|
||||
K: 'a,
|
||||
V: 'a,
|
||||
{
|
||||
iter: slice::Iter<'a, Bucket<K, V>>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for Iter<'a, K, V>
|
||||
where
|
||||
K: 'a,
|
||||
V: 'a,
|
||||
{
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|bucket| (&bucket.key, &bucket.value))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, K, V>
|
||||
where
|
||||
K: 'a,
|
||||
V: 'a,
|
||||
{
|
||||
iter: slice::IterMut<'a, Bucket<K, V>>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for IterMut<'a, K, V>
|
||||
where
|
||||
K: 'a,
|
||||
V: 'a,
|
||||
{
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter
|
||||
.next()
|
||||
.map(|bucket| (&bucket.key, &mut bucket.value))
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_with<K, S>(key: &K, build_hasher: &S) -> HashValue
|
||||
where
|
||||
K: ?Sized + Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
let mut h = build_hasher.build_hasher();
|
||||
key.hash(&mut h);
|
||||
HashValue(h.finish() as u16)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::mem;
|
||||
|
||||
use generic_array::typenum::Unsigned;
|
||||
|
||||
use consts::*;
|
||||
use FnvIndexMap;
|
||||
|
||||
#[test]
|
||||
fn size() {
|
||||
type Cap = U4;
|
||||
|
||||
let cap = Cap::to_usize();
|
||||
assert_eq!(
|
||||
mem::size_of::<FnvIndexMap<i16, u16, Cap>>(),
|
||||
cap * mem::size_of::<u32>() + // indices
|
||||
cap * (mem::size_of::<i16>() + // key
|
||||
mem::size_of::<u16>() + // value
|
||||
mem::size_of::<u16>() // hash
|
||||
) + // buckets
|
||||
mem::size_of::<usize>() // entries.length
|
||||
)
|
||||
}
|
||||
}
|
624
src/indexset.rs
Normal file
624
src/indexset.rs
Normal file
@ -0,0 +1,624 @@
|
||||
use core::borrow::Borrow;
|
||||
use core::fmt;
|
||||
use core::iter::FromIterator;
|
||||
|
||||
use generic_array::typenum::PowerOfTwo;
|
||||
use generic_array::ArrayLength;
|
||||
use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher};
|
||||
|
||||
use indexmap::{self, Bucket, IndexMap, Pos};
|
||||
|
||||
/// An `IndexSet` using the default FNV hasher
|
||||
pub type FnvIndexSet<T, N> = IndexSet<T, N, BuildHasherDefault<FnvHasher>>;
|
||||
|
||||
/// Fixed capacity [`IndexSet`](https://docs.rs/indexmap/1/indexmap/set/struct.IndexSet.html)
|
||||
///
|
||||
/// Note that the capacity of the `IndexSet` must be a power of 2.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// // A hash set with a capacity of 16 elements
|
||||
/// let mut books = FnvIndexSet::<_, U16>::new();
|
||||
///
|
||||
/// // Add some books.
|
||||
/// books.insert("A Dance With Dragons").unwrap();
|
||||
/// books.insert("To Kill a Mockingbird").unwrap();
|
||||
/// books.insert("The Odyssey").unwrap();
|
||||
/// books.insert("The Great Gatsby").unwrap();
|
||||
///
|
||||
/// // Check for a specific one.
|
||||
/// if !books.contains("The Winds of Winter") {
|
||||
/// println!("We have {} books, but The Winds of Winter ain't one.",
|
||||
/// books.len());
|
||||
/// }
|
||||
///
|
||||
/// // Remove a book.
|
||||
/// books.remove("The Odyssey");
|
||||
///
|
||||
/// // Iterate over everything.
|
||||
/// for book in &books {
|
||||
/// println!("{}", book);
|
||||
/// }
|
||||
/// ```
|
||||
pub struct IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
map: IndexMap<T, (), N, S>,
|
||||
}
|
||||
|
||||
impl<T, N, S> IndexSet<T, N, BuildHasherDefault<S>>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: Default + Hasher,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>> + PowerOfTwo,
|
||||
{
|
||||
/// Creates an empty `IndexSet`
|
||||
pub fn new() -> Self {
|
||||
IndexSet {
|
||||
map: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N, S> IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
/// Returns the number of elements the set can hold
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let set = FnvIndexSet::<i32, U16>::new();
|
||||
/// assert_eq!(set.capacity(), 16);
|
||||
/// ```
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.map.capacity()
|
||||
}
|
||||
|
||||
/// Return an iterator over the values of the set, in their order
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut set = FnvIndexSet::<_, U16>::new();
|
||||
/// set.insert("a").unwrap();
|
||||
/// set.insert("b").unwrap();
|
||||
///
|
||||
/// // Will print in an arbitrary order.
|
||||
/// for x in set.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter {
|
||||
iter: self.map.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Visits the values representing the difference, i.e. the values that are in `self` but not in
|
||||
/// `other`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let mut b: FnvIndexSet<_, U16> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
///
|
||||
/// // Can be seen as `a - b`.
|
||||
/// for x in a.difference(&b) {
|
||||
/// println!("{}", x); // Print 1
|
||||
/// }
|
||||
///
|
||||
/// let diff: FnvIndexSet<_, U16> = a.difference(&b).collect();
|
||||
/// assert_eq!(diff, [1].iter().collect::<FnvIndexSet<_, U16>>());
|
||||
///
|
||||
/// // Note that difference is not symmetric,
|
||||
/// // and `b - a` means something else:
|
||||
/// let diff: FnvIndexSet<_, U16> = b.difference(&a).collect();
|
||||
/// assert_eq!(diff, [4].iter().collect::<FnvIndexSet<_, U16>>());
|
||||
/// ```
|
||||
pub fn difference<'a, N2, S2>(
|
||||
&'a self,
|
||||
other: &'a IndexSet<T, N2, S2>,
|
||||
) -> Difference<'a, T, N2, S2>
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
Difference {
|
||||
iter: self.iter(),
|
||||
other,
|
||||
}
|
||||
}
|
||||
|
||||
/// Visits the values representing the symmetric difference, i.e. the values that are in `self`
|
||||
/// or in `other` but not in both.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let mut b: FnvIndexSet<_, U16> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
///
|
||||
/// // Print 1, 4 in that order order.
|
||||
/// for x in a.symmetric_difference(&b) {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let diff1: FnvIndexSet<_, U16> = a.symmetric_difference(&b).collect();
|
||||
/// let diff2: FnvIndexSet<_, U16> = b.symmetric_difference(&a).collect();
|
||||
///
|
||||
/// assert_eq!(diff1, diff2);
|
||||
/// assert_eq!(diff1, [1, 4].iter().collect::<FnvIndexSet<_, U16>>());
|
||||
/// ```
|
||||
pub fn symmetric_difference<'a, N2, S2>(
|
||||
&'a self,
|
||||
other: &'a IndexSet<T, N2, S2>,
|
||||
) -> impl Iterator<Item = &'a T>
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
self.difference(other).chain(other.difference(self))
|
||||
}
|
||||
|
||||
/// Visits the values representing the intersection, i.e. the values that are both in `self` and
|
||||
/// `other`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let mut b: FnvIndexSet<_, U16> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
///
|
||||
/// // Print 2, 3 in that order.
|
||||
/// for x in a.intersection(&b) {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let intersection: FnvIndexSet<_, U16> = a.intersection(&b).collect();
|
||||
/// assert_eq!(intersection, [2, 3].iter().collect::<FnvIndexSet<_, U16>>());
|
||||
/// ```
|
||||
pub fn intersection<'a, N2, S2>(
|
||||
&'a self,
|
||||
other: &'a IndexSet<T, N2, S2>,
|
||||
) -> Intersection<'a, T, N2, S2>
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
Intersection {
|
||||
iter: self.iter(),
|
||||
other,
|
||||
}
|
||||
}
|
||||
|
||||
/// Visits the values representing the union, i.e. all the values in `self` or `other`, without
|
||||
/// duplicates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut a: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let mut b: FnvIndexSet<_, U16> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
///
|
||||
/// // Print 1, 2, 3, 4 in that order.
|
||||
/// for x in a.union(&b) {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let union: FnvIndexSet<_, U16> = a.union(&b).collect();
|
||||
/// assert_eq!(union, [1, 2, 3, 4].iter().collect::<FnvIndexSet<_, U16>>());
|
||||
/// ```
|
||||
pub fn union<'a, N2, S2>(
|
||||
&'a self,
|
||||
other: &'a IndexSet<T, N2, S2>,
|
||||
) -> impl Iterator<Item = &'a T>
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
self.iter().chain(other.difference(self))
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut v: FnvIndexSet<_, U16> = FnvIndexSet::new();
|
||||
/// assert_eq!(v.len(), 0);
|
||||
/// v.insert(1).unwrap();
|
||||
/// assert_eq!(v.len(), 1);
|
||||
/// ```
|
||||
pub fn len(&self) -> usize {
|
||||
self.map.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains no elements.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut v: FnvIndexSet<_, U16> = FnvIndexSet::new();
|
||||
/// assert!(v.is_empty());
|
||||
/// v.insert(1).unwrap();
|
||||
/// assert!(!v.is_empty());
|
||||
/// ```
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.map.is_empty()
|
||||
}
|
||||
|
||||
/// Clears the set, removing all values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut v: FnvIndexSet<_, U16> = FnvIndexSet::new();
|
||||
/// v.insert(1).unwrap();
|
||||
/// v.clear();
|
||||
/// assert!(v.is_empty());
|
||||
/// ```
|
||||
pub fn clear(&mut self) {
|
||||
self.map.clear()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains a value.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the
|
||||
/// borrowed form must match those for the value type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let set: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// assert_eq!(set.contains(&1), true);
|
||||
/// assert_eq!(set.contains(&4), false);
|
||||
/// ```
|
||||
pub fn contains<Q>(&self, value: &Q) -> bool
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: ?Sized + Eq + Hash,
|
||||
{
|
||||
self.map.contains_key(value)
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` has no elements in common with `other`. This is equivalent to
|
||||
/// checking for an empty intersection.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let a: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let mut b = FnvIndexSet::<_, U16>::new();
|
||||
///
|
||||
/// assert_eq!(a.is_disjoint(&b), true);
|
||||
/// b.insert(4).unwrap();
|
||||
/// assert_eq!(a.is_disjoint(&b), true);
|
||||
/// b.insert(1).unwrap();
|
||||
/// assert_eq!(a.is_disjoint(&b), false);
|
||||
/// ```
|
||||
pub fn is_disjoint<N2, S2>(&self, other: &IndexSet<T, N2, S2>) -> bool
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
self.iter().all(|v| !other.contains(v))
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a subset of another, i.e. `other` contains at least all the
|
||||
/// values in `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let sup: FnvIndexSet<_, U16> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let mut set = FnvIndexSet::<_, U16>::new();
|
||||
///
|
||||
/// assert_eq!(set.is_subset(&sup), true);
|
||||
/// set.insert(2).unwrap();
|
||||
/// assert_eq!(set.is_subset(&sup), true);
|
||||
/// set.insert(4).unwrap();
|
||||
/// assert_eq!(set.is_subset(&sup), false);
|
||||
/// ```
|
||||
pub fn is_subset<N2, S2>(&self, other: &IndexSet<T, N2, S2>) -> bool
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
self.iter().all(|v| other.contains(v))
|
||||
}
|
||||
|
||||
// Returns `true` if the set is a superset of another, i.e. `self` contains at least all the
|
||||
// values in `other`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let sub: FnvIndexSet<_, U16> = [1, 2].iter().cloned().collect();
|
||||
/// let mut set = FnvIndexSet::<_, U16>::new();
|
||||
///
|
||||
/// assert_eq!(set.is_superset(&sub), false);
|
||||
///
|
||||
/// set.insert(0).unwrap();
|
||||
/// set.insert(1).unwrap();
|
||||
/// assert_eq!(set.is_superset(&sub), false);
|
||||
///
|
||||
/// set.insert(2).unwrap();
|
||||
/// assert_eq!(set.is_superset(&sub), true);
|
||||
/// ```
|
||||
pub fn is_superset<N2, S2>(&self, other: &IndexSet<T, N2, S2>) -> bool
|
||||
where
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
S2: BuildHasher,
|
||||
{
|
||||
other.is_subset(self)
|
||||
}
|
||||
|
||||
/// Adds a value to the set.
|
||||
///
|
||||
/// If the set did not have this value present, `true` is returned.
|
||||
///
|
||||
/// If the set did have this value present, `false` is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut set = FnvIndexSet::<_, U16>::new();
|
||||
///
|
||||
/// assert_eq!(set.insert(2).unwrap(), true);
|
||||
/// assert_eq!(set.insert(2).unwrap(), false);
|
||||
/// assert_eq!(set.len(), 1);
|
||||
/// ```
|
||||
pub fn insert(&mut self, value: T) -> Result<bool, T> {
|
||||
self.map
|
||||
.insert(value, ())
|
||||
.map(|old| old.is_none())
|
||||
.map_err(|(k, _)| k)
|
||||
}
|
||||
|
||||
/// Removes a value from the set. Returns `true` if the value was present in the set.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the
|
||||
/// borrowed form must match those for the value type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::FnvIndexSet;
|
||||
/// use heapless::consts::*;
|
||||
///
|
||||
/// let mut set = FnvIndexSet::<_, U16>::new();
|
||||
///
|
||||
/// set.insert(2).unwrap();
|
||||
/// assert_eq!(set.remove(&2), true);
|
||||
/// assert_eq!(set.remove(&2), false);
|
||||
/// ```
|
||||
pub fn remove<Q>(&mut self, value: &Q) -> bool
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: ?Sized + Eq + Hash,
|
||||
{
|
||||
self.map.remove(value).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N, S> fmt::Debug for IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash + fmt::Debug,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_set().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N, S> Default for IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
IndexSet {
|
||||
map: <_>::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N1, N2, S1, S2> PartialEq<IndexSet<T, N2, S2>> for IndexSet<T, N1, S1>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S1: BuildHasher,
|
||||
S2: BuildHasher,
|
||||
N1: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
N2: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn eq(&self, other: &IndexSet<T, N2, S2>) -> bool {
|
||||
self.len() == other.len() && self.is_subset(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N, S> Extend<T> for IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn extend<I>(&mut self, iterable: I)
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
self.map.extend(iterable.into_iter().map(|k| (k, ())))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, N, S> Extend<&'a T> for IndexSet<T, N, S>
|
||||
where
|
||||
T: 'a + Eq + Hash + Copy,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn extend<I>(&mut self, iterable: I)
|
||||
where
|
||||
I: IntoIterator<Item = &'a T>,
|
||||
{
|
||||
self.extend(iterable.into_iter().cloned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, N, S> FromIterator<T> for IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
fn from_iter<I>(iter: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut set = IndexSet::default();
|
||||
set.extend(iter);
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, N, S> IntoIterator for &'a IndexSet<T, N, S>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, T>
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
iter: indexmap::Iter<'a, T, ()>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Iter<'a, T>
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|(k, _)| k)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Difference<'a, T, N, S>
|
||||
where
|
||||
S: 'a + BuildHasher,
|
||||
T: 'a + Eq + Hash,
|
||||
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
iter: Iter<'a, T>,
|
||||
other: &'a IndexSet<T, N, S>,
|
||||
}
|
||||
|
||||
impl<'a, T, N, S> Iterator for Difference<'a, T, N, S>
|
||||
where
|
||||
S: 'a + BuildHasher,
|
||||
T: 'a + Eq + Hash,
|
||||
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let elt = self.iter.next()?;
|
||||
if !self.other.contains(elt) {
|
||||
return Some(elt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Intersection<'a, T, N, S>
|
||||
where
|
||||
S: 'a + BuildHasher,
|
||||
T: 'a + Eq + Hash,
|
||||
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
iter: Iter<'a, T>,
|
||||
other: &'a IndexSet<T, N, S>,
|
||||
}
|
||||
|
||||
impl<'a, T, N, S> Iterator for Intersection<'a, T, N, S>
|
||||
where
|
||||
S: 'a + BuildHasher,
|
||||
T: 'a + Eq + Hash,
|
||||
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let elt = self.iter.next()?;
|
||||
if self.other.contains(elt) {
|
||||
return Some(elt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/lib.rs
11
src/lib.rs
@ -40,32 +40,41 @@
|
||||
//! List of currently implemented data structures:
|
||||
//!
|
||||
//! - [`BinaryHeap`](binary_heap/struct.BinaryHeap.html) -- priority queue
|
||||
//! - [`IndexMap`](struct.IndexMap.html) -- hash table
|
||||
//! - [`IndexSet`](struct.IndexSet.html) -- hash set
|
||||
//! - [`LinearMap`](struct.LinearMap.html)
|
||||
//! - [`RingBuffer`](ring_buffer/struct.RingBuffer.html) -- single producer single consumer lockless
|
||||
//! queue
|
||||
//! - [`String`](struct.String.html)
|
||||
//! - [`Vec`](struct.Vec.html)
|
||||
|
||||
#![allow(stable_features)]
|
||||
#![allow(warnings)]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(nll)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(untagged_unions)]
|
||||
#![no_std]
|
||||
|
||||
extern crate generic_array;
|
||||
extern crate hash32;
|
||||
#[cfg(test)]
|
||||
extern crate std;
|
||||
|
||||
pub use binary_heap::BinaryHeap;
|
||||
pub use generic_array::typenum::consts;
|
||||
pub use indexmap::{FnvIndexMap, IndexMap};
|
||||
pub use indexset::{FnvIndexSet, IndexSet};
|
||||
pub use linear_map::LinearMap;
|
||||
pub use ring_buffer::RingBuffer;
|
||||
pub use string::String;
|
||||
pub use vec::Vec;
|
||||
|
||||
mod cfail;
|
||||
mod indexmap;
|
||||
mod indexset;
|
||||
mod linear_map;
|
||||
mod string;
|
||||
mod vec;
|
||||
|
57
src/vec.rs
57
src/vec.rs
@ -17,6 +17,7 @@ impl<T, N> Vec<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
/* Constructors */
|
||||
/// Constructs a new, empty vector with a fixed capacity of `N`
|
||||
pub const fn new() -> Self {
|
||||
Vec {
|
||||
@ -25,9 +26,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/* Public API */
|
||||
/// Returns the maximum number of elements the vector can hold
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.buffer.as_slice().len()
|
||||
N::to_usize()
|
||||
}
|
||||
|
||||
/// Clears the vector, removing all values.
|
||||
@ -68,35 +70,44 @@ where
|
||||
|
||||
/// Removes the last element from a vector and return it, or `None` if it's empty
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
let buffer = self.buffer.as_slice();
|
||||
|
||||
if self.len != 0 {
|
||||
self.len -= 1;
|
||||
let item = unsafe { ptr::read(&buffer[self.len]) };
|
||||
Some(item)
|
||||
Some(unsafe { self.pop_unchecked() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn pop_unchecked(&mut self) -> T {
|
||||
debug_assert!(!self.is_empty());
|
||||
|
||||
let buffer = self.buffer.as_slice();
|
||||
|
||||
self.len -= 1;
|
||||
let item = ptr::read(buffer.get_unchecked(self.len));
|
||||
item
|
||||
}
|
||||
|
||||
/// Appends an `item` to the back of the collection
|
||||
///
|
||||
/// Returns back the `item` if the vector is full
|
||||
pub fn push(&mut self, item: T) -> Result<(), T> {
|
||||
let capacity = self.capacity();
|
||||
let buffer = self.buffer.as_mut_slice();
|
||||
|
||||
if self.len < capacity {
|
||||
// NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We
|
||||
// use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
|
||||
unsafe { ptr::write(&mut buffer[self.len], item) }
|
||||
self.len += 1;
|
||||
if self.len < self.capacity() {
|
||||
unsafe { self.push_unchecked(item) }
|
||||
Ok(())
|
||||
} else {
|
||||
Err(item)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn push_unchecked(&mut self, item: T) {
|
||||
let buffer = self.buffer.as_mut_slice();
|
||||
|
||||
// NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We
|
||||
// use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
|
||||
ptr::write(buffer.get_unchecked_mut(self.len), item);
|
||||
self.len += 1;
|
||||
}
|
||||
|
||||
/// Shortens the vector, keeping the first `len` elements and dropping the rest.
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
unsafe {
|
||||
@ -180,9 +191,23 @@ where
|
||||
/// assert_eq!(&*v, ["baz", "qux"]);
|
||||
/// ```
|
||||
pub fn swap_remove(&mut self, index: usize) -> T {
|
||||
assert!(index < self.len());
|
||||
unsafe { self.swap_remove_unchecked(index) }
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T {
|
||||
let length = self.len();
|
||||
self.swap(index, length - 1);
|
||||
self.pop().unwrap()
|
||||
debug_assert!(index < length);
|
||||
ptr::swap(
|
||||
self.get_unchecked_mut(index),
|
||||
self.get_unchecked_mut(length - 1),
|
||||
);
|
||||
self.pop_unchecked()
|
||||
}
|
||||
|
||||
/* Private API */
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
self.capacity() == self.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user