tvl-depot/users/sterni/nix/int/default.nix
sterni 81fc87e29e refactor(nix/sterni/int): rename div & mod to quot & rem
This mirrors the terminology Haskell uses: quot and rem truncate towards
zero which is also the case for builtins.div. We can give us the option
to introduce Haskell-style int.div and int.mod (to complete the
confusion) which would truncate towards negative infinity.

Change-Id: Ibebb0a01a73c9718cd62121b2fc2a19c3a4be0de
Reviewed-on: https://cl.tvl.fyi/c/depot/+/9009
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
2023-08-09 12:12:47 +00:00

114 lines
2.4 KiB
Nix

{ depot, lib, ... }:
let
inherit (depot.users.sterni.nix)
string
num
;
inherit (builtins)
bitOr
bitAnd
bitXor
;
exp = base: pow:
if pow > 0
then base * (exp base (pow - 1))
else if pow < 0
then 1.0 / exp base (num.abs pow)
else 1;
bitShiftR = bit: count:
if count == 0
then bit
else (bitShiftR bit (count - 1)) / 2;
bitShiftL = bit: count:
if count == 0
then bit
else 2 * (bitShiftL bit (count - 1));
hexdigits = "0123456789ABCDEF";
toHex = int:
let
go = i:
if i == 0
then ""
else go (bitShiftR i 4)
+ string.charAt (bitAnd i 15) hexdigits;
sign = lib.optionalString (int < 0) "-";
in
if int == 0
then "0"
else "${sign}${go (num.abs int)}";
fromHexMap = builtins.listToAttrs
(lib.imap0 (i: c: { name = c; value = i; })
(lib.stringToCharacters hexdigits));
fromHex = literal:
let
negative = string.charAt 0 literal == "-";
start = if negative then 1 else 0;
len = builtins.stringLength literal;
# reversed list of all digits
digits = builtins.genList
(i: string.charAt (len - 1 - i) literal)
(len - start);
parsed = builtins.foldl'
(v: d: {
val = v.val + (fromHexMap."${d}" * v.mul);
mul = v.mul * 16;
})
{ val = 0; mul = 1; }
digits;
in
if negative
then -parsed.val
else parsed.val;
# A nix integer is a 64bit signed integer
maxBound = 9223372036854775807;
# fun fact: -9223372036854775808 is the lower bound
# for a nix integer (as you would expect), but you can't
# use it as an integer literal or you'll be greeted with:
# error: invalid integer '9223372036854775808'
# This is because all int literals when parsing are
# positive, negative "literals" are positive literals
# which are preceded by the arithmetric negation operator.
minBound = -9223372036854775807 - 1;
odd = x: bitAnd x 1 == 1;
even = x: bitAnd x 1 == 0;
quot' = builtins.div; # no typecheck
rem = a: b:
assert builtins.isInt a && builtins.isInt b;
let res = quot' a b; in a - (res * b);
quot = a: b:
assert builtins.isInt a && builtins.isInt b;
quot' a b;
in
{
inherit
maxBound
minBound
exp
odd
even
quot
rem
bitShiftR
bitShiftL
bitOr
bitAnd
bitXor
toHex
fromHex
;
}