mirror of
https://github.com/RGBCube/cstree
synced 2025-07-27 09:07:44 +00:00
Version 0.6.1
This commit is contained in:
parent
1728df28f8
commit
40d3e96fb1
2 changed files with 55 additions and 60 deletions
|
@ -99,12 +99,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn node<It>(&mut self, kind: SyntaxKind, children: It) -> GreenNode
|
||||
where
|
||||
It: IntoIterator<Item = GreenElement>,
|
||||
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<It>(&mut self, kind: SyntaxKind, children: It) -> GreenNode
|
||||
where
|
||||
It: IntoIterator<Item = GreenElement>,
|
||||
It::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
#[derive(Clone)]
|
||||
struct ChildrenIter {
|
||||
data: [Option<GreenElement>; 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<Self::Item> {
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,39 @@ impl GreenNode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new Node.
|
||||
#[inline]
|
||||
pub(super) fn new_with_len_and_hash<I>(
|
||||
kind: SyntaxKind,
|
||||
children: I,
|
||||
text_len: TextSize,
|
||||
child_hash: u32,
|
||||
) -> GreenNode
|
||||
where
|
||||
I: IntoIterator<Item = GreenElement>,
|
||||
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<I>(header: GreenNodeHead, children: I) -> GreenNode
|
||||
where
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue