Files
OpenVulkano/openVulkanoCpp/Math/ByteSize.hpp
2025-06-23 01:11:22 +02:00

165 lines
6.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 <array>
#include <string>
#include <sstream>
#include <regex>
#include <iomanip>
#include <magic_enum/magic_enum.hpp>
namespace OpenVulkano
{
namespace ByteSizeUnitHelper
{
consteval 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;
}
consteval std::array<double, 13> BuildDivisors()
{
std::array<uint64_t, 13> factors = BuildFactors();
std::array<double, 13> divs{{1}};
for (size_t 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 = 0, kiB, MiB, GiB, TiB, PiB, EiB, kB, MB, GB, TB, PB, EB };
constexpr ByteSizeUnit(const 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(R"(\s*(\d+(\.\d*)?|\.\d+)\s*([kMGTPE]i?B)\s*)");
uint64_t bytes;
public:
constexpr ByteSize(const uint64_t size = 0) : bytes(size) {}
template<typename T>
constexpr ByteSize(const T size, const 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 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); }
std::ostream& FormatStream(std::ostream& oss, const bool si = false) const
{
oss << std::setprecision(3);
auto unit = ByteSizeUnit::GetClosestUnit(bytes, si);
oss << static_cast<double>(bytes) * unit.GetDivisor() << ' ' << unit.GetName();
return oss;
}
[[nodiscard]] std::string Format(const bool si = false) const
{
std::ostringstream oss;
FormatStream(oss, si);
return oss.str();
}
constexpr operator uint64_t() const { return bytes; }
operator std::string() const { return Format(); }
ByteSize operator +(const ByteSize other) const { return bytes + other.bytes; }
ByteSize operator -(const ByteSize other) const { return bytes - other.bytes; }
ByteSize operator +(const size_t other) const { return bytes + other; }
ByteSize operator -(const size_t other) const { return bytes - other; }
ByteSize& operator =(const size_t other) { bytes = other; return *this; }
ByteSize& operator =(const ByteSize other) { bytes = other.bytes; return *this; }
ByteSize& operator +=(const size_t other) { bytes += other; return *this; }
ByteSize& operator +=(const ByteSize other) { bytes += other.bytes; return *this; }
ByteSize& operator -=(const size_t other) { bytes -= other; return *this; }
ByteSize& operator -=(const ByteSize other) { bytes -= other.bytes; return *this; }
};
constexpr ByteSize operator""_kiB(long double num) { return { num, ByteSizeUnit::kiB }; }
constexpr ByteSize operator""_MiB(long double num) { return { num, ByteSizeUnit::MiB }; }
constexpr ByteSize operator""_GiB(long double num) { return { num, ByteSizeUnit::GiB }; }
constexpr ByteSize operator""_TiB(long double num) { return { num, ByteSizeUnit::TiB }; }
constexpr ByteSize operator""_PiB(long double num) { return { num, ByteSizeUnit::PiB }; }
constexpr ByteSize operator""_EiB(long double num) { return { num, ByteSizeUnit::EiB }; }
constexpr ByteSize operator""_kB (long double num) { return { num, ByteSizeUnit::kB }; }
constexpr ByteSize operator""_MB (long double num) { return { num, ByteSizeUnit::MB }; }
constexpr ByteSize operator""_GB (long double num) { return { num, ByteSizeUnit::GB }; }
constexpr ByteSize operator""_TB (long double num) { return { num, ByteSizeUnit::TB }; }
constexpr ByteSize operator""_PB (long double num) { return { num, ByteSizeUnit::PB }; }
constexpr ByteSize operator""_EB (long double num) { return { num, ByteSizeUnit::EB }; }
constexpr ByteSize operator""_B (unsigned long long int num) { return { num }; }
constexpr ByteSize operator""_kiB(unsigned long long int num) { return { num << 10 }; }
constexpr ByteSize operator""_MiB(unsigned long long int num) { return { num << 20 }; }
constexpr ByteSize operator""_GiB(unsigned long long int num) { return { num << 30 }; }
constexpr ByteSize operator""_TiB(unsigned long long int num) { return { num << 40 }; }
constexpr ByteSize operator""_PiB(unsigned long long int num) { return { num << 50 }; }
constexpr ByteSize operator""_EiB(unsigned long long int num) { return { num << 60 }; }
constexpr ByteSize operator""_kB (unsigned long long int num) { return { num, ByteSizeUnit::kB }; }
constexpr ByteSize operator""_MB (unsigned long long int num) { return { num, ByteSizeUnit::MB }; }
constexpr ByteSize operator""_GB (unsigned long long int num) { return { num, ByteSizeUnit::GB }; }
constexpr ByteSize operator""_TB (unsigned long long int num) { return { num, ByteSizeUnit::TB }; }
constexpr ByteSize operator""_PB (unsigned long long int num) { return { num, ByteSizeUnit::PB }; }
constexpr ByteSize operator""_EB (unsigned long long int num) { return { num, ByteSizeUnit::EB }; }
}