Skip to content

Add dynamically-sized slices of maps and sets #177

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

Merged
merged 16 commits into from
May 7, 2022
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
include:
- rust: 1.56.0 # MSRV
- rust: 1.56.1 # MSRV
features:
- rust: stable
features: serde
Expand Down Expand Up @@ -57,7 +57,7 @@ jobs:
strategy:
matrix:
include:
- rust: 1.56.0
- rust: 1.56.1
target: thumbv6m-none-eabi
- rust: stable
target: thumbv6m-none-eabi
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "Apache-2.0 OR MIT"
description = "A hash table with consistent order and fast iteration."
keywords = ["hashmap", "no_std"]
categories = ["data-structures", "no-std"]
rust-version = "1.56"
rust-version = "1.56.1"

[lib]
bench = false
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![build status](https://github.com/bluss/indexmap/workflows/Continuous%20integration/badge.svg?branch=master)](https://github.com/bluss/indexmap/actions)
[![crates.io](https://img.shields.io/crates/v/indexmap.svg)](https://crates.io/crates/indexmap)
[![docs](https://docs.rs/indexmap/badge.svg)](https://docs.rs/indexmap)
[![rustc](https://img.shields.io/badge/rust-1.56%2B-orange.svg)](https://img.shields.io/badge/rust-1.56%2B-orange.svg)
[![rustc](https://img.shields.io/badge/rust-1.56.1%2B-orange.svg)](https://img.shields.io/badge/rust-1.56.1%2B-orange.svg)

A pure-Rust hash table which preserves (in a limited sense) insertion order.

Expand Down
7 changes: 6 additions & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
- 2.0.0 (pending)

- **MSRV**: Rust 1.56 or later is now required.
- **MSRV**: Rust 1.56.1 or later is now required.

- The `hashbrown` dependency has been updated to version 0.12.

Expand All @@ -19,6 +19,11 @@
- The new `IndexMap::shrink_to` and `IndexSet::shrink_to` methods shrink
the capacity with a lower bound.

- The new `map::Slice<K, V>` and `set::Slice<T>` offer a linear view of maps
and sets, behaving a lot like normal `[(K, V)]` and `[T]` slices. Notably,
comparison traits like `Eq` only consider items in order, rather than hash
lookups, and slices even implement `Hash`.

- 1.8.1

- The new `IndexSet::replace_full` will return the index of the item along
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
//!
//! ### Rust Version
//!
//! This version of indexmap requires Rust 1.56 or later.
//! This version of indexmap requires Rust 1.56.1 or later.
//!
//! The indexmap 2.x release series will use a carefully considered version
//! upgrade policy, where in a later 2.x version, we will raise the minimum
Expand Down
68 changes: 65 additions & 3 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
//! pairs is independent of the hash values of the keys.

mod core;
mod slice;

pub use self::slice::Slice;
pub use crate::mutable_keys::MutableKeys;

#[cfg(feature = "rayon")]
Expand All @@ -15,13 +17,14 @@ use ::core::hash::{BuildHasher, Hash, Hasher};
use ::core::iter::FusedIterator;
use ::core::ops::{Index, IndexMut, RangeBounds};
use ::core::slice::{Iter as SliceIter, IterMut as SliceIterMut};
use alloc::boxed::Box;

#[cfg(feature = "std")]
use std::collections::hash_map::RandomState;

use self::core::IndexMapCore;
use crate::equivalent::Equivalent;
use crate::util::third;
use crate::util::{third, try_simplify_range};
use crate::{Bucket, Entries, HashValue};

pub use self::core::{Entry, OccupiedEntry, VacantEntry};
Expand Down Expand Up @@ -758,6 +761,27 @@ where
}

impl<K, V, S> IndexMap<K, V, S> {
/// Returns a slice of all the key-value pairs in the map.
///
/// Computes in **O(1)** time.
pub fn as_slice(&self) -> &Slice<K, V> {
Slice::from_slice(self.as_entries())
}

/// Returns a mutable slice of all the key-value pairs in the map.
///
/// Computes in **O(1)** time.
pub fn as_mut_slice(&mut self) -> &mut Slice<K, V> {
Slice::from_mut_slice(self.as_entries_mut())
}

/// Converts into a boxed slice of all the key-value pairs in the map.
///
/// Note that this will drop the inner hash table and any excess capacity.
pub fn into_boxed_slice(self) -> Box<Slice<K, V>> {
Slice::from_boxed(self.into_entries().into_boxed_slice())
}

/// Get a key-value pair by index
///
/// Valid indices are *0 <= index < self.len()*
Expand All @@ -776,6 +800,28 @@ impl<K, V, S> IndexMap<K, V, S> {
self.as_entries_mut().get_mut(index).map(Bucket::ref_mut)
}

/// Returns a slice of key-value pairs in the given range of indices.
///
/// Valid indices are *0 <= index < self.len()*
///
/// Computes in **O(1)** time.
pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Slice<K, V>> {
let entries = self.as_entries();
let range = try_simplify_range(range, entries.len())?;
entries.get(range).map(Slice::from_slice)
}

/// Returns a mutable slice of key-value pairs in the given range of indices.
///
/// Valid indices are *0 <= index < self.len()*
///
/// Computes in **O(1)** time.
pub fn get_range_mut<R: RangeBounds<usize>>(&mut self, range: R) -> Option<&mut Slice<K, V>> {
let entries = self.as_entries_mut();
let range = try_simplify_range(range, entries.len())?;
entries.get_mut(range).map(Slice::from_mut_slice)
}

/// Get the first key-value pair
///
/// Computes in **O(1)** time.
Expand Down Expand Up @@ -846,7 +892,7 @@ impl<K, V, S> IndexMap<K, V, S> {
/// [`keys`]: struct.IndexMap.html#method.keys
/// [`IndexMap`]: struct.IndexMap.html
pub struct Keys<'a, K, V> {
pub(crate) iter: SliceIter<'a, Bucket<K, V>>,
iter: SliceIter<'a, Bucket<K, V>>,
}

impl<'a, K, V> Iterator for Keys<'a, K, V> {
Expand Down Expand Up @@ -1045,6 +1091,13 @@ pub struct Iter<'a, K, V> {
iter: SliceIter<'a, Bucket<K, V>>,
}

impl<'a, K, V> Iter<'a, K, V> {
/// Returns a slice of the remaining entries in the iterator.
pub fn as_slice(&self) -> &'a Slice<K, V> {
Slice::from_slice(self.iter.as_slice())
}
}

impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = (&'a K, &'a V);

Expand Down Expand Up @@ -1089,6 +1142,15 @@ pub struct IterMut<'a, K, V> {
iter: SliceIterMut<'a, Bucket<K, V>>,
}

impl<'a, K, V> IterMut<'a, K, V> {
/// Returns a slice of the remaining entries in the iterator.
///
/// To avoid creating `&mut` references that alias, this is forced to consume the iterator.
pub fn into_slice(self) -> &'a mut Slice<K, V> {
Slice::from_mut_slice(self.iter.into_slice())
}
}

impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);

Expand Down Expand Up @@ -1122,7 +1184,7 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> {
/// [`into_iter`]: struct.IndexMap.html#method.into_iter
/// [`IndexMap`]: struct.IndexMap.html
pub struct IntoIter<K, V> {
pub(crate) iter: vec::IntoIter<Bucket<K, V>>,
iter: vec::IntoIter<Bucket<K, V>>,
}

impl<K, V> Iterator for IntoIter<K, V> {
Expand Down
Loading