util/binaryMerge: init

This commit is contained in:
Oystein Kristoffer Tveit 2024-09-27 21:42:26 +02:00
parent 21ab209d6e
commit 842f60715b
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
2 changed files with 34 additions and 0 deletions

View File

@ -3,7 +3,13 @@
outputs = { self, nixpkgs-lib }: let outputs = { self, nixpkgs-lib }: let
inherit (nixpkgs-lib) lib; inherit (nixpkgs-lib) lib;
util = {
binaryMerge = import ./util/binaryMerge.nix;
};
in { in {
inherit util;
genAttrs = import ./src/genAttrs.nix lib; genAttrs = import ./src/genAttrs.nix lib;
subtractLists = import ./src/subtractLists.nix lib; subtractLists = import ./src/subtractLists.nix lib;
unique = import ./src/unique.nix lib; unique = import ./src/unique.nix lib;

28
util/binaryMerge.nix Normal file
View File

@ -0,0 +1,28 @@
# binaryMerge :: (b -> b -> b) -> [b] -> b | null
merge:
list:
let
# `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
# Type: Int -> Int -> b
binaryMerge' = start: end:
# assert start < end; # Invariant
if end - start >= 2 then
let
# If there's at least 2 elements, split the range in two, recurse on each part and merge the result
# The invariant is satisfied because each half will have at least 1 element
firstHalf = binaryMerge' start (start + (end - start) / 2);
secondHalf = binaryMerge' (start + (end - start) / 2) end;
in merge firstHalf secondHalf
else
# Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
builtins.elemAt list start;
in
if list == [ ] then
# Calling binaryMerge as below would not satisfy its invariant
null
else
binaryMerge' 0 (builtins.length list)
# Source: taken and modified from
# https://github.com/NixOS/nixpkgs/blob/3cae63521d93eb2fb0aba28218ca9b00150ffdc1/lib/attrsets.nix#L1488-L1507