From a54f2231c9c4ea9e456511e855df11fe7df5ba71 Mon Sep 17 00:00:00 2001 From: polykernel <81340136+polykernel@users.noreply.github.com> Date: Mon, 27 Dec 2021 17:16:14 -0500 Subject: [PATCH 1/2] lib/attrset: optimize element access in recursiveUpdateUntil - Eta reduce formal arguments of `recursiveUpdate'. - Access elements in `recursiveUpdateUntil` using `elemAt` and `head` directly instead of `head (tail xs)` which copies a singleton unnecessarily. (`elemAt` is used instead of `last` to save a primitive call to `length`, this is possible because the 2-tuple structure is guranteed) - Use `length` instead of comparison to empty list to save a copy. --- lib/attrsets.nix | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 812521ce6d1c..4e88601dbd3e 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -369,7 +369,7 @@ rec { value = f name (catAttrs name sets); }) names); - /* Implementation note: Common names appear multiple times in the list of + /* Implementation note: Common names appear multiple times in the list of names, hopefully this does not affect the system because the maximal laziness avoid computing twice the same expression and listToAttrs does not care about duplicated attribute names. @@ -419,8 +419,8 @@ rec { let f = attrPath: zipAttrsWith (n: values: let here = attrPath ++ [n]; in - if tail values == [] - || pred here (head (tail values)) (head values) then + if length values == 1 + || pred here (elemAt values 1) (head values) then head values else f here values @@ -446,10 +446,7 @@ rec { } */ - recursiveUpdate = lhs: rhs: - recursiveUpdateUntil (path: lhs: rhs: - !(isAttrs lhs && isAttrs rhs) - ) lhs rhs; + recursiveUpdate = recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)); /* Returns true if the pattern is contained in the set. False otherwise. From 63ce7d3184bf841da8239d8a78e7e9c931022a5c Mon Sep 17 00:00:00 2001 From: polykernel <81340136+polykernel@users.noreply.github.com> Date: Mon, 27 Dec 2021 17:53:15 -0500 Subject: [PATCH 2/2] lib/attrset: miscellaneous optimizations - Eta reduce `mapAttrsRecursiveCond`, `foldAttrs`, `getAttrFromPath`. - Modify `matchAttrs` to use `elemAt` instead of `head (tail xs)` to access elements. - Modify `matchAttrs` to use `any id` instead of `foldr and true`. --- lib/attrsets.nix | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 4e88601dbd3e..9e47304959a1 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -3,9 +3,9 @@ let inherit (builtins) head tail length; - inherit (lib.trivial) and; + inherit (lib.trivial) id; inherit (lib.strings) concatStringsSep sanitizeDerivationName; - inherit (lib.lists) foldr foldl' concatMap concatLists elemAt; + inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all; in rec { @@ -73,9 +73,9 @@ rec { getAttrFromPath ["z" "z"] x => error: cannot find attribute `z.z' */ - getAttrFromPath = attrPath: set: + getAttrFromPath = attrPath: let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'"; - in attrByPath attrPath (abort errorMsg) set; + in attrByPath attrPath (abort errorMsg); /* Return the specified attributes from a set. @@ -154,12 +154,12 @@ rec { foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }] => { a = [ 2 3 ]; } */ - foldAttrs = op: nul: list_of_attrs: + foldAttrs = op: nul: foldr (n: a: foldr (name: o: o // { ${name} = op n.${name} (a.${name} or nul); } ) a (attrNames n) - ) {} list_of_attrs; + ) {}; /* Recursively collect sets that verify a given predicate named `pred' @@ -295,14 +295,14 @@ rec { */ mapAttrsRecursiveCond = cond: f: set: let - recurse = path: set: + recurse = path: let g = name: value: if isAttrs value && cond value then recurse (path ++ [name]) value else f (path ++ [name]) value; - in mapAttrs g set; + in mapAttrs g; in recurse [] set; @@ -455,8 +455,8 @@ rec { => true */ matchAttrs = pattern: attrs: assert isAttrs pattern; - foldr and true (attrValues (zipAttrsWithNames (attrNames pattern) (n: values: - let pat = head values; val = head (tail values); in + all id (attrValues (zipAttrsWithNames (attrNames pattern) (n: values: + let pat = head values; val = elemAt values 1; in if length values == 1 then false else if isAttrs pat then isAttrs val && matchAttrs pat val else pat == val