|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import absolute_import |
|
|
from __future__ import print_function |
|
|
from __future__ import unicode_literals |
|
|
|
|
|
|
|
|
class STARTEVENT: |
|
|
pass |
|
|
|
|
|
|
|
|
class ENDEVENT: |
|
|
pass |
|
|
|
|
|
|
|
|
def prefix_event(level_prefixed_items, root_item=None): |
|
|
''' convert iterable of (level, item) into iterable of (event, item) |
|
|
''' |
|
|
baselevel = None |
|
|
stack = [root_item] |
|
|
for level, item in level_prefixed_items: |
|
|
if baselevel is None: |
|
|
baselevel = level |
|
|
level = 0 |
|
|
else: |
|
|
level -= baselevel |
|
|
|
|
|
while level + 1 < len(stack): |
|
|
yield ENDEVENT, stack.pop() |
|
|
while len(stack) < level + 1: |
|
|
raise Exception('invalid level: %d, %d, %s' % |
|
|
(level, len(stack) - 1, item)) |
|
|
assert(len(stack) == level + 1) |
|
|
|
|
|
stack.append(item) |
|
|
yield STARTEVENT, item |
|
|
|
|
|
while 1 < len(stack): |
|
|
yield ENDEVENT, stack.pop() |
|
|
|
|
|
|
|
|
def prefix_ancestors(event_prefixed_items, root_item=None): |
|
|
''' convert iterable of (event, item) into iterable of (ancestors, item) |
|
|
''' |
|
|
stack = [root_item] |
|
|
for event, item in event_prefixed_items: |
|
|
if event is STARTEVENT: |
|
|
yield stack, item |
|
|
stack.append(item) |
|
|
elif event is ENDEVENT: |
|
|
stack.pop() |
|
|
|
|
|
|
|
|
def prefix_ancestors_from_level(level_prefixed_items, root_item=None): |
|
|
''' convert iterable of (level, item) into iterable of (ancestors, item) |
|
|
|
|
|
@param level_prefixed items: iterable of tuple(level, item) |
|
|
@return iterable of tuple(ancestors, item) |
|
|
''' |
|
|
baselevel = None |
|
|
stack = [root_item] |
|
|
for level, item in level_prefixed_items: |
|
|
if baselevel is None: |
|
|
baselevel = level |
|
|
level = 0 |
|
|
else: |
|
|
level -= baselevel |
|
|
|
|
|
while level + 1 < len(stack): |
|
|
stack.pop() |
|
|
while len(stack) < level + 1: |
|
|
raise Exception('invalid level: %d, %d, %s' % |
|
|
(level, len(stack) - 1, item)) |
|
|
assert(len(stack) == level + 1) |
|
|
|
|
|
yield stack, item |
|
|
stack.append(item) |
|
|
|
|
|
|
|
|
def build_subtree(event_prefixed_items): |
|
|
''' build a tree from (event, item) stream |
|
|
|
|
|
Example Scenario:: |
|
|
|
|
|
... |
|
|
(STARTEVENT, rootitem) # should be consumed by the caller |
|
|
--- call build_subtree() --- |
|
|
(STARTEVENT, child1) # consumed by build_subtree() |
|
|
(STARTEVENT, grandchild) # (same) |
|
|
(ENDEVENT, grandchild) # (same) |
|
|
(ENDEVENT, child1) # (same) |
|
|
(STARTEVENT, child2) # (same) |
|
|
(ENDEVENT, child2) # (same) |
|
|
(ENDEVENT, rootitem) # same, buildsubtree() returns |
|
|
--- build_subtree() returns --- |
|
|
(STARTEVENT, another_root) |
|
|
... |
|
|
|
|
|
result will be (rootitem, [(child1, [(grandchild, [])]), |
|
|
(child2, [])]) |
|
|
|
|
|
''' |
|
|
childs = [] |
|
|
for event, item in event_prefixed_items: |
|
|
if event == STARTEVENT: |
|
|
childs.append(build_subtree(event_prefixed_items)) |
|
|
elif event == ENDEVENT: |
|
|
return item, childs |
|
|
|
|
|
|
|
|
def iter_subevents(event_prefixed_items): |
|
|
level = 0 |
|
|
for event, item in event_prefixed_items: |
|
|
yield event, item |
|
|
if event is STARTEVENT: |
|
|
level += 1 |
|
|
elif event is ENDEVENT: |
|
|
if level > 0: |
|
|
level -= 1 |
|
|
else: |
|
|
return |
|
|
|
|
|
|
|
|
def tree_events(rootitem, childs): |
|
|
''' generate tuples of (event, item) from a tree |
|
|
''' |
|
|
yield STARTEVENT, rootitem |
|
|
for k in tree_events_multi(childs): |
|
|
yield k |
|
|
yield ENDEVENT, rootitem |
|
|
|
|
|
|
|
|
def tree_events_multi(trees): |
|
|
''' generate tuples of (event, item) from trees |
|
|
''' |
|
|
for rootitem, childs in trees: |
|
|
for k in tree_events(rootitem, childs): |
|
|
yield k |
|
|
|