125 lines
5.3 KiB
C++
125 lines
5.3 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <regex>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <spdlog/fmt/fmt.h>
|
|
|
|
namespace openVulkanoCpp
|
|
{
|
|
class ByteSize final
|
|
{
|
|
static inline const std::regex REGEX_PATTERN = std::regex("\\s*(\\d+(\\.\\d*)?|\\.\\d+)\\s*([kMGTPE]i?)[Bb]\\s*");
|
|
|
|
size_t bytes;
|
|
|
|
public:
|
|
constexpr ByteSize(size_t size = 0) : bytes(size) {}
|
|
|
|
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;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os) const { return FormatStream(os); }
|
|
|
|
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";
|
|
}
|
|
return oss;
|
|
}
|
|
|
|
[[nodiscard]] std::string Format(bool si = false) const
|
|
{
|
|
std::ostringstream oss;
|
|
FormatStream(oss, si);
|
|
return oss.str();
|
|
}
|
|
|
|
constexpr operator size_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); }
|
|
// 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); }
|
|
}
|
|
|
|
template<> struct fmt::formatter<openVulkanoCpp::ByteSize>
|
|
{
|
|
template<typename ParseContext> constexpr auto parse(ParseContext& ctx)
|
|
{
|
|
return ctx.begin();
|
|
}
|
|
|
|
template<typename FormatContext> auto format(const openVulkanoCpp::ByteSize& bs, FormatContext& ctx)
|
|
{
|
|
return format_to(ctx.out(), "{}", bs.Format());
|
|
}
|
|
}; |