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

Adding reverse() to IndexMap & IndexSet #128

Merged
merged 4 commits into from
Jun 9, 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
26 changes: 26 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,13 @@ where
self.into_iter()
}

/// Reverses the order of the map’s key-value pairs in place.
///
/// Computes in **O(n)** time and **O(1)** space.
linclelinkpart5 marked this conversation as resolved.
Show resolved Hide resolved
pub fn reverse(&mut self) {
self.core.reverse()
}

/// Clears the `IndexMap`, returning all key-value pairs as a drain iterator.
/// Keeps the allocated memory for reuse.
pub fn drain(&mut self, range: RangeFull) -> Drain<K, V> {
Expand Down Expand Up @@ -1752,6 +1759,25 @@ impl<K, V> OrderMapCore<K, V> {
self.restore_hash_index(side_index);
}

fn reverse(&mut self) {
self.entries.reverse();

// No need to save hash indices, can easily calculate what they should
// be, given that this is an in-place reversal.
dispatch_32_vs_64!(self => apply_new_index(&mut self.indices, self.entries.len()));

fn apply_new_index<Sz>(indices: &mut [Pos], len: usize)
where
Sz: Size,
{
for pos in indices {
if let Some((i, _)) = pos.resolve::<Sz>() {
pos.set_pos::<Sz>(len - i - 1);
}
}
}
}

fn save_hash_index(&mut self) -> Vec<usize> {
// Temporarily use the hash field in a bucket to store the old index.
// Save the old hash values in `side_index`. Then we can sort
Expand Down
7 changes: 7 additions & 0 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,13 @@ where
}
}

/// Reverses the order of the set’s values in place.
///
/// Computes in **O(n)** time and **O(1)** space.
pub fn reverse(&mut self) {
self.map.reverse()
}

/// Clears the `IndexSet`, returning all values as a drain iterator.
/// Keeps the allocated memory for reuse.
pub fn drain(&mut self, range: RangeFull) -> Drain<T> {
Expand Down
53 changes: 53 additions & 0 deletions tests/quick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,59 @@ quickcheck! {
map.sort_by(|_, v1, _, v2| Ord::cmp(v1, v2));
assert_sorted_by_key(map, |t| t.1);
}

fn reverse(keyvals: Large<Vec<(i8, i8)>>) -> () {
let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec());

fn generate_answer(input: &Vec<(i8, i8)>) -> Vec<(i8, i8)> {
// to mimic what `IndexMap::from_iter` does:
// need to get (A) the unique keys in forward order, and (B) the
// last value of each of those keys.

// create (A): an iterable that yields the unique keys in ltr order
let mut seen_keys = HashSet::new();
let unique_keys_forward = input.iter().filter_map(move |(k, _)| {
if seen_keys.contains(k) { None }
else { seen_keys.insert(*k); Some(*k) }
});

// create (B): a mapping of keys to the last value seen for that key
// this is the same as reversing the input and taking the first
// value seen for that key!
let mut last_val_per_key = HashMap::new();
for &(k, v) in input.iter().rev() {
if !last_val_per_key.contains_key(&k) {
last_val_per_key.insert(k, v);
}
}

// iterate over the keys in (A) in order, and match each one with
// the corresponding last value from (B)
let mut ans: Vec<_> = unique_keys_forward
.map(|k| (k, *last_val_per_key.get(&k).unwrap()))
.collect();

// finally, since this test is testing `.reverse()`, reverse the
// answer in-place
ans.reverse();

ans
}

let answer = generate_answer(&keyvals.0);

// perform the work
map.reverse();

// check it contains all the values it should
for &(key, val) in &answer {
assert_eq!(map[&key], val);
}

// check the order
let mapv = Vec::from_iter(map);
assert_eq!(answer, mapv);
}
}

fn assert_sorted_by_key<I, Key, X>(iterable: I, key: Key)
Expand Down