use crate::ops::*;
const MAX_OPS: usize = 1_000_000;
const MAX_DELETE_OPS: usize = MAX_OPS * 2;
#[derive(Debug)]
pub struct Text {
value: String,
num_ops: usize,
operation_stack: Vec<UndoableOperation>,
}
impl Text {
pub fn new(init: impl AsRef<str>, num_ops: usize) -> Self {
Self {
value: init.as_ref().into(),
num_ops,
operation_stack: vec![],
}
}
pub fn apply(&mut self, ops: Vec<Operation>) {
assert!(
ops.len() <= MAX_OPS,
format!(
"The input exceeds the max number of operations permitted. ({})",
MAX_OPS
)
);
assert!(
ops.len() == self.num_ops,
format!("The provided count doesn't match the number of valid operations parsed. (count = {}, valid operations = {})", self.num_ops, ops.len())
);
let mut delete_count = 0_usize;
for op in ops {
match op {
Operation::Append(val) => {
self.value.push_str(val);
self.operation_stack
.push(UndoableOperation::Append(val.len()));
}
Operation::Delete(n) if n <= self.value.len() => {
delete_count += n;
assert!(
delete_count <= MAX_DELETE_OPS,
format!("The input exceeds the max number of characters which can be deleted. ({})", MAX_DELETE_OPS)
);
let mut deleted = vec![];
for _ in 0..n {
deleted.push(self.value.pop().unwrap() as u8);
}
self.operation_stack
.push(UndoableOperation::Delete(deleted));
}
Operation::Print(i) if i <= self.value.len() => {
println!("{}", self.value.chars().nth(i - 1).unwrap());
}
Operation::Undo => {
if let Some(op) = self.operation_stack.pop() {
match op {
UndoableOperation::Append(n) => {
for _ in 0..n {
self.value.pop();
}
}
UndoableOperation::Delete(mut val) => {
val.reverse();
val.iter().for_each(|c| self.value.push(*c as char));
}
}
}
}
_ => {}
}
}
}
pub fn output(self) -> String {
self.value
}
}