Skip to content

Instantly share code, notes, and snippets.

@FuuuOverclocking
Created February 2, 2023 03:36
Show Gist options
  • Save FuuuOverclocking/a8fa886948ed421de6652cda8ec6ff99 to your computer and use it in GitHub Desktop.
Save FuuuOverclocking/a8fa886948ed421de6652cda8ec6ff99 to your computer and use it in GitHub Desktop.
[Rust] Traverse and consume the vector in the given order
use std::mem::{self, ManuallyDrop};
use std::ptr;
/// Traverse the vector in the given order. The vector will be consumed, and its
/// elements will be moved in when calling the closure. `order` must contain all
/// values in the range `0..vec.len()` without repetition or omission, but the
/// order of elements can be arbitrary.
///
/// # Example
/// ```
/// use {YOUR CRATE NAME}::consume_vec_in_order;
///
/// let src = vec![
/// "0".to_string(),
/// "1".to_string(),
/// "2".to_string(),
/// "3".to_string(),
/// "4".to_string(),
/// ];
/// let mut dst = vec![];
///
/// consume_vec_in_order(
/// src,
/// &[2, 1, 3, 0, 4],
/// |elem| dst.push(elem),
/// );
/// assert_eq!(dst, vec!["2", "1", "3", "0", "4"]);
/// ```
pub fn consume_vec_in_order<T>(vec: Vec<T>, order: &[usize], mut cb: impl FnMut(T)) {
// Check whether `order` contains all numbers in 0..len without repetition
// or omission.
if cfg!(debug_assertions) {
use std::collections::HashSet;
let n = order.len();
if n != vec.len() {
panic!("The length of `order` is not equal to that of `vec`.");
}
let mut set = HashSet::<usize>::new();
for &idx in order {
if idx >= n {
panic!("`{idx}` in the `order` is out of range (0..{n}).");
} else if set.contains(&idx) {
panic!("`order` contains the repeated element `{idx}`");
} else {
set.insert(idx);
}
}
}
unsafe {
for &idx in order {
let s = ptr::read(vec.get_unchecked(idx));
cb(s);
}
let vec: Vec<ManuallyDrop<T>> = mem::transmute(vec);
drop(vec);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment