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

Implement direct usize indexing #132

Merged
merged 2 commits into from
Aug 7, 2020
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
132 changes: 132 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,28 @@ impl<K, V, S> IntoIterator for IndexMap<K, V, S> {
}
}

/// Access `IndexMap` values corresponding to a key.
///
/// # Examples
///
/// ```
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// for word in "Lorem ipsum dolor sit amet".split_whitespace() {
/// map.insert(word.to_lowercase(), word.to_uppercase());
/// }
/// assert_eq!(map["lorem"], "LOREM");
/// assert_eq!(map["ipsum"], "IPSUM");
/// ```
///
/// ```should_panic
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// map.insert("foo", 1);
/// println!("{:?}", map["bar"]); // panics!
/// ```
impl<K, V, Q: ?Sized, S> Index<&Q> for IndexMap<K, V, S>
where
Q: Hash + Equivalent<K>,
Expand All @@ -1001,28 +1023,138 @@ where
{
type Output = V;

/// Returns a reference to the value corresponding to the supplied `key`.
///
/// ***Panics*** if `key` is not present in the map.
fn index(&self, key: &Q) -> &V {
self.get(key).expect("IndexMap: key not found")
}
}

/// Access `IndexMap` values corresponding to a key.
///
/// Mutable indexing allows changing / updating values of key-value
/// pairs that are already present.
///
/// You can **not** insert new pairs with index syntax, use `.insert()`.
///
/// # Examples
///
/// ```
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// for word in "Lorem ipsum dolor sit amet".split_whitespace() {
/// map.insert(word.to_lowercase(), word.to_string());
/// }
/// let lorem = &mut map["lorem"];
/// assert_eq!(lorem, "Lorem");
/// lorem.retain(char::is_lowercase);
/// assert_eq!(map["lorem"], "orem");
/// ```
///
/// ```should_panic
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// map.insert("foo", 1);
/// map["bar"] = 1; // panics!
/// ```
impl<K, V, Q: ?Sized, S> IndexMut<&Q> for IndexMap<K, V, S>
where
Q: Hash + Equivalent<K>,
K: Hash + Eq,
S: BuildHasher,
{
/// Returns a mutable reference to the value corresponding to the supplied `key`.
///
/// ***Panics*** if `key` is not present in the map.
fn index_mut(&mut self, key: &Q) -> &mut V {
self.get_mut(key).expect("IndexMap: key not found")
}
}

/// Access `IndexMap` values at indexed positions.
///
/// # Examples
///
/// ```
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// for word in "Lorem ipsum dolor sit amet".split_whitespace() {
/// map.insert(word.to_lowercase(), word.to_uppercase());
/// }
/// assert_eq!(map[0], "LOREM");
/// assert_eq!(map[1], "IPSUM");
/// map.reverse();
/// assert_eq!(map[0], "AMET");
/// assert_eq!(map[1], "SIT");
/// map.sort_keys();
/// assert_eq!(map[0], "AMET");
/// assert_eq!(map[1], "DOLOR");
/// ```
///
/// ```should_panic
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// map.insert("foo", 1);
/// println!("{:?}", map[10]); // panics!
/// ```
impl<K, V, S> Index<usize> for IndexMap<K, V, S> {
type Output = V;

/// Returns a reference to the value at the supplied `index`.
///
/// ***Panics*** if `index` is out of bounds.
fn index(&self, index: usize) -> &V {
self.get_index(index)
.expect("IndexMap: index out of bounds")
.1
}
}

/// Access `IndexMap` values at indexed positions.
///
/// Mutable indexing allows changing / updating indexed values
/// that are already present.
///
/// You can **not** insert new values with index syntax, use `.insert()`.
///
/// # Examples
///
/// ```
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// for word in "Lorem ipsum dolor sit amet".split_whitespace() {
/// map.insert(word.to_lowercase(), word.to_string());
/// }
/// let lorem = &mut map[0];
/// assert_eq!(lorem, "Lorem");
/// lorem.retain(char::is_lowercase);
/// assert_eq!(map["lorem"], "orem");
/// ```
///
/// ```should_panic
/// use indexmap::IndexMap;
///
/// let mut map = IndexMap::new();
/// map.insert("foo", 1);
/// map[10] = 1; // panics!
/// ```
impl<K, V, S> IndexMut<usize> for IndexMap<K, V, S> {
/// Returns a mutable reference to the value at the supplied `index`.
///
/// ***Panics*** if `index` is out of bounds.
fn index_mut(&mut self, index: usize) -> &mut V {
self.get_index_mut(index)
.expect("IndexMap: index out of bounds")
.1
}
}

impl<K, V, S> FromIterator<(K, V)> for IndexMap<K, V, S>
where
K: Hash + Eq,
Expand Down
42 changes: 41 additions & 1 deletion src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::cmp::Ordering;
use core::fmt;
use core::hash::{BuildHasher, Hash};
use core::iter::{Chain, FromIterator};
use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub};
use core::ops::{BitAnd, BitOr, BitXor, Index, RangeBounds, Sub};
use core::slice;

use super::{Entries, Equivalent, IndexMap};
Expand Down Expand Up @@ -606,6 +606,46 @@ impl<T, S> IndexSet<T, S> {
}
}

/// Access `IndexSet` values at indexed positions.
///
/// # Examples
///
/// ```
/// use indexmap::IndexSet;
///
/// let mut set = IndexSet::new();
/// for word in "Lorem ipsum dolor sit amet".split_whitespace() {
/// set.insert(word.to_string());
/// }
/// assert_eq!(set[0], "Lorem");
/// assert_eq!(set[1], "ipsum");
/// set.reverse();
/// assert_eq!(set[0], "amet");
/// assert_eq!(set[1], "sit");
/// set.sort();
/// assert_eq!(set[0], "Lorem");
/// assert_eq!(set[1], "amet");
/// ```
///
/// ```should_panic
/// use indexmap::IndexSet;
///
/// let mut set = IndexSet::new();
/// set.insert("foo");
/// println!("{:?}", set[10]); // panics!
/// ```
impl<T, S> Index<usize> for IndexSet<T, S> {
type Output = T;

/// Returns a reference to the value at the supplied `index`.
///
/// ***Panics*** if `index` is out of bounds.
fn index(&self, index: usize) -> &T {
self.get_index(index)
.expect("IndexSet: index out of bounds")
}
}

/// An owning iterator over the items of a `IndexSet`.
///
/// This `struct` is created by the [`into_iter`] method on [`IndexSet`]
Expand Down
22 changes: 21 additions & 1 deletion tests/quick.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;

use quickcheck::quickcheck;
Expand Down Expand Up @@ -163,6 +163,26 @@ quickcheck! {
elements.iter().all(|k| map.get(k).is_some())
}

fn indexing(insert: Vec<u8>) -> bool {
let mut map: IndexMap<_, _> = insert.into_iter().map(|x| (x, x)).collect();
let set: IndexSet<_> = map.keys().cloned().collect();
assert_eq!(map.len(), set.len());

for (i, &key) in set.iter().enumerate() {
assert_eq!(map.get_index(i), Some((&key, &key)));
assert_eq!(set.get_index(i), Some(&key));
assert_eq!(map[i], key);
assert_eq!(set[i], key);

*map.get_index_mut(i).unwrap().1 >>= 1;
map[i] <<= 1;
}

set.iter().enumerate().all(|(i, &key)| {
let value = key & !1;
map[&key] == value && map[i] == value
})
}
}

use crate::Op::*;
Expand Down