From 65fcb6fde3583ded9626d44930278068c485bea1 Mon Sep 17 00:00:00 2001 From: Ethiraric Date: Fri, 14 Jun 2024 18:25:40 +0200 Subject: [PATCH] Move `next_can_be_plain_scalar` as free fn. This is, for some reason, a huge pessimization. `rustc` fails to optimize it as well as it did when it was part of `Scanner`. This is however kinda needed if I want to avoid having this code duplicated in every implementation of the input. --- parser/src/scanner.rs | 53 ++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/parser/src/scanner.rs b/parser/src/scanner.rs index 9c74e7c..7e37976 100644 --- a/parser/src/scanner.rs +++ b/parser/src/scanner.rs @@ -2144,7 +2144,13 @@ impl Scanner { )); } - if !is_blank_or_breakz(self.input.peek()) && self.next_can_be_plain_scalar() { + if !is_blank_or_breakz(self.input.peek()) + && next_can_be_plain_scalar( + self.input.peek(), + self.input.peek_nth(1), + self.flow_level > 0, + ) + { if self.leading_whitespace { if leading_break.is_empty() { string.push_str(&leading_break); @@ -2179,7 +2185,16 @@ impl Scanner { // hence the `for` loop looping `self.input.bufmaxlen() - 1` times. self.input.lookahead(self.input.bufmaxlen()); for _ in 0..self.input.bufmaxlen() - 1 { - if is_blank_or_breakz(self.input.peek()) || !self.next_can_be_plain_scalar() + // We need to have `c` and `nc`'s assignations at the beginning of the + // loop. If at the end of it, we will peek one index further than we + // looked ahead. On the first iteration of the loop, `c` is a characte we + // already pushed in `string` a bit earlier. + if is_blank_or_breakz(self.input.peek()) + || !next_can_be_plain_scalar( + self.input.peek(), + self.input.peek_nth(1), + self.flow_level > 0, + ) { end = true; break; @@ -2507,25 +2522,6 @@ impl Scanner { Ok(()) } - /// Check whether the next characters may be part of a plain scalar. - /// - /// This function assumes we are not given a blankz character. - // For some reason, `#[inline]` is not enough. - #[allow(clippy::inline_always)] - #[inline(always)] - fn next_can_be_plain_scalar(&self) -> bool { - match self.input.peek() { - // indicators can end a plain scalar, see 7.3.3. Plain Style - ':' if is_blank_or_breakz(self.input.peek_nth(1)) - || (self.flow_level > 0 && is_flow(self.input.peek_nth(1))) => - { - false - } - c if self.flow_level > 0 && is_flow(c) => false, - _ => true, - } - } - /// Return whether the scanner is inside a block but outside of a flow sequence. fn is_within_block(&self) -> bool { !self.indents.is_empty() @@ -2595,6 +2591,21 @@ pub enum Chomping { Keep, } +/// Check whether the next characters may be part of a plain scalar. +/// +/// This function assumes we are not given a blankz character. +// For some reason, `#[inline]` is not enough. +#[allow(clippy::inline_always)] +#[inline(always)] +pub fn next_can_be_plain_scalar(c: char, nc: char, in_flow: bool) -> bool { + match c { + // indicators can end a plain scalar, see 7.3.3. Plain Style + ':' if is_blank_or_breakz(nc) || (in_flow && is_flow(nc)) => false, + c if in_flow && is_flow(c) => false, + _ => true, + } +} + #[cfg(test)] mod test { #[test]