mirror of
https://github.com/koreader/koreader
synced 2024-11-13 19:11:25 +00:00
107 lines
3.1 KiB
Lua
107 lines
3.1 KiB
Lua
|
--[[--
|
||
|
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
|