From 03203498f7d650004d5b44c1d04ca7af37e7711d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Mar 2018 22:19:13 +0100 Subject: [PATCH 1/3] add Vec.swap_remove --- src/vec.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/vec.rs b/src/vec.rs index 79e387db..a9fa765f 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -156,6 +156,41 @@ where { self.resize(new_len, T::default()) } + + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. + /// + /// This does not preserve ordering, but is O(1). + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// extern crate heapless; + /// + /// use heapless::Vec; + /// + /// let mut v: Vec<_, [_; 8]> = Vec::new(); + /// v.push("foo").unwrap(); + /// v.push("bar").unwrap(); + /// v.push("baz").unwrap(); + /// v.push("qux").unwrap(); + /// + /// assert_eq!(v.swap_remove(1), "bar"); + /// assert_eq!(&*v, ["foo", "qux", "baz"]); + /// + /// assert_eq!(v.swap_remove(0), "foo"); + /// assert_eq!(&*v, ["baz", "qux"]); + /// ``` + pub fn swap_remove(&mut self, index: usize) -> T { + let length = self.len(); + self.swap(index, length - 1); + self.pop().unwrap() + } } impl fmt::Debug for Vec From d1e51cb43f943167e19677678cacfedb8af1b45f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Mar 2018 22:19:18 +0100 Subject: [PATCH 2/3] add LinearMap --- src/lib.rs | 27 ++- src/linear_map.rs | 425 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+), 2 deletions(-) create mode 100644 src/linear_map.rs diff --git a/src/lib.rs b/src/lib.rs index bcfdc62d..ff7b7729 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,26 @@ //! assert_eq!(s.as_bytes(), b"hello"); //! ``` //! +//! ## `LinearMap` +//! +//! ``` +//! use heapless::LinearMap; +//! +//! let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); +//! +//! map.insert("a", 1); +//! map.insert("b", 2); +//! map.insert("c", 3); +//! +//! assert_eq!(map["a"], 1); +//! +//! map["b"] += 1; +//! assert_eq!(map["b"], 3); +//! +//! map.remove("c"); +//! assert_eq!(map.len(), 2); +//! ``` +//! //! ## `RingBuffer` //! //! ``` @@ -93,18 +113,21 @@ #![deny(warnings)] #![feature(const_fn)] #![feature(core_intrinsics)] +#![feature(conservative_impl_trait)] #![feature(unsize)] #![no_std] extern crate untagged_option; -pub use vec::Vec; +pub use linear_map::LinearMap; pub use ring_buffer::RingBuffer; pub use string::String; +pub use vec::Vec; +mod linear_map; mod cfail; -mod vec; mod string; +mod vec; pub mod ring_buffer; /// Error raised when the buffer is full diff --git a/src/linear_map.rs b/src/linear_map.rs new file mode 100644 index 00000000..7512c82b --- /dev/null +++ b/src/linear_map.rs @@ -0,0 +1,425 @@ +use core::borrow::Borrow; +use core::marker::Unsize; +use core::{mem, ops, slice}; + +use {BufferFullError, Vec}; + +/// A map / dictionary backed by an array that performs lookups via linear search +/// +/// Note that as this map doesn't use hashing so most operations are **O(N)** instead of O(1) +pub struct LinearMap +where + ARRAY: Unsize<[(KEY, VALUE)]>, + KEY: Eq, +{ + buffer: Vec<(KEY, VALUE), ARRAY>, +} + +impl LinearMap +where + A: Unsize<[(K, V)]>, + K: Eq, +{ + /// Creates an empty `LinearMap` + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<&str, isize, [_; 8]> = LinearMap::new(); + /// ``` + pub fn new() -> Self { + LinearMap { buffer: Vec::new() } + } + + /// Returns the number of elements that the map can hold + /// + /// Computes in **O(1)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<&str, isize, [_; 8]> = LinearMap::new(); + /// assert_eq!(map.capacity(), 8); + /// ``` + pub fn capacity(&mut self) -> usize { + self.buffer.capacity() + } + + /// Clears the map, removing all key-value pairs + /// + /// Computes in **O(1)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// map.insert(1, "a").unwrap(); + /// map.clear(); + /// assert!(map.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.buffer.clear() + } + + /// Returns true if the map contains a value for the specified key. + /// + /// Computes in **O(N)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// map.insert(1, "a").unwrap(); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + pub fn contains_key(&self, key: &K) -> bool { + self.get(key).is_some() + } + + /// Returns a reference to the value corresponding to the key + /// + /// Computes in **O(N)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// map.insert(1, "a").unwrap(); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + pub fn get(&self, key: &Q) -> Option<&V> + where + K: Borrow, + Q: Eq + ?Sized, + { + self.iter() + .find(|&(k, _)| k.borrow() == key) + .map(|(_, v)| v) + } + + /// Returns a mutable reference to the value corresponding to the key + /// + /// Computes in **O(N)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::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(&mut self, key: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Eq + ?Sized, + { + self.iter_mut() + .find(|&(k, _)| k.borrow() == key) + .map(|(_, v)| v) + } + + /// Returns the number of elements in this map + /// + /// Computes in **O(1)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut a: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a").unwrap(); + /// assert_eq!(a.len(), 1); + /// ``` + pub fn len(&self) -> usize { + self.buffer.len() + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the value is updated, and the old value is returned. + /// + /// Computes in **O(N)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// assert_eq!(map.insert(37, "a").unwrap(), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b").unwrap(); + /// assert_eq!(map.insert(37, "c").unwrap(), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + pub fn insert(&mut self, key: K, mut value: V) -> Result, BufferFullError> { + if let Some((_, v)) = self.iter_mut().find(|&(k, _)| *k == key) { + mem::swap(v, &mut value); + return Ok(Some(value)); + } + + self.buffer.push((key, value))?; + Ok(None) + } + + /// Returns true if the map contains no elements + /// + /// Computes in **O(1)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut a: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a").unwrap(); + /// assert!(!a.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::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 { + Iter { + iter: self.buffer.iter(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, with mutable references to the + /// values + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// map.insert("a", 1).unwrap(); + /// map.insert("b", 2).unwrap(); + /// map.insert("c", 3).unwrap(); + /// + /// // Update all values + /// 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 { + IterMut { + iter: self.buffer.iter_mut(), + } + } + + /// An iterator visiting all keys in arbitrary order + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::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 { + self.iter().map(|(k, _)| k) + } + + /// Removes a key from the map, returning the value at the key if the key was previously in the + /// map + /// + /// Computes in **O(N)** time + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::new(); + /// map.insert(1, "a").unwrap(); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + pub fn remove(&mut self, key: &Q) -> Option + where + K: Borrow, + Q: Eq + ?Sized, + { + let idx = self.keys() + .enumerate() + .find(|&(_, k)| k.borrow() == key) + .map(|(idx, _)| idx); + + idx.map(|idx| self.buffer.swap_remove(idx).1) + } + + /// An iterator visiting all values in arbitrary order + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::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 { + self.iter().map(|(_, v)| v) + } + + /// An iterator visiting all values mutably in arbitrary order + /// + /// # Examples + /// + /// ``` + /// use heapless::LinearMap; + /// + /// let mut map: LinearMap<_, _, [_; 8]> = LinearMap::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 { + self.iter_mut().map(|(_, v)| v) + } +} + +impl<'a, K, V, A, Q> ops::Index<&'a Q> for LinearMap +where + A: Unsize<[(K, V)]>, + K: Borrow + Eq, + Q: Eq + ?Sized, + V: 'a, +{ + type Output = V; + + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +impl<'a, K, V, A, Q> ops::IndexMut<&'a Q> for LinearMap +where + A: Unsize<[(K, V)]>, + K: Borrow + Eq, + Q: Eq + ?Sized, + V: 'a, +{ + fn index_mut(&mut self, key: &Q) -> &mut V { + self.get_mut(key).expect("no entry found for key") + } +} + +impl<'a, K, V, A> IntoIterator for &'a LinearMap +where + A: Unsize<[(K, V)]>, + K: Eq, +{ + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +pub struct Iter<'a, K, V> +where + K: 'a, + V: 'a, +{ + iter: slice::Iter<'a, (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.iter.next().map(|&(ref k, ref v)| (k, v)) + } +} + +pub struct IterMut<'a, K, V> +where + K: 'a, + V: 'a, +{ + iter: slice::IterMut<'a, (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.iter.next().map(|&mut (ref k, ref mut v)| (k, v)) + } +} From 0f4555895ab76213e689f63fca7c501fb3f4423a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Mar 2018 22:35:40 +0100 Subject: [PATCH 3/3] remove unnecessary extern crate from example --- src/vec.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index a9fa765f..9a1c9b3d 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -170,8 +170,6 @@ where /// # Examples /// /// ``` - /// extern crate heapless; - /// /// use heapless::Vec; /// /// let mut v: Vec<_, [_; 8]> = Vec::new();