mirror of
https://github.com/NixOS/nix.git
synced 2025-11-15 23:12:44 +01:00
progress-bar: use dynamic size units
This commit is contained in:
parent
da637a05da
commit
0c53c88367
4 changed files with 205 additions and 14 deletions
|
|
@ -99,6 +99,42 @@ N string2IntWithUnitPrefix(std::string_view s)
|
|||
throw UsageError("'%s' is not an integer", s);
|
||||
}
|
||||
|
||||
// Base also uses 'K', because it should also displayed as KiB => 100 Bytes => 0.1 KiB
|
||||
#define NIX_UTIL_SIZE_UNITS \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Base, 'K') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Kilo, 'K') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Mega, 'M') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Giga, 'G') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Tera, 'T') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Peta, 'P') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Exa, 'E') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Zetta, 'Z') \
|
||||
NIX_UTIL_DEFINE_SIZE_UNIT(Yotta, 'Y')
|
||||
|
||||
enum class SizeUnit {
|
||||
#define NIX_UTIL_DEFINE_SIZE_UNIT(name, suffix) name,
|
||||
NIX_UTIL_SIZE_UNITS
|
||||
#undef NIX_UTIL_DEFINE_SIZE_UNIT
|
||||
};
|
||||
|
||||
constexpr inline auto sizeUnits = std::to_array<SizeUnit>({
|
||||
#define NIX_UTIL_DEFINE_SIZE_UNIT(name, suffix) SizeUnit::name,
|
||||
NIX_UTIL_SIZE_UNITS
|
||||
#undef NIX_UTIL_DEFINE_SIZE_UNIT
|
||||
});
|
||||
|
||||
SizeUnit getSizeUnit(int64_t value);
|
||||
|
||||
/**
|
||||
* Returns the unit if all values would be rendered using the same unit
|
||||
* otherwise returns `std::nullopt`.
|
||||
*/
|
||||
std::optional<SizeUnit> getCommonSizeUnit(std::initializer_list<int64_t> values);
|
||||
|
||||
std::string renderSizeWithoutUnit(int64_t value, SizeUnit unit, bool align = false);
|
||||
|
||||
char getSizeUnitSuffix(SizeUnit unit);
|
||||
|
||||
/**
|
||||
* Pretty-print a byte value, e.g. 12433615056 is rendered as `11.6
|
||||
* GiB`. If `align` is set, the number will be right-justified by
|
||||
|
|
|
|||
|
|
@ -132,17 +132,62 @@ std::optional<N> string2Float(const std::string_view s)
|
|||
template std::optional<double> string2Float<double>(const std::string_view s);
|
||||
template std::optional<float> string2Float<float>(const std::string_view s);
|
||||
|
||||
static const int64_t conversionNumber = 1024;
|
||||
|
||||
SizeUnit getSizeUnit(int64_t value)
|
||||
{
|
||||
auto unit = sizeUnits.begin();
|
||||
uint64_t absValue = std::abs(value);
|
||||
while (absValue > conversionNumber && unit < sizeUnits.end()) {
|
||||
unit++;
|
||||
absValue /= conversionNumber;
|
||||
}
|
||||
return *unit;
|
||||
}
|
||||
|
||||
std::optional<SizeUnit> getCommonSizeUnit(std::initializer_list<int64_t> values)
|
||||
{
|
||||
assert(values.size() > 0);
|
||||
|
||||
auto it = values.begin();
|
||||
SizeUnit unit = getSizeUnit(*it);
|
||||
it++;
|
||||
|
||||
for (; it != values.end(); it++) {
|
||||
if (unit != getSizeUnit(*it)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
std::string renderSizeWithoutUnit(int64_t value, SizeUnit unit, bool align)
|
||||
{
|
||||
// bytes should also displayed as KiB => 100 Bytes => 0.1 KiB
|
||||
auto power = std::max<std::underlying_type_t<SizeUnit>>(1, std::to_underlying(unit));
|
||||
double denominator = std::pow(conversionNumber, power);
|
||||
double result = (double) value / denominator;
|
||||
return fmt(align ? "%6.1f" : "%.1f", result);
|
||||
}
|
||||
|
||||
char getSizeUnitSuffix(SizeUnit unit)
|
||||
{
|
||||
switch (unit) {
|
||||
#define NIX_UTIL_DEFINE_SIZE_UNIT(name, suffix) \
|
||||
case SizeUnit::name: \
|
||||
return suffix;
|
||||
NIX_UTIL_SIZE_UNITS
|
||||
#undef NIX_UTIL_DEFINE_SIZE_UNIT
|
||||
}
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
std::string renderSize(int64_t value, bool align)
|
||||
{
|
||||
static const std::array<char, 9> prefixes{{'K', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'}};
|
||||
size_t power = 0;
|
||||
double abs_value = std::abs(value);
|
||||
while (abs_value > 1024 && power < prefixes.size()) {
|
||||
++power;
|
||||
abs_value /= 1024;
|
||||
}
|
||||
double res = (double) value / std::pow(1024.0, power);
|
||||
return fmt(align ? "%6.1f %ciB" : "%.1f %ciB", power == 0 ? res / 1024 : res, prefixes.at(power));
|
||||
SizeUnit unit = getSizeUnit(value);
|
||||
return fmt("%s %ciB", renderSizeWithoutUnit(value, unit, align), getSizeUnitSuffix(unit));
|
||||
}
|
||||
|
||||
bool hasPrefix(std::string_view s, std::string_view prefix)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue