Files
OpenVulkano/openVulkanoCpp/Math/ByteSize.hpp

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());
}
};