From 8301cd37b5299721b9ab60c3f8eaf0d0b0b6967e Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Thu, 18 Feb 2021 02:52:26 +0100 Subject: [PATCH] Add ByteSize class for size string formatting --- openVulkanoCpp/Math/ByteSize.hpp | 125 +++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 openVulkanoCpp/Math/ByteSize.hpp diff --git a/openVulkanoCpp/Math/ByteSize.hpp b/openVulkanoCpp/Math/ByteSize.hpp new file mode 100644 index 0000000..e566d48 --- /dev/null +++ b/openVulkanoCpp/Math/ByteSize.hpp @@ -0,0 +1,125 @@ +/* + * 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 +#include +#include +#include +#include +#include + +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 +{ + template constexpr auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template auto format(const openVulkanoCpp::ByteSize& bs, FormatContext& ctx) + { + return format_to(ctx.out(), "{}", bs.Format()); + } +}; \ No newline at end of file