summaryrefslogtreecommitdiff
path: root/src/support/topological_orders.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/support/topological_orders.h')
-rw-r--r--src/support/topological_orders.h86
1 files changed, 82 insertions, 4 deletions
diff --git a/src/support/topological_orders.h b/src/support/topological_orders.h
index 48941c021..4332f7a91 100644
--- a/src/support/topological_orders.h
+++ b/src/support/topological_orders.h
@@ -17,8 +17,10 @@
#ifndef wasm_support_topological_orders_h
#define wasm_support_topological_orders_h
+#include <cassert>
#include <cstddef>
#include <optional>
+#include <unordered_map>
#include <vector>
namespace wasm {
@@ -36,7 +38,8 @@ struct TopologicalOrders {
// Takes an adjacency list, where the list for each vertex is a sorted list of
// the indices of its children, which will appear after it in the order.
- TopologicalOrders(const std::vector<std::vector<size_t>>& graph);
+ TopologicalOrders(const std::vector<std::vector<size_t>>& graph)
+ : TopologicalOrders(graph, InPlace) {}
TopologicalOrders begin() { return TopologicalOrders(graph); }
TopologicalOrders end() { return TopologicalOrders({}); }
@@ -47,11 +50,16 @@ struct TopologicalOrders {
bool operator!=(const TopologicalOrders& other) const {
return !(*this == other);
}
- const std::vector<size_t>& operator*() { return buf; }
- const std::vector<size_t>* operator->() { return &buf; }
+ const std::vector<size_t>& operator*() const { return buf; }
+ const std::vector<size_t>* operator->() const { return &buf; }
TopologicalOrders& operator++();
TopologicalOrders operator++(int) { return ++(*this); }
+protected:
+ enum SelectionMethod { InPlace, MinHeap };
+ TopologicalOrders(const std::vector<std::vector<size_t>>& graph,
+ SelectionMethod method);
+
private:
// The input graph given as an adjacency list with edges from vertices to
// their dependent children.
@@ -64,6 +72,9 @@ private:
// sequence of selected vertices followed by a sequence of possible choices
// for the next vertex.
std::vector<size_t> buf;
+ // When we are finding the minimal topological order, store the possible
+ // choices in this separate min-heap instead of directly in `buf`.
+ std::vector<size_t> choiceHeap;
// The state for tracking the possible choices for a single vertex in the
// output order.
@@ -78,7 +89,7 @@ private:
// Select the next available vertex, decrement in-degrees, and update the
// sequence of available vertices. Return the Selector for the next vertex.
- Selector select(TopologicalOrders& ctx);
+ Selector select(TopologicalOrders& ctx, SelectionMethod method);
// Undo the current selection, move the next selection into the first
// position and return the new selector for the next position. Returns
@@ -86,11 +97,78 @@ private:
std::optional<Selector> advance(TopologicalOrders& ctx);
};
+ void pushChoice(size_t);
+ size_t popChoice();
+
// A stack of selectors, one for each vertex in a complete topological order.
// Empty if we've already seen every possible ordering.
std::vector<Selector> selectors;
};
+// A utility for finding a single topological order of a graph.
+struct TopologicalSort : private TopologicalOrders {
+ TopologicalSort(const std::vector<std::vector<size_t>>& graph)
+ : TopologicalOrders(graph) {}
+
+ const std::vector<size_t>& operator*() const {
+ return TopologicalOrders::operator*();
+ }
+};
+
+// A utility for finding the topological order that is as close as possible to
+// the original order of elements. Internally uses a min-heap to choose the best
+// available next element.
+struct MinTopologicalSort : private TopologicalOrders {
+ MinTopologicalSort(const std::vector<std::vector<size_t>>& graph)
+ : TopologicalOrders(graph, MinHeap) {}
+
+ const std::vector<size_t>& operator*() const {
+ return TopologicalOrders::operator*();
+ }
+};
+
+// A utility that finds a topological sort of a graph with arbitrary element
+// types.
+template<typename T, typename TopoSort = TopologicalSort>
+struct TopologicalSortOf {
+ std::vector<T> order;
+
+ // The value of the iterators must be a pair of an element and an iterable of
+ // its children.
+ template<typename It> TopologicalSortOf(It begin, It end) {
+ std::unordered_map<T, size_t> indices;
+ std::vector<T> elements;
+ // Assign indices to each element.
+ for (auto it = begin; it != end; ++it) {
+ auto inserted = indices.insert({it->first, elements.size()});
+ assert(inserted.second && "unexpected repeat element");
+ elements.push_back(inserted.first->first);
+ }
+ // Collect the graph in terms of indices.
+ std::vector<std::vector<size_t>> indexGraph;
+ indexGraph.reserve(elements.size());
+ for (auto it = begin; it != end; ++it) {
+ indexGraph.emplace_back();
+ for (const auto& child : it->second) {
+ indexGraph.back().push_back(indices.at(child));
+ }
+ }
+ // Compute the topological order and convert back to original elements.
+ order.reserve(elements.size());
+ auto indexOrder = *TopoSort(indexGraph);
+ for (auto i : indexOrder) {
+ order.emplace_back(std::move(elements[i]));
+ }
+ }
+
+ const std::vector<T>& operator*() const { return order; }
+};
+
+// A utility that finds the minimum topological sort of a graph with arbitrary
+// element types.
+template<typename T>
+using MinTopologicalSortOf = TopologicalSortOf<T, MinTopologicalSort>;
+
} // namespace wasm
#endif // wasm_support_topological_orders_h