@@ -56,26 +56,40 @@ local function mark_for_compile(n: Node)
5656 end
5757end
5858
59+ local function collect_recursive_dependents (of: Node , set: {Node :boolean } )
60+ if set[of] then return end
61+ set[of] = true
62+ for dependent in keys (of.dependents ) do
63+ set[dependent] = true
64+ collect_recursive_dependents (dependent, set)
65+ end
66+ end
67+
5968local function make_dependent_counter (): function (Node ): integer
6069 local cache <const> : {Node :integer } = {}
70+
6171 local function count_dependents (n: Node ): integer
6272 if cache[n] then return cache[n] end
63- local deps = 0
64- for v in keys (n.dependents ) do
65- deps = deps + count_dependents (v) + 1
66- end
67- cache[n] = deps
68- return deps
73+ local set <const> = {}
74+ collect_recursive_dependents (n, set)
75+ set[n] = false
76+ local count = 0
77+ for _ in next, set do count = count + 1 end
78+ cache[n] = count
79+ return count
6980 end
7081 return count_dependents
7182end
7283
7384---@desc
74- --- Iterate over nodes in order of dependents
85+ --- Collect the nodes of this graph into a mapping from the number of
86+ --- dependents to lists of nodes with that number of dependents
87+ ---
88+ --- Returns that map of lists and the most dependents that any node had
7589---
7690--- If two nodes have the same number of dependent nodes, they are sorted by
7791--- input filename lexicographically
78- function Dag :nodes (): function (): Node
92+ function Dag :collect_by_dependent_count (): { integer : { Node } } , integer
7993 local count <const> = make_dependent_counter ()
8094 local most_deps = 0
8195 local nodes_by_deps <const> : {integer :{Node } } = setmetatable ({}, {
@@ -91,18 +105,23 @@ function Dag:nodes(): function(): Node
91105 for n in values (self ._nodes_by_filename ) do
92106 table.insert (nodes_by_deps[count (n)], n)
93107 end
94-
95108 setmetatable (nodes_by_deps, nil )
96-
97109 for i = 0 , most_deps do
98110 if nodes_by_deps[i] then
99111 table.sort (nodes_by_deps[i], function (a: Node , b: Node ): boolean
100112 return a.input :to_string () < b.input :to_string ()
101113 end )
102114 end
103115 end
116+ return nodes_by_deps, most_deps
117+ end
104118
105- local i = most_deps
119+ ---@desc
120+ --- Iterate over nodes in order of dependents
121+ ---
122+ --- This is a convenience wrapper over `collect_by_dependent_count`
123+ function Dag :nodes (): function (): Node
124+ local nodes_by_deps <const> , i = self :collect_by_dependent_count ()
106125 if not nodes_by_deps[i] then
107126 return function (): nil end
108127 end
0 commit comments