Skip to content

Commit

Permalink
Implement direct usize indexing
Browse files Browse the repository at this point in the history
```rust
where
    IndexMap<K, V, S>: IndexMut<usize, Output = V>,
    IndexSet<T, S>: Index<usize, Output = T>,
```

This allows `map[i]` and `set[i]` indexing to access values directly,
panicking if the index is out of bounds, similar to slices.

On maps, this somewhat overlaps with `Index<&Q> + IndexMut<&Q>` where
`Q: Equivalent<K>`. The reference makes this indexing unambiguous, but
it could be confusing to users if the key type is also an integer.
  • Loading branch information
cuviper committed Jul 23, 2020
1 parent 041ee54 commit ce1d38b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
20 changes: 20 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,26 @@ where
}
}

impl<K, V, S> Index<usize> for IndexMap<K, V, S> {
type Output = V;

/// ***Panics*** if `index` is out of bounds.
fn index(&self, index: usize) -> &V {
self.get_index(index).expect("IndexMap: index out of bounds").1
}
}

/// Mutable indexing allows changing / updating indexed values
/// that are already present.
///
/// You can **not** insert new values with index syntax, use `.insert()`.
impl<K, V, S> IndexMut<usize> for IndexMap<K, V, S> {
/// ***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
11 changes: 10 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, RangeFull, Sub};
use core::ops::{BitAnd, BitOr, BitXor, Index, RangeFull, Sub};
use core::slice;

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

impl<T, S> Index<usize> for IndexSet<T, S> {
type Output = T;

/// ***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 @@ -135,6 +135,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

0 comments on commit ce1d38b

Please sign in to comment.