Nix 2.93.3
Lix: A modern, delicious implementation of the Nix package manager; unstable internal interfaces
Loading...
Searching...
No Matches
topo-sort.hh
Go to the documentation of this file.
1#pragma once
3
6#include <kj/async.h>
7
8namespace nix {
9
10template<typename T>
11std::vector<T> topoSort(std::set<T> items,
12 std::function<std::set<T>(const T &)> getChildren,
13 std::function<Error(const T &, const T &)> makeCycleError)
14{
15 std::vector<T> sorted;
16 std::set<T> visited, parents;
17
18 std::function<void(const T & path, const T * parent)> dfsVisit;
19
20 dfsVisit = [&](const T & path, const T * parent) {
21 if (parents.count(path)) {
22 throw makeCycleError(path, *parent); // NOLINT(lix-foreign-exceptions): type dependent
23 }
24
25 if (!visited.insert(path).second) return;
26 parents.insert(path);
27
28 std::set<T> references = getChildren(path);
29
30 for (auto & i : references)
31 /* Don't traverse into items that don't exist in our starting set. */
32 if (i != path && items.count(i))
33 dfsVisit(i, &path);
34
35 sorted.push_back(path);
36 parents.erase(path);
37 };
38
39 for (auto & i : items)
40 dfsVisit(i, nullptr);
41
42 std::reverse(sorted.begin(), sorted.end());
43
44 return sorted;
45}
46
47template<typename T>
48kj::Promise<Result<std::vector<T>>> topoSortAsync(std::set<T> items,
49 std::function<kj::Promise<Result<std::set<T>>>(const T &)> getChildren,
50 std::function<Error(const T &, const T &)> makeCycleError)
51try {
52 std::vector<T> sorted;
53 std::set<T> visited, parents;
54
55 std::function<kj::Promise<Result<void>>(const T & path, const T * parent)> dfsVisit;
56
57 // NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
58 dfsVisit = [&](const T & path, const T * parent) -> kj::Promise<Result<void>> {
59 try {
60 if (parents.count(path)) {
61 // NOLINTNEXTLINE(lix-foreign-exceptions): type dependent
62 throw makeCycleError(path, *parent);
63 }
64
65 if (!visited.insert(path).second) co_return result::success();
66 parents.insert(path);
67
68 std::set<T> references = TRY_AWAIT(getChildren(path));
69
70 for (auto & i : references)
71 /* Don't traverse into items that don't exist in our starting set. */
72 if (i != path && items.count(i))
73 TRY_AWAIT(dfsVisit(i, &path));
74
75 sorted.push_back(path);
76 parents.erase(path);
77 co_return result::success();
78 } catch (...) {
79 co_return result::current_exception();
80 }
81 };
82
83 for (auto & i : items)
84 TRY_AWAIT(dfsVisit(i, nullptr));
85
86 std::reverse(sorted.begin(), sorted.end());
87
88 co_return sorted;
89} catch (...) {
90 co_return result::current_exception();
91}
92
93}
This file defines two main structs/classes used in nix error handling.