224 lines
9.7 KiB
C++
224 lines
9.7 KiB
C++
#include <cassert>
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include "toolbox.hpp"
|
|
|
|
namespace asp {
|
|
/**
|
|
* @brief Swap two given memory values
|
|
*
|
|
* @tparam T Type of memory placeholder
|
|
* @param a Firat memory pointer
|
|
* @param b Second memory pointer
|
|
*/
|
|
template<typename T>
|
|
constexpr void swap(T* const a, T* const b) noexcept {
|
|
const T temp = *a;
|
|
*a = *b;
|
|
*b = temp;
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Convert a given number to string
|
|
*
|
|
* @param num Number to convert
|
|
* @param offset of the string location to append
|
|
* @param str String to append the number to
|
|
* @return number of written bytes
|
|
*/
|
|
constexpr size_t ullstr(uint64_t num, const size_t offset, char* const str) noexcept {
|
|
size_t i = 0;
|
|
|
|
for (; num > 0; num /= 10)
|
|
str[offset + i++] = num % 10 + '0';
|
|
|
|
str[offset + i] = '\0';
|
|
|
|
for (size_t j = 0; j < i / 2; ++j)
|
|
swap(str + offset + j, str + offset + i - j - 1);
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* @brief Cast a variable to an unsigned 64 bit integer
|
|
*
|
|
* @tparam T Type of the variable to cast
|
|
* @param vae Variable to cast
|
|
* @return Casted variable
|
|
*/
|
|
template<typename T>
|
|
static constexpr uint64_t u64(const T var) noexcept {
|
|
return static_cast<uint64_t>(var);
|
|
}
|
|
|
|
static constexpr const size_t STR_BUFFER_SIZE = 64;
|
|
static constexpr const int8_t N_TIMES = 11;
|
|
static constexpr const std::array<const char* const, N_TIMES> time_formats = { "ns", "us", "ms", "s", "m", "h", "j", "w", "M", "y", "c" };
|
|
static constexpr const std::array<const uint64_t, N_TIMES> time_numbers = { 1, 1000, 1000000, u64(1e9), u64(6e10), u64(36e11), u64(864e11),
|
|
u64(6048e11), u64(26298e11), u64(315576e11), u64(315576e13) };
|
|
|
|
|
|
static constexpr size_t N_BYTES = 7;
|
|
static constexpr const std::array<const char[3], N_BYTES> format_prefix = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
|
|
|
|
/**
|
|
* @brief Convert a given numbers of bytes to a human readable format
|
|
*
|
|
* @param n Number of bytes
|
|
* @return Human readable format of the numbers of bytes
|
|
*/
|
|
std::string format_byte_size(uint64_t n) noexcept {
|
|
char s[STR_BUFFER_SIZE] = { 0 };
|
|
|
|
if(n == 0){
|
|
sprintf(s, "0%s", format_prefix[0]);
|
|
return s;
|
|
}
|
|
|
|
size_t j = 0;
|
|
for(int8_t i = static_cast<int8_t>(format_prefix.size() - 1) * 10; i >= 0; i -= 10){
|
|
const uint64_t nsi = n >> i;
|
|
if(nsi > 0){
|
|
const int8_t idx = i / 10;
|
|
j += ullstr(nsi, j, s);
|
|
for(int k = 0; format_prefix[idx][k] > 0; ++k)
|
|
s[j++] = format_prefix[idx][k];
|
|
s[j++] = ' ';
|
|
n &= u64(-1) >> (64 - i);
|
|
}
|
|
}
|
|
|
|
/* Remove trailing character */
|
|
s[j - 1] = '\0';
|
|
|
|
return std::string(s);
|
|
}
|
|
|
|
/**
|
|
* @brief Convert a given number of nanoseconds to a human readable format
|
|
*
|
|
* @param time Number of nanoseconds
|
|
* @return Human readable formatted string
|
|
*/
|
|
std::string format_time_ns(uint64_t time) noexcept {
|
|
char s[STR_BUFFER_SIZE] = {0};
|
|
size_t j = 0;
|
|
|
|
if (time == 0){
|
|
sprintf(s, "0%s", time_formats[0]);
|
|
return s;
|
|
}
|
|
|
|
uint64_t res;
|
|
for (int8_t i = time_numbers.size() - 1; i >= 0; --i) {
|
|
if (time >= time_numbers[i]) {
|
|
res = time / time_numbers[i];
|
|
time %= time_numbers[i];
|
|
j += ullstr(res, j, s);
|
|
for(int k = 0; time_formats[i][k] > 0; ++k)
|
|
s[j++] = time_formats[i][k];
|
|
s[j++] = ' ';
|
|
}
|
|
}
|
|
|
|
/* Remove trailing character */
|
|
s[j - 1] = '\0';
|
|
|
|
std::string ss(s);
|
|
|
|
return ss;
|
|
}
|
|
|
|
/**
|
|
* @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("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(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("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));
|
|
}
|
|
|
|
std::string thousand_sep(const uint64_t& k, const char& sep) noexcept {
|
|
std::string s = "", n = std::to_string(k);
|
|
|
|
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, ',');
|
|
}
|
|
}
|