From 787319fe75234ca0870d7c1dc5121a267b95b9ef Mon Sep 17 00:00:00 2001 From: Aissurteivos Date: Wed, 13 Sep 2023 08:59:17 -0400 Subject: [PATCH] Add IndexMap capability --- Cargo.toml | 3 + src/index.rs | 1221 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 + 3 files changed, 1229 insertions(+) create mode 100644 src/index.rs diff --git a/Cargo.toml b/Cargo.toml index c8d6b29..177c5ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,12 @@ edition = "2018" [features] default = ["std"] std = [] +serde = ["dep:serde", "indexmap?/serde"] +indexmap = ["dep:indexmap"] [dependencies] serde = { version = "1.0", optional = true } +indexmap = { version = "2.0", optional = true } [dev-dependencies] serde_json = "1.0" diff --git a/src/index.rs b/src/index.rs new file mode 100644 index 0000000..a463af6 --- /dev/null +++ b/src/index.rs @@ -0,0 +1,1221 @@ +//! A bimap backed by two `IndexMap`s. + +use crate::{ + mem::{Ref, Wrapper}, + Overwritten, +}; +use std::{ + borrow::Borrow, + fmt, + collections::hash_map, + hash::{BuildHasher, Hash}, + iter::{Extend, FromIterator, FusedIterator}, + rc::Rc, +}; +use indexmap::{ + IndexMap, + map +}; + +/// A bimap backed by two `IndexMap`s. +/// +/// See the [module-level documentation] for more details and examples. +/// +/// [module-level documentation]: crate +pub struct BiIndexMap { + left2right: IndexMap, Ref, LS>, + right2left: IndexMap, Ref, RS>, +} + +impl BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, +{ + /// Creates an empty `BiIndexMap`. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let bimap = BiIndexMap::::new(); + /// ``` + pub fn new() -> Self { + Self { + left2right: IndexMap::new(), + right2left: IndexMap::new(), + } + } + + /// Creates a new empty `BiIndexMap` with the given capacity. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let bimap = BiIndexMap::::with_capacity(10); + /// assert!(bimap.capacity() >= 10); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + Self { + left2right: IndexMap::with_capacity(capacity), + right2left: IndexMap::with_capacity(capacity), + } + } +} + +impl BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, +{ + /// Returns the number of left-right pairs in the bimap. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// assert_eq!(bimap.len(), 3); + /// ``` + pub fn len(&self) -> usize { + self.left2right.len() + } + + /// Returns `true` if the bimap contains no left-right pairs, and `false` + /// otherwise. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// assert!(bimap.is_empty()); + /// bimap.insert('a', 1); + /// assert!(!bimap.is_empty()); + /// bimap.remove_by_right(&1); + /// assert!(bimap.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.left2right.is_empty() + } + + /// Returns a lower bound on the number of left-right pairs the `BiIndexMap` + /// can store without reallocating memory. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let bimap = BiIndexMap::::with_capacity(10); + /// assert!(bimap.capacity() >= 10); + /// ``` + pub fn capacity(&self) -> usize { + self.left2right.capacity().min(self.right2left.capacity()) + } + + /// Removes all left-right pairs from the bimap. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// bimap.clear(); + /// assert!(bimap.len() == 0); + /// ``` + pub fn clear(&mut self) { + self.left2right.clear(); + self.right2left.clear(); + } + + /// Creates an iterator over the left-right pairs in the bimap in arbitrary + /// order. + /// + /// The iterator element type is `(&L, &R)`. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// + /// for (left, right) in bimap.iter() { + /// println!("({}, {})", left, right); + /// } + /// ``` + pub fn iter(&self) -> Iter<'_, L, R> { + Iter { + inner: self.left2right.iter(), + } + } + + /// Creates an iterator over the left values in the bimap in arbitrary + /// order. + /// + /// The iterator element type is `&L`. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// + /// for char_value in bimap.left_values() { + /// println!("{}", char_value); + /// } + /// ``` + pub fn left_values(&self) -> LeftValues<'_, L, R> { + LeftValues { + inner: self.left2right.iter(), + } + } + + /// Creates an iterator over the right values in the bimap in arbitrary + /// order. + /// + /// The iterator element type is `&R`. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// + /// for int_value in bimap.right_values() { + /// println!("{}", int_value); + /// } + /// ``` + pub fn right_values(&self) -> RightValues<'_, L, R> { + RightValues { + inner: self.right2left.iter(), + } + } +} + +impl BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, + LS: BuildHasher, + RS: BuildHasher, +{ + /// Creates a new empty `BiIndexMap` using `hash_builder_left` to hash left + /// values and `hash_builder_right` to hash right values. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::RandomState; + /// use bimap::BiIndexMap; + /// + /// let s_left = RandomState::new(); + /// let s_right = RandomState::new(); + /// let mut bimap = BiIndexMap::::with_hashers(s_left, s_right); + /// bimap.insert('a', 42); + /// ``` + pub fn with_hashers(hash_builder_left: LS, hash_builder_right: RS) -> Self { + Self { + left2right: IndexMap::with_hasher(hash_builder_left), + right2left: IndexMap::with_hasher(hash_builder_right), + } + } + + /// Creates a new empty `BiIndexMap` with the given capacity, using + /// `hash_builder_left` to hash left values and `hash_builder_right` to + /// hash right values. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::RandomState; + /// use bimap::BiIndexMap; + /// + /// let s_left = RandomState::new(); + /// let s_right = RandomState::new(); + /// let bimap = BiIndexMap::::with_capacity_and_hashers(10, s_left, s_right); + /// assert!(bimap.capacity() >= 10); + /// ``` + pub fn with_capacity_and_hashers( + capacity: usize, + hash_builder_left: LS, + hash_builder_right: RS, + ) -> Self { + Self { + left2right: IndexMap::with_capacity_and_hasher(capacity, hash_builder_left), + right2left: IndexMap::with_capacity_and_hasher(capacity, hash_builder_right), + } + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `BiIndexMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows [`usize`]. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::::new(); + /// bimap.reserve(10); + /// assert!(bimap.capacity() >= 10); + /// ``` + pub fn reserve(&mut self, additional: usize) { + self.left2right.reserve(additional); + self.right2left.reserve(additional); + } + + /// Shrinks the capacity of the bimap as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::::with_capacity(100); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// assert!(bimap.capacity() >= 100); + /// bimap.shrink_to_fit(); + /// assert!(bimap.capacity() >= 2); + /// ``` + pub fn shrink_to_fit(&mut self) { + self.left2right.shrink_to_fit(); + self.right2left.shrink_to_fit(); + } + + /// Shrinks the capacity of the bimap with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal + /// rules and possibly leaving some space in accordance with the resize + /// policy. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::::with_capacity(100); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// assert!(bimap.capacity() >= 100); + /// bimap.shrink_to(10); + /// assert!(bimap.capacity() >= 10); + /// bimap.shrink_to(0); + /// assert!(bimap.capacity() >= 2); + /// ``` + pub fn shrink_to(&mut self, min_capacity: usize) { + self.left2right.shrink_to(min_capacity); + self.right2left.shrink_to(min_capacity); + } + + /// Returns a reference to the right value corresponding to the given left + /// value. + /// + /// The input may be any borrowed form of the bimap's left type, but `Eq` + /// and `Hash` on the borrowed form *must* match those for the left type. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// assert_eq!(bimap.get_by_left(&'a'), Some(&1)); + /// assert_eq!(bimap.get_by_left(&'z'), None); + /// ``` + pub fn get_by_left(&self, left: &Q) -> Option<&R> + where + L: Borrow, + Q: Eq + Hash + ?Sized, + { + self.left2right.get(Wrapper::wrap(left)).map(|r| &*r.0) + } + + /// Returns a reference to the left value corresponding to the given right + /// value. + /// + /// The input may be any borrowed form of the bimap's right type, but `Eq` + /// and `Hash` on the borrowed form *must* match those for the right type. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// assert_eq!(bimap.get_by_right(&1), Some(&'a')); + /// assert_eq!(bimap.get_by_right(&2), None); + /// ``` + pub fn get_by_right(&self, right: &Q) -> Option<&L> + where + R: Borrow, + Q: Eq + Hash + ?Sized, + { + self.right2left.get(Wrapper::wrap(right)).map(|l| &*l.0) + } + + /// Returns `true` if the bimap contains the given left value and `false` + /// otherwise. + /// + /// The input may be any borrowed form of the bimap's left type, but `Eq` + /// and `Hash` on the borrowed form *must* match those for the left type. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// assert!(bimap.contains_left(&'a')); + /// assert!(!bimap.contains_left(&'b')); + /// ``` + pub fn contains_left(&self, left: &Q) -> bool + where + L: Borrow, + Q: Eq + Hash + ?Sized, + { + self.left2right.contains_key(Wrapper::wrap(left)) + } + + /// Returns `true` if the map contains the given right value and `false` + /// otherwise. + /// + /// The input may be any borrowed form of the bimap's right type, but `Eq` + /// and `Hash` on the borrowed form *must* match those for the right type. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// assert!(bimap.contains_right(&1)); + /// assert!(!bimap.contains_right(&2)); + /// ``` + pub fn contains_right(&self, right: &Q) -> bool + where + R: Borrow, + Q: Eq + Hash + ?Sized, + { + self.right2left.contains_key(Wrapper::wrap(right)) + } + + /// Removes the left-right pair corresponding to the given left value. + /// + /// Returns the previous left-right pair if the map contained the left value + /// and `None` otherwise. + /// + /// The input may be any borrowed form of the bimap's left type, but `Eq` + /// and `Hash` on the borrowed form *must* match those for the left type. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// + /// assert_eq!(bimap.remove_by_left(&'b'), Some(('b', 2))); + /// assert_eq!(bimap.remove_by_left(&'b'), None); + /// ``` + pub fn remove_by_left(&mut self, left: &Q) -> Option<(L, R)> + where + L: Borrow, + Q: Eq + Hash + ?Sized, + { + self.left2right.remove(Wrapper::wrap(left)).map(|right_rc| { + // unwrap is safe because we know right2left contains the key (it's a bimap) + let left_rc = self.right2left.remove(&right_rc).unwrap(); + // at this point we can safely unwrap because the other pointers are gone + ( + Rc::try_unwrap(left_rc.0).ok().unwrap(), + Rc::try_unwrap(right_rc.0).ok().unwrap(), + ) + }) + } + + /// Removes the left-right pair corresponding to the given right value. + /// + /// Returns the previous left-right pair if the map contained the right + /// value and `None` otherwise. + /// + /// The input may be any borrowed form of the bimap's right type, but `Eq` + /// and `Hash` on the borrowed form *must* match those for the right type. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// + /// assert_eq!(bimap.remove_by_right(&2), Some(('b', 2))); + /// assert_eq!(bimap.remove_by_right(&2), None); + /// ``` + pub fn remove_by_right(&mut self, right: &Q) -> Option<(L, R)> + where + R: Borrow, + Q: Eq + Hash + ?Sized, + { + self.right2left.remove(Wrapper::wrap(right)).map(|left_rc| { + // unwrap is safe because we know left2right contains the key (it's a bimap) + let right_rc = self.left2right.remove(&left_rc).unwrap(); + // at this point we can safely unwrap because the other pointers are gone + ( + Rc::try_unwrap(left_rc.0).ok().unwrap(), + Rc::try_unwrap(right_rc.0).ok().unwrap(), + ) + }) + } + + /// Inserts the given left-right pair into the bimap. + /// + /// Returns an enum `Overwritten` representing any left-right pairs that + /// were overwritten by the call to `insert`. The example below details + /// all possible enum variants that can be returned. + /// + /// # Warnings + /// + /// Somewhat paradoxically, calling `insert()` can actually reduce the size + /// of the bimap! This is because of the invariant that each left value + /// maps to exactly one right value and vice versa. + /// + /// # Examples + /// + /// ``` + /// use bimap::{BiIndexMap, Overwritten}; + /// + /// let mut bimap = BiIndexMap::new(); + /// assert_eq!(bimap.len(), 0); // {} + /// + /// // no values are overwritten. + /// assert_eq!(bimap.insert('a', 1), Overwritten::Neither); + /// assert_eq!(bimap.len(), 1); // {'a' <> 1} + /// + /// // no values are overwritten. + /// assert_eq!(bimap.insert('b', 2), Overwritten::Neither); + /// assert_eq!(bimap.len(), 2); // {'a' <> 1, 'b' <> 2} + /// + /// // ('a', 1) already exists, so inserting ('a', 4) overwrites 'a', the left value. + /// // the previous left-right pair ('a', 1) is returned. + /// assert_eq!(bimap.insert('a', 4), Overwritten::Left('a', 1)); + /// assert_eq!(bimap.len(), 2); // {'a' <> 4, 'b' <> 2} + /// + /// // ('b', 2) already exists, so inserting ('c', 2) overwrites 2, the right value. + /// // the previous left-right pair ('b', 2) is returned. + /// assert_eq!(bimap.insert('c', 2), Overwritten::Right('b', 2)); + /// assert_eq!(bimap.len(), 2); // {'a' <> 1, 'c' <> 2} + /// + /// // both ('a', 4) and ('c', 2) already exist, so inserting ('a', 2) overwrites both. + /// // ('a', 4) has the overwritten left value ('a'), so it's the first tuple returned. + /// // ('c', 2) has the overwritten right value (2), so it's the second tuple returned. + /// assert_eq!(bimap.insert('a', 2), Overwritten::Both(('a', 4), ('c', 2))); + /// assert_eq!(bimap.len(), 1); // {'a' <> 2} // bimap is smaller than before! + /// + /// // ('a', 2) already exists, so inserting ('a', 2) overwrites the pair. + /// // the previous left-right pair ('a', 2) is returned. + /// assert_eq!(bimap.insert('a', 2), Overwritten::Pair('a', 2)); + /// assert_eq!(bimap.len(), 1); // {'a' <> 2} + /// ``` + pub fn insert(&mut self, left: L, right: R) -> Overwritten { + let retval = match (self.remove_by_left(&left), self.remove_by_right(&right)) { + (None, None) => Overwritten::Neither, + (None, Some(r_pair)) => Overwritten::Right(r_pair.0, r_pair.1), + (Some(l_pair), None) => { + // since remove_by_left() was called first, it's possible the right value was + // removed if a duplicate pair is being inserted + if l_pair.1 == right { + Overwritten::Pair(l_pair.0, l_pair.1) + } else { + Overwritten::Left(l_pair.0, l_pair.1) + } + } + (Some(l_pair), Some(r_pair)) => Overwritten::Both(l_pair, r_pair), + }; + self.insert_unchecked(left, right); + retval + } + + /// Inserts the given left-right pair into the bimap without overwriting any + /// existing values. + /// + /// Returns `Ok(())` if the pair was successfully inserted into the bimap. + /// If either value exists in the map, `Err((left, right)` is returned + /// with the attempted left-right pair and the map is unchanged. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// assert_eq!(bimap.insert_no_overwrite('a', 1), Ok(())); + /// assert_eq!(bimap.insert_no_overwrite('b', 2), Ok(())); + /// assert_eq!(bimap.insert_no_overwrite('a', 3), Err(('a', 3))); + /// assert_eq!(bimap.insert_no_overwrite('c', 2), Err(('c', 2))); + /// ``` + pub fn insert_no_overwrite(&mut self, left: L, right: R) -> Result<(), (L, R)> { + if self.contains_left(&left) || self.contains_right(&right) { + Err((left, right)) + } else { + self.insert_unchecked(left, right); + Ok(()) + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all left-right pairs `(l, r)` such that `f(&l, + /// &r)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use bimap::BiIndexMap; + /// + /// let mut bimap = BiIndexMap::new(); + /// bimap.insert('a', 1); + /// bimap.insert('b', 2); + /// bimap.insert('c', 3); + /// bimap.retain(|&l, &r| r >= 2); + /// assert_eq!(bimap.len(), 2); + /// assert_eq!(bimap.get_by_left(&'b'), Some(&2)); + /// assert_eq!(bimap.get_by_left(&'c'), Some(&3)); + /// assert_eq!(bimap.get_by_left(&'a'), None); + /// ``` + pub fn retain(&mut self, f: F) + where + F: FnMut(&L, &R) -> bool, + { + let mut f = f; + let right2left = &mut self.right2left; + self.left2right.retain(|l, r| { + let to_retain = f(&l.0, &r.0); + if !to_retain { + right2left.remove(r); + } + to_retain + }); + } + + /// Inserts the given left-right pair into the bimap without checking if the + /// pair already exists. + fn insert_unchecked(&mut self, left: L, right: R) { + let left = Ref(Rc::new(left)); + let right = Ref(Rc::new(right)); + self.left2right.insert(left.clone(), right.clone()); + self.right2left.insert(right, left); + } +} + +impl Clone for BiIndexMap +where + L: Clone + Eq + Hash, + R: Clone + Eq + Hash, + LS: BuildHasher + Clone, + RS: BuildHasher + Clone, +{ + fn clone(&self) -> BiIndexMap { + let mut new_bimap = BiIndexMap::with_capacity_and_hashers( + self.capacity(), + self.left2right.hasher().clone(), + self.right2left.hasher().clone(), + ); + for (l, r) in self.iter() { + new_bimap.insert(l.clone(), r.clone()); + } + new_bimap + } +} + +impl fmt::Debug for BiIndexMap +where + L: fmt::Debug, + R: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct EntryDebugger<'a, L, R> { + left: &'a L, + right: &'a R, + } + impl<'a, L, R> fmt::Debug for EntryDebugger<'a, L, R> + where + L: fmt::Debug, + R: fmt::Debug, + { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.left.fmt(f)?; + write!(f, " <> ")?; + self.right.fmt(f) + } + } + f.debug_set() + .entries( + self.left2right + .iter() + .map(|(left, right)| EntryDebugger { left, right }), + ) + .finish() + } +} + +impl Default for BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, + LS: BuildHasher + Default, + RS: BuildHasher + Default, +{ + fn default() -> BiIndexMap { + BiIndexMap { + left2right: IndexMap::default(), + right2left: IndexMap::default(), + } + } +} + +impl Eq for BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, + LS: BuildHasher, + RS: BuildHasher, +{ +} + +impl FromIterator<(L, R)> for BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, + LS: BuildHasher + Default, + RS: BuildHasher + Default, +{ + fn from_iter(iter: I) -> BiIndexMap + where + I: IntoIterator, + { + let iter = iter.into_iter(); + let mut bimap = match iter.size_hint() { + (lower, None) => { + BiIndexMap::with_capacity_and_hashers(lower, LS::default(), RS::default()) + } + (_, Some(upper)) => { + BiIndexMap::with_capacity_and_hashers(upper, LS::default(), RS::default()) + } + }; + for (left, right) in iter { + bimap.insert(left, right); + } + bimap + } +} + +impl<'a, L, R, LS, RS> IntoIterator for &'a BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, +{ + type Item = (&'a L, &'a R); + type IntoIter = Iter<'a, L, R>; + + fn into_iter(self) -> Iter<'a, L, R> { + self.iter() + } +} + +impl IntoIterator for BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, +{ + type Item = (L, R); + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.left2right.into_iter(), + } + } +} + +impl Extend<(L, R)> for BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, + LS: BuildHasher, + RS: BuildHasher, +{ + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(move |(l, r)| { + self.insert(l, r); + }); + } +} + +impl PartialEq for BiIndexMap +where + L: Eq + Hash, + R: Eq + Hash, + LS: BuildHasher, + RS: BuildHasher, +{ + fn eq(&self, other: &Self) -> bool { + self.left2right == other.left2right + } +} + +/// An owning iterator over the left-right pairs in a `BiIndexMap`. +pub struct IntoIter { + inner: map::IntoIter, Ref>, +} + +impl ExactSizeIterator for IntoIter {} + +impl FusedIterator for IntoIter {} + +impl Iterator for IntoIter { + type Item = (L, R); + + fn next(&mut self) -> Option { + self.inner.next().map(|(l, r)| { + ( + Rc::try_unwrap(l.0).ok().unwrap(), + Rc::try_unwrap(r.0).ok().unwrap(), + ) + }) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +/// An iterator over the left-right pairs in a `BiIndexMap`. +/// +/// This struct is created by the [`iter`] method of `BiIndexMap`. +/// +/// [`iter`]: BiIndexMap::iter +#[derive(Debug, Clone)] +pub struct Iter<'a, L, R> { + inner: map::Iter<'a, Ref, Ref>, +} + +impl<'a, L, R> ExactSizeIterator for Iter<'a, L, R> {} + +impl<'a, L, R> FusedIterator for Iter<'a, L, R> {} + +impl<'a, L, R> Iterator for Iter<'a, L, R> { + type Item = (&'a L, &'a R); + + fn next(&mut self) -> Option { + self.inner.next().map(|(l, r)| (&*l.0, &*r.0)) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +/// An iterator over the left values in a `BiIndexMap`. +/// +/// This struct is created by the [`left_values`] method of `BiIndexMap`. +/// +/// [`left_values`]: BiIndexMap::left_values +#[derive(Debug, Clone)] +pub struct LeftValues<'a, L, R> { + inner: map::Iter<'a, Ref, Ref>, +} + +impl<'a, L, R> ExactSizeIterator for LeftValues<'a, L, R> {} + +impl<'a, L, R> FusedIterator for LeftValues<'a, L, R> {} + +impl<'a, L, R> Iterator for LeftValues<'a, L, R> { + type Item = &'a L; + + fn next(&mut self) -> Option { + self.inner.next().map(|(l, _)| &*l.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +/// An iterator over the right values in a `BiIndexMap`. +/// +/// This struct is created by the [`right_values`] method of `BiIndexMap`. +/// +/// [`right_values`]: BiIndexMap::right_values +#[derive(Debug, Clone)] +pub struct RightValues<'a, L, R> { + inner: map::Iter<'a, Ref, Ref>, +} + +impl<'a, L, R> ExactSizeIterator for RightValues<'a, L, R> {} + +impl<'a, L, R> FusedIterator for RightValues<'a, L, R> {} + +impl<'a, L, R> Iterator for RightValues<'a, L, R> { + type Item = &'a R; + + fn next(&mut self) -> Option { + self.inner.next().map(|(r, _)| &*r.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +// safe because internal Rcs are not exposed by the api and the reference counts +// only change in methods with &mut self +unsafe impl Send for BiIndexMap +where + L: Send, + R: Send, + LS: Send, + RS: Send, +{ +} +unsafe impl Sync for BiIndexMap +where + L: Sync, + R: Sync, + LS: Sync, + RS: Sync, +{ +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn clone() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 1); + bimap.insert('b', 2); + let bimap2 = bimap.clone(); + assert_eq!(bimap, bimap2); + } + + #[test] + fn deep_clone() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 1); + bimap.insert('b', 2); + let mut bimap2 = bimap.clone(); + + // would panic if clone() didn't deep clone + bimap.insert('b', 5); + bimap2.insert('a', 12); + bimap2.remove_by_left(&'a'); + bimap.remove_by_right(&2); + } + + #[test] + fn debug() { + let mut bimap = BiIndexMap::new(); + assert_eq!("{}", format!("{:?}", bimap)); + + bimap.insert('a', 1); + assert_eq!("{'a' <> 1}", format!("{:?}", bimap)); + + bimap.insert('b', 2); + let expected1 = "{'a' <> 1, 'b' <> 2}"; + let expected2 = "{'b' <> 2, 'a' <> 1}"; + let formatted = format!("{:?}", bimap); + assert!(formatted == expected1 || formatted == expected2); + } + + #[test] + fn default() { + let _ = BiIndexMap::::default(); + } + + #[test] + fn eq() { + let mut bimap = BiIndexMap::new(); + assert_eq!(bimap, bimap); + bimap.insert('a', 1); + assert_eq!(bimap, bimap); + bimap.insert('b', 2); + assert_eq!(bimap, bimap); + + let mut bimap2 = BiIndexMap::new(); + assert_ne!(bimap, bimap2); + bimap2.insert('a', 1); + assert_ne!(bimap, bimap2); + bimap2.insert('b', 2); + assert_eq!(bimap, bimap2); + bimap2.insert('c', 3); + assert_ne!(bimap, bimap2); + } + + #[test] + fn from_iter() { + let bimap = BiIndexMap::from_iter(vec![ + ('a', 1), + ('b', 2), + ('c', 3), + ('b', 2), + ('a', 4), + ('b', 3), + ]); + let mut bimap2 = BiIndexMap::new(); + bimap2.insert('a', 4); + bimap2.insert('b', 3); + assert_eq!(bimap, bimap2); + } + + #[test] + fn into_iter() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 3); + bimap.insert('b', 2); + bimap.insert('c', 1); + let mut pairs = bimap.into_iter().collect::>(); + pairs.sort(); + assert_eq!(pairs, vec![('a', 3), ('b', 2), ('c', 1)]); + } + + #[test] + fn into_iter_ref() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 3); + bimap.insert('b', 2); + bimap.insert('c', 1); + let mut pairs = (&bimap).into_iter().collect::>(); + pairs.sort(); + assert_eq!(pairs, vec![(&'a', &3), (&'b', &2), (&'c', &1)]); + } + + #[test] + fn extend() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 3); + bimap.insert('b', 2); + bimap.extend(vec![('c', 3), ('b', 1), ('a', 4)]); + let mut bimap2 = BiIndexMap::new(); + bimap2.insert('a', 4); + bimap2.insert('b', 1); + bimap2.insert('c', 3); + assert_eq!(bimap, bimap2); + } + + #[test] + fn iter() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 1); + bimap.insert('b', 2); + bimap.insert('c', 3); + let mut pairs = bimap.iter().map(|(c, i)| (*c, *i)).collect::>(); + pairs.sort(); + assert_eq!(pairs, vec![('a', 1), ('b', 2), ('c', 3)]); + } + + #[test] + fn left_values() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 3); + bimap.insert('b', 2); + bimap.insert('c', 1); + let mut left_values = bimap.left_values().cloned().collect::>(); + left_values.sort(); + assert_eq!(left_values, vec!['a', 'b', 'c']) + } + + #[test] + fn right_values() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 3); + bimap.insert('b', 2); + bimap.insert('c', 1); + let mut right_values = bimap.right_values().cloned().collect::>(); + right_values.sort(); + assert_eq!(right_values, vec![1, 2, 3]) + } + + #[test] + fn capacity() { + let bimap = BiIndexMap::::with_capacity(10); + assert!(bimap.capacity() >= 10); + } + + #[test] + fn with_hashers() { + let s_left = hash_map::RandomState::new(); + let s_right = hash_map::RandomState::new(); + let mut bimap = BiIndexMap::::with_hashers(s_left, s_right); + bimap.insert('a', 42); + assert_eq!(Some(&'a'), bimap.get_by_right(&42)); + assert_eq!(Some(&42), bimap.get_by_left(&'a')); + } + + #[test] + fn reserve() { + let mut bimap = BiIndexMap::::new(); + assert!(bimap.is_empty()); + assert_eq!(bimap.len(), 0); + assert_eq!(bimap.capacity(), 0); + + bimap.reserve(10); + assert!(bimap.is_empty()); + assert_eq!(bimap.len(), 0); + assert!(bimap.capacity() >= 10); + } + + #[test] + fn shrink_to_fit() { + let mut bimap = BiIndexMap::::with_capacity(100); + assert!(bimap.is_empty()); + assert_eq!(bimap.len(), 0); + assert!(bimap.capacity() >= 100); + + bimap.insert('a', 1); + bimap.insert('b', 2); + assert!(!bimap.is_empty()); + assert_eq!(bimap.len(), 2); + assert!(bimap.capacity() >= 100); + + bimap.shrink_to_fit(); + assert!(!bimap.is_empty()); + assert_eq!(bimap.len(), 2); + assert!(bimap.capacity() >= 2); + } + + #[test] + fn shrink_to() { + let mut bimap = BiIndexMap::::with_capacity(100); + assert!(bimap.is_empty()); + assert_eq!(bimap.len(), 0); + assert!(bimap.capacity() >= 100); + + bimap.insert('a', 1); + bimap.insert('b', 2); + assert!(!bimap.is_empty()); + assert_eq!(bimap.len(), 2); + assert!(bimap.capacity() >= 100); + + bimap.shrink_to(10); + assert!(!bimap.is_empty()); + assert_eq!(bimap.len(), 2); + assert!(bimap.capacity() >= 10); + + bimap.shrink_to(0); + assert!(!bimap.is_empty()); + assert_eq!(bimap.len(), 2); + assert!(bimap.capacity() >= 2); + } + + #[test] + fn clear() { + let mut bimap = vec![('a', 1)].into_iter().collect::>(); + assert_eq!(bimap.len(), 1); + assert!(!bimap.is_empty()); + + bimap.clear(); + + assert_eq!(bimap.len(), 0); + assert!(bimap.is_empty()); + } + + #[test] + fn get_contains() { + let bimap = vec![('a', 1)].into_iter().collect::>(); + + assert_eq!(bimap.get_by_left(&'a'), Some(&1)); + assert!(bimap.contains_left(&'a')); + + assert_eq!(bimap.get_by_left(&'b'), None); + assert!(!bimap.contains_left(&'b')); + + assert_eq!(bimap.get_by_right(&1), Some(&'a')); + assert!(bimap.contains_right(&1)); + + assert_eq!(bimap.get_by_right(&2), None); + assert!(!bimap.contains_right(&2)); + } + + #[test] + fn insert() { + let mut bimap = BiIndexMap::new(); + + assert_eq!(bimap.insert('a', 1), Overwritten::Neither); + assert_eq!(bimap.insert('a', 2), Overwritten::Left('a', 1)); + assert_eq!(bimap.insert('b', 2), Overwritten::Right('a', 2)); + assert_eq!(bimap.insert('b', 2), Overwritten::Pair('b', 2)); + + assert_eq!(bimap.insert('c', 3), Overwritten::Neither); + assert_eq!(bimap.insert('b', 3), Overwritten::Both(('b', 2), ('c', 3))); + } + + #[test] + fn insert_no_overwrite() { + let mut bimap = BiIndexMap::new(); + + assert!(bimap.insert_no_overwrite('a', 1).is_ok()); + assert!(bimap.insert_no_overwrite('a', 2).is_err()); + assert!(bimap.insert_no_overwrite('b', 1).is_err()); + } + + #[test] + fn retain_calls_f_once() { + let mut bimap = BiIndexMap::new(); + bimap.insert('a', 1); + bimap.insert('b', 2); + bimap.insert('c', 3); + + // retain one element + let mut i = 0; + bimap.retain(|_l, _r| { + i += 1; + i <= 1 + }); + assert_eq!(bimap.len(), 1); + assert_eq!(i, 3); + } +} diff --git a/src/lib.rs b/src/lib.rs index f814032..98e92ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -204,6 +204,11 @@ mod mem; pub mod btree; pub use btree::BiBTreeMap; +#[cfg(all(feature = "indexmap", feature = "std"))] +pub mod index; +#[cfg(all(feature = "indexmap", feature = "std"))] +pub use index::BiIndexMap; + #[cfg(feature = "std")] pub mod hash; #[cfg(feature = "std")]