Skip to content

Commit

Permalink
Abstract the pretty printer's ringbuffer to be infinitely sized
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Jan 17, 2022
1 parent ee5d8d3 commit 7b5b3cf
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 22 deletions.
36 changes: 14 additions & 22 deletions compiler/rustc_ast_pretty/src/pp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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("[");
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
53 changes: 53 additions & 0 deletions compiler/rustc_ast_pretty/src/pp/ring.rs
Original file line number Diff line number Diff line change
@@ -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()]
}
}

0 comments on commit 7b5b3cf

Please sign in to comment.