From 40d3e96fb101c1957f800d2cc406bdcd68bbd14e Mon Sep 17 00:00:00 2001 From: DQ Date: Wed, 23 Jun 2021 18:13:42 +0200 Subject: [PATCH] Version 0.6.1 --- src/green/builder.rs | 82 ++++++++++++-------------------------------- src/green/node.rs | 33 ++++++++++++++++++ 2 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/green/builder.rs b/src/green/builder.rs index 81a35dd..167ea3e 100644 --- a/src/green/builder.rs +++ b/src/green/builder.rs @@ -99,12 +99,14 @@ where } } - fn node(&mut self, kind: SyntaxKind, children: It) -> GreenNode - where - It: IntoIterator, - It::IntoIter: ExactSizeIterator, - { - let children = children.into_iter(); + fn node(&mut self, kind: SyntaxKind, children: &[GreenElement]) -> GreenNode { + let mut hasher = FxHasher32::default(); + let mut text_len: TextSize = 0.into(); + for child in children { + text_len += child.text_len(); + child.hash(&mut hasher); + } + let child_hash = hasher.finish() as u32; // Green nodes are fully immutable, so it's ok to deduplicate them. // This is the same optimization that Roslyn does @@ -114,70 +116,30 @@ where // For `libsyntax/parse/parser.rs`, measurements show that deduping saves // 17% of the memory for green nodes! if children.len() <= CHILDREN_CACHE_THRESHOLD { - self.get_cached_node(kind, children) + self.get_cached_node(kind, children, text_len, child_hash) } else { - GreenNode::new(kind, children) + GreenNode::new_with_len_and_hash(kind, children.iter().cloned(), text_len, child_hash) } } /// Creates a [`GreenNode`] by looking inside the cache or inserting /// a new node into the cache if it's a cache miss. - fn get_cached_node(&mut self, kind: SyntaxKind, children: It) -> GreenNode - where - It: IntoIterator, - It::IntoIter: ExactSizeIterator, - { - #[derive(Clone)] - struct ChildrenIter { - data: [Option; CHILDREN_CACHE_THRESHOLD], - idx: usize, - len: usize, - } - - impl ChildrenIter { - fn new() -> Self { - ChildrenIter { - data: [None, None, None], - idx: 0, - len: 0, - } - } - } - - impl Iterator for ChildrenIter { - type Item = GreenElement; - - fn next(&mut self) -> Option { - let item = self.data.get_mut(self.idx)?; - self.idx += 1; - item.take() - } - } - - impl ExactSizeIterator for ChildrenIter { - fn len(&self) -> usize { - self.len - self.idx - } - } - - let mut new_children = ChildrenIter::new(); - let mut hasher = FxHasher32::default(); - let mut text_len: TextSize = 0.into(); - for (i, child) in children.into_iter().enumerate() { - text_len += child.text_len(); - child.hash(&mut hasher); - new_children.data[i] = Some(child); - new_children.len += 1; - } - + #[inline] + fn get_cached_node( + &mut self, + kind: SyntaxKind, + children: &[GreenElement], + text_len: TextSize, + child_hash: u32, + ) -> GreenNode { let head = GreenNodeHead { kind, text_len, - child_hash: hasher.finish() as u32, + child_hash, }; self.nodes .entry(head) - .or_insert_with_key(|head| GreenNode::from_head_and_children(head.clone(), new_children)) + .or_insert_with_key(|head| GreenNode::from_head_and_children(head.clone(), children.iter().cloned())) .clone() } @@ -315,8 +277,8 @@ where #[inline] pub fn finish_node(&mut self) { let (kind, first_child) = self.parents.pop().unwrap(); - let children = self.children.drain(first_child..); - let node = self.cache.node(kind, children); + let node = self.cache.node(kind, &self.children[first_child..]); + self.children.truncate(first_child); self.children.push(node.into()); } diff --git a/src/green/node.rs b/src/green/node.rs index e0b8464..6f0a1c6 100644 --- a/src/green/node.rs +++ b/src/green/node.rs @@ -70,6 +70,39 @@ impl GreenNode { } } + /// Creates a new Node. + #[inline] + pub(super) fn new_with_len_and_hash( + kind: SyntaxKind, + children: I, + text_len: TextSize, + child_hash: u32, + ) -> GreenNode + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let children = children.into_iter().map(PackedGreenElement::from); + let header = HeaderWithLength::new( + GreenNodeHead { + kind, + text_len: 0.into(), + child_hash: 0, + }, + children.len(), + ); + let mut data = Arc::from_header_and_iter(header, children); + + // XXX: fixup `text_len` and `child_hash` after construction, because + // we can't iterate `children` twice. + let header = &mut Arc::get_mut(&mut data).unwrap().header.header; + header.text_len = text_len; + header.child_hash = child_hash; + GreenNode { + data: Arc::into_thin(data), + } + } + #[inline] pub(super) fn from_head_and_children(header: GreenNodeHead, children: I) -> GreenNode where