Abstract the pretty printer's ringbuffer to be infinitely sized

This commit is contained in:
David Tolnay 2022-01-14 21:29:52 -08:00
parent ee5d8d37ba
commit 7b5b3cf82c
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
2 changed files with 67 additions and 22 deletions

View File

@ -132,6 +132,9 @@
//! methods called `Printer::scan_*`, and the 'PRINT' process is the
//! method called `Printer::print`.
mod ring;
use ring::RingBuffer;
use std::borrow::Cow;
use std::collections::VecDeque;
use std::fmt;
@ -190,8 +193,7 @@ impl fmt::Display for Token {
}
}
fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
let n = buf.len();
fn buf_str(buf: &RingBuffer<BufEntry>, left: usize, right: usize, lim: usize) -> String {
let mut i = left;
let mut l = lim;
let mut s = String::from("[");
@ -202,7 +204,6 @@ fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
}
s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
i += 1;
i %= n;
}
s.push(']');
s
@ -224,7 +225,6 @@ const SIZE_INFINITY: isize = 0xffff;
pub struct Printer {
out: String,
buf_max_len: usize,
/// Width of lines we're constrained to
margin: isize,
/// Number of spaces left on line
@ -234,7 +234,7 @@ pub struct Printer {
/// Index of right side of input stream
right: usize,
/// Ring-buffer of tokens and calculated sizes
buf: Vec<BufEntry>,
buf: RingBuffer<BufEntry>,
/// Running size of stream "...left"
left_total: isize,
/// Running size of stream "...right"
@ -267,19 +267,16 @@ impl Default for BufEntry {
impl Printer {
pub fn new() -> Self {
let linewidth = 78;
// Yes 55, it makes the ring buffers big enough to never fall behind.
let n: usize = 55 * linewidth;
debug!("Printer::new {}", linewidth);
let mut buf = RingBuffer::new();
buf.advance_right();
Printer {
out: String::new(),
buf_max_len: n,
margin: linewidth as isize,
space: linewidth as isize,
left: 0,
right: 0,
// Initialize a single entry; advance_right() will extend it on demand
// up to `buf_max_len` elements.
buf: vec![BufEntry::default()],
buf,
left_total: 0,
right_total: 0,
scan_stack: VecDeque::new(),
@ -308,8 +305,8 @@ impl Printer {
if self.scan_stack.is_empty() {
self.left_total = 1;
self.right_total = 1;
self.left = 0;
self.right = 0;
self.right = self.left;
self.buf.truncate(1);
} else {
self.advance_right();
}
@ -332,8 +329,8 @@ impl Printer {
if self.scan_stack.is_empty() {
self.left_total = 1;
self.right_total = 1;
self.left = 0;
self.right = 0;
self.right = self.left;
self.buf.truncate(1);
} else {
self.advance_right();
}
@ -400,12 +397,7 @@ impl Printer {
fn advance_right(&mut self) {
self.right += 1;
self.right %= self.buf_max_len;
// Extend the buf if necessary.
if self.right == self.buf.len() {
self.buf.push(BufEntry::default());
}
assert_ne!(self.right, self.left);
self.buf.advance_right();
}
fn advance_left(&mut self) {
@ -437,8 +429,8 @@ impl Printer {
break;
}
self.buf.advance_left();
self.left += 1;
self.left %= self.buf_max_len;
left_size = self.buf[self.left].size;
}

View File

@ -0,0 +1,53 @@
use std::collections::VecDeque;
use std::ops::{Index, IndexMut};
/// A view onto a finite range of an infinitely long sequence of T.
///
/// The Ts are indexed 0..infinity. A RingBuffer begins as a view of elements
/// 0..0 (i.e. nothing). The user of the RingBuffer advances its left and right
/// position independently, although only in the positive direction, and only
/// with left <= right at all times.
///
/// Holding a RingBuffer whose view is elements left..right gives the ability to
/// use Index and IndexMut to access elements i in the infinitely long queue for
/// which left <= i < right.
pub struct RingBuffer<T> {
data: VecDeque<T>,
// Abstract index of data[0] in the infinitely sized queue.
offset: usize,
}
impl<T> RingBuffer<T> {
pub fn new() -> Self {
RingBuffer { data: VecDeque::new(), offset: 0 }
}
pub fn advance_right(&mut self)
where
T: Default,
{
self.data.push_back(T::default());
}
pub fn advance_left(&mut self) {
self.data.pop_front().unwrap();
self.offset += 1;
}
pub fn truncate(&mut self, len: usize) {
self.data.truncate(len);
}
}
impl<T> Index<usize> for RingBuffer<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index.checked_sub(self.offset).unwrap()]
}
}
impl<T> IndexMut<usize> for RingBuffer<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.data[index.checked_sub(self.offset).unwrap()]
}
}