/* * Copyright (c) 2023, Dan Klishch * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include "Compiler/EnableGraphPointers.h" namespace JSSpecCompiler { namespace Detail { template class StronglyConnectedComponents : private EnableGraphPointers> { using Self = StronglyConnectedComponents; using Vertex = typename EnableGraphPointers::Vertex; public: StronglyConnectedComponents(Vector const& graph) : m_graph(graph) { } Vector> find() { Vector> result; size_t n = m_graph.size(); Self::with_graph(n, [&] { for (size_t i = 0; i < m_graph.size(); ++i) find_order(i); for (size_t i = n; i--;) { if (!m_order[i]->is_processed) { result.empend(); find_component(GraphVertex(m_order[i]), result.last()); } } }); return result; } private: friend EnableGraphPointers; void find_order(Vertex u) { if (u->is_visited) return; u->is_visited = true; for (auto v : GraphVertex(u)->incoming_edges) find_order(Vertex(v)); m_order.append(u); } void find_component(GraphVertex u, Vector& current_scc) { current_scc.empend(u); Vertex(u)->is_processed = true; for (auto v : u->outgoing_edges) if (!Vertex(v)->is_processed) find_component(v, current_scc); } struct NodeData { bool is_visited = false; bool is_processed = false; }; Vector const& m_graph; Vector m_nodes; Vector m_order; }; } template auto find_strongly_connected_components(Vector const& graph) { using Vertex = RemoveCVReference; return Detail::StronglyConnectedComponents(graph).find(); } }