diff options
Diffstat (limited to 'util/human/units.lua')
-rw-r--r-- | util/human/units.lua | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/util/human/units.lua b/util/human/units.lua new file mode 100644 index 00000000..af233e98 --- /dev/null +++ b/util/human/units.lua @@ -0,0 +1,80 @@ +local math_abs = math.abs; +local math_ceil = math.ceil; +local math_floor = math.floor; +local math_log = math.log; +local math_max = math.max; +local math_min = math.min; +local unpack = table.unpack or unpack; --luacheck: ignore 113 + +if math_log(10, 10) ~= 1 then + -- Lua 5.1 COMPAT + local log10 = math.log10; + function math_log(n, base) + return log10(n) / log10(base); + end +end + +local large = { + "k", 1000, + "M", 1000000, + "G", 1000000000, + "T", 1000000000000, + "P", 1000000000000000, + "E", 1000000000000000000, + "Z", 1000000000000000000000, + "Y", 1000000000000000000000000, +} +local small = { + "m", 0.001, + "μ", 0.000001, + "n", 0.000000001, + "p", 0.000000000001, + "f", 0.000000000000001, + "a", 0.000000000000000001, + "z", 0.000000000000000000001, + "y", 0.000000000000000000000001, +} + +local binary = { + "Ki", 2^10, + "Mi", 2^20, + "Gi", 2^30, + "Ti", 2^40, + "Pi", 2^50, + "Ei", 2^60, + "Zi", 2^70, + "Yi", 2^80, +} + +local function adjusted_unit(n, b) + local round = math_floor; + local prefixes = large; + local logbase = 1000; + if b == 'b' then + prefixes = binary; + logbase = 1024; + elseif n < 1 then + prefixes = small; + round = math_ceil; + end + local m = math_max(0, math_min(8, round(math_abs(math_log(math_abs(n), logbase))))); + local prefix, multiplier = unpack(prefixes, m * 2-1, m*2); + return multiplier or 1, prefix; +end + +-- n: number, the number to format +-- unit: string, the base unit +-- b: optional enum 'b', thousands base +local function format(n, unit, b) --> string + local fmt = "%.3g %s%s"; + if n == 0 then + return fmt:format(n, "", unit); + end + local multiplier, prefix = adjusted_unit(n, b); + return fmt:format(n / multiplier, prefix or "", unit); +end + +return { + adjust = adjusted_unit; + format = format; +}; |