1#ifndef NEFORCE_CORE_UTILITY_BYTE_SIZE_HPP__
2#define NEFORCE_CORE_UTILITY_BYTE_SIZE_HPP__
16NEFORCE_BEGIN_NAMESPACE__
214 NEFORCE_NODISCARD
constexpr uint64_t bytes() const noexcept {
return bytes_; }
238 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
unit u,
int precision = 2,
bool binary =
true)
const;
244 NEFORCE_NODISCARD
constexpr bool is_zero() const noexcept {
return bytes_ == 0; }
247 bytes_ += rhs.bytes_;
251 constexpr byte_size& operator-=(
const byte_size& rhs) {
252 if (bytes_ < rhs.bytes_) {
253 NEFORCE_THROW_EXCEPTION(value_exception(
"Memory size subtraction underflow"));
255 bytes_ -= rhs.bytes_;
259 constexpr byte_size& operator*=(uint64_t factor)
noexcept {
264 constexpr byte_size& operator/=(uint64_t divisor) {
266 NEFORCE_THROW_EXCEPTION(value_exception(
"Division by zero"));
272 NEFORCE_NODISCARD
constexpr byte_size
operator+(
const byte_size& rhs)
const noexcept {
273 return byte_size(bytes_ + rhs.bytes_);
276 NEFORCE_NODISCARD
constexpr byte_size
operator-(
const byte_size& rhs)
const {
277 if (bytes_ < rhs.bytes_) {
278 NEFORCE_THROW_EXCEPTION(value_exception(
"Memory size subtraction underflow"));
280 return byte_size(bytes_ - rhs.bytes_);
283 NEFORCE_NODISCARD
constexpr byte_size
operator*(uint64_t factor)
const {
284 if (factor > 0 && bytes_ > numeric_traits<uint64_t>::max() / factor) {
285 NEFORCE_THROW_EXCEPTION(value_exception(
"Memory size multiplication overflow"));
287 return byte_size(bytes_ * factor);
290 NEFORCE_NODISCARD
constexpr byte_size
operator/(uint64_t divisor)
const {
292 NEFORCE_THROW_EXCEPTION(value_exception(
"Division by zero"));
294 return byte_size(bytes_ / divisor);
297 NEFORCE_NODISCARD
friend constexpr byte_size
operator*(uint64_t factor,
const byte_size& size) {
298 return size * factor;
301 NEFORCE_NODISCARD
constexpr bool equal_to(
const byte_size& rhs)
const noexcept {
return bytes_ == rhs.bytes_; }
302 NEFORCE_NODISCARD
constexpr bool less_than(
const byte_size& rhs)
const noexcept {
return bytes_ < rhs.bytes_; }
331struct byte_size_unit_mapping {
338NEFORCE_INLINE17
constexpr uint64_t byte_size_binary_multipliers[] = {
342 1024ULL * 1024 * 1024,
343 1024ULL * 1024 * 1024 * 1024,
344 1024ULL * 1024 * 1024 * 1024 * 1024,
345 1024ULL * 1024 * 1024 * 1024 * 1024 * 1024
348NEFORCE_INLINE17
constexpr uint64_t byte_size_decimal_multipliers[] = {
352 1000ULL * 1000 * 1000,
353 1000ULL * 1000 * 1000 * 1000,
354 1000ULL * 1000 * 1000 * 1000 * 1000,
355 1000ULL * 1000 * 1000 * 1000 * 1000 * 1000
358NEFORCE_INLINE17
constexpr byte_size_unit_mapping byte_size_unit_mappings[] = {
359 {
"B",
"", byte_size::unit::B}, {
"KB",
"K", byte_size::unit::KB}, {
"MB",
"M", byte_size::unit::MB},
360 {
"GB",
"G", byte_size::unit::GB}, {
"TB",
"T", byte_size::unit::TB}, {
"PB",
"P", byte_size::unit::PB},
361 {
"EB",
"E", byte_size::unit::EB},
364constexpr uint64_t byte_size_get_multiplier(byte_size::unit u,
bool binary) {
365 const auto& table = binary ? byte_size_binary_multipliers : byte_size_decimal_multipliers;
366 const auto index =
static_cast<size_t>(u);
367 constexpr size_t table_size = 7;
368 if (index >= table_size) {
369 NEFORCE_THROW_EXCEPTION(value_exception(
"Invalid unit for multiplier"));
374constexpr byte_size::unit byte_size_parse_unit(
const string_view unit_str) {
375 if (unit_str.empty()) {
376 return byte_size::unit::B;
379 for (
const auto& mapping: byte_size_unit_mappings) {
380 if (unit_str.compare_ignore_case(mapping.name) == 0) {
381 return mapping.unit_val;
383 if (!mapping.alt_name.empty() && unit_str.compare_ignore_case(mapping.alt_name) == 0) {
384 return mapping.unit_val;
388 return byte_size::unit::AUTO;
391NEFORCE_CONSTEXPR20
string byte_size_unit_to_string(byte_size::unit unit,
bool binary) {
393 case byte_size::unit::B:
395 case byte_size::unit::KB:
396 return binary ?
"KiB" :
"kB";
397 case byte_size::unit::MB:
398 return binary ?
"MiB" :
"MB";
399 case byte_size::unit::GB:
400 return binary ?
"GiB" :
"GB";
401 case byte_size::unit::TB:
402 return binary ?
"TiB" :
"TB";
403 case byte_size::unit::PB:
404 return binary ?
"PiB" :
"PB";
405 case byte_size::unit::EB:
406 return binary ?
"EiB" :
"EB";
415constexpr byte_size::byte_size(decimal_t value, unit u,
bool binary) {
417 NEFORCE_THROW_EXCEPTION(value_exception(
"Memory size cannot be negative"));
419 if (u == unit::AUTO) {
420 NEFORCE_THROW_EXCEPTION(value_exception(
"Cannot construct byte_size with AUTO unit"));
423 const uint64_t multiplier = inner::byte_size_get_multiplier(u, binary);
426 constexpr decimal_t max_safe =
static_cast<decimal_t>(numeric_traits<uint64_t>::max()) - 0.5L;
427 if (bytes > max_safe) {
428 NEFORCE_THROW_EXCEPTION(value_exception(
"Memory size exceeds maximum representable value"));
432 bytes_ =
static_cast<uint64_t>(bytes + 0.5L);
435NEFORCE_CONSTEXPR20 byte_size byte_size::parse(string_view str,
bool binary) {
438 NEFORCE_THROW_EXCEPTION(value_exception(
"Empty memory size string"));
443 if (i < str.size() && (str[i] ==
'+' || str[i] ==
'-')) {
447 const size_t num_start = i;
449 while (i < str.size() &&
is_digit(str[i])) {
452 if (i < str.size() && str[i] ==
'.') {
454 while (i < str.size() &&
is_digit(str[i])) {
460 if (i == num_start || (i == num_start + 1 && !
is_digit(str[num_start]))) {
461 NEFORCE_THROW_EXCEPTION(value_exception(
"Missing numeric value"));
464 decimal_t value = numeric_traits<decimal_t>::quiet_nan();
466 value = decimal::parse(num_str).value();
468 NEFORCE_THROW_EXCEPTION(value_exception((
"Invalid numeric value: "_s + num_str).
data()));
471 NEFORCE_THROW_EXCEPTION(value_exception(
"Memory size cannot be negative"));
475 const unit parsed_unit = inner::byte_size_parse_unit(unit_str);
476 if (parsed_unit == unit::AUTO && !unit_str.empty()) {
477 NEFORCE_THROW_EXCEPTION(value_exception((
"Unknown unit")));
480 return {value, parsed_unit == unit::AUTO ? unit::B : parsed_unit, binary};
483constexpr decimal_t byte_size::as(unit u,
bool binary)
const {
484 if (u == unit::AUTO) {
485 NEFORCE_THROW_EXCEPTION(value_exception(
"unit cannot be Auto for as"));
487 const uint64_t divisor = inner::byte_size_get_multiplier(u, binary);
491NEFORCE_CONSTEXPR20
string byte_size::to_string(unit u,
int precision,
bool binary)
const {
492 if (u == unit::AUTO) {
494 const string fmt =
"{" +
format(
":.{}f", precision) +
"} B";
498 const string fmt =
"{" +
format(
":.{}f", precision) +
"} {}";
499 const uint64_t base = binary ? 1024 : 1000;
500 auto val =
static_cast<decimal_t>(bytes_);
501 auto current_unit = unit::B;
503 constexpr unit units[] = {unit::B, unit::KB, unit::MB, unit::GB, unit::TB, unit::PB, unit::EB};
505 for (
size_t i = 0; i < 6; ++i) {
506 if (val <
static_cast<decimal_t>(base)) {
510 current_unit = units[i + 1];
513 return format(fmt.view(), val, inner::byte_size_unit_to_string(current_unit, binary));
516 const string fmt =
"{" +
format(
":.{}f", precision) +
"} {}";
518 return format(fmt.view(), val, inner::byte_size_unit_to_string(u, binary));
524NEFORCE_BEGIN_LITERALS__
537NEFORCE_NODISCARD
constexpr byte_size operator""_B(
const unsigned long long bytes)
noexcept {
return byte_size{bytes}; }
553NEFORCE_NODISCARD
constexpr byte_size operator""_KB(
const unsigned long long bytes) {
571NEFORCE_NODISCARD
constexpr byte_size operator""_MB(
const unsigned long long bytes) {
589NEFORCE_NODISCARD
constexpr byte_size operator""_GB(
const unsigned long long bytes) {
607NEFORCE_NODISCARD
constexpr byte_size operator""_TB(
const unsigned long long bytes) {
625NEFORCE_NODISCARD
constexpr byte_size operator""_PB(
const unsigned long long bytes) {
643NEFORCE_NODISCARD
constexpr byte_size operator""_EB(
const unsigned long long bytes) {
658NEFORCE_END_LITERALS__
660NEFORCE_END_NAMESPACE__
constexpr basic_string_view trim() const noexcept
去除两侧空白字符
constexpr basic_string_view view(const size_type off, const size_type count=npos) const
获取子视图
constexpr decimal_t as(unit u, bool binary=true) const
转换为指定单位的值
static constexpr byte_size parse(string_view str, bool binary)
从字符串解析字节大小(指定进制)
constexpr string to_string(unit u, int precision=2, bool binary=true) const
转换为指定单位的字符串
constexpr byte_size() noexcept=default
默认构造函数
constexpr byte_size(decimal_t value, unit u, bool binary=true)
从值和单位构造
constexpr size_t to_hash() const noexcept
计算哈希值
static constexpr byte_size parse(string_view str)
从字符串解析字节大小
constexpr bool is_zero() const noexcept
检查是否为零
constexpr string to_string() const
转换为可读字符串
constexpr uint64_t bytes() const noexcept
获取字节数
constexpr bool is_digit(const CharT c) noexcept
检查字符是否为数字
unsigned long uint64_t
64位无符号整数类型
long double decimal_t
扩展精度浮点数类型
constexpr duration< inner::__common_rep_t< Rep1, enable_if_t<!is_duration_v< Rep2 >, Rep2 > >, Period > operator/(const duration< Rep1, Period > &value, const Rep2 &scalar)
除法运算符(持续时间 / 标量)
constexpr duration< inner::__common_rep_t< Rep1, Rep2 >, Period > operator*(const duration< Rep1, Period > &value, const Rep2 &scalar)
乘法运算符(持续时间 * 标量)
constexpr auto operator-(const normal_iterator< LeftIter > &lhs, const normal_iterator< RightIter > &rhs) noexcept -> decltype(lhs.base() - rhs.base())
减法运算符
constexpr normal_iterator< Iterator > operator+(iter_difference_t< normal_iterator< Iterator > > n, const normal_iterator< Iterator > &iter) noexcept
加法运算符
basic_string_view< char > string_view
字符字符串视图
constexpr decltype(auto) size(const Container &cont) noexcept(noexcept(cont.size()))
获取容器的大小
constexpr decltype(auto) data(Container &cont) noexcept(noexcept(cont.data()))
获取容器的底层数据指针