Skip to content

Instantly share code, notes, and snippets.

@jonpalmisc
Created October 3, 2021 06:31
Show Gist options
  • Save jonpalmisc/ed3708deb60070dd332fbfa123c62f3f to your computer and use it in GitHub Desktop.
Save jonpalmisc/ed3708deb60070dd332fbfa123c62f3f to your computer and use it in GitHub Desktop.
Rust: DataView
/// DataView wraps a vector and provides a multi-cursor interface over it.
#[derive(Clone, Debug)]
pub struct DataView<'a, T> {
data: &'a Vec<T>,
pivot_pos: usize,
cursor_pos: usize,
}
#[allow(dead_code)]
impl<'a, T: std::cmp::PartialEq + std::clone::Clone> DataView<'a, T> {
/// Create a new DataView backed by the given vector.
pub fn new(data: &'a Vec<T>) -> Self {
DataView {
data,
pivot_pos: 0,
cursor_pos: 0,
}
}
/// Get the underlying data.
pub fn data(&self) -> &'a Vec<T> {
self.data
}
/// Get the length of the underlying data.
pub fn len(&self) -> usize {
self.data.len()
}
/// Get the index of the cursor.
pub fn cursor_pos(&self) -> usize {
self.cursor_pos
}
/// Get the index of the pivot.
pub fn pivot_pos(&self) -> usize {
self.pivot_pos
}
/// Get at the element under the cursor. Will return `None` if the cursor is
/// past the end of the data.
pub fn peek(&self) -> Option<&T> {
self.data.get(self.cursor_pos)
}
/// Peek at the next N elements from the cursor. Will return `None` if
/// cursor index + N is past the end of the data.
pub fn peek_many(&self, n: usize) -> Option<&[T]> {
if self.cursor_pos + n >= self.data.len() {
None
} else {
Some(&self.data[self.cursor_pos..self.cursor_pos + n])
}
}
/// Get the element under the cursor, then advance the cursor. This method
/// can potentially advance the cursor to an invalid index. Will return
/// `None` if the cursor is past the end of the data.
pub fn next(&mut self) -> Option<&T> {
self.cursor_pos += 1;
self.data.get(self.cursor_pos - 1)
}
/// Shorthand for doing `next()` then `reset_pivot()`.
pub fn next_and_reset(&mut self) -> Option<&T> {
self.cursor_pos += 1;
self.pivot_pos = self.cursor_pos;
self.data.get(self.cursor_pos - 1)
}
/// Advance the cursor to skip N elements.
pub fn skip(&mut self, n: usize) {
self.cursor_pos += n;
}
/// Advance the pivot to the cursor. This method can potentially advance the
/// pivot to an invalid index if the cursor is already at an invalid index.
pub fn reset_pivot(&mut self) {
self.pivot_pos = self.cursor_pos
}
/// Get the elements between the pivot and the cursor.
pub fn window(&self) -> Option<&[T]> {
if self.pivot_pos >= self.len() || self.cursor_pos >= self.len() {
None
} else {
Some(&self.data[self.pivot_pos..self.cursor_pos])
}
}
/// Get the elements between the pivot and the cursor as a Vec<T>.
pub fn owned_window(&self) -> Option<Vec<T>> {
self.window().map(|w| w.to_vec())
}
/// Move the cursor until the next element is (not) in the given set.
pub fn advance_set(&mut self, set: &[T], include: bool) {
while let Some(c) = self.peek() {
if include == set.contains(c) && self.next().is_some() {
continue;
}
break;
}
}
/// Move the cursor each time the test function returns true.
pub fn advance_while(&mut self, test: fn(&T) -> bool) {
while let Some(t) = self.peek() {
if test(t) && self.next().is_some() {
continue;
}
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment