Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract the pretty printer's ringbuffer to be infinitely sized #92923

Merged
merged 1 commit into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()]
}
}