[otTraverse] allow to use custom callback to iterate over subtables

This commit is contained in:
Cosimo Lupo 2023-03-08 19:13:48 +00:00
parent 92fbac8a64
commit 7433c5dbb9
No known key found for this signature in database
GPG Key ID: DF65A8A5A119C9A8

View File

@ -31,6 +31,9 @@ def dfs_base_table(
root_accessor: Optional[str] = None, root_accessor: Optional[str] = None,
skip_root: bool = False, skip_root: bool = False,
predicate: Optional[Callable[[SubTablePath], bool]] = None, predicate: Optional[Callable[[SubTablePath], bool]] = None,
iter_subtables_fn: Optional[
Callable[[BaseTable], Iterable[BaseTable.SubTableEntry]]
] = None,
) -> Iterable[SubTablePath]: ) -> Iterable[SubTablePath]:
"""Depth-first search tree of BaseTables. """Depth-first search tree of BaseTables.
@ -43,6 +46,9 @@ def dfs_base_table(
predicate (Optional[Callable[[SubTablePath], bool]]): function to filter out predicate (Optional[Callable[[SubTablePath], bool]]): function to filter out
paths. If True, the path is yielded and its subtables are added to the paths. If True, the path is yielded and its subtables are added to the
queue. If False, the path is skipped and its subtables are not traversed. queue. If False, the path is skipped and its subtables are not traversed.
iter_subtables_fn (Optional[Callable[[BaseTable], Iterable[BaseTable.SubTableEntry]]]):
function to iterate over subtables of a table. If None, the default
BaseTable.iterSubTables() is used.
Yields: Yields:
SubTablePath: tuples of BaseTable.SubTableEntry(name, table, index) namedtuples SubTablePath: tuples of BaseTable.SubTableEntry(name, table, index) namedtuples
@ -56,6 +62,7 @@ def dfs_base_table(
skip_root, skip_root,
predicate, predicate,
lambda frontier, new: frontier.extendleft(reversed(new)), lambda frontier, new: frontier.extendleft(reversed(new)),
iter_subtables_fn,
) )
@ -64,11 +71,14 @@ def bfs_base_table(
root_accessor: Optional[str] = None, root_accessor: Optional[str] = None,
skip_root: bool = False, skip_root: bool = False,
predicate: Optional[Callable[[SubTablePath], bool]] = None, predicate: Optional[Callable[[SubTablePath], bool]] = None,
iter_subtables_fn: Optional[
Callable[[BaseTable], Iterable[BaseTable.SubTableEntry]]
] = None,
) -> Iterable[SubTablePath]: ) -> Iterable[SubTablePath]:
"""Breadth-first search tree of BaseTables. """Breadth-first search tree of BaseTables.
Args: Args:
root (BaseTable): the root of the tree. the root of the tree.
root_accessor (Optional[str]): attribute name for the root table, if any (mostly root_accessor (Optional[str]): attribute name for the root table, if any (mostly
useful for debugging). useful for debugging).
skip_root (Optional[bool]): if True, the root itself is not visited, only its skip_root (Optional[bool]): if True, the root itself is not visited, only its
@ -76,6 +86,9 @@ def bfs_base_table(
predicate (Optional[Callable[[SubTablePath], bool]]): function to filter out predicate (Optional[Callable[[SubTablePath], bool]]): function to filter out
paths. If True, the path is yielded and its subtables are added to the paths. If True, the path is yielded and its subtables are added to the
queue. If False, the path is skipped and its subtables are not traversed. queue. If False, the path is skipped and its subtables are not traversed.
iter_subtables_fn (Optional[Callable[[BaseTable], Iterable[BaseTable.SubTableEntry]]]):
function to iterate over subtables of a table. If None, the default
BaseTable.iterSubTables() is used.
Yields: Yields:
SubTablePath: tuples of BaseTable.SubTableEntry(name, table, index) namedtuples SubTablePath: tuples of BaseTable.SubTableEntry(name, table, index) namedtuples
@ -89,6 +102,7 @@ def bfs_base_table(
skip_root, skip_root,
predicate, predicate,
lambda frontier, new: frontier.extend(new), lambda frontier, new: frontier.extend(new),
iter_subtables_fn,
) )
@ -98,6 +112,9 @@ def _traverse_ot_data(
skip_root: bool, skip_root: bool,
predicate: Optional[Callable[[SubTablePath], bool]], predicate: Optional[Callable[[SubTablePath], bool]],
add_to_frontier_fn: AddToFrontierFn, add_to_frontier_fn: AddToFrontierFn,
iter_subtables_fn: Optional[
Callable[[BaseTable], Iterable[BaseTable.SubTableEntry]]
] = None,
) -> Iterable[SubTablePath]: ) -> Iterable[SubTablePath]:
# no visited because general otData cannot cycle (forward-offset only) # no visited because general otData cannot cycle (forward-offset only)
if root_accessor is None: if root_accessor is None:
@ -108,6 +125,11 @@ def _traverse_ot_data(
def predicate(path): def predicate(path):
return True return True
if iter_subtables_fn is None:
def iter_subtables_fn(table):
return table.iterSubTables()
frontier: Deque[SubTablePath] = deque() frontier: Deque[SubTablePath] = deque()
root_entry = BaseTable.SubTableEntry(root_accessor, root) root_entry = BaseTable.SubTableEntry(root_accessor, root)
@ -116,7 +138,10 @@ def _traverse_ot_data(
else: else:
add_to_frontier_fn( add_to_frontier_fn(
frontier, frontier,
[(root_entry, subtable_entry) for subtable_entry in root.iterSubTables()], [
(root_entry, subtable_entry)
for subtable_entry in iter_subtables_fn(root)
],
) )
while frontier: while frontier:
@ -130,7 +155,7 @@ def _traverse_ot_data(
yield SubTablePath(path) yield SubTablePath(path)
new_entries = [ new_entries = [
path + (subtable_entry,) for subtable_entry in current.iterSubTables() path + (subtable_entry,) for subtable_entry in iter_subtables_fn(current)
] ]
add_to_frontier_fn(frontier, new_entries) add_to_frontier_fn(frontier, new_entries)