NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
byte_size.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_UTILITY_BYTE_SIZE_HPP__
2#define NEFORCE_CORE_UTILITY_BYTE_SIZE_HPP__
3
11
16NEFORCE_BEGIN_NAMESPACE__
17
105
146class NEFORCE_API byte_size : public iobject<byte_size>, public icommon<byte_size> {
147public:
152 enum class unit {
153 B,
154 KB,
155 MB,
156 GB,
157 TB,
158 PB,
159 EB,
160 AUTO
161 };
162
163private:
164 uint64_t bytes_{0};
165
166public:
172 constexpr byte_size() noexcept = default;
173
178 constexpr explicit byte_size(uint64_t bytes) noexcept :
179 bytes_(bytes) {}
180
188 constexpr byte_size(decimal_t value, unit u, bool binary = true);
189
199 NEFORCE_NODISCARD static NEFORCE_CONSTEXPR20 byte_size parse(string_view str) { return parse(str, true); }
200
208 NEFORCE_NODISCARD static NEFORCE_CONSTEXPR20 byte_size parse(string_view str, bool binary);
209
214 NEFORCE_NODISCARD constexpr uint64_t bytes() const noexcept { return bytes_; }
215
223 NEFORCE_NODISCARD constexpr decimal_t as(unit u, bool binary = true) const;
224
229 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const { return to_string(unit::AUTO, 2, true); }
230
238 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(unit u, int precision = 2, bool binary = true) const;
239
244 NEFORCE_NODISCARD constexpr bool is_zero() const noexcept { return bytes_ == 0; }
245
246 constexpr byte_size& operator+=(const byte_size& rhs) noexcept {
247 bytes_ += rhs.bytes_;
248 return *this;
249 }
250
251 constexpr byte_size& operator-=(const byte_size& rhs) {
252 if (bytes_ < rhs.bytes_) {
253 NEFORCE_THROW_EXCEPTION(value_exception("Memory size subtraction underflow"));
254 }
255 bytes_ -= rhs.bytes_;
256 return *this;
257 }
258
259 constexpr byte_size& operator*=(uint64_t factor) noexcept {
260 bytes_ *= factor;
261 return *this;
262 }
263
264 constexpr byte_size& operator/=(uint64_t divisor) {
265 if (divisor == 0) {
266 NEFORCE_THROW_EXCEPTION(value_exception("Division by zero"));
267 }
268 bytes_ /= divisor;
269 return *this;
270 }
271
272 NEFORCE_NODISCARD constexpr byte_size operator+(const byte_size& rhs) const noexcept {
273 return byte_size(bytes_ + rhs.bytes_);
274 }
275
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"));
279 }
280 return byte_size(bytes_ - rhs.bytes_);
281 }
282
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"));
286 }
287 return byte_size(bytes_ * factor);
288 }
289
290 NEFORCE_NODISCARD constexpr byte_size operator/(uint64_t divisor) const {
291 if (divisor == 0) {
292 NEFORCE_THROW_EXCEPTION(value_exception("Division by zero"));
293 }
294 return byte_size(bytes_ / divisor);
295 }
296
297 NEFORCE_NODISCARD friend constexpr byte_size operator*(uint64_t factor, const byte_size& size) {
298 return size * factor;
299 }
300
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_; }
303
308 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept { return hash<uint64_t>()(bytes_); }
309};
310
320template <>
322 using type = uint64_t;
323};
324 // ByteSize
326
327
329NEFORCE_BEGIN_INNER__
330
331struct byte_size_unit_mapping {
332 string_view name;
333 string_view alt_name;
334 byte_size::unit unit_val;
335};
336
337
338NEFORCE_INLINE17 constexpr uint64_t byte_size_binary_multipliers[] = {
339 1ULL, // B
340 1024ULL, // KB
341 1024ULL * 1024, // MB
342 1024ULL * 1024 * 1024, // GB
343 1024ULL * 1024 * 1024 * 1024, // TB
344 1024ULL * 1024 * 1024 * 1024 * 1024, // PB
345 1024ULL * 1024 * 1024 * 1024 * 1024 * 1024 // EB
346};
347
348NEFORCE_INLINE17 constexpr uint64_t byte_size_decimal_multipliers[] = {
349 1ULL, // B
350 1000ULL, // KB
351 1000ULL * 1000, // MB
352 1000ULL * 1000 * 1000, // GB
353 1000ULL * 1000 * 1000 * 1000, // TB
354 1000ULL * 1000 * 1000 * 1000 * 1000, // PB
355 1000ULL * 1000 * 1000 * 1000 * 1000 * 1000 // EB
356};
357
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},
362};
363
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; // B, KB, MB, GB, TB, PB, EB
368 if (index >= table_size) {
369 NEFORCE_THROW_EXCEPTION(value_exception("Invalid unit for multiplier"));
370 }
371 return table[index];
372}
373
374constexpr byte_size::unit byte_size_parse_unit(const string_view unit_str) {
375 if (unit_str.empty()) {
376 return byte_size::unit::B;
377 }
378
379 for (const auto& mapping: byte_size_unit_mappings) {
380 if (unit_str.compare_ignore_case(mapping.name) == 0) {
381 return mapping.unit_val;
382 }
383 if (!mapping.alt_name.empty() && unit_str.compare_ignore_case(mapping.alt_name) == 0) {
384 return mapping.unit_val;
385 }
386 }
387
388 return byte_size::unit::AUTO;
389}
390
391NEFORCE_CONSTEXPR20 string byte_size_unit_to_string(byte_size::unit unit, bool binary) {
392 switch (unit) {
393 case byte_size::unit::B:
394 return "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";
407 default:
408 return "";
409 }
410}
411
412NEFORCE_END_INNER__
413
414
415constexpr byte_size::byte_size(decimal_t value, unit u, bool binary) {
416 if (value < 0.0L) {
417 NEFORCE_THROW_EXCEPTION(value_exception("Memory size cannot be negative"));
418 }
419 if (u == unit::AUTO) {
420 NEFORCE_THROW_EXCEPTION(value_exception("Cannot construct byte_size with AUTO unit"));
421 }
422
423 const uint64_t multiplier = inner::byte_size_get_multiplier(u, binary);
424 const decimal_t bytes = value * static_cast<decimal_t>(multiplier);
425
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"));
429 }
430
431 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
432 bytes_ = static_cast<uint64_t>(bytes + 0.5L);
433}
434
435NEFORCE_CONSTEXPR20 byte_size byte_size::parse(string_view str, bool binary) {
436 str = str.trim();
437 if (str.empty()) {
438 NEFORCE_THROW_EXCEPTION(value_exception("Empty memory size string"));
439 }
440
441 size_t i = 0;
442
443 if (i < str.size() && (str[i] == '+' || str[i] == '-')) {
444 ++i;
445 }
446
447 const size_t num_start = i;
448
449 while (i < str.size() && is_digit(str[i])) {
450 ++i;
451 }
452 if (i < str.size() && str[i] == '.') {
453 ++i;
454 while (i < str.size() && is_digit(str[i])) {
455 ++i;
456 }
457 }
458
459 const string_view num_str = str.view(0, i);
460 if (i == num_start || (i == num_start + 1 && !is_digit(str[num_start]))) {
461 NEFORCE_THROW_EXCEPTION(value_exception("Missing numeric value"));
462 }
463
464 decimal_t value = numeric_traits<decimal_t>::quiet_nan();
465 try {
466 value = decimal::parse(num_str).value();
467 } catch (...) {
468 NEFORCE_THROW_EXCEPTION(value_exception(("Invalid numeric value: "_s + num_str).data()));
469 }
470 if (value < 0.0L) {
471 NEFORCE_THROW_EXCEPTION(value_exception("Memory size cannot be negative"));
472 }
473
474 const string_view unit_str = str.view(i).trim();
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")));
478 }
479
480 return {value, parsed_unit == unit::AUTO ? unit::B : parsed_unit, binary};
481}
482
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"));
486 }
487 const uint64_t divisor = inner::byte_size_get_multiplier(u, binary);
488 return static_cast<decimal_t>(bytes_) / static_cast<decimal_t>(divisor);
489}
490
491NEFORCE_CONSTEXPR20 string byte_size::to_string(unit u, int precision, bool binary) const {
492 if (u == unit::AUTO) {
493 if (bytes_ == 0) {
494 const string fmt = "{" + format(":.{}f", precision) + "} B";
495 return format(fmt.view(), static_cast<decimal_t>(0));
496 }
497
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;
502
503 constexpr unit units[] = {unit::B, unit::KB, unit::MB, unit::GB, unit::TB, unit::PB, unit::EB};
504
505 for (size_t i = 0; i < 6; ++i) {
506 if (val < static_cast<decimal_t>(base)) {
507 break;
508 }
509 val /= static_cast<decimal_t>(base);
510 current_unit = units[i + 1];
511 }
512
513 return format(fmt.view(), val, inner::byte_size_unit_to_string(current_unit, binary));
514 }
515
516 const string fmt = "{" + format(":.{}f", precision) + "} {}";
517 const decimal_t val = as(u, binary);
518 return format(fmt.view(), val, inner::byte_size_unit_to_string(u, binary));
519}
520
522
523
524NEFORCE_BEGIN_LITERALS__
525
531
537NEFORCE_NODISCARD constexpr byte_size operator""_B(const unsigned long long bytes) noexcept { return byte_size{bytes}; }
538
544NEFORCE_NODISCARD constexpr byte_size operator""_B(const decimal_t bytes) {
545 return byte_size{bytes, byte_size::unit::B};
546}
547
553NEFORCE_NODISCARD constexpr byte_size operator""_KB(const unsigned long long bytes) {
554 return byte_size{static_cast<decimal_t>(bytes), byte_size::unit::KB};
555}
556
562NEFORCE_NODISCARD constexpr byte_size operator""_KB(const decimal_t bytes) {
563 return byte_size{bytes, byte_size::unit::KB};
564}
565
571NEFORCE_NODISCARD constexpr byte_size operator""_MB(const unsigned long long bytes) {
572 return byte_size{static_cast<decimal_t>(bytes), byte_size::unit::MB};
573}
574
580NEFORCE_NODISCARD constexpr byte_size operator""_MB(const decimal_t bytes) {
581 return byte_size{bytes, byte_size::unit::MB};
582}
583
589NEFORCE_NODISCARD constexpr byte_size operator""_GB(const unsigned long long bytes) {
590 return byte_size{static_cast<decimal_t>(bytes), byte_size::unit::GB};
591}
592
598NEFORCE_NODISCARD constexpr byte_size operator""_GB(const decimal_t bytes) {
599 return byte_size{bytes, byte_size::unit::GB};
600}
601
607NEFORCE_NODISCARD constexpr byte_size operator""_TB(const unsigned long long bytes) {
608 return byte_size{static_cast<decimal_t>(bytes), byte_size::unit::TB};
609}
610
616NEFORCE_NODISCARD constexpr byte_size operator""_TB(const decimal_t bytes) {
617 return byte_size{bytes, byte_size::unit::TB};
618}
619
625NEFORCE_NODISCARD constexpr byte_size operator""_PB(const unsigned long long bytes) {
626 return byte_size{static_cast<decimal_t>(bytes), byte_size::unit::PB};
627}
628
634NEFORCE_NODISCARD constexpr byte_size operator""_PB(const decimal_t bytes) {
635 return byte_size{bytes, byte_size::unit::PB};
636}
637
643NEFORCE_NODISCARD constexpr byte_size operator""_EB(const unsigned long long bytes) {
644 return byte_size{static_cast<decimal_t>(bytes), byte_size::unit::EB};
645}
646
652NEFORCE_NODISCARD constexpr byte_size operator""_EB(const decimal_t bytes) {
653 return byte_size{bytes, byte_size::unit::EB};
654}
655
657
658NEFORCE_END_LITERALS__
659
660NEFORCE_END_NAMESPACE__
661#endif
constexpr basic_string_view trim() const noexcept
去除两侧空白字符
constexpr basic_string_view view(const size_type off, const size_type count=npos) const
获取子视图
unit
字节大小单位枚举
@ AUTO
自动选择合适单位
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 string format(const string_view fmt, Args &&... args)
格式化字符串
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()))
获取容器的底层数据指针
数值类型包装类
哈希函数的主模板
通用接口,同时具备可比较和可哈希功能
可解析对象接口
类型解包器模板
字符串到数值的转换函数
类型擦除辅助函数