diff --git a/SuperScriptDecorator/DecoratorBB.py b/SuperScriptDecorator/DecoratorBB.py index 2876341..d3bb091 100644 --- a/SuperScriptDecorator/DecoratorBB.py +++ b/SuperScriptDecorator/DecoratorBB.py @@ -1,16 +1,35 @@ import sqlite3, collections import DecoratorData, DecoratorConst -class IntermediateTreeNode(object): - def __init__(self): - self.m_FirstVisit: bool = True - self.m_LoactedLayer: int = DecoratorData.TreeLayout.NO_REFERENCE_LAYER - self.m_LocatedPos: int = DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER - self.m_Collection: collections.deque[int] = collections.deque() +class BuildBBEnvironment(object): + def __init__(self, + cursor: sqlite3.Cursor, tree: DecoratorData.TreeLayout[DecoratorData.BBTreeNodeWrapper], + depth: int, query_bb: int): -class IntermediateOperDownwardSearch(object): - def __init__(self): - self.m_Collection: collections.deque[int] = collections.deque() + self.m_Cursor: sqlite3.Cursor = cursor + self.m_Tree: DecoratorData.TreeLayout[DecoratorData.BBTreeNodeWrapper] = tree + self.m_Depth: int = depth + self.m_QueryBB: int = query_bb + +class BuildOperEnvironment(object): + def __init__(self, + cursor: sqlite3.Cursor, tree: DecoratorData.TreeLayout[DecoratorData.OperTreeNodeWrapper], + depth: int, query_oper: int): + + self.m_Cursor: sqlite3.Cursor = cursor + self.m_Tree: DecoratorData.TreeLayout[DecoratorData.OperTreeNodeWrapper] = tree + self.m_Depth: int = depth + self.m_QueryOper: int = query_oper + +class FindOperRootEnvironment(object): + def __init__(self, + cursor: sqlite3.Cursor, walked_oper: set[int], + depth: int, query_oper: int): + + self.m_Cursor: sqlite3.Cursor = cursor + self.m_WalkedOper: set[int] = walked_oper + self.m_Depth: int = depth + self.m_QueryOper: int = query_oper class BlocksFactory(object): def __init__(self, db: sqlite3.Connection, graph: DecoratorData.GraphResult): @@ -49,222 +68,201 @@ class BlocksFactory(object): cursor.close() - def __FindBBBottomOperRoot(self, start_pOut: tuple[int]) -> tuple[int]: - cursor: sqlite3.Cursor = self.m_Db.cursor() - cursor_outget: sqlite3.Cursor = self.m_Db.cursor() + def __RecursiveFindOperRoot(self, envir: FindOperRootEnvironment) -> tuple[int]: + envir.m_Cursor.execute('SELECT [output_obj], [output_type], [output_is_bb] FROM [script_pLink] WHERE ([input_obj] == ? AND [input_is_bb] == ? AND NOT (([output_type] == ? OR [output_type] == ?) AND [output_is_bb] == ?) AND [parent] == ?);', + (envir.m_QueryOper, (DecoratorConst.Export_Boolean.TRUE if envir.m_Depth == 0 else DecoratorConst.Export_Boolean.FALSE), + DecoratorConst.Export_pLink_InputOutputType.PIN, DecoratorConst.Export_pLink_InputOutputType.PTARGET, DecoratorConst.Export_Boolean.TRUE, # filter all BB's pIn + self.m_Graph.m_GraphCKID) + ) - # prepare something - stack: collections.deque[int] = collections.deque() - procedOut: set[int] = set() - result: set[int] = set() - # prepare start symbol - stack.extend(start_pOut) + opers: set[int] = set() + results: set[int] = set() - # analyze - while len(stack) != 0: - # peek again - pout: int = stack.pop() + # read datas + for (output_obj, output_type, output_is_bb, ) in envir.m_Cursor.fetchall(): + # check dup + if output_obj in envir.m_WalkedOper: + continue + envir.m_WalkedOper.add(output_obj) - # search this pOut in pLink - cursor.execute('SELECT [output], [output_obj], [output_type], [output_is_bb] FROM [script_pLink] WHERE ([input] == ? AND NOT (([output_type] == ? OR [output_type] == ?) AND [output_is_bb] == ?) AND [parent] == ?);', - (pout, - DecoratorConst.Export_pLink_InputOutputType.PIN, DecoratorConst.Export_pLink_InputOutputType.PTARGET, DecoratorConst.Export_Boolean.TRUE, # filter all BB's pIn - self.m_Graph.m_GraphCKID) - ) + if output_type == DecoratorConst.Export_pLink_InputOutputType.PIN: + # this is a oper. find its pOut and add into stack + opers.add(output_obj) + else: + # this oper point to non-pIn, should be add into result + results.add(output_obj) - # read datas - for (output, output_obj, output_type, output_is_bb, ) in cursor.fetchall(): - # check dup - if output in procedOut: - continue - procedOut.add(output) + # recursive calling opers to get root + for oper in opers: + results.update(self.__RecursiveFindOperRoot(FindOperRootEnvironment( + envir.m_Cursor, envir.m_WalkedOper, envir.m_Depth + 1, oper + ))) + + return tuple(i for i in results) - if output_type == DecoratorConst.Export_pLink_InputOutputType.PIN and output_is_bb == DecoratorConst.Export_Boolean.FALSE: - # this is a oper. find its pOut and add into stack - cursor_outget.execute('SELECT [thisobj] FROM [script_pOut] WHERE [parent] == ?;', - (output_obj, ) - ) - for (thisobj, ) in cursor_outget.fetchall(): - stack.append(thisobj) - else: - # this oper point to non-pIn, should be add into result - result.add(output_obj) - - # free cursor and return - cursor.close() - cursor_outget.close() - return tuple(i for i in result) - - def __BuildOper(self, tree: DecoratorData.TreeLayout[DecoratorData.OperTreeNode], start_oper: int): - # prepare stack and start condition - stack: collections.deque[IntermediateTreeNode] = collections.deque() - - # check whether this BB has been processed - if start_oper not in self.__AllOper: - return - self.__AllOper.remove(start_oper) - - # create cursor - cursor: sqlite3.Cursor = self.m_Db.cursor() - - # create new layer and insert it - tree.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) - tree.NewItem(self.m_Graph.m_BlockDict[start_oper]) - - # prepare stack data - start_oper_data: IntermediateTreeNode = IntermediateTreeNode() - start_oper_data.m_LoactedLayer = tree.GetCurrentLayerIndex() - start_oper_data.m_LocatedPos = tree.GetCurrentItemIndex() - cursor.execute("SELECT [input_obj] FROM [script_pLink] WHERE ([output_obj] == ? AND [output_type] == ? AND [input_type] == ? AND [input_is_bb] == ? AND [parent] = ?);", - (start_oper, DecoratorConst.Export_pLink_InputOutputType.PIN, # order pOper's pIn + def __RecursiveBuildOper(self, envir: BuildOperEnvironment): + envir.m_Cursor.execute("SELECT [input_obj] FROM [script_pLink] WHERE ([output_obj] == ? AND [output_type] == ? AND [input_type] == ? AND [input_is_bb] == ? AND [parent] = ?);", + (envir.m_QueryOper, DecoratorConst.Export_pLink_InputOutputType.PIN, # order pOper's pIn DecoratorConst.Export_pLink_InputOutputType.POUT, DecoratorConst.Export_Boolean.FALSE, # order pOper's pOut self.m_Graph.m_GraphCKID, ) ) - for (input_obj, ) in cursor.fetchall(): - start_oper_data.m_Collection.append(input_obj) - stack.append(start_oper_data) - # start analyze - while len(stack) != 0: - # pick stack and decide whether pop this - stack_entry: IntermediateTreeNode = stack[-1] - if len(stack_entry.m_Collection) == 0: - stack.pop() - continue + gottenOper: list[int] = [] + for (input_obj, ) in envir.m_Cursor.fetchall(): + if input_obj in self.__AllOper: + self.__AllOper.remove(input_obj) + gottenOper.append(input_obj) - # pick a new Oper from collection. - # check whether it need process - oper_id: int = stack_entry.m_Collection[-1] - if oper_id not in self.__AllOper: - stack_entry.m_Collection.pop() - continue - self.__AllOper.remove(oper_id) - - # get corresponding tree node - tree_node: DecoratorData.BBTreeNode = self.m_Graph.m_BlockDict[oper_id] - - # start proc Oper - # create new stack entry - oper_data: IntermediateTreeNode = IntermediateTreeNode() - # push tree node into tree layout and get corresponding index. - # create new layer according to whether first visit - if stack_entry.m_FirstVisit: - tree.NewItem(tree_node) - - oper_data.m_LoactedLayer = stack_entry.m_LoactedLayer - oper_data.m_LocatedPos = stack_entry.m_LocatedPos + 1 - # reset first visit - stack_entry.m_FirstVisit = False - else: - tree.NewLayer(stack_entry.m_LoactedLayer, stack_entry.m_LocatedPos) - tree.NewItem(tree_node) - - oper_data.m_LoactedLayer = tree.GetCurrentLayerIndex() - oper_data.m_LocatedPos = tree.GetCurrentItemIndex() - # query and fill stack entry data - cursor.execute("SELECT [input_obj] FROM [script_pLink] WHERE ([output_obj] == ? AND [output_type] == ? AND [input_type] == ? AND [input_is_bb] == ? AND [parent] = ?);", - (oper_id, DecoratorConst.Export_pLink_InputOutputType.PIN, # order pOper's pIn - DecoratorConst.Export_pLink_InputOutputType.POUT, DecoratorConst.Export_Boolean.FALSE, # order pOper's pOut - self.m_Graph.m_GraphCKID, ) - ) - for (output_obj, ) in cursor.fetchall(): - oper_data.m_Collection.append(output_obj) - stack.append(oper_data) - - cursor.close() - - def __BuildBB(self, tree: DecoratorData.TreeLayout[DecoratorData.BBTreeNode], start_bb: int): - # prepare stack and start condition - stack: collections.deque[IntermediateTreeNode] = collections.deque() - - # check whether this BB has been processed - if start_bb not in self.__AllBB: + if len(gottenOper) == 0: return - self.__AllBB.remove(start_bb) - # create cursor - cursor: sqlite3.Cursor = self.m_Db.cursor() + if envir.m_Depth == 0: + # if depth == 0, all item should start from a new layer + for item in gottenOper: + envir.m_Tree.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) + envir.m_Tree.NewItem(self.m_Graph.m_BlockDict[item]) + self.__RecursiveBuildOper(BuildOperEnvironment( + envir.m_Cursor, envir.m_Tree, envir.m_Depth + 1, item + )) + else: + # otherwise, only non-first node need new layer + # proc first node + first: int = gottenOper[0] + envir.m_Tree.NewItem(self.m_Graph.m_BlockDict[first]) + self.__RecursiveBuildOper(BuildOperEnvironment( + envir.m_Cursor, envir.m_Tree, envir.m_Depth + 1, first + )) - # create new layer and insert it - tree.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) - tree.NewItem(self.m_Graph.m_BlockDict[start_bb]) + # get layer and pos + cur_layer = envir.m_Tree.GetCurrentLayerIndex() + cur_idx = envir.m_Tree.GetCurrentItemIndex() - # prepare stack data - start_bb_data: IntermediateTreeNode = IntermediateTreeNode() - start_bb_data.m_LoactedLayer = tree.GetCurrentLayerIndex() - start_bb_data.m_LocatedPos = tree.GetCurrentItemIndex() - cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [parent] = ?) ORDER BY [input_index] ASC;", - (start_bb, DecoratorConst.Export_bLink_InputOutputType.OUTPUT, self.m_Graph.m_GraphCKID, ) + # proc other node + for other in gottenOper[1:]: + envir.m_Tree.NewLayer(cur_layer, cur_idx) + envir.m_Tree.NewItem(self.m_Graph.m_BlockDict[other]) + self.__RecursiveBuildOper(BuildOperEnvironment( + envir.m_Cursor, envir.m_Tree, envir.m_Depth + 1, other + )) + + def __RecursiveBuildBB(self, envir: BuildBBEnvironment): + # query all link for next bb + envir.m_Cursor.execute('SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [parent] = ?) ORDER BY [input_index] ASC;', + (envir.m_QueryBB, + (DecoratorConst.Export_bLink_InputOutputType.INPUT if envir.m_Depth == 0 else DecoratorConst.Export_bLink_InputOutputType.OUTPUT), + self.m_Graph.m_GraphCKID) ) - for (output_obj, ) in cursor.fetchall(): - start_bb_data.m_Collection.append(output_obj) - stack.append(start_bb_data) - # start analyze - while len(stack) != 0: - # pick stack and decide whether pop this - stack_entry: IntermediateTreeNode = stack[-1] - if len(stack_entry.m_Collection) == 0: - stack.pop() - continue + # filter useless bb + gottenBB: list[int] = [] + for (output_obj, ) in envir.m_Cursor.fetchall(): + if output_obj in self.__AllBB: + self.__AllBB.remove(output_obj) + gottenBB.append(output_obj) - # pick a new BB from collection. - # check whether it need process - bb_id: int = stack_entry.m_Collection[-1] - if bb_id not in self.__AllBB: - stack_entry.m_Collection.pop() - continue - self.__AllBB.remove(bb_id) + if len(gottenBB) == 0: + return - # get corresponding tree node - tree_node: DecoratorData.BBTreeNode = self.m_Graph.m_BlockDict[bb_id] + # we need process this BB related opers now + # for every item + for bbid in gottenBB: + bb: DecoratorData.BBTreeNodeWrapper = self.m_Graph.m_BlockDict[bbid] + # upper opers + self.__RecursiveBuildOper(BuildOperEnvironment( + envir.m_Cursor, bb.m_UpperOper, 0, bbid + )) + # lower opers + lower_root: tuple[int] = self.__RecursiveFindOperRoot(FindOperRootEnvironment( + envir.m_Cursor, set(), 0, bbid + )) + for operid in lower_root: + # we need add it manually + self.__AllOper.remove(operid) + bb.m_LowerOper.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) + bb.m_LowerOper.NewItem(self.m_Graph.m_BlockDict[operid]) - # start proc BB - # create new stack entry - bb_data: IntermediateTreeNode = IntermediateTreeNode() - # push tree node into tree layout and get corresponding index. - # create new layer according to whether first visit - if stack_entry.m_FirstVisit: - tree.NewItem(tree_node) + # gotten "root" is oper's CKID, so use depth 1 to cheat this function + self.__RecursiveBuildOper(BuildOperEnvironment( + envir.m_Cursor, bb.m_LowerOper, 1, operid + )) - bb_data.m_LoactedLayer = stack_entry.m_LoactedLayer - bb_data.m_LocatedPos = stack_entry.m_LocatedPos + 1 - # reset first visit - stack_entry.m_FirstVisit = False - else: - tree.NewLayer(stack_entry.m_LoactedLayer, stack_entry.m_LocatedPos) - tree.NewItem(tree_node) + # now we place BB in tree layout + if envir.m_Depth == 0: + # if depth == 0, all item should start from a new layer + for item in gottenBB: + envir.m_Tree.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) + envir.m_Tree.NewItem(self.m_Graph.m_BlockDict[item]) + self.__RecursiveBuildBB(BuildBBEnvironment( + envir.m_Cursor, envir.m_Tree, envir.m_Depth + 1, item + )) + else: + # otherwise, only non-first node need new layer + # proc first node + first: int = gottenBB[0] + envir.m_Tree.NewItem(self.m_Graph.m_BlockDict[first]) + self.__RecursiveBuildBB(BuildBBEnvironment( + envir.m_Cursor, envir.m_Tree, envir.m_Depth + 1, first + )) - bb_data.m_LoactedLayer = tree.GetCurrentLayerIndex() - bb_data.m_LocatedPos = tree.GetCurrentItemIndex() - # query and fill stack entry data - cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", - (bb_id, DecoratorConst.Export_bLink_InputOutputType.OUTPUT, self.m_Graph.m_GraphCKID, ) - ) - for (output_obj, ) in cursor.fetchall(): - bb_data.m_Collection.append(output_obj) - stack.append(bb_data) + # get layer and pos + cur_layer = envir.m_Tree.GetCurrentLayerIndex() + cur_idx = envir.m_Tree.GetCurrentItemIndex() - # todo: executing oper finder for current bb - - cursor.close() + # proc other node + for other in gottenBB[1:]: + envir.m_Tree.NewLayer(cur_layer, cur_idx) + envir.m_Tree.NewItem(self.m_Graph.m_BlockDict[other]) + self.__RecursiveBuildBB(BuildBBEnvironment( + envir.m_Cursor, envir.m_Tree, envir.m_Depth + 1, other + )) + def __ProcActiveBB(self): cursor: sqlite3.Cursor = self.m_Db.cursor() - cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", - (self.m_Graph.m_GraphCKID, DecoratorConst.Export_bLink_InputOutputType.INPUT, self.m_Graph.m_GraphCKID, ) - ) - for (output_obj, ) in cursor.fetchall(): - self.__BuildBB(self.m_Graph.m_ActiveBB, output_obj) - + self.__RecursiveBuildBB(BuildBBEnvironment( + cursor, self.m_Graph.m_ActivePassiveBB, 0, self.m_Graph.m_GraphCKID + )) cursor.close() def __ProcPassiveBB(self): cursor: sqlite3.Cursor = self.m_Db.cursor() while len(self.__AllBB) != 0: - self.__BuildBB(self.m_PassiveBBLayer, self.__GetOneFromSet(self.__AllBB)) + # we manually add first + bbid = self.__GetOneFromSet(self.__AllBB) + + self.__AllBB.remove(bbid) + self.m_Graph.m_ActivePassiveBB.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) + self.m_Graph.m_ActivePassiveBB.NewItem(self.m_Graph.m_BlockDict[bbid]) + # use depth = 1 to cheat this function for avoiding error bIO type + self.__RecursiveBuildBB(BuildBBEnvironment( + cursor, self.m_Graph.m_ActivePassiveBB, 1, bbid + )) cursor.close() def __ProcPassiveOper(self): - pass + cursor: sqlite3.Cursor = self.m_Db.cursor() + while len(self.__AllOper) != 0: + # peek one randomly and try finding root + peek: int = self.__GetOneFromSet(self.__AllOper) + roots: tuple[int] = self.__RecursiveFindOperRoot(FindOperRootEnvironment( + cursor, set(), 1, peek # use 1 to cheat this function + )) + + # if no root found, add self + roots = (peek, ) + + # generate tree + for operid in roots: + # we need add it manually + self.__AllOper.remove(operid) + self.m_Graph.m_PassiveOper.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) + self.m_Graph.m_PassiveOper.NewItem(self.m_Graph.m_BlockDict[operid]) + + # gotten "roots" is oper's CKID, so use depth 1 to cheat this function + self.__RecursiveBuildOper(BuildOperEnvironment( + cursor, self.m_Graph.m_PassiveOper, 1, operid + )) + + cursor.close() + diff --git a/SuperScriptDecorator/DecoratorData.py b/SuperScriptDecorator/DecoratorData.py index 29a2df4..794c1a5 100644 --- a/SuperScriptDecorator/DecoratorData.py +++ b/SuperScriptDecorator/DecoratorData.py @@ -157,16 +157,17 @@ class OperDataPayload(object): self.m_OpGuid: str = v.op_guid self.m_Parent: int = v.parent -class OperTreeNode(ICanManipulate): +class OperTreeNodeWrapper(ICanManipulate): def __init__(self, payload: OperDataPayload): self.m_Payload: OperDataPayload = payload -class BBTreeNode(ICanManipulate): +class BBTreeNodeWrapper(ICanManipulate): def __init__(self, payload: BBDataPayload): - self.m_UpperOper: TreeLayout[OperTreeNode] = TreeLayout() - self.m_LowerOper: TreeLayout[OperTreeNode] = TreeLayout() + self.m_UpperOper: TreeLayout[OperTreeNodeWrapper] = TreeLayout() + self.m_LowerOper: TreeLayout[OperTreeNodeWrapper] = TreeLayout() self.m_Upperval: collections.deque = collections.deque() self.m_LowerVal: collections.deque = collections.deque() + self.m_Payload: BBDataPayload = payload @@ -184,8 +185,7 @@ class GraphResult(ICanManipulate): self.m_pOut: collections.deque = collections.deque() self.m_PassiveVal: collections.deque = collections.deque() - self.m_PassiveOper: TreeLayout[OperTreeNode] = TreeLayout() - self.m_ActiveBB: TreeLayout[BBTreeNode] = TreeLayout() - self.m_PassiveBB: TreeLayout[BBTreeNode] = TreeLayout() + self.m_PassiveOper: TreeLayout[OperTreeNodeWrapper] = TreeLayout() + self.m_ActivePassiveBB: TreeLayout[BBTreeNodeWrapper] = TreeLayout()