1717#ifndef wasm_support_topological_orders_h
1818#define wasm_support_topological_orders_h
1919
20+ #include < cassert>
2021#include < cstddef>
2122#include < optional>
23+ #include < unordered_map>
2224#include < vector>
2325
2426namespace wasm {
@@ -36,7 +38,8 @@ struct TopologicalOrders {
3638
3739 // Takes an adjacency list, where the list for each vertex is a sorted list of
3840 // the indices of its children, which will appear after it in the order.
39- TopologicalOrders (const std::vector<std::vector<size_t >>& graph);
41+ TopologicalOrders (const std::vector<std::vector<size_t >>& graph)
42+ : TopologicalOrders(graph, InPlace) {}
4043
4144 TopologicalOrders begin () { return TopologicalOrders (graph); }
4245 TopologicalOrders end () { return TopologicalOrders ({}); }
@@ -47,11 +50,16 @@ struct TopologicalOrders {
4750 bool operator !=(const TopologicalOrders& other) const {
4851 return !(*this == other);
4952 }
50- const std::vector<size_t >& operator *() { return buf; }
51- const std::vector<size_t >* operator ->() { return &buf; }
53+ const std::vector<size_t >& operator *() const { return buf; }
54+ const std::vector<size_t >* operator ->() const { return &buf; }
5255 TopologicalOrders& operator ++();
5356 TopologicalOrders operator ++(int ) { return ++(*this ); }
5457
58+ protected:
59+ enum SelectionMethod { InPlace, MinHeap };
60+ TopologicalOrders (const std::vector<std::vector<size_t >>& graph,
61+ SelectionMethod method);
62+
5563private:
5664 // The input graph given as an adjacency list with edges from vertices to
5765 // their dependent children.
@@ -64,6 +72,9 @@ struct TopologicalOrders {
6472 // sequence of selected vertices followed by a sequence of possible choices
6573 // for the next vertex.
6674 std::vector<size_t > buf;
75+ // When we are finding the minimal topological order, store the possible
76+ // choices in this separate min-heap instead of directly in `buf`.
77+ std::vector<size_t > choiceHeap;
6778
6879 // The state for tracking the possible choices for a single vertex in the
6980 // output order.
@@ -78,19 +89,86 @@ struct TopologicalOrders {
7889
7990 // Select the next available vertex, decrement in-degrees, and update the
8091 // sequence of available vertices. Return the Selector for the next vertex.
81- Selector select (TopologicalOrders& ctx);
92+ Selector select (TopologicalOrders& ctx, SelectionMethod method );
8293
8394 // Undo the current selection, move the next selection into the first
8495 // position and return the new selector for the next position. Returns
8596 // nullopt if advancing wraps back around to the original configuration.
8697 std::optional<Selector> advance (TopologicalOrders& ctx);
8798 };
8899
100+ void pushChoice (size_t );
101+ size_t popChoice ();
102+
89103 // A stack of selectors, one for each vertex in a complete topological order.
90104 // Empty if we've already seen every possible ordering.
91105 std::vector<Selector> selectors;
92106};
93107
108+ // A utility for finding a single topological order of a graph.
109+ struct TopologicalSort : private TopologicalOrders {
110+ TopologicalSort (const std::vector<std::vector<size_t >>& graph)
111+ : TopologicalOrders(graph) {}
112+
113+ const std::vector<size_t >& operator *() const {
114+ return TopologicalOrders::operator *();
115+ }
116+ };
117+
118+ // A utility for finding the topological order that is as close as possible to
119+ // the original order of elements. Internally uses a min-heap to choose the best
120+ // available next element.
121+ struct MinTopologicalSort : private TopologicalOrders {
122+ MinTopologicalSort (const std::vector<std::vector<size_t >>& graph)
123+ : TopologicalOrders(graph, MinHeap) {}
124+
125+ const std::vector<size_t >& operator *() const {
126+ return TopologicalOrders::operator *();
127+ }
128+ };
129+
130+ // A utility that finds a topological sort of a graph with arbitrary element
131+ // types.
132+ template <typename T, typename TopoSort = TopologicalSort>
133+ struct TopologicalSortOf {
134+ std::vector<T> order;
135+
136+ // The value of the iterators must be a pair of an element and an iterable of
137+ // its children.
138+ template <typename It> TopologicalSortOf (It begin, It end) {
139+ std::unordered_map<T, size_t > indices;
140+ std::vector<T> elements;
141+ // Assign indices to each element.
142+ for (auto it = begin; it != end; ++it) {
143+ auto inserted = indices.insert ({it->first , elements.size ()});
144+ assert (inserted.second && " unexpected repeat element" );
145+ elements.push_back (inserted.first ->first );
146+ }
147+ // Collect the graph in terms of indices.
148+ std::vector<std::vector<size_t >> indexGraph;
149+ indexGraph.reserve (elements.size ());
150+ for (auto it = begin; it != end; ++it) {
151+ indexGraph.emplace_back ();
152+ for (const auto & child : it->second ) {
153+ indexGraph.back ().push_back (indices.at (child));
154+ }
155+ }
156+ // Compute the topological order and convert back to original elements.
157+ order.reserve (elements.size ());
158+ auto indexOrder = *TopoSort (indexGraph);
159+ for (auto i : indexOrder) {
160+ order.emplace_back (std::move (elements[i]));
161+ }
162+ }
163+
164+ const std::vector<T>& operator *() const { return order; }
165+ };
166+
167+ // A utility that finds the minimum topological sort of a graph with arbitrary
168+ // element types.
169+ template <typename T>
170+ using MinTopologicalSortOf = TopologicalSortOf<T, MinTopologicalSort>;
171+
94172} // namespace wasm
95173
96174#endif // wasm_support_topological_orders_h
0 commit comments