1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 20:16:03 +01:00

treewide: Replace a lot of std::function with recursive lambdas via 'deducing this'

This is much simpler and has less overhead than a std::function, which does
type erasure.
This commit is contained in:
Sergei Zimmerman 2025-10-17 02:58:10 +03:00
parent 64c55961eb
commit b9ecd329ae
No known key found for this signature in database
13 changed files with 50 additions and 81 deletions

View file

@ -2160,9 +2160,7 @@ void EvalState::forceValueDeep(Value & v)
{ {
std::set<const Value *> seen; std::set<const Value *> seen;
std::function<void(Value & v)> recurse; auto recurse = [&](this auto & recurse, Value & v) {
recurse = [&](Value & v) {
if (!seen.insert(&v).second) if (!seen.insert(&v).second)
return; return;

View file

@ -92,7 +92,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
std::istringstream tomlStream(std::string{toml}); std::istringstream tomlStream(std::string{toml});
auto visit = [&](auto & self, Value & v, toml::value t) -> void { auto visit = [&](this auto & visit, Value & v, toml::value t) -> void {
switch (t.type()) { switch (t.type()) {
case toml::value_t::table: { case toml::value_t::table: {
auto table = toml::get<toml::table>(t); auto table = toml::get<toml::table>(t);
@ -100,7 +100,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
for (auto & elem : table) { for (auto & elem : table) {
forceNoNullByte(elem.first); forceNoNullByte(elem.first);
self(self, attrs.alloc(elem.first), elem.second); visit(attrs.alloc(elem.first), elem.second);
} }
v.mkAttrs(attrs); v.mkAttrs(attrs);
@ -110,7 +110,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
auto list = state.buildList(array.size()); auto list = state.buildList(array.size());
for (const auto & [n, v] : enumerate(list)) for (const auto & [n, v] : enumerate(list))
self(self, *(v = state.allocValue()), array[n]); visit(*(v = state.allocValue()), array[n]);
v.mkList(list); v.mkList(list);
} break; } break;
case toml::value_t::boolean: case toml::value_t::boolean:
@ -155,7 +155,6 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va
try { try {
visit( visit(
visit,
val, val,
toml::parse( toml::parse(
tomlStream, tomlStream,

View file

@ -469,17 +469,7 @@ lockFlake(const Settings & settings, EvalState & state, const FlakeRef & topRef,
std::vector<FlakeRef> parents; std::vector<FlakeRef> parents;
std::function<void( auto computeLocks = [&](this auto & computeLocks,
const FlakeInputs & flakeInputs,
ref<Node> node,
const InputAttrPath & inputAttrPathPrefix,
std::shared_ptr<const Node> oldNode,
const InputAttrPath & followsPrefix,
const SourcePath & sourcePath,
bool trustLock)>
computeLocks;
computeLocks = [&](
/* The inputs of this node, either from flake.nix or /* The inputs of this node, either from flake.nix or
flake.lock. */ flake.lock. */
const FlakeInputs & flakeInputs, const FlakeInputs & flakeInputs,
@ -497,13 +487,13 @@ lockFlake(const Settings & settings, EvalState & state, const FlakeRef & topRef,
const InputAttrPath & followsPrefix, const InputAttrPath & followsPrefix,
/* The source path of this node's flake. */ /* The source path of this node's flake. */
const SourcePath & sourcePath, const SourcePath & sourcePath,
bool trustLock) { bool trustLock) -> void {
debug("computing lock file node '%s'", printInputAttrPath(inputAttrPathPrefix)); debug("computing lock file node '%s'", printInputAttrPath(inputAttrPathPrefix));
/* Get the overrides (i.e. attributes of the form /* Get the overrides (i.e. attributes of the form
'inputs.nixops.inputs.nixpkgs.url = ...'). */ 'inputs.nixops.inputs.nixpkgs.url = ...'). */
std::function<void(const FlakeInput & input, const InputAttrPath & prefix)> addOverrides; auto addOverrides =
addOverrides = [&](const FlakeInput & input, const InputAttrPath & prefix) { [&](this auto & addOverrides, const FlakeInput & input, const InputAttrPath & prefix) -> void {
for (auto & [idOverride, inputOverride] : input.overrides) { for (auto & [idOverride, inputOverride] : input.overrides) {
auto inputAttrPath(prefix); auto inputAttrPath(prefix);
inputAttrPath.push_back(idOverride); inputAttrPath.push_back(idOverride);

View file

@ -149,9 +149,7 @@ LockFile::LockFile(const fetchers::Settings & fetchSettings, std::string_view co
std::map<std::string, ref<Node>> nodeMap; std::map<std::string, ref<Node>> nodeMap;
std::function<void(Node & node, const nlohmann::json & jsonNode)> getInputs; auto getInputs = [&](this auto & getInputs, Node & node, const nlohmann::json & jsonNode) -> void {
getInputs = [&](Node & node, const nlohmann::json & jsonNode) {
if (jsonNode.find("inputs") == jsonNode.end()) if (jsonNode.find("inputs") == jsonNode.end())
return; return;
for (auto & i : jsonNode["inputs"].items()) { for (auto & i : jsonNode["inputs"].items()) {
@ -276,9 +274,7 @@ std::optional<FlakeRef> LockFile::isUnlocked(const fetchers::Settings & fetchSet
{ {
std::set<ref<const Node>> nodes; std::set<ref<const Node>> nodes;
std::function<void(ref<const Node> node)> visit; auto visit = [&](this auto & visit, ref<const Node> node) -> void {
visit = [&](ref<const Node> node) {
if (!nodes.insert(node).second) if (!nodes.insert(node).second)
return; return;
for (auto & i : node->inputs) for (auto & i : node->inputs)
@ -332,9 +328,7 @@ std::map<InputAttrPath, Node::Edge> LockFile::getAllInputs() const
std::set<ref<Node>> done; std::set<ref<Node>> done;
std::map<InputAttrPath, Node::Edge> res; std::map<InputAttrPath, Node::Edge> res;
std::function<void(const InputAttrPath & prefix, ref<Node> node)> recurse; auto recurse = [&](this auto & recurse, const InputAttrPath & prefix, ref<Node> node) -> void {
recurse = [&](const InputAttrPath & prefix, ref<Node> node) {
if (!done.insert(node).second) if (!done.insert(node).second)
return; return;

View file

@ -6,15 +6,14 @@ namespace nix {
template<typename V> template<typename V>
typename DerivedPathMap<V>::ChildNode & DerivedPathMap<V>::ensureSlot(const SingleDerivedPath & k) typename DerivedPathMap<V>::ChildNode & DerivedPathMap<V>::ensureSlot(const SingleDerivedPath & k)
{ {
std::function<ChildNode &(const SingleDerivedPath &)> initIter; auto initIter = [&](this auto & initIter, const auto & k) -> ChildNode & {
initIter = [&](const auto & k) -> auto & {
return std::visit( return std::visit(
overloaded{ overloaded{
[&](const SingleDerivedPath::Opaque & bo) -> auto & { [&](const SingleDerivedPath::Opaque & bo) -> ChildNode & {
// will not overwrite if already there // will not overwrite if already there
return map[bo.path]; return map[bo.path];
}, },
[&](const SingleDerivedPath::Built & bfd) -> auto & { [&](const SingleDerivedPath::Built & bfd) -> ChildNode & {
auto & n = initIter(*bfd.drvPath); auto & n = initIter(*bfd.drvPath);
return n.childMap[bfd.output]; return n.childMap[bfd.output];
}, },
@ -27,15 +26,14 @@ typename DerivedPathMap<V>::ChildNode & DerivedPathMap<V>::ensureSlot(const Sing
template<typename V> template<typename V>
typename DerivedPathMap<V>::ChildNode * DerivedPathMap<V>::findSlot(const SingleDerivedPath & k) typename DerivedPathMap<V>::ChildNode * DerivedPathMap<V>::findSlot(const SingleDerivedPath & k)
{ {
std::function<ChildNode *(const SingleDerivedPath &)> initIter; auto initIter = [&](this auto & initIter, const auto & k) -> ChildNode * {
initIter = [&](const auto & k) {
return std::visit( return std::visit(
overloaded{ overloaded{
[&](const SingleDerivedPath::Opaque & bo) { [&](const SingleDerivedPath::Opaque & bo) -> ChildNode * {
auto it = map.find(bo.path); auto it = map.find(bo.path);
return it != map.end() ? &it->second : nullptr; return it != map.end() ? &it->second : nullptr;
}, },
[&](const SingleDerivedPath::Built & bfd) { [&](const SingleDerivedPath::Built & bfd) -> ChildNode * {
auto * n = initIter(*bfd.drvPath); auto * n = initIter(*bfd.drvPath);
if (!n) if (!n)
return (ChildNode *) nullptr; return (ChildNode *) nullptr;

View file

@ -146,9 +146,7 @@ struct NarAccessor : public SourceAccessor
{ {
using json = nlohmann::json; using json = nlohmann::json;
std::function<void(NarMember &, const json &)> recurse; auto recurse = [&](this auto & recurse, NarMember & member, const json & v) -> void {
recurse = [&](NarMember & member, const json & v) {
std::string type = v["type"]; std::string type = v["type"];
if (type == "directory") { if (type == "directory") {

View file

@ -284,8 +284,7 @@ TEST_F(GitTest, both_roundrip)
MemorySink sinkFiles2{*files2}; MemorySink sinkFiles2{*files2};
std::function<void(const CanonPath, const Hash &, BlobMode)> mkSinkHook; auto mkSinkHook = [&](this auto & mkSinkHook, auto prefix, auto & hash, auto blobMode) -> void {
mkSinkHook = [&](auto prefix, auto & hash, auto blobMode) {
StringSource in{cas[hash]}; StringSource in{cas[hash]};
parse( parse(
sinkFiles2, sinkFiles2,

View file

@ -14,9 +14,7 @@ std::vector<T> topoSort(
std::vector<T> sorted; std::vector<T> sorted;
decltype(items) visited, parents; decltype(items) visited, parents;
std::function<void(const T & path, const T * parent)> dfsVisit; auto dfsVisit = [&](this auto & dfsVisit, const T & path, const T * parent) -> void {
dfsVisit = [&](const T & path, const T * parent) {
if (parents.count(path)) if (parents.count(path))
throw makeCycleError(path, *parent); throw makeCycleError(path, *parent);

View file

@ -85,9 +85,8 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
if (pathExists(*writeTo)) if (pathExists(*writeTo))
throw Error("path '%s' already exists", writeTo->string()); throw Error("path '%s' already exists", writeTo->string());
std::function<void(Value & v, const PosIdx pos, const std::filesystem::path & path)> recurse; auto recurse =
[&](this auto & recurse, Value & v, const PosIdx pos, const std::filesystem::path & path) -> void {
recurse = [&](Value & v, const PosIdx pos, const std::filesystem::path & path) {
state->forceValue(v, pos); state->forceValue(v, pos);
if (v.type() == nString) if (v.type() == nString)
// FIXME: disallow strings with contexts? // FIXME: disallow strings with contexts?

View file

@ -38,8 +38,7 @@ struct CmdFlakePrefetchInputs : FlakeCommand
std::atomic<size_t> nrFailed{0}; std::atomic<size_t> nrFailed{0};
std::function<void(const Node & node)> visit; auto visit = [&](this auto & visit, const Node & node) -> void {
visit = [&](const Node & node) {
if (!state_.lock()->done.insert(&node).second) if (!state_.lock()->done.insert(&node).second)
return; return;

View file

@ -269,9 +269,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
std::set<ref<Node>> visited; std::set<ref<Node>> visited;
std::function<void(const Node & node, const std::string & prefix)> recurse; auto recurse = [&](this auto & recurse, const Node & node, const std::string & prefix) -> void {
recurse = [&](const Node & node, const std::string & prefix) {
for (const auto & [i, input] : enumerate(node.inputs)) { for (const auto & [i, input] : enumerate(node.inputs)) {
bool last = i + 1 == node.inputs.size(); bool last = i + 1 == node.inputs.size();

View file

@ -90,10 +90,10 @@ struct CmdSearch : InstallableValueCommand, MixJSON
uint64_t results = 0; uint64_t results = 0;
std::function<void(eval_cache::AttrCursor & cursor, const std::vector<Symbol> & attrPath, bool initialRecurse)> auto visit = [&](this auto & visit,
visit; eval_cache::AttrCursor & cursor,
const std::vector<Symbol> & attrPath,
visit = [&](eval_cache::AttrCursor & cursor, const std::vector<Symbol> & attrPath, bool initialRecurse) { bool initialRecurse) -> void {
auto attrPathS = state->symbols.resolve(attrPath); auto attrPathS = state->symbols.resolve(attrPath);
Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", concatStringsSep(".", attrPathS)));

View file

@ -160,16 +160,15 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
} }
} }
struct BailOut
{};
/* Print the subgraph of nodes that have 'dependency' in their /* Print the subgraph of nodes that have 'dependency' in their
closure (i.e., that have a non-infinite distance to closure (i.e., that have a non-infinite distance to
'dependency'). Print every edge on a path between `package` 'dependency'). Print every edge on a path between `package`
and `dependency`. */ and `dependency`. */
std::function<void(Node &, const std::string &, const std::string &)> printNode; auto printNode =
[&](this auto & printNode, Node & node, const std::string & firstPad, const std::string & tailPad) -> void {
struct BailOut
{};
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
assert(node.dist != inf); assert(node.dist != inf);
if (precise) { if (precise) {
logger->cout( logger->cout(