From 7b5b3cf82cd406e0fa2e95c2c3e762d85decb40d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 14 Jan 2022 21:29:52 -0800 Subject: [PATCH] Abstract the pretty printer's ringbuffer to be infinitely sized --- compiler/rustc_ast_pretty/src/pp.rs | 36 +++++++--------- compiler/rustc_ast_pretty/src/pp/ring.rs | 53 ++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 compiler/rustc_ast_pretty/src/pp/ring.rs diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 20954a322a578..ad9d15f1ce345 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -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, 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, + buf: RingBuffer, /// 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; } diff --git a/compiler/rustc_ast_pretty/src/pp/ring.rs b/compiler/rustc_ast_pretty/src/pp/ring.rs new file mode 100644 index 0000000000000..7e4e353ef1f8c --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pp/ring.rs @@ -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 { + data: VecDeque, + // Abstract index of data[0] in the infinitely sized queue. + offset: usize, +} + +impl RingBuffer { + 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 Index for RingBuffer { + type Output = T; + fn index(&self, index: usize) -> &Self::Output { + &self.data[index.checked_sub(self.offset).unwrap()] + } +} + +impl IndexMut for RingBuffer { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.data[index.checked_sub(self.offset).unwrap()] + } +}