Skip to content

Commit 6985811

Browse files
committed
docs: add time complexity to relevant primops
1 parent 3645671 commit 6985811

File tree

1 file changed

+183
-1
lines changed

1 file changed

+183
-1
lines changed

src/libexpr/primops.cc

Lines changed: 183 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2999,6 +2999,13 @@ static RegisterPrimOp primop_attrNames({
29992999
Return the names of the attributes in the set *set* in an
30003000
alphabetically sorted list. For instance, `builtins.attrNames { y
30013001
= 1; x = "foo"; }` evaluates to `[ "x" "y" ]`.
3002+
3003+
## Time Complexity
3004+
3005+
- O(n) best case (attribute set already sorted)
3006+
- O(n log n) worst case (requires sorting), where:
3007+
3008+
n = number of attributes in the set
30023009
)",
30033010
.fun = prim_attrNames,
30043011
});
@@ -3031,6 +3038,13 @@ static RegisterPrimOp primop_attrValues({
30313038
.doc = R"(
30323039
Return the values of the attributes in the set *set* in the order
30333040
corresponding to the sorted attribute names.
3041+
3042+
## Time Complexity
3043+
3044+
- O(n) best case (attribute set already sorted)
3045+
- O(n log n) worst case (requires sorting), where:
3046+
3047+
n = number of attributes in the set
30343048
)",
30353049
.fun = prim_attrValues,
30363050
});
@@ -3056,6 +3070,10 @@ static RegisterPrimOp primop_getAttr({
30563070
aborts if the attribute doesn’t exist. This is a dynamic version of
30573071
the `.` operator, since *s* is an expression rather than an
30583072
identifier.
3073+
3074+
# Time Complexity
3075+
3076+
O(log n) where n = number of attributes in the set
30593077
)",
30603078
.fun = prim_getAttr,
30613079
});
@@ -3144,6 +3162,10 @@ static RegisterPrimOp primop_hasAttr({
31443162
`hasAttr` returns `true` if *set* has an attribute named *s*, and
31453163
`false` otherwise. This is a dynamic version of the `?` operator,
31463164
since *s* is an expression rather than an identifier.
3165+
3166+
# Time Complexity
3167+
3168+
O(log n) where n = number of attributes in the set
31473169
)",
31483170
.fun = prim_hasAttr,
31493171
});
@@ -3203,6 +3225,13 @@ static RegisterPrimOp primop_removeAttrs({
32033225
```
32043226
32053227
evaluates to `{ y = 2; }`.
3228+
3229+
# Time Complexity
3230+
3231+
O(n + k log k) where:
3232+
3233+
n = number of attributes in input set
3234+
k = number of attribute names to remove
32063235
)",
32073236
.fun = prim_removeAttrs,
32083237
});
@@ -3290,6 +3319,10 @@ static RegisterPrimOp primop_listToAttrs({
32903319
```nix
32913320
{ foo = 123; bar = 456; }
32923321
```
3322+
3323+
# Time Complexity
3324+
3325+
O(n log n) where n = number of list elements
32933326
)",
32943327
.fun = prim_listToAttrs,
32953328
});
@@ -3366,7 +3399,12 @@ static RegisterPrimOp primop_intersectAttrs({
33663399
Return a set consisting of the attributes in the set *e2* which have the
33673400
same name as some attribute in *e1*.
33683401
3369-
Performs in O(*n* log *m*) where *n* is the size of the smaller set and *m* the larger set's size.
3402+
# Time Complexity
3403+
3404+
O(n * log m) where:
3405+
3406+
n = number of attributes in the smaller set
3407+
m = number of attributes in the larger set
33703408
)",
33713409
.fun = prim_intersectAttrs,
33723410
});
@@ -3406,6 +3444,13 @@ static RegisterPrimOp primop_catAttrs({
34063444
```
34073445
34083446
evaluates to `[1 2]`.
3447+
3448+
# Time Complexity
3449+
3450+
O(n * log m) where:
3451+
3452+
n = number of sets in input list
3453+
m = average number of attributes per set
34093454
)",
34103455
.fun = prim_catAttrs,
34113456
});
@@ -3449,6 +3494,10 @@ static RegisterPrimOp primop_functionArgs({
34493494
"Formal argument" here refers to the attributes pattern-matched by
34503495
the function. Plain lambdas are not included, e.g. `functionArgs (x:
34513496
...) = { }`.
3497+
3498+
# Time Complexity
3499+
3500+
O(n) where n = number of formal arguments
34523501
)",
34533502
.fun = prim_functionArgs,
34543503
});
@@ -3481,6 +3530,13 @@ static RegisterPrimOp primop_mapAttrs({
34813530
```
34823531
34833532
evaluates to `{ a = 10; b = 20; }`.
3533+
3534+
# Time Complexity
3535+
3536+
O(n * T_f) where:
3537+
3538+
n = number of attributes
3539+
T_f = function evaluation time
34843540
)",
34853541
.fun = prim_mapAttrs,
34863542
});
@@ -3568,6 +3624,15 @@ static RegisterPrimOp primop_zipAttrsWith({
35683624
b = { name = "b"; values = [ "z" ]; };
35693625
}
35703626
```
3627+
3628+
# Time Complexity
3629+
3630+
O(n * k * log k) worst case, where:
3631+
3632+
n = number of attribute sets in input list
3633+
k = number of unique keys across all sets
3634+
3635+
More precisely: O(n * m * log k) where m ≤ k is average number of attributes per set
35713636
)",
35723637
.fun = prim_zipAttrsWith,
35733638
});
@@ -3633,6 +3698,10 @@ static RegisterPrimOp primop_head({
36333698
Return the first element of a list; abort evaluation if the argument
36343699
isn’t a list or is an empty list. You can test whether a list is
36353700
empty by comparing it with `[]`.
3701+
3702+
# Time Complexity
3703+
3704+
O(1)
36363705
)",
36373706
.fun = prim_head,
36383707
});
@@ -3664,6 +3733,10 @@ static RegisterPrimOp primop_tail({
36643733
> This function should generally be avoided since it's inefficient:
36653734
> unlike Haskell's `tail`, it takes O(n) time, so recursing over a
36663735
> list by repeatedly calling `tail` takes O(n^2) time.
3736+
3737+
# Time Complexity
3738+
3739+
O(n) where n = list length (must copy n-1 elements)
36673740
)",
36683741
.fun = prim_tail,
36693742
});
@@ -3698,6 +3771,13 @@ static RegisterPrimOp primop_map({
36983771
```
36993772
37003773
evaluates to `[ "foobar" "foobla" "fooabc" ]`.
3774+
3775+
# Time Complexity
3776+
3777+
O(n * T_f) where:
3778+
3779+
n = list length
3780+
T_f = function evaluation time
37013781
)",
37023782
.fun = prim_map,
37033783
});
@@ -3747,6 +3827,13 @@ static RegisterPrimOp primop_filter({
37473827
.doc = R"(
37483828
Return a list consisting of the elements of *list* for which the
37493829
function *f* returns `true`.
3830+
3831+
# Time Complexity
3832+
3833+
O(n * T_f) where:
3834+
3835+
n = list length
3836+
T_f = predicate evaluation time
37503837
)",
37513838
.fun = prim_filter,
37523839
});
@@ -3770,6 +3857,15 @@ static RegisterPrimOp primop_elem({
37703857
.doc = R"(
37713858
Return `true` if a value equal to *x* occurs in the list *xs*, and
37723859
`false` otherwise.
3860+
3861+
# Time Complexity
3862+
3863+
O(n * T) (worst case) where:
3864+
3865+
n = list length
3866+
T = time to compare average element
3867+
3868+
returns early if the elements is found
37733869
)",
37743870
.fun = prim_elem,
37753871
});
@@ -3792,6 +3888,13 @@ static RegisterPrimOp primop_concatLists({
37923888
.args = {"lists"},
37933889
.doc = R"(
37943890
Concatenate a list of lists into a single list.
3891+
3892+
# Time Complexity
3893+
3894+
O(k + N) where:
3895+
3896+
k = number of input lists
3897+
N = total number of elements across all lists
37953898
)",
37963899
.fun = prim_concatLists,
37973900
});
@@ -3808,6 +3911,10 @@ static RegisterPrimOp primop_length({
38083911
.args = {"e"},
38093912
.doc = R"(
38103913
Return the length of the list *e*.
3914+
3915+
# Time Complexity
3916+
3917+
O(1)
38113918
)",
38123919
.fun = prim_length,
38133920
});
@@ -3851,6 +3958,13 @@ static RegisterPrimOp primop_foldlStrict({
38513958
argument is the current element being processed. The return value
38523959
of each application of `op` is evaluated immediately, even for
38533960
intermediate values.
3961+
3962+
# Time Complexity
3963+
3964+
O(n * T_f) where:
3965+
3966+
n = list length
3967+
T_f = fold function evaluation time
38543968
)",
38553969
.fun = prim_foldlStrict,
38563970
});
@@ -3889,6 +4003,15 @@ static RegisterPrimOp primop_any({
38894003
.doc = R"(
38904004
Return `true` if the function *pred* returns `true` for at least one
38914005
element of *list*, and `false` otherwise.
4006+
4007+
## Time Complexity
4008+
4009+
O(n * T_f) where:
4010+
4011+
- n = list length
4012+
- T_f = predicate evaluation time
4013+
4014+
returns early when predicate returns true
38924015
)",
38934016
.fun = prim_any,
38944017
});
@@ -3904,6 +4027,13 @@ static RegisterPrimOp primop_all({
39044027
.doc = R"(
39054028
Return `true` if the function *pred* returns `true` for all elements
39064029
of *list*, and `false` otherwise.
4030+
4031+
## Time Complexity
4032+
4033+
O(n * T_f) where:
4034+
4035+
- n = list length
4036+
- T_f = predicate evaluation time
39074037
)",
39084038
.fun = prim_all,
39094039
});
@@ -3942,6 +4072,13 @@ static RegisterPrimOp primop_genList({
39424072
```
39434073
39444074
returns the list `[ 0 1 4 9 16 ]`.
4075+
4076+
# Time Complexity
4077+
4078+
O(n * T_f) where:
4079+
4080+
n = requested length
4081+
T_f = generator function evaluation time
39454082
)",
39464083
.fun = prim_genList,
39474084
});
@@ -4036,6 +4173,14 @@ static RegisterPrimOp primop_sort({
40364173
40374174
If the *comparator* violates any of these properties, then `builtins.sort`
40384175
reorders elements in an unspecified manner.
4176+
4177+
# Time Complexity
4178+
4179+
O(n log n * T_cmp) worst case
4180+
O(n * T_cmp) best case (input already sorted), where:
4181+
4182+
n = list length
4183+
T_cmp = comparator evaluation time
40394184
)",
40404185
.fun = prim_sort,
40414186
});
@@ -4097,6 +4242,13 @@ static RegisterPrimOp primop_partition({
40974242
```nix
40984243
{ right = [ 23 42 ]; wrong = [ 1 9 3 ]; }
40994244
```
4245+
4246+
# Time Complexity
4247+
4248+
O(n * T_f) where:
4249+
4250+
n = list length
4251+
T_f = predicate evaluation time
41004252
)",
41014253
.fun = prim_partition,
41024254
});
@@ -4150,7 +4302,17 @@ static RegisterPrimOp primop_groupBy({
41504302
```nix
41514303
{ b = [ "bar" "baz" ]; f = [ "foo" ]; }
41524304
```
4305+
4306+
# Time Complexity
4307+
4308+
O(N * T_f + N * log k) where:
4309+
4310+
N = number of list elements
4311+
T_f = grouping function evaluation time
4312+
k = number of unique groups
41534313
)",
4314+
T_f = grouping function evaluation time
4315+
k = number of unique groups
41544316
.fun = prim_groupBy,
41554317
});
41564318

@@ -4192,6 +4354,14 @@ static RegisterPrimOp primop_concatMap({
41924354
.doc = R"(
41934355
This function is equivalent to `builtins.concatLists (map f list)`
41944356
but is more efficient.
4357+
4358+
# Time Complexity
4359+
4360+
O(k * T_f + N) where:
4361+
4362+
k = length of input list
4363+
T_f = time to evaluate function on each element
4364+
N = total elements in all output lists
41954365
)",
41964366
.fun = prim_concatMap,
41974367
});
@@ -4888,6 +5058,10 @@ static RegisterPrimOp primop_concatStringsSep({
48885058
Concatenate a list of strings with a separator between each
48895059
element, e.g. `concatStringsSep "/" ["usr" "local" "bin"] ==
48905060
"usr/local/bin"`.
5061+
5062+
# Time Complexity
5063+
5064+
O(n) where n = total length of output string
48915065
)",
48925066
.fun = prim_concatStringsSep,
48935067
});
@@ -4972,6 +5146,14 @@ static RegisterPrimOp primop_replaceStrings({
49725146
```
49735147
49745148
evaluates to `"fabir"`.
5149+
5150+
# Time Complexity
5151+
5152+
O(n * k * c) where:
5153+
5154+
n = length of input string
5155+
k = number of replacement patterns
5156+
c = average length of patterns in 'from' list
49755157
)",
49765158
.fun = prim_replaceStrings,
49775159
});

0 commit comments

Comments
 (0)