aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/include/vcpkg_Graphs.h
blob: 3c8c024c2679836f115d5e7e860a6f8bbdb827dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#pragma once

#include <unordered_map>

namespace vcpkg::Graphs
{
    enum class ExplorationStatus
    {
        // We have not visited this vertex
        NOT_EXPLORED,

        // We have visited this vertex but haven't visited all vertices in its subtree
        PARTIALLY_EXPLORED,

        // We have visited this vertex and all vertices in its subtree
        FULLY_EXPLORED
    };

    template<class V, class U>
    __interface AdjacencyProvider
    {
        std::vector<V> adjacency_list(const U& vertex) const;

        U load_vertex_data(const V& vertex) const;
    };

    template<class V, class U>
    static void topological_sort_internal(const V& vertex,
                                          const AdjacencyProvider<V, U>& f,
                                          std::unordered_map<V, ExplorationStatus>& exploration_status,
                                          std::vector<U>& sorted)
    {
        ExplorationStatus& status = exploration_status[vertex];
        switch (status)
        {
            case ExplorationStatus::FULLY_EXPLORED: return;
            case ExplorationStatus::PARTIALLY_EXPLORED: Checks::exit_with_message(VCPKG_LINE_INFO, "cycle in graph");
            case ExplorationStatus::NOT_EXPLORED:
            {
                status = ExplorationStatus::PARTIALLY_EXPLORED;
                U vertex_data = f.load_vertex_data(vertex);
                for (const V& neighbour : f.adjacency_list(vertex_data))
                    topological_sort_internal(neighbour, f, exploration_status, sorted);

                sorted.push_back(std::move(vertex_data));
                status = ExplorationStatus::FULLY_EXPLORED;
                return;
            }
            default: Checks::unreachable(VCPKG_LINE_INFO);
        }
    }

    template<class V, class U>
    std::vector<U> topological_sort(const std::vector<V>& starting_vertices, const AdjacencyProvider<V, U>& f)
    {
        std::vector<U> sorted;
        std::unordered_map<V, ExplorationStatus> exploration_status;

        for (auto& vertex : starting_vertices)
        {
            topological_sort_internal(vertex, f, exploration_status, sorted);
        }

        return sorted;
    }
}