-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
docs: add time complexity to relevant primops #14554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2999,6 +2999,12 @@ static RegisterPrimOp primop_attrNames({ | |
| Return the names of the attributes in the set *set* in an | ||
| alphabetically sorted list. For instance, `builtins.attrNames { y | ||
| = 1; x = "foo"; }` evaluates to `[ "x" "y" ]`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| - O(n log n), where: | ||
|
|
||
| n = number of attributes in the set | ||
| )", | ||
| .fun = prim_attrNames, | ||
| }); | ||
|
|
@@ -3031,6 +3037,12 @@ static RegisterPrimOp primop_attrValues({ | |
| .doc = R"( | ||
| Return the values of the attributes in the set *set* in the order | ||
| corresponding to the sorted attribute names. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| - O(n log n), where: | ||
|
|
||
| n = number of attributes in the set | ||
| )", | ||
| .fun = prim_attrValues, | ||
| }); | ||
|
|
@@ -3056,6 +3068,10 @@ static RegisterPrimOp primop_getAttr({ | |
| aborts if the attribute doesn’t exist. This is a dynamic version of | ||
| the `.` operator, since *s* is an expression rather than an | ||
| identifier. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(log n) where n = number of attributes in the set | ||
| )", | ||
| .fun = prim_getAttr, | ||
| }); | ||
|
|
@@ -3144,6 +3160,10 @@ static RegisterPrimOp primop_hasAttr({ | |
| `hasAttr` returns `true` if *set* has an attribute named *s*, and | ||
| `false` otherwise. This is a dynamic version of the `?` operator, | ||
| since *s* is an expression rather than an identifier. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(log n) where n = number of attributes in the set | ||
| )", | ||
| .fun = prim_hasAttr, | ||
| }); | ||
|
|
@@ -3203,6 +3223,13 @@ static RegisterPrimOp primop_removeAttrs({ | |
| ``` | ||
|
|
||
| evaluates to `{ y = 2; }`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n + k log k) where: | ||
|
|
||
| n = number of attributes in input set | ||
| k = number of attribute names to remove | ||
| )", | ||
| .fun = prim_removeAttrs, | ||
| }); | ||
|
|
@@ -3290,6 +3317,10 @@ static RegisterPrimOp primop_listToAttrs({ | |
| ```nix | ||
| { foo = 123; bar = 456; } | ||
| ``` | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n log n) where n = number of list elements | ||
| )", | ||
| .fun = prim_listToAttrs, | ||
| }); | ||
|
|
@@ -3366,7 +3397,12 @@ static RegisterPrimOp primop_intersectAttrs({ | |
| Return a set consisting of the attributes in the set *e2* which have the | ||
| same name as some attribute in *e1*. | ||
|
|
||
| Performs in O(*n* log *m*) where *n* is the size of the smaller set and *m* the larger set's size. | ||
| # Time Complexity | ||
|
|
||
| O(n * log m) where: | ||
|
|
||
| n = number of attributes in the smaller set | ||
| m = number of attributes in the larger set | ||
| )", | ||
| .fun = prim_intersectAttrs, | ||
| }); | ||
|
|
@@ -3406,6 +3442,13 @@ static RegisterPrimOp primop_catAttrs({ | |
| ``` | ||
|
|
||
| evaluates to `[1 2]`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * log m) where: | ||
|
|
||
| n = number of sets in input list | ||
| m = number of attributes per set | ||
| )", | ||
| .fun = prim_catAttrs, | ||
| }); | ||
|
|
@@ -3449,6 +3492,10 @@ static RegisterPrimOp primop_functionArgs({ | |
| "Formal argument" here refers to the attributes pattern-matched by | ||
| the function. Plain lambdas are not included, e.g. `functionArgs (x: | ||
| ...) = { }`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n) where n = number of formal arguments | ||
| )", | ||
| .fun = prim_functionArgs, | ||
| }); | ||
|
|
@@ -3481,6 +3528,14 @@ static RegisterPrimOp primop_mapAttrs({ | |
| ``` | ||
|
|
||
| evaluates to `{ a = 10; b = 20; }`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n) where: | ||
|
|
||
| n = number of attributes | ||
|
|
||
| Calls to `f` are performed afterwards, when needed | ||
| )", | ||
| .fun = prim_mapAttrs, | ||
| }); | ||
|
|
@@ -3568,6 +3623,15 @@ static RegisterPrimOp primop_zipAttrsWith({ | |
| b = { name = "b"; values = [ "z" ]; }; | ||
| } | ||
| ``` | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * k * log k) worst case, where: | ||
|
|
||
| n = number of attribute sets in input list | ||
| k = number of unique keys across all sets | ||
|
|
||
| More precisely: O(n * m * log k) where m ≤ k is average number of attributes per set | ||
| )", | ||
| .fun = prim_zipAttrsWith, | ||
| }); | ||
|
|
@@ -3633,6 +3697,10 @@ static RegisterPrimOp primop_head({ | |
| Return the first element of a list; abort evaluation if the argument | ||
| isn’t a list or is an empty list. You can test whether a list is | ||
| empty by comparing it with `[]`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(1) | ||
| )", | ||
| .fun = prim_head, | ||
| }); | ||
|
|
@@ -3664,6 +3732,10 @@ static RegisterPrimOp primop_tail({ | |
| > This function should generally be avoided since it's inefficient: | ||
| > unlike Haskell's `tail`, it takes O(n) time, so recursing over a | ||
| > list by repeatedly calling `tail` takes O(n^2) time. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n) where n = list length (copies n-1 elements) | ||
| )", | ||
| .fun = prim_tail, | ||
| }); | ||
|
|
@@ -3698,6 +3770,14 @@ static RegisterPrimOp primop_map({ | |
| ``` | ||
|
|
||
| evaluates to `[ "foobar" "foobla" "fooabc" ]`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n) where: | ||
|
|
||
| n = list length | ||
|
|
||
| Calls to `f` are performed afterwards when needed. | ||
| )", | ||
| .fun = prim_map, | ||
| }); | ||
|
|
@@ -3747,6 +3827,13 @@ static RegisterPrimOp primop_filter({ | |
| .doc = R"( | ||
| Return a list consisting of the elements of *list* for which the | ||
| function *f* returns `true`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * T_f) where: | ||
|
|
||
| n = list length | ||
| T_f = predicate evaluation time | ||
hsjobeki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| )", | ||
| .fun = prim_filter, | ||
| }); | ||
|
|
@@ -3770,6 +3857,15 @@ static RegisterPrimOp primop_elem({ | |
| .doc = R"( | ||
| Return `true` if a value equal to *x* occurs in the list *xs*, and | ||
| `false` otherwise. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * T) (worst case) where: | ||
|
|
||
| n = list length | ||
| T = time to compare two elements | ||
|
|
||
| returns early if the elements is found | ||
| )", | ||
| .fun = prim_elem, | ||
| }); | ||
|
|
@@ -3792,6 +3888,12 @@ static RegisterPrimOp primop_concatLists({ | |
| .args = {"lists"}, | ||
| .doc = R"( | ||
| Concatenate a list of lists into a single list. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(N) where: | ||
|
|
||
| N = total number of elements across all lists | ||
| )", | ||
| .fun = prim_concatLists, | ||
| }); | ||
|
|
@@ -3808,6 +3910,10 @@ static RegisterPrimOp primop_length({ | |
| .args = {"e"}, | ||
| .doc = R"( | ||
| Return the length of the list *e*. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(1) | ||
| )", | ||
| .fun = prim_length, | ||
| }); | ||
|
|
@@ -3851,6 +3957,17 @@ static RegisterPrimOp primop_foldlStrict({ | |
| argument is the current element being processed. The return value | ||
| of each application of `op` is evaluated immediately, even for | ||
| intermediate values. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * T_op) where: | ||
|
|
||
| n = list length | ||
| T_op = `op` call evaluation time | ||
|
|
||
| Note: Because foldl' evaluates results only to [WHNF](@docroot@/language/evaluation.md#values), | ||
| deeper parts of values returned by op may be evaluated later. | ||
| Their cost (and errors) therefore may not clearly belong to T_op or to foldl' itself. | ||
| )", | ||
| .fun = prim_foldlStrict, | ||
| }); | ||
|
|
@@ -3889,6 +4006,15 @@ static RegisterPrimOp primop_any({ | |
| .doc = R"( | ||
| Return `true` if the function *pred* returns `true` for at least one | ||
| element of *list*, and `false` otherwise. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * T_pred) where: | ||
|
|
||
| - n = `list` length | ||
| - T_pred = `pred` call evaluation time | ||
|
|
||
| returns early when `pred` returns `true` | ||
| )", | ||
| .fun = prim_any, | ||
| }); | ||
|
|
@@ -3904,6 +4030,13 @@ static RegisterPrimOp primop_all({ | |
| .doc = R"( | ||
| Return `true` if the function *pred* returns `true` for all elements | ||
| of *list*, and `false` otherwise. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * T_f) where: | ||
|
|
||
| - n = list length | ||
| - T_f = predicate evaluation time | ||
hsjobeki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| )", | ||
| .fun = prim_all, | ||
| }); | ||
|
|
@@ -3942,6 +4075,14 @@ static RegisterPrimOp primop_genList({ | |
| ``` | ||
|
|
||
| returns the list `[ 0 1 4 9 16 ]`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n) where: | ||
|
|
||
| n = requested length. | ||
|
|
||
| Calls to `generator` are performed afterwards, when needed. | ||
| )", | ||
| .fun = prim_genList, | ||
| }); | ||
|
|
@@ -4036,6 +4177,13 @@ static RegisterPrimOp primop_sort({ | |
|
|
||
| If the *comparator* violates any of these properties, then `builtins.sort` | ||
| reorders elements in an unspecified manner. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n log n * T_cmp), where: | ||
|
|
||
| n = `list` length | ||
| T_cmp = `comparator` call evaluation time | ||
| )", | ||
| .fun = prim_sort, | ||
| }); | ||
|
|
@@ -4097,6 +4245,13 @@ static RegisterPrimOp primop_partition({ | |
| ```nix | ||
| { right = [ 23 42 ]; wrong = [ 1 9 3 ]; } | ||
| ``` | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * T_pred) where: | ||
|
|
||
| n = list length | ||
| T_pred = `pred` call evaluation time | ||
| )", | ||
| .fun = prim_partition, | ||
| }); | ||
|
|
@@ -4150,6 +4305,14 @@ static RegisterPrimOp primop_groupBy({ | |
| ```nix | ||
| { b = [ "bar" "baz" ]; f = [ "foo" ]; } | ||
| ``` | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(N * T_f + N * log k) where: | ||
|
|
||
| N = number of `list` elements | ||
| T_f = `f` call evaluation time | ||
| k = number of unique groups | ||
| )", | ||
| .fun = prim_groupBy, | ||
| }); | ||
|
|
@@ -4192,6 +4355,14 @@ static RegisterPrimOp primop_concatMap({ | |
| .doc = R"( | ||
| This function is equivalent to `builtins.concatLists (map f list)` | ||
| but is more efficient. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(k * T_f + N) where: | ||
|
|
||
| k = length of input list | ||
| T_f = time to call `f` on an element | ||
| N = total number of elements returned by `f` calls | ||
| )", | ||
| .fun = prim_concatMap, | ||
| }); | ||
|
|
@@ -4888,6 +5059,10 @@ static RegisterPrimOp primop_concatStringsSep({ | |
| Concatenate a list of strings with a separator between each | ||
| element, e.g. `concatStringsSep "/" ["usr" "local" "bin"] == | ||
| "usr/local/bin"`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n) where n = total length of output string | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically there's also the evaluation of each element, as this function is currently strict in those.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. O(n+m) where: |
||
| )", | ||
| .fun = prim_concatStringsSep, | ||
| }); | ||
|
|
@@ -4972,6 +5147,14 @@ static RegisterPrimOp primop_replaceStrings({ | |
| ``` | ||
|
|
||
| evaluates to `"fabir"`. | ||
|
|
||
| # Time Complexity | ||
|
|
||
| O(n * k * c) where: | ||
|
|
||
| n = length of input string | ||
| k = number of replacement patterns | ||
| c = average length of patterns in 'from' list | ||
hsjobeki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| )", | ||
| .fun = prim_replaceStrings, | ||
| }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't checked this one.