Skip to content

Commit

Permalink
Merge pull request #305 from cuviper/raw_entry-index
Browse files Browse the repository at this point in the history
Add indexing methods to raw entry
  • Loading branch information
cuviper authored Jan 31, 2024
2 parents 7264ce4 + f4bb006 commit 1a50e7b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "indexmap"
edition = "2021"
version = "2.2.1"
version = "2.2.2"
documentation = "https://docs.rs/indexmap/"
repository = "https://github.com/indexmap-rs/indexmap"
license = "Apache-2.0 OR MIT"
Expand Down
5 changes: 5 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
- 2.2.2

- Added indexing methods to raw entries: `RawEntryBuilder::from_hash_full`,
`RawEntryBuilder::index_from_hash`, and `RawEntryMut::index`.

- 2.2.1

- Corrected the signature of `RawOccupiedEntryMut::into_key(self) -> &'a mut K`,
Expand Down
49 changes: 43 additions & 6 deletions src/map/core/raw_entry_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,18 @@ pub trait RawEntryApiV1<K, V, S>: private::Sealed {
///
/// for k in ["a", "b", "c", "d", "e", "f"] {
/// let hash = compute_hash(map.hasher(), k);
/// let v = map.get(k).cloned();
/// let kv = v.as_ref().map(|v| (&k, v));
/// let i = map.get_index_of(k);
/// let v = map.get(k);
/// let kv = map.get_key_value(k);
/// let ikv = map.get_full(k);
///
/// println!("Key: {} and value: {:?}", k, v);
///
/// assert_eq!(map.raw_entry_v1().from_key(k), kv);
/// assert_eq!(map.raw_entry_v1().from_hash(hash, |q| *q == k), kv);
/// assert_eq!(map.raw_entry_v1().from_key_hashed_nocheck(hash, k), kv);
/// assert_eq!(map.raw_entry_v1().from_hash_full(hash, |q| *q == k), ikv);
/// assert_eq!(map.raw_entry_v1().index_from_hash(hash, |q| *q == k), i);
/// }
/// ```
fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S>;
Expand Down Expand Up @@ -116,6 +120,7 @@ pub trait RawEntryApiV1<K, V, S>: private::Sealed {
/// match map.raw_entry_mut_v1().from_key("a") {
/// RawEntryMut::Vacant(_) => unreachable!(),
/// RawEntryMut::Occupied(mut view) => {
/// assert_eq!(view.index(), 0);
/// assert_eq!(view.get(), &100);
/// let v = view.get_mut();
/// let new_v = (*v) * 10;
Expand All @@ -132,6 +137,7 @@ pub trait RawEntryApiV1<K, V, S>: private::Sealed {
/// match map.raw_entry_mut_v1().from_key_hashed_nocheck(hash, "c") {
/// RawEntryMut::Vacant(_) => unreachable!(),
/// RawEntryMut::Occupied(view) => {
/// assert_eq!(view.index(), 2);
/// assert_eq!(view.shift_remove_entry(), ("c", 300));
/// }
/// }
Expand All @@ -144,6 +150,7 @@ pub trait RawEntryApiV1<K, V, S>: private::Sealed {
/// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) {
/// RawEntryMut::Occupied(_) => unreachable!(),
/// RawEntryMut::Vacant(view) => {
/// assert_eq!(view.index(), 2);
/// let (k, value) = view.insert("d", 4000);
/// assert_eq!((*k, *value), ("d", 4000));
/// *value = 40000;
Expand All @@ -155,6 +162,7 @@ pub trait RawEntryApiV1<K, V, S>: private::Sealed {
/// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) {
/// RawEntryMut::Vacant(_) => unreachable!(),
/// RawEntryMut::Occupied(view) => {
/// assert_eq!(view.index(), 2);
/// assert_eq!(view.swap_remove_entry(), ("d", 40000));
/// }
/// }
Expand Down Expand Up @@ -205,19 +213,39 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> {
{
let hash = HashValue(hash as usize);
let i = self.map.core.get_index_of(hash, key)?;
Some(self.map.core.entries[i].refs())
self.map.get_index(i)
}

/// Access an entry by hash.
pub fn from_hash<F>(self, hash: u64, mut is_match: F) -> Option<(&'a K, &'a V)>
pub fn from_hash<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)>
where
F: FnMut(&K) -> bool,
{
let map = self.map;
let i = self.index_from_hash(hash, is_match)?;
map.get_index(i)
}

/// Access an entry by hash, including its index.
pub fn from_hash_full<F>(self, hash: u64, is_match: F) -> Option<(usize, &'a K, &'a V)>
where
F: FnMut(&K) -> bool,
{
let map = self.map;
let i = self.index_from_hash(hash, is_match)?;
let (key, value) = map.get_index(i)?;
Some((i, key, value))
}

/// Access the index of an entry by hash.
pub fn index_from_hash<F>(self, hash: u64, mut is_match: F) -> Option<usize>
where
F: FnMut(&K) -> bool,
{
let hash = HashValue(hash as usize);
let entries = &*self.map.core.entries;
let eq = move |&i: &usize| is_match(&entries[i].key);
let i = *self.map.core.indices.get(hash.get(), eq)?;
Some(entries[i].refs())
self.map.core.indices.get(hash.get(), eq).copied()
}
}

Expand Down Expand Up @@ -294,6 +322,15 @@ impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for RawEntryMut<'_, K, V, S> {
}

impl<'a, K, V, S> RawEntryMut<'a, K, V, S> {
/// Return the index where the key-value pair exists or may be inserted.
#[inline]
pub fn index(&self) -> usize {
match self {
Self::Occupied(entry) => entry.index(),
Self::Vacant(entry) => entry.index(),
}
}

/// Inserts the given default key and value in the entry if it is vacant and returns mutable
/// references to them. Otherwise mutable references to an already existent pair are returned.
pub fn or_insert(self, default_key: K, default_value: V) -> (&'a mut K, &'a mut V)
Expand Down

0 comments on commit 1a50e7b

Please sign in to comment.