Skip to content

Commit

Permalink
Merge pull request #77 from yegorvk/missing-methods-frozen-indexmap-i…
Browse files Browse the repository at this point in the history
…ndexset

Add some missing methods to `FrozenIndexMap` and `FrozenIndexSet`
  • Loading branch information
Manishearth authored Jul 16, 2024
2 parents ab1beef + 1ae1448 commit 94214fa
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 40 deletions.
104 changes: 74 additions & 30 deletions src/index_map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::borrow::Borrow;
use std::cell::{Cell, UnsafeCell};
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash};
Expand All @@ -8,6 +7,8 @@ use std::ops::Index;
use indexmap::IndexMap;
use stable_deref_trait::StableDeref;

pub use indexmap::Equivalent;

/// Append-only version of `indexmap::IndexMap` where
/// insertion does not require mutable access
pub struct FrozenIndexMap<K, V, S = RandomState> {
Expand Down Expand Up @@ -41,10 +42,6 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
///
/// Existing values are never overwritten.
///
/// 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.
///
/// # Example
/// ```
/// use elsa::index_map::FrozenIndexMap;
Expand Down Expand Up @@ -72,10 +69,6 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
///
/// Existing values are never overwritten.
///
/// 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.
///
/// # Example
/// ```
/// use elsa::index_map::FrozenIndexMap;
Expand All @@ -97,10 +90,9 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
}

/// 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.
///
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<K>`].
///
/// # Examples
///
Expand All @@ -112,10 +104,9 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
/// assert_eq!(map.get(&1), Some(&"a"));
/// assert_eq!(map.get(&2), None);
/// ```
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V::Target>
pub fn get<Q>(&self, k: &Q) -> Option<&V::Target>
where
K: Borrow<Q>,
Q: Hash + Eq,
Q: ?Sized + Hash + Equivalent<K>,
{
assert!(!self.in_use.get());
self.in_use.set(true);
Expand All @@ -127,11 +118,36 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
ret
}

/// Returns a reference to the key-value mapping corresponding to an index.
/// Returns the index corresponding to the key
///
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<K>`].
///
/// # Examples
///
/// 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.
/// ```
/// use elsa::index_map::FrozenIndexMap;
///
/// let map = FrozenIndexMap::new();
/// map.insert(1, Box::new("a"));
/// assert_eq!(map.get_index_of(&1), Some(0));
/// assert_eq!(map.get_index_of(&2), None);
/// ```
pub fn get_index_of<Q>(&self, k: &Q) -> Option<usize>
where
Q: ?Sized + Hash + Equivalent<K>,
{
assert!(!self.in_use.get());
self.in_use.set(true);
let ret = unsafe {
let map = self.map.get();
(*map).get_index_of(k)
};
self.in_use.set(false);
ret
}

/// Returns a reference to the key-value mapping corresponding to an index.
///
/// # Examples
///
Expand All @@ -158,11 +174,40 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
ret
}

/// Returns a reference to the key, along with its index and a reference to its value
///
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<K>`].
///
/// # Examples
///
/// ```
/// use elsa::index_map::FrozenIndexMap;
///
/// let map = FrozenIndexMap::new();
/// map.insert("1", Box::new("a"));
/// assert_eq!(map.get_full("1"), Some((0, "1", &"a")));
/// assert_eq!(map.get_full("2"), None);
/// ```
pub fn get_full<Q>(&self, k: &Q) -> Option<(usize, &K::Target, &V::Target)>
where
Q: ?Sized + Hash + Equivalent<K>,
K: StableDeref,
{
assert!(!self.in_use.get());
self.in_use.set(true);
let ret = unsafe {
let map = self.map.get();
(*map).get_full(k).map(|(i, k, v)| (i, &**k, &**v))
};
self.in_use.set(false);
ret
}

/// Applies a function to the owner of the value corresponding to the key (if any).
///
/// 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.
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<K>`].
///
/// # Examples
///
Expand All @@ -174,10 +219,9 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
/// assert_eq!(map.map_get(&1, Clone::clone), Some(Box::new("a")));
/// assert_eq!(map.map_get(&2, Clone::clone), None);
/// ```
pub fn map_get<Q: ?Sized, T, F>(&self, k: &Q, f: F) -> Option<T>
pub fn map_get<Q, T, F>(&self, k: &Q, f: F) -> Option<T>
where
K: Borrow<Q>,
Q: Hash + Eq,
Q: ?Sized + Hash + Equivalent<K>,
F: FnOnce(&V) -> T,
{
assert!(!self.in_use.get());
Expand Down Expand Up @@ -246,10 +290,10 @@ impl<K, V, S> From<IndexMap<K, V, S>> for FrozenIndexMap<K, V, S> {
}
}

impl<Q: ?Sized, K: Eq + Hash, V: StableDeref, S: BuildHasher> Index<&Q> for FrozenIndexMap<K, V, S>
impl<Q, K, V, S> Index<&Q> for FrozenIndexMap<K, V, S>
where
Q: Eq + Hash,
K: Eq + Hash + Borrow<Q>,
Q: ?Sized + Hash + Equivalent<K>,
K: Eq + Hash,
V: StableDeref,
S: BuildHasher,
{
Expand All @@ -265,7 +309,7 @@ where
/// assert_eq!(map[&1], "a");
/// ```
fn index(&self, idx: &Q) -> &V::Target {
self.get(&idx)
self.get(idx)
.expect("attempted to index FrozenIndexMap with unknown key")
}
}
Expand Down
54 changes: 44 additions & 10 deletions src/index_set.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::borrow::Borrow;
use std::cell::{Cell, UnsafeCell};
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash};
Expand All @@ -8,6 +7,8 @@ use std::ops::Index;
use indexmap::IndexSet;
use stable_deref_trait::StableDeref;

use crate::index_map::Equivalent;

/// Append-only version of `indexmap::IndexSet` where
/// insertion does not require mutable access
pub struct FrozenIndexSet<T, S = RandomState> {
Expand Down Expand Up @@ -72,9 +73,9 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
/// # Example
/// ```
/// use elsa::index_set::FrozenIndexSet;
/// let map = FrozenIndexSet::new();
/// assert_eq!(map.insert_full(Box::new("a")), (0, &"a"));
/// assert_eq!(map.insert_full(Box::new("b")), (1, &"b"));
/// let set = FrozenIndexSet::new();
/// assert_eq!(set.insert_full(Box::new("a")), (0, &"a"));
/// assert_eq!(set.insert_full(Box::new("b")), (1, &"b"));
/// ```
pub fn insert_full(&self, value: T) -> (usize, &T::Target) {
assert!(!self.in_use.get());
Expand Down Expand Up @@ -116,6 +117,9 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
// }

/// Returns a reference to the value passed as argument if present in the set.
///
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<T>`].
///
/// # Examples
///
Expand All @@ -127,10 +131,9 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
/// assert_eq!(set.get(&Box::new("a")), Some(&"a"));
/// assert_eq!(set.get(&Box::new("b")), None);
/// ```
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&T::Target>
pub fn get<Q>(&self, k: &Q) -> Option<&T::Target>
where
T: Borrow<Q>,
Q: Hash + Eq,
Q: ?Sized + Hash + Equivalent<T>,
{
assert!(!self.in_use.get());
self.in_use.set(true);
Expand All @@ -142,8 +145,40 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
ret
}

/// Returns the index corresponding to the value if present in the set
///
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<T>`].
///
/// # Examples
///
/// ```
/// use elsa::FrozenIndexSet;
///
/// let set = FrozenIndexSet::new();
/// set.insert(Box::new("a"));
/// assert_eq!(set.get_index_of(&Box::new("a")), Some(0));
/// assert_eq!(set.get_index_of(&Box::new("b")), None);
/// ```
pub fn get_index_of<Q>(&self, k: &Q) -> Option<usize>
where
Q: ?Sized + Hash + Equivalent<T>,
{
assert!(!self.in_use.get());
self.in_use.set(true);
let ret = unsafe {
let set = self.set.get();
(*set).get_index_of(k)
};
self.in_use.set(false);
ret
}

/// Returns a reference to the value passed as argument if present in the set,
/// along with its index
///
/// # Arguments
/// * `k` may be any type that implements [`Equivalent<T>`].
///
/// # Examples
///
Expand All @@ -155,10 +190,9 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
/// assert_eq!(set.get_full(&Box::new("a")), Some((0, &"a")));
/// assert_eq!(set.get_full(&Box::new("b")), None);
/// ```
pub fn get_full<Q: ?Sized>(&self, k: &Q) -> Option<(usize, &T::Target)>
pub fn get_full<Q>(&self, k: &Q) -> Option<(usize, &T::Target)>
where
T: Borrow<Q>,
Q: Hash + Eq,
Q: ?Sized + Hash + Equivalent<T>,
{
assert!(!self.in_use.get());
self.in_use.set(true);
Expand Down

0 comments on commit 94214fa

Please sign in to comment.