Cache child sibling lookups
Removes catastrophically quadratic behavior on nodes with very many siblings.
This commit is contained in:
parent
ec31ee967d
commit
2228890d62
@ -814,6 +814,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
|
|||||||
|
|
||||||
* fixed unnecessary slowdown when long list literals where found in a file
|
* fixed unnecessary slowdown when long list literals where found in a file
|
||||||
|
|
||||||
|
* fixed unnecessary slowdown on AST nodes with very many siblings
|
||||||
|
|
||||||
|
|
||||||
### 18.6b2
|
### 18.6b2
|
||||||
|
|
||||||
|
@ -115,8 +115,9 @@ def replace(self, new):
|
|||||||
else:
|
else:
|
||||||
l_children.append(ch)
|
l_children.append(ch)
|
||||||
assert found, (self.children, self, new)
|
assert found, (self.children, self, new)
|
||||||
self.parent.changed()
|
|
||||||
self.parent.children = l_children
|
self.parent.children = l_children
|
||||||
|
self.parent.changed()
|
||||||
|
self.parent.invalidate_sibling_maps()
|
||||||
for x in new:
|
for x in new:
|
||||||
x.parent = self.parent
|
x.parent = self.parent
|
||||||
self.parent = None
|
self.parent = None
|
||||||
@ -143,8 +144,9 @@ def remove(self):
|
|||||||
if self.parent:
|
if self.parent:
|
||||||
for i, node in enumerate(self.parent.children):
|
for i, node in enumerate(self.parent.children):
|
||||||
if node is self:
|
if node is self:
|
||||||
self.parent.changed()
|
|
||||||
del self.parent.children[i]
|
del self.parent.children[i]
|
||||||
|
self.parent.changed()
|
||||||
|
self.parent.invalidate_sibling_maps()
|
||||||
self.parent = None
|
self.parent = None
|
||||||
return i
|
return i
|
||||||
|
|
||||||
@ -157,13 +159,9 @@ def next_sibling(self):
|
|||||||
if self.parent is None:
|
if self.parent is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Can't use index(); we need to test by identity
|
if self.parent.next_sibling_map is None:
|
||||||
for i, child in enumerate(self.parent.children):
|
self.parent.update_sibling_maps()
|
||||||
if child is self:
|
return self.parent.next_sibling_map[id(self)]
|
||||||
try:
|
|
||||||
return self.parent.children[i+1]
|
|
||||||
except IndexError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def prev_sibling(self):
|
def prev_sibling(self):
|
||||||
@ -174,12 +172,9 @@ def prev_sibling(self):
|
|||||||
if self.parent is None:
|
if self.parent is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Can't use index(); we need to test by identity
|
if self.parent.prev_sibling_map is None:
|
||||||
for i, child in enumerate(self.parent.children):
|
self.parent.update_sibling_maps()
|
||||||
if child is self:
|
return self.parent.prev_sibling_map[id(self)]
|
||||||
if i == 0:
|
|
||||||
return None
|
|
||||||
return self.parent.children[i-1]
|
|
||||||
|
|
||||||
def leaves(self):
|
def leaves(self):
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
@ -226,6 +221,7 @@ def __init__(self,type, children,
|
|||||||
for ch in self.children:
|
for ch in self.children:
|
||||||
assert ch.parent is None, repr(ch)
|
assert ch.parent is None, repr(ch)
|
||||||
ch.parent = self
|
ch.parent = self
|
||||||
|
self.invalidate_sibling_maps()
|
||||||
if prefix is not None:
|
if prefix is not None:
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
if fixers_applied:
|
if fixers_applied:
|
||||||
@ -294,6 +290,7 @@ def set_child(self, i, child):
|
|||||||
self.children[i].parent = None
|
self.children[i].parent = None
|
||||||
self.children[i] = child
|
self.children[i] = child
|
||||||
self.changed()
|
self.changed()
|
||||||
|
self.invalidate_sibling_maps()
|
||||||
|
|
||||||
def insert_child(self, i, child):
|
def insert_child(self, i, child):
|
||||||
"""
|
"""
|
||||||
@ -303,6 +300,7 @@ def insert_child(self, i, child):
|
|||||||
child.parent = self
|
child.parent = self
|
||||||
self.children.insert(i, child)
|
self.children.insert(i, child)
|
||||||
self.changed()
|
self.changed()
|
||||||
|
self.invalidate_sibling_maps()
|
||||||
|
|
||||||
def append_child(self, child):
|
def append_child(self, child):
|
||||||
"""
|
"""
|
||||||
@ -312,7 +310,21 @@ def append_child(self, child):
|
|||||||
child.parent = self
|
child.parent = self
|
||||||
self.children.append(child)
|
self.children.append(child)
|
||||||
self.changed()
|
self.changed()
|
||||||
|
self.invalidate_sibling_maps()
|
||||||
|
|
||||||
|
def invalidate_sibling_maps(self):
|
||||||
|
self.prev_sibling_map = None
|
||||||
|
self.next_sibling_map = None
|
||||||
|
|
||||||
|
def update_sibling_maps(self):
|
||||||
|
self.prev_sibling_map = _prev = {}
|
||||||
|
self.next_sibling_map = _next = {}
|
||||||
|
previous = None
|
||||||
|
for current in self.children:
|
||||||
|
_prev[id(current)] = previous
|
||||||
|
_next[id(previous)] = current
|
||||||
|
previous = current
|
||||||
|
_next[id(current)] = None
|
||||||
|
|
||||||
class Leaf(Base):
|
class Leaf(Base):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user