--[[-- DepGraph module. Library for constructing dependency graphs. Example: local dg = DepGraph:new{} dg:addNode('a1', {'a2', 'b1'}) dg:addNode('b1', {'a2', 'c1'}) dg:addNode('c1') -- The return value of dg:serialize() will be: -- {'a2', 'c1', 'b1', 'a1'} ]] local DepGraph = {} function DepGraph:new(new_o) local o = new_o or {} o.nodes = {} setmetatable(o, self) self.__index = self return o end function DepGraph:addNode(node_key, deps) if not self.nodes[node_key] then self.nodes[node_key] = {} end if not deps then return end local node_deps = {} for _,dep_node_key in ipairs(deps) do if not self.nodes[dep_node_key] then self.nodes[dep_node_key] = {} end table.insert(node_deps, dep_node_key) end self.nodes[node_key].deps = node_deps end function DepGraph:removeNode(node_key) self.nodes[node_key] = nil for curr_node_key, curr_node in pairs(self.nodes) do if curr_node.deps then local remove_idx for idx, dep_node_key in ipairs(self.nodes) do if dep_node_key == node_key then remove_idx = idx break end end if remove_idx then table.remove(curr_node.deps, remove_idx) end end end end function DepGraph:addNodeDep(node_key, dep_node_key) local node = self.nodes[node_key] if not node then node = {} self.nodes[node_key] = node end if not node.deps then node.deps = {} end table.insert(node.deps, dep_node_key) end function DepGraph:serialize() local visited = {} local ordered_nodes = {} for node_key,_ in pairs(self.nodes) do if not visited[node_key] then local queue = {node_key} while #queue > 0 do local pos = #queue local curr_node_key = queue[pos] local curr_node = self.nodes[curr_node_key] local all_deps_visited = true if curr_node.deps then for _, dep_node_key in ipairs(curr_node.deps) do if not visited[dep_node_key] then -- only insert to queue for later process if node -- has dependencies if self.nodes[dep_node_key].deps then table.insert(queue, dep_node_key) else table.insert(ordered_nodes, dep_node_key) end visited[dep_node_key] = true all_deps_visited = false break end end end if all_deps_visited then visited[curr_node_key] = true table.remove(queue, pos) table.insert(ordered_nodes, curr_node_key) end end end end return ordered_nodes end return DepGraph