infra/lib/default.nix
Raito Bezarius 53dc94ca00 chore: reformat properly the library file
Missed reformatting.

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2024-12-23 21:43:22 +01:00

65 lines
3 KiB
Nix

# Some useful utilities to do things that depends on the nixpkgs library.
{ lib }:
let
inherit (lib) listToAttrs zipListsWith nameValuePair length range foldl any mapAttrs;
in
rec {
closedOpenInterval = a: b: { start = a; end = b; };
interval = a: b: closedOpenInterval a b;
singleton = x: interval x (x + 1);
inRange = i: range: i >= range.start && i < range.end;
# Build a selector function that will filters point-by-point any index in xs.
# e.g. if you want to select specific indexes you can just use that.
# If you want to select contiguous interval of indexes, you are better served by
# `mkIntervalFilter`.
mkPointwiseFilter = xs: index: any (allowedIndex: index == allowedIndex) xs;
# Build a selector function that will filters interval-by-interval any index in intervals.
# It will check if the given index is present in any of the passed intervals according
# to `inRange`.
mkIntervalFilter = intervals: index: any (allowedRange: inRange index allowedRange) intervals;
# Build an attribute set map from values to indexes.
# e.g. reversedEnumerate [ "a" "b" ] == { "a" = 0; "b" = 1; }.
reversedEnumerate = list: listToAttrs
(zipListsWith
(index: value: nameValuePair value index)
(range 0 (length list - 1))
list);
# Collect a list of attribute sets into an attribute set.
# Merge order depends on attrValues iteration order and foldl.
chainAttrs = attrs: foldl (a: b: a // b) { } (builtins.attrValues attrs);
# Given an attribute set of an attribute set of items, does it describe a valid partition of some global set?
# This does not check for completeness.
# idFunction :: Attrs K V → List Identifier
isValidPartition = attrs:
let
values = builtins.attrValues attrs;
in
# TODO(performance?): this is the simple dumb idea.
# A better idea would use n(n - 1)/2 iterations over values to exploit symmetry of item equality.
# To do so, a strategy could be to consider all shifted toplevel identifiers lists and zip them.
# There's sum_k(n - k) such lists, and therefore: n(n - 1)/2 lists.
# For every list, we need to perform list intersection which is supposedly in O(n log n) in the size of the nodes identifiers.
# So, if we have N subsets in the partition and each subset has at most K items, we end up doing something like (K log K) * N(N - 1)/2
# In practice, K should be the biggest and N is quite small.
lib.all (subset:
lib.all (anotherSubset:
subset != anotherSubset -> lib.intersectAttrs subset anotherSubset == {}
) values
) values;
# Renumber an attribute set of items.
# For each item in the attribute set, we replace its value by a call to the renumbering function
# where we pass renumberedIndex and value.
# It's a form of imap for attribute sets.
renumber = indexFn: renumberingFn: attrs:
let
indexes = reversedEnumerate (map (n: toString (indexFn n)) (builtins.attrValues attrs));
in
mapAttrs (name: value: renumberingFn indexes.${toString (indexFn value)} value) attrs;
}