Replace hasAttr/getAttr calls with the ? and . operators

For NixOS evaluation, this gives a ~21% reduction in the number of
values allocated and a ~4% speedup. It's also more readable.
This commit is contained in:
Eelco Dolstra 2014-10-05 00:03:52 +02:00
parent 0e120dc68f
commit 97220c973f
8 changed files with 51 additions and 55 deletions

View file

@ -20,8 +20,8 @@ rec {
let attr = head attrPath; let attr = head attrPath;
in in
if attrPath == [] then e if attrPath == [] then e
else if hasAttr attr e else if e ? ${attr}
then attrByPath (tail attrPath) default (getAttr attr e) then attrByPath (tail attrPath) default e.${attr}
else default; else default;
@ -44,8 +44,7 @@ rec {
attrVals ["a" "b" "c"] as attrVals ["a" "b" "c"] as
=> [as.a as.b as.c] => [as.a as.b as.c]
*/ */
attrVals = nameList: set: attrVals = nameList: set: map (x: set.${x}) nameList;
map (x: getAttr x set) nameList;
/* Return the values of all attributes in the given set, sorted by /* Return the values of all attributes in the given set, sorted by
@ -66,7 +65,7 @@ rec {
=> [1 2] => [1 2]
*/ */
catAttrs = builtins.catAttrs or catAttrs = builtins.catAttrs or
(attr: l: concatLists (map (s: if hasAttr attr s then [(getAttr attr s)] else []) l)); (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
/* Filter an attribute set by removing all attributes for which the /* Filter an attribute set by removing all attributes for which the
@ -77,7 +76,7 @@ rec {
=> { foo = 1; } => { foo = 1; }
*/ */
filterAttrs = pred: set: filterAttrs = pred: set:
listToAttrs (fold (n: ys: let v = getAttr n set; in if pred n v then [(nameValuePair n v)] ++ ys else ys) [] (attrNames set)); listToAttrs (fold (n: ys: let v = set.${n}; in if pred n v then [(nameValuePair n v)] ++ ys else ys) [] (attrNames set));
/* foldAttrs: apply fold functions to values grouped by key. Eg accumulate values as list: /* foldAttrs: apply fold functions to values grouped by key. Eg accumulate values as list:
@ -87,7 +86,7 @@ rec {
foldAttrs = op: nul: list_of_attrs: foldAttrs = op: nul: list_of_attrs:
fold (n: a: fold (n: a:
fold (name: o: fold (name: o:
o // (listToAttrs [{inherit name; value = op (getAttr name n) (maybeAttr name nul a); }]) o // (listToAttrs [{inherit name; value = op n.${name} (maybeAttr name nul a); }])
) a (attrNames n) ) a (attrNames n)
) {} list_of_attrs; ) {} list_of_attrs;
@ -133,7 +132,7 @@ rec {
=> { x = "x-foo"; y = "y-bar"; } => { x = "x-foo"; y = "y-bar"; }
*/ */
mapAttrs = f: set: mapAttrs = f: set:
listToAttrs (map (attr: { name = attr; value = f attr (getAttr attr set); }) (attrNames set)); listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set));
/* Like `mapAttrs', but allows the name of each attribute to be /* Like `mapAttrs', but allows the name of each attribute to be
@ -146,7 +145,7 @@ rec {
=> { foo_x = "bar-a"; foo_y = "bar-b"; } => { foo_x = "bar-a"; foo_y = "bar-b"; }
*/ */
mapAttrs' = f: set: mapAttrs' = f: set:
listToAttrs (map (attr: f attr (getAttr attr set)) (attrNames set)); listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
/* Call a function for each attribute in the given set and return /* Call a function for each attribute in the given set and return
@ -158,7 +157,7 @@ rec {
=> [ "xa" "yb" ] => [ "xa" "yb" ]
*/ */
mapAttrsToList = f: attrs: mapAttrsToList = f: attrs:
map (name: f name (getAttr name attrs)) (attrNames attrs); map (name: f name attrs.${name}) (attrNames attrs);
/* Like `mapAttrs', except that it recursively applies itself to /* Like `mapAttrs', except that it recursively applies itself to
@ -323,7 +322,7 @@ rec {
# override only the attributes that are already present in the old set # override only the attributes that are already present in the old set
# useful for deep-overriding # useful for deep-overriding
overrideExisting = old: new: overrideExisting = old: new:
old // listToAttrs (map (attr: nameValuePair attr (attrByPath [attr] (getAttr attr old) new)) (attrNames old)); old // listToAttrs (map (attr: nameValuePair attr (attrByPath [attr] old.${attr} new)) (attrNames old));
deepSeqAttrs = x: y: deepSeqList (attrValues x) y; deepSeqAttrs = x: y: deepSeqList (attrValues x) y;
} }

View file

@ -1,6 +1,6 @@
let lib = import ./default.nix; let
inherit (builtins) getAttr attrNames isFunction; lib = import ./default.nix;
inherit (builtins) attrNames isFunction;
in in
rec { rec {
@ -107,10 +107,10 @@ rec {
outputToAttrListElement = outputName: outputToAttrListElement = outputName:
{ name = outputName; { name = outputName;
value = commonAttrs // { value = commonAttrs // {
inherit (builtins.getAttr outputName drv) outPath drvPath type outputName; inherit (drv.${outputName}) outPath drvPath type outputName;
}; };
}; };
outputsList = map outputToAttrListElement outputs; outputsList = map outputToAttrListElement outputs;
in builtins.getAttr drv.outputName commonAttrs; in commonAttrs.${drv.outputName};
} }

View file

@ -1,5 +1,5 @@
let lib = import ./default.nix; let lib = import ./default.nix;
inherit (builtins) isFunction hasAttr getAttr head tail isList isAttrs isInt attrNames; inherit (builtins) isFunction head tail isList isAttrs isInt attrNames;
in in
@ -61,7 +61,7 @@ rec {
fun = n : x : fun = n : x :
let newArgs = fixed : let newArgs = fixed :
let args = takeFixed fixed; let args = takeFixed fixed;
mergeFun = getAttr n args; mergeFun = args.${n};
in if isAttrs x then (mergeFun args x) in if isAttrs x then (mergeFun args x)
else assert isFunction x; else assert isFunction x;
mergeFun args (x ( args // { inherit fixed; })); mergeFun args (x ( args // { inherit fixed; }));
@ -102,15 +102,12 @@ rec {
# } # }
composedArgsAndFun = f: foldArgs defaultMerge f {}; composedArgsAndFun = f: foldArgs defaultMerge f {};
# shortcut for attrByPath ["name"] default attrs
maybeAttrNullable = name: default: attrs:
if attrs == null then default else
if __hasAttr name attrs then (__getAttr name attrs) else default;
# shortcut for attrByPath ["name"] default attrs # shortcut for attrByPath ["name"] default attrs
maybeAttr = name: default: attrs: maybeAttrNullable = maybeAttr;
if __hasAttr name attrs then (__getAttr name attrs) else default;
# shortcut for attrByPath ["name"] default attrs
maybeAttr = name: default: attrs: attrs.${name} or default;
# Return the second argument if the first one is true or the empty version # Return the second argument if the first one is true or the empty version
@ -233,7 +230,7 @@ rec {
closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);}); closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);});
# calls a function (f attr value ) for each record item. returns a list # calls a function (f attr value ) for each record item. returns a list
mapAttrsFlatten = f : r : map (attr: f attr (builtins.getAttr attr r) ) (attrNames r); mapAttrsFlatten = f : r : map (attr: f attr r.${attr}) (attrNames r);
# attribute set containing one attribute # attribute set containing one attribute
nvs = name : value : listToAttrs [ (nameValuePair name value) ]; nvs = name : value : listToAttrs [ (nameValuePair name value) ];
@ -250,10 +247,10 @@ rec {
# merge attributes with custom function handling the case that the attribute # merge attributes with custom function handling the case that the attribute
# exists in both sets # exists in both sets
mergeAttrsWithFunc = f : set1 : set2 : mergeAttrsWithFunc = f : set1 : set2 :
fold (n: set : if (__hasAttr n set) fold (n: set : if set ? ${n}
then setAttr set n (f (__getAttr n set) (__getAttr n set2)) then setAttr set n (f set.${n} set2.${n})
else set ) else set )
(set2 // set1) (__attrNames set2); (set2 // set1) (attrNames set2);
# merging two attribute set concatenating the values of same attribute names # merging two attribute set concatenating the values of same attribute names
# eg { a = 7; } { a = [ 2 3 ]; } becomes { a = [ 7 2 3 ]; } # eg { a = 7; } { a = [ 2 3 ]; } becomes { a = [ 7 2 3 ]; }
@ -270,15 +267,15 @@ rec {
overrideSnd ? [ "buildPhase" ] overrideSnd ? [ "buildPhase" ]
} : attrs1 : attrs2 : } : attrs1 : attrs2 :
fold (n: set : fold (n: set :
setAttr set n ( if (__hasAttr n set) setAttr set n ( if set ? ${n}
then # merge then # merge
if elem n mergeLists # attribute contains list, merge them by concatenating if elem n mergeLists # attribute contains list, merge them by concatenating
then (__getAttr n attrs2) ++ (__getAttr n attrs1) then attrs2.${n} ++ attrs1.${n}
else if elem n overrideSnd else if elem n overrideSnd
then __getAttr n attrs1 then attrs1.${n}
else throw "error mergeAttrsNoOverride, attribute ${n} given in both attributes - no merge func defined" else throw "error mergeAttrsNoOverride, attribute ${n} given in both attributes - no merge func defined"
else __getAttr n attrs2 # add attribute not existing in attr1 else attrs2.${n} # add attribute not existing in attr1
)) attrs1 (__attrNames attrs2); )) attrs1 (attrNames attrs2);
# example usage: # example usage:
@ -300,14 +297,14 @@ rec {
fold lib.mergeAttrs {} [ fold lib.mergeAttrs {} [
x y x y
(mapAttrs ( a : v : # merge special names using given functions (mapAttrs ( a : v : # merge special names using given functions
if (hasAttr a x) if x ? ${a}
then if (hasAttr a y) then if y ? ${a}
then v (getAttr a x) (getAttr a y) # both have attr, use merge func then v x.${a} y.${a} # both have attr, use merge func
else (getAttr a x) # only x has attr else x.${a} # only x has attr
else (getAttr a y) # only y has attr) else y.${a} # only y has attr)
) (removeAttrs mergeAttrBy2 ) (removeAttrs mergeAttrBy2
# don't merge attrs which are neither in x nor y # don't merge attrs which are neither in x nor y
(filter (a : (! hasAttr a x) && (! hasAttr a y) ) (filter (a: ! x ? ${a} && ! y ? ${a})
(attrNames mergeAttrBy2)) (attrNames mergeAttrBy2))
) )
) )
@ -403,7 +400,7 @@ rec {
// args2.cfg; // args2.cfg;
opts = attrValues (mapAttrs (a : v : opts = attrValues (mapAttrs (a : v :
let v2 = if v ? set || v ? unset then v else { set = v; }; let v2 = if v ? set || v ? unset then v else { set = v; };
n = if (getAttr (flagName a) cfgWithDefaults) then "set" else "unset"; n = if cfgWithDefaults.${flagName a} then "set" else "unset";
attr = maybeAttr n {} v2; in attr = maybeAttr n {} v2; in
if (maybeAttr "assertion" true attr) if (maybeAttr "assertion" true attr)
then attr then attr

View file

@ -30,7 +30,7 @@ rec {
if check && set ? _definedNames then if check && set ? _definedNames then
fold (m: res: fold (m: res:
fold (name: res: fold (name: res:
if hasAttr name set then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.") if set ? ${name} then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.")
res m.names) res m.names)
res set._definedNames res set._definedNames
else else
@ -94,22 +94,22 @@ rec {
loc = prefix ++ [name]; loc = prefix ++ [name];
# Get all submodules that declare name. # Get all submodules that declare name.
decls = concatLists (map (m: decls = concatLists (map (m:
if hasAttr name m.options if m.options ? ${name}
then [ { inherit (m) file; options = getAttr name m.options; } ] then [ { inherit (m) file; options = m.options.${name}; } ]
else [] else []
) options); ) options);
# Get all submodules that define name. # Get all submodules that define name.
defns = concatLists (map (m: defns = concatLists (map (m:
if hasAttr name m.config if m.config ? ${name}
then map (config: { inherit (m) file; inherit config; }) then map (config: { inherit (m) file; inherit config; })
(pushDownProperties (getAttr name m.config)) (pushDownProperties m.config.${name})
else [] else []
) configs); ) configs);
nrOptions = count (m: isOption m.options) decls; nrOptions = count (m: isOption m.options) decls;
# Process mkMerge and mkIf properties. # Process mkMerge and mkIf properties.
defns' = concatMap (m: defns' = concatMap (m:
if hasAttr name m.config if m.config ? ${name}
then map (m': { inherit (m) file; value = m'; }) (dischargeProperties (getAttr name m.config)) then map (m': { inherit (m) file; value = m'; }) (dischargeProperties m.config.${name})
else [] else []
) configs; ) configs;
in in

View file

@ -62,8 +62,8 @@ rec {
in { result = x.result ++ [entry.text] ++ y.result; in { result = x.result ++ [entry.text] ++ y.result;
done = y.done; done = y.done;
} }
else if hasAttr entry done then f done (tail todo) else if done ? ${entry} then f done (tail todo)
else f (done // listToAttrs [{name = entry; value = 1;}]) ([(builtins.getAttr entry predefined)] ++ tail todo); else f (done // listToAttrs [{name = entry; value = 1;}]) ([predefined.${entry}] ++ tail todo);
in (f {} arg).result; in (f {} arg).result;
textClosureMap = f: predefined: names: textClosureMap = f: predefined: names:

View file

@ -399,8 +399,8 @@ in
services.xserver.drivers = flip concatMap cfg.videoDrivers (name: services.xserver.drivers = flip concatMap cfg.videoDrivers (name:
let driver = let driver =
attrByPath [name] attrByPath [name]
(if (hasAttr ("xf86video" + name) xorg) (if xorg ? ${"xf86video" + name}
then { modules = [(getAttr ("xf86video" + name) xorg) ]; } then { modules = [xorg.${"xf86video" + name}]; }
else null) else null)
knownVideoDrivers; knownVideoDrivers;
in optional (driver != null) ({ inherit name; driverName = name; } // driver)); in optional (driver != null) ({ inherit name; driverName = name; } // driver));

View file

@ -6,8 +6,8 @@ let
checkService = v: checkService = v:
let assertValueOneOf = name: values: attr: let assertValueOneOf = name: values: attr:
let val = getAttr name attr; let val = attr.${name};
in optional ( hasAttr name attr && !elem val values) "Systemd service field `${name}' cannot have value `${val}'."; in optional (attr ? ${name} && !elem val values) "Systemd service field `${name}' cannot have value `${val}'.";
checkType = assertValueOneOf "Type" ["simple" "forking" "oneshot" "dbus" "notify" "idle"]; checkType = assertValueOneOf "Type" ["simple" "forking" "oneshot" "dbus" "notify" "idle"];
checkRestart = assertValueOneOf "Restart" ["no" "on-success" "on-failure" "on-abort" "always"]; checkRestart = assertValueOneOf "Restart" ["no" "on-success" "on-failure" "on-abort" "always"];
errors = concatMap (c: c v) [checkType checkRestart]; errors = concatMap (c: c v) [checkType checkRestart];

View file

@ -321,7 +321,7 @@ let
[Service] [Service]
${let env = cfg.globalEnvironment // def.environment; ${let env = cfg.globalEnvironment // def.environment;
in concatMapStrings (n: in concatMapStrings (n:
let s = "Environment=\"${n}=${getAttr n env}\"\n"; let s = "Environment=\"${n}=${env.${n}}\"\n";
in if stringLength s >= 2048 then throw "The value of the environment variable ${n} in systemd service ${name}.service is too long." else s) (attrNames env)} in if stringLength s >= 2048 then throw "The value of the environment variable ${n} in systemd service ${name}.service is too long." else s) (attrNames env)}
${if def.reloadIfChanged then '' ${if def.reloadIfChanged then ''
X-ReloadIfChanged=true X-ReloadIfChanged=true