2022-04-25 12:24:44 -05:00

82 lines
2.2 KiB
Ruby

module VagrantPlugins
module CommandServe
class Mappers
module Internal
class Graph
# Provides topological sorting of a Graph
class Topological
class NoRootError < StandardError; end
class CycleError < StandardError; end
attr_reader :graph
# Create a new topological sorting instance
#
# @param graph [Graph] Graph used for sorting
def initialize(graph:)
@graph = graph.copy
@m = Mutex.new
end
# Generate a topological sorted path of the defined
# graph.
#
# @return [Array<Vertex>]
# @raises [NoRootError, CycleError]
def sort
@m.synchronize do
s = Stack.new
graph.vertices.each do |v|
s.push(v) if graph.edges_in(v).size < 1
end
if s.size < 1
raise NoRootError,
"graph does not contain any root vertices"
end
kahn(s)
end
end
protected
# Sort the graph vertices using Kahn's algorithm
#
# @param s [Stack] Stack to hold vertices
# @return [Array<Vertex>]
# @raises [CycleError]
def kahn(s)
p = Queue.new
while s.size > 0
v = s.pop
p.push(v)
graph.edges_out(v).each do |next_v|
graph.remove_edge(v, next_v)
if graph.edges_in(next_v).size < 1
s.push(next_v)
end
end
end
graph.vertices.each do |v|
if graph.edges_in(v).size > 1 || graph.edges_out(v).size > 1
raise CycleError,
"graph contains at least one cycle"
end
end
Array.new.tap do |path|
while p.size > 0
path << p.pop
end
end
end
end
end
end
end
end
end