From 6e8e8a8b23c5489fdb2154029488dfcfe9cba80a Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 17 Nov 2021 17:58:51 +0100 Subject: [PATCH] apollo-parser: optimises performance of peek_n and peek_data_n (#113) * query parsing benchmark * avoid allocations in peek_n and peek_data_n --- crates/apollo-parser/benches/peek_n.rs | 35 ++++++++++++++++++++++++++ crates/apollo-parser/src/parser/mod.rs | 22 ++++++++-------- 2 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 crates/apollo-parser/benches/peek_n.rs diff --git a/crates/apollo-parser/benches/peek_n.rs b/crates/apollo-parser/benches/peek_n.rs new file mode 100644 index 000000000..aadd4df88 --- /dev/null +++ b/crates/apollo-parser/benches/peek_n.rs @@ -0,0 +1,35 @@ +#![feature(test)] +extern crate test; +use apollo_parser::ast; +use test::{black_box, Bencher}; + +#[bench] +fn bench_peek_n(b: &mut Bencher) { + let query = "query ExampleQuery($topProductsFirst: Int) {\n me { \n id\n }\n topProducts(first: $topProductsFirst) {\n name\n price\n inStock\n weight\n test test test test test test test test test test test test }\n}"; + + b.iter(|| { + let parser = apollo_parser::Parser::new(query); + let tree = parser.parse(); + + if !tree.errors().is_empty() { + panic!("error parsing query: {:?}", tree.errors()); + } + let document = tree.document(); + + for definition in document.definitions() { + if let ast::Definition::OperationDefinition(operation) = definition { + let selection_set = operation + .selection_set() + .expect("the node SelectionSet is not optional in the spec; qed"); + for selection in selection_set.selections() { + match selection { + ast::Selection::Field(field) => { + let _selection_set = field.selection_set(); + } + _ => {} + } + } + } + } + }); +} diff --git a/crates/apollo-parser/src/parser/mod.rs b/crates/apollo-parser/src/parser/mod.rs index a6a224335..a4fc152b0 100644 --- a/crates/apollo-parser/src/parser/mod.rs +++ b/crates/apollo-parser/src/parser/mod.rs @@ -195,13 +195,12 @@ impl Parser { /// Peek Token `n` and return its TokenKind. pub(crate) fn peek_n(&self, n: usize) -> Option { - let tok = self - .tokens - .clone() - .into_iter() + self.tokens + .iter() + .rev() .filter(|token| !matches!(token.kind(), TokenKind::Whitespace | TokenKind::Comment)) - .collect::>(); - tok.get(tok.len() - n).map(|token| token.kind()) + .nth(n - 1) + .map(|token| token.kind()) } /// Peek next Token's `data` property. @@ -211,13 +210,12 @@ impl Parser { /// Peek `n` Token's `data` property. pub(crate) fn peek_data_n(&self, n: usize) -> Option { - let tok = self - .tokens - .clone() - .into_iter() + self.tokens + .iter() + .rev() .filter(|token| !matches!(token.kind(), TokenKind::Whitespace | TokenKind::Comment)) - .collect::>(); - tok.get(tok.len() - n).map(|token| token.data().to_string()) + .nth(n - 1) + .map(|token| token.data().to_string()) } }