1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-04 16:10:59 +01:00

topoSort: Optimize templating

- No `std::function` overhead

- Don't copy if not necessary

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
This commit is contained in:
John Ericson 2025-11-27 18:56:38 -05:00
parent 0903b0aa7d
commit 13b4512cbe
4 changed files with 42 additions and 40 deletions

View file

@ -989,10 +989,10 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
error if a cycle is detected and roll back the
transaction. Cycles can only occur when a derivation
has multiple outputs. */
auto topoSortResult = topoSort(paths, {[&](const StorePath & path) {
auto i = infos.find(path);
return i == infos.end() ? StorePathSet() : i->second.references;
}});
auto topoSortResult = topoSort(paths, [&](const StorePath & path) {
auto i = infos.find(path);
return i == infos.end() ? StorePathSet() : i->second.references;
});
std::visit(
overloaded{

View file

@ -313,13 +313,13 @@ MissingPaths Store::queryMissing(const std::vector<DerivedPath> & targets)
StorePaths Store::topoSortPaths(const StorePathSet & paths)
{
auto result = topoSort(paths, {[&](const StorePath & path) {
try {
return queryPathInfo(path)->references;
} catch (InvalidPath &) {
return StorePathSet();
}
}});
auto result = topoSort(paths, [&](const StorePath & path) {
try {
return queryPathInfo(path)->references;
} catch (InvalidPath &) {
return StorePathSet();
}
});
return std::visit(
overloaded{

View file

@ -1470,32 +1470,32 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
outputStats.insert_or_assign(outputName, std::move(st));
}
auto topoSortResult = topoSort(outputsToSort, {[&](const std::string & name) {
auto orifu = get(outputReferencesIfUnregistered, name);
if (!orifu)
throw BuildError(
BuildResult::Failure::OutputRejected,
"no output reference for '%s' in build of '%s'",
name,
store.printStorePath(drvPath));
return std::visit(
overloaded{
/* Since we'll use the already installed versions of these, we
can treat them as leaves and ignore any references they
have. */
[&](const AlreadyRegistered &) { return StringSet{}; },
[&](const PerhapsNeedToRegister & refs) {
StringSet referencedOutputs;
/* FIXME build inverted map up front so no quadratic waste here */
for (auto & r : refs.refs)
for (auto & [o, p] : scratchOutputs)
if (r == p)
referencedOutputs.insert(o);
return referencedOutputs;
},
},
*orifu);
}});
auto topoSortResult = topoSort(outputsToSort, [&](const std::string & name) {
auto orifu = get(outputReferencesIfUnregistered, name);
if (!orifu)
throw BuildError(
BuildResult::Failure::OutputRejected,
"no output reference for '%s' in build of '%s'",
name,
store.printStorePath(drvPath));
return std::visit(
overloaded{
/* Since we'll use the already installed versions of these, we
can treat them as leaves and ignore any references they
have. */
[&](const AlreadyRegistered &) { return StringSet{}; },
[&](const PerhapsNeedToRegister & refs) {
StringSet referencedOutputs;
/* FIXME build inverted map up front so no quadratic waste here */
for (auto & r : refs.refs)
for (auto & [o, p] : scratchOutputs)
if (r == p)
referencedOutputs.insert(o);
return referencedOutputs;
},
},
*orifu);
});
auto sortedOutputNames = std::visit(
overloaded{

View file

@ -3,6 +3,7 @@
#include "nix/util/error.hh"
#include <variant>
#include <concepts>
namespace nix {
@ -16,8 +17,9 @@ struct Cycle
template<typename T>
using TopoSortResult = std::variant<std::vector<T>, Cycle<T>>;
template<typename T, typename Compare>
TopoSortResult<T> topoSort(std::set<T, Compare> items, std::function<std::set<T, Compare>(const T &)> getChildren)
template<typename T, typename Compare, std::invocable<const T &> F>
requires std::same_as<std::remove_cvref_t<std::invoke_result_t<F, const T &>>, std::set<T, Compare>>
TopoSortResult<T> topoSort(std::set<T, Compare> items, F && getChildren)
{
std::vector<T> sorted;
decltype(items) visited, parents;
@ -34,7 +36,7 @@ TopoSortResult<T> topoSort(std::set<T, Compare> items, std::function<std::set<T,
}
parents.insert(path);
auto references = getChildren(path);
auto && references = std::invoke(getChildren, path);
for (auto & i : references)
/* Don't traverse into items that don't exist in our starting set. */