Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some missing methods to FrozenIndexMap and FrozenIndexSet #77

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading