From cb53d0bd3dafb0a7ba8604be5abcf1d730a79ca7 Mon Sep 17 00:00:00 2001 From: saundersp Date: Sun, 24 Aug 2025 18:54:04 +0200 Subject: [PATCH] toolbox.cpp : thousand_sep now supports negative integers && added doxygen --- toolbox.cpp | 200 ++++++++++++++++++++++++++++++++-------------------- toolbox.hpp | 4 +- 2 files changed, 127 insertions(+), 77 deletions(-) diff --git a/toolbox.cpp b/toolbox.cpp index d5048dc..b578360 100644 --- a/toolbox.cpp +++ b/toolbox.cpp @@ -131,94 +131,144 @@ namespace asp { return ss; } + struct separate_thousands : std::numpunct { + char sep_; + separate_thousands(const char sep) noexcept : sep_(sep) {} + char_type do_thousands_sep() const override { return sep_; } // separate with commas + string_type do_grouping() const override { return "\3"; } // groups of 3 digit + }; + + /** + * @brief Format a given integer with a given seperator for each thousands. + * + * @param k Integer + * @param sep Thousand seperator + * @return Formatted integer + */ + std::string thousand_sep(const int64_t k, const char sep) noexcept { + std::ostringstream out; + out.imbue(std::locale(out.getloc(), new separate_thousands(sep))); + out << k; + return out.str(); + } + + /** + * @brief Format a given integer with ',' for each thousands. + * + * @param k Integer + * @return Formatted integer + */ + std::string thousand_sep(const int64_t k) noexcept { + return thousand_sep(k, ','); + } + /** * @brief Run some unitary tests on format functions * */ void toolbox_unit_test(void) noexcept { - assert(std::string("0B") == format_byte_size(u64(0))); - assert(std::string("1B") == format_byte_size(u64(1))); - assert(std::string("1KB") == format_byte_size(u64(1) << 10)); - assert(std::string("1MB") == format_byte_size(u64(1) << 20)); - assert(std::string("1GB") == format_byte_size(u64(1) << 30)); + assert(std::string("0B") == format_byte_size(0)); + assert(std::string("1B") == format_byte_size(1)); + assert(std::string("1KB") == format_byte_size(1 << 10)); + assert(std::string("1MB") == format_byte_size(1 << 20)); + assert(std::string("1GB") == format_byte_size(1 << 30)); assert(std::string("1TB") == format_byte_size(u64(1) << 40)); assert(std::string("1PB") == format_byte_size(u64(1) << 50)); assert(std::string("1EB") == format_byte_size(u64(1) << 60)); - // uint64_t_MAX == 2**64 == 18446744073709551615 == -1 - assert(std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B") == format_byte_size(u64(-1))); + assert(std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B") == format_byte_size(std::numeric_limits::max())); assert(std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B") == format_byte_size(18446744073709551615ull)); assert(std::string("10EB 1000PB 1000TB 1000GB 1000MB 1000KB 1000B") == format_byte_size(12656215539330294760ull)); - // https://en.wikipedia.org/wiki/Unit_of_time - assert(std::string("0ns") == format_time_ns(u64(0))); - assert(std::string("1ns") == format_time_ns(u64(1))); - assert(std::string("10ns") == format_time_ns(u64(10))); - assert(std::string("1us") == format_time_ns(u64(1e3))); - assert(std::string("1ms") == format_time_ns(u64(1e6))); - assert(std::string("10ms") == format_time_ns(u64(1e7))); - assert(std::string("100ms") == format_time_ns(u64(1e8))); - assert(std::string("1s") == format_time_ns(u64(1e9))); - assert(std::string("10s") == format_time_ns(u64(1e10))); - assert(std::string("1m") == format_time_ns(u64(6e10))); - assert(std::string("1m 26s 400ms") == format_time_ns(u64(864e8))); - assert(std::string("1m 40s") == format_time_ns(u64(1e11))); - assert(std::string("16m 40s") == format_time_ns(u64(1e12))); - assert(std::string("1h") == format_time_ns(u64(36e11))); - assert(std::string("1j") == format_time_ns(u64(864e11))); - assert(std::string("1w") == format_time_ns(u64(6048e11))); - assert(std::string("1w 4j 13h 46m 40s") == format_time_ns(u64(1e15))); - assert(std::string("2w") == format_time_ns(u64(12096e11))); - assert(std::string("3w 6j 5h 5m 35s 800ms") == format_time_ns(u64(23511358e8))); - assert(std::string("3w 6j 7h 43m 4s 700ms") == format_time_ns(u64(23605847e8))); - assert(std::string("3w 6j 7h 43m 11s 600ms") == format_time_ns(u64(23605916e8))); - assert(std::string("3w 6j 13h 18m 33s 200ms") == format_time_ns(u64(23807132e8))); - assert(std::string("4w 1j 12h 44m 2s 900ms") == format_time_ns(u64(25514429e8))); - assert(std::string("1M") == format_time_ns(u64(26298e11))); - assert(std::string("1M 1w 2j 13h 30m") == format_time_ns(u64(3456e12))); - assert(std::string("4M 4j 6h") == format_time_ns(u64(108864e11))); - assert(std::string("11M 2w 5j 13h 22m 48s") == format_time_ns(u64(30617568e9))); - assert(std::string("11M 4w 2j 4h 30m") == format_time_ns(u64(31536e12))); - assert(std::string("1y") == format_time_ns(u64(315576e11))); - assert(std::string("11M 4w 2j 10h 18m 45s") == format_time_ns(u64(31556925e9))); - assert(std::string("11M 4w 2j 10h 19m 12s") == format_time_ns(u64(31556952e9))); - assert(std::string("1y 9m 9s") == format_time_ns(u64(31558149e9))); - assert(std::string("1y 18h") == format_time_ns(u64(316224e11))); - assert(std::string("4y") == format_time_ns(u64(1262304e11))); - assert(std::string("5y") == format_time_ns(u64(157788e12))); - assert(std::string("10y") == format_time_ns(u64(315576e12))); - assert(std::string("15y") == format_time_ns(u64(473364e12))); - assert(std::string("20y") == format_time_ns(u64(631152e12))); - assert(std::string("31y 8M 1w 19h 46m 40s") == format_time_ns(u64(1e18))); - assert(std::string("50y") == format_time_ns(u64(157788e13))); - assert(std::string("1c") == format_time_ns(u64(315576e13))); - // uint64_t_MAX == 2**64 == 18446744073709551615 == -1 - assert(std::string("5c 84y 6M 2w 1j 8h 34m 33s 709ms 551us 615ns") == format_time_ns(u64(-1))); + assert(std::string("0ns") == format_time_ns(0)); + assert(std::string("1ns") == format_time_ns(1)); + assert(std::string("10ns") == format_time_ns(10)); + assert(std::string("1us") == format_time_ns(1e3)); + assert(std::string("1ms") == format_time_ns(1e6)); + assert(std::string("10ms") == format_time_ns(1e7)); + assert(std::string("100ms") == format_time_ns(1e8)); + assert(std::string("1s") == format_time_ns(1e9)); + assert(std::string("10s") == format_time_ns(1e10)); + assert(std::string("1m") == format_time_ns(6e10)); + assert(std::string("1m 26s 400ms") == format_time_ns(864e8)); + assert(std::string("1m 40s") == format_time_ns(1e11)); + assert(std::string("16m 40s") == format_time_ns(1e12)); + assert(std::string("1h") == format_time_ns(36e11)); + assert(std::string("1j") == format_time_ns(864e11)); + assert(std::string("1w") == format_time_ns(6048e11)); + assert(std::string("1w 4j 13h 46m 40s") == format_time_ns(1e15)); + assert(std::string("2w") == format_time_ns(12096e11)); + assert(std::string("3w 6j 5h 5m 35s 800ms") == format_time_ns(23511358e8)); + assert(std::string("3w 6j 7h 43m 4s 700ms") == format_time_ns(23605847e8)); + assert(std::string("3w 6j 7h 43m 11s 600ms") == format_time_ns(23605916e8)); + assert(std::string("3w 6j 13h 18m 33s 200ms") == format_time_ns(23807132e8)); + assert(std::string("4w 1j 12h 44m 2s 900ms") == format_time_ns(25514429e8)); + assert(std::string("1M") == format_time_ns(26298e11)); + assert(std::string("1M 1w 2j 13h 30m") == format_time_ns(3456e12)); + assert(std::string("4M 4j 6h") == format_time_ns(108864e11)); + assert(std::string("11M 2w 5j 13h 22m 48s") == format_time_ns(30617568e9)); + assert(std::string("11M 4w 2j 4h 30m") == format_time_ns(31536e12)); + assert(std::string("1y") == format_time_ns(315576e11)); + assert(std::string("11M 4w 2j 10h 18m 45s") == format_time_ns(31556925e9)); + assert(std::string("11M 4w 2j 10h 19m 12s") == format_time_ns(31556952e9)); + assert(std::string("1y 9m 9s") == format_time_ns(31558149e9)); + assert(std::string("1y 18h") == format_time_ns(316224e11)); + assert(std::string("4y") == format_time_ns(1262304e11)); + assert(std::string("5y") == format_time_ns(157788e12)); + assert(std::string("10y") == format_time_ns(315576e12)); + assert(std::string("15y") == format_time_ns(473364e12)); + assert(std::string("20y") == format_time_ns(631152e12)); + assert(std::string("31y 8M 1w 19h 46m 40s") == format_time_ns(1e18)); + assert(std::string("50y") == format_time_ns(157788e13)); + assert(std::string("1c") == format_time_ns(315576e13)); + assert(std::string("5c 84y 6M 2w 1j 8h 34m 33s 709ms 551us 615ns") == format_time_ns(std::numeric_limits::max())); assert(std::string("5c 84y 6M 2w 1j 8h 34m 33s 709ms 551us 615ns") == format_time_ns(18446744073709551615ull)); - assert(std::string("1c 10y 10M 3w 6j 10h 10m 10s 100ms 100us 100ns") == format_time_ns(3500003410100100100ull)); - } + assert(std::string("1c 10y 10M 3w 6j 10h 10m 10s 100ms 100us 100ns") == format_time_ns(3500003410100100100)); - std::string thousand_sep(const uint64_t& k, const char& sep) noexcept { - std::string s = "", n = std::to_string(k); + assert(std::string("0") == thousand_sep(0)); + assert(std::string("1") == thousand_sep(1)); + assert(std::string("10") == thousand_sep(10)); + assert(std::string("100") == thousand_sep(100)); + assert(std::string("1,000") == thousand_sep(1e3)); + assert(std::string("10,000") == thousand_sep(1e4)); + assert(std::string("100,000") == thousand_sep(1e5)); + assert(std::string("1,000,000") == thousand_sep(1e6)); + assert(std::string("10,000,000") == thousand_sep(1e7)); + assert(std::string("100,000,000") == thousand_sep(1e8)); + assert(std::string("1,000,000,000") == thousand_sep(1e9)); + assert(std::string("10,000,000,000") == thousand_sep(1e10)); + assert(std::string("100,000,000,000") == thousand_sep(1e11)); + assert(std::string("1,000,000,000,000") == thousand_sep(1e12)); + assert(std::string("10,000,000,000,000") == thousand_sep(1e13)); + assert(std::string("100,000,000,000,000") == thousand_sep(1e14)); + assert(std::string("1,000,000,000,000,000") == thousand_sep(1e15)); + assert(std::string("10,000,000,000,000,000") == thousand_sep(1e16)); + assert(std::string("100,000,000,000,000,000") == thousand_sep(1e17)); + assert(std::string("1,000,000,000,000,000,000") == thousand_sep(1e18)); + assert(std::string("1,234,567,890") == thousand_sep(1234567890)); + assert(std::string("9,876,543,210") == thousand_sep(9876543210)); + assert(std::string("9,223,372,036,854,775,807") == thousand_sep(std::numeric_limits::max())); - uint8_t c = 0; - for (int64_t i = int64_t(n.size()) - 1; i >= 0; --i) { - ++c; - s.push_back(n[i]); - if (c == 3) { - s.push_back(sep); - c = 0; - } - } - - std::reverse(s.begin(), s.end()); - - if (s.size() % 4 == 0) - s.erase(s.begin()); - - return s; - } - - std::string thousand_sep(const uint64_t& k) noexcept { - return thousand_sep(k, ','); + assert(std::string("-1") == thousand_sep(-1)); + assert(std::string("-10") == thousand_sep(-10)); + assert(std::string("-100") == thousand_sep(-100)); + assert(std::string("-1,000") == thousand_sep(-1e3)); + assert(std::string("-10,000") == thousand_sep(-1e4)); + assert(std::string("-100,000") == thousand_sep(-1e5)); + assert(std::string("-1,000,000") == thousand_sep(-1e6)); + assert(std::string("-10,000,000") == thousand_sep(-1e7)); + assert(std::string("-100,000,000") == thousand_sep(-1e8)); + assert(std::string("-1,000,000,000") == thousand_sep(-1e9)); + assert(std::string("-10,000,000,000") == thousand_sep(-1e10)); + assert(std::string("-100,000,000,000") == thousand_sep(-1e11)); + assert(std::string("-1,000,000,000,000") == thousand_sep(-1e12)); + assert(std::string("-10,000,000,000,000") == thousand_sep(-1e13)); + assert(std::string("-100,000,000,000,000") == thousand_sep(-1e14)); + assert(std::string("-1,000,000,000,000,000") == thousand_sep(-1e15)); + assert(std::string("-10,000,000,000,000,000") == thousand_sep(-1e16)); + assert(std::string("-100,000,000,000,000,000") == thousand_sep(-1e17)); + assert(std::string("-1,000,000,000,000,000,000") == thousand_sep(-1e18)); + assert(std::string("-1,234,567,890") == thousand_sep(-1234567890)); + assert(std::string("-9,876,543,210") == thousand_sep(-9876543210)); + assert(std::string("-9,223,372,036,854,775,808") == thousand_sep(std::numeric_limits::min())); } } diff --git a/toolbox.hpp b/toolbox.hpp index 7fe398a..4d1e5c7 100644 --- a/toolbox.hpp +++ b/toolbox.hpp @@ -18,8 +18,8 @@ namespace asp { std::string format_time(const uint64_t) noexcept; std::string format_time_ns(uint64_t) noexcept; void toolbox_unit_test(void) noexcept; - std::string thousand_sep(const uint64_t&, const char&) noexcept; - std::string thousand_sep(const uint64_t&) noexcept; + std::string thousand_sep(const int64_t, const char) noexcept; + std::string thousand_sep(const int64_t) noexcept; /** * @brief Print a formatted row of titles with of gaps seperated by a separator.