1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-05 16:41:01 +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 error if a cycle is detected and roll back the
transaction. Cycles can only occur when a derivation transaction. Cycles can only occur when a derivation
has multiple outputs. */ has multiple outputs. */
auto topoSortResult = topoSort(paths, {[&](const StorePath & path) { auto topoSortResult = topoSort(paths, [&](const StorePath & path) {
auto i = infos.find(path); auto i = infos.find(path);
return i == infos.end() ? StorePathSet() : i->second.references; return i == infos.end() ? StorePathSet() : i->second.references;
}}); });
std::visit( std::visit(
overloaded{ overloaded{

View file

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

View file

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

View file

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