Nix  2.93.0-dev
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)) throw makeCycleError(path, *parent);
22
23 if (!visited.insert(path).second) return;
24 parents.insert(path);
25
26 std::set<T> references = getChildren(path);
27
28 for (auto & i : references)
29 /* Don't traverse into items that don't exist in our starting set. */
30 if (i != path && items.count(i))
31 dfsVisit(i, &path);
32
33 sorted.push_back(path);
34 parents.erase(path);
35 };
36
37 for (auto & i : items)
38 dfsVisit(i, nullptr);
39
40 std::reverse(sorted.begin(), sorted.end());
41
42 return sorted;
43}
44
45template<typename T>
46kj::Promise<Result<std::vector<T>>> topoSortAsync(std::set<T> items,
47 std::function<kj::Promise<Result<std::set<T>>>(const T &)> getChildren,
48 std::function<Error(const T &, const T &)> makeCycleError)
49try {
50 std::vector<T> sorted;
51 std::set<T> visited, parents;
52
53 std::function<kj::Promise<Result<void>>(const T & path, const T * parent)> dfsVisit;
54
55 // NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
56 dfsVisit = [&](const T & path, const T * parent) -> kj::Promise<Result<void>> {
57 try {
58 if (parents.count(path)) throw makeCycleError(path, *parent);
59
60 if (!visited.insert(path).second) co_return result::success();
61 parents.insert(path);
62
63 std::set<T> references = TRY_AWAIT(getChildren(path));
64
65 for (auto & i : references)
66 /* Don't traverse into items that don't exist in our starting set. */
67 if (i != path && items.count(i))
68 TRY_AWAIT(dfsVisit(i, &path));
69
70 sorted.push_back(path);
71 parents.erase(path);
72 co_return result::success();
73 } catch (...) {
74 co_return result::current_exception();
75 }
76 };
77
78 for (auto & i : items)
79 TRY_AWAIT(dfsVisit(i, nullptr));
80
81 std::reverse(sorted.begin(), sorted.end());
82
83 co_return sorted;
84} catch (...) {
85 co_return result::current_exception();
86}
87
88}
This file defines two main structs/classes used in nix error handling.