Modernized code and fancier code printing
This commit is contained in:
		
							
								
								
									
										258
									
								
								toolbox.cpp
									
									
									
									
									
								
							
							
						
						
									
										258
									
								
								toolbox.cpp
									
									
									
									
									
								
							@@ -1,83 +1,133 @@
 | 
			
		||||
#include <numeric>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include "toolbox.hpp"
 | 
			
		||||
 | 
			
		||||
namespace asp {
 | 
			
		||||
	static constexpr size_t N_TIMES = 10;
 | 
			
		||||
	static constexpr std::array<const char* const, N_TIMES> time_formats = { "ns", "us", "ms", "s", "m", "h", "j", "w", "M", "y" };
 | 
			
		||||
	static constexpr std::array<uint16_t, N_TIMES> time_numbers = { 1, 1000, 1000, 1000, 60, 60, 24, 7, 4, 12 };
 | 
			
		||||
	static const uint64_t total_time = std::accumulate(time_numbers.begin(), time_numbers.end(), uint64_t(1), std::multiplies<uint64_t>());
 | 
			
		||||
	/**
 | 
			
		||||
	 * @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 std::array<const char*, N_BYTES> bytes_formats = { "", "K", "M", "G", "P", "E", "Z" }; //, "Y" };
 | 
			
		||||
	static constexpr uint64_t total_bytes = uint64_t(1)<<(10 * (N_BYTES - 1));
 | 
			
		||||
	static constexpr const std::array<const char[3], N_BYTES> format_prefix = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @brief Format the time in seconds in human readable format.
 | 
			
		||||
	 * @brief Convert a given numbers of bytes to a human readable format
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param time Time in seconds
 | 
			
		||||
	 * @return std::string The formatted human readable string.
 | 
			
		||||
	 * @param n Number of bytes
 | 
			
		||||
	 * @return Human readable format of the numbers of bytes
 | 
			
		||||
	 */
 | 
			
		||||
	std::string format_time(const uint64_t time) noexcept {
 | 
			
		||||
		return time < 2 ? std::to_string(time) + "s" : format_time_ns(time * (uint64_t)1e9);
 | 
			
		||||
	}
 | 
			
		||||
	std::string format_byte_size(uint64_t n) noexcept {
 | 
			
		||||
		char s[STR_BUFFER_SIZE] = { 0 };
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @brief Format the time in nanoseconds in human readable format.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param time Time in nanoseconds
 | 
			
		||||
	 * @return std::string The formatted human readable string.
 | 
			
		||||
	 */
 | 
			
		||||
	std::string format_byte_size(uint64_t bytes) noexcept {
 | 
			
		||||
		if (bytes == 0)
 | 
			
		||||
			return "0B";
 | 
			
		||||
		uint64_t prod = total_bytes;
 | 
			
		||||
 | 
			
		||||
		std::string s = "";
 | 
			
		||||
		uint64_t res;
 | 
			
		||||
		for (size_t i = N_BYTES; i > 0; --i) {
 | 
			
		||||
			if (bytes >= prod) {
 | 
			
		||||
				res = bytes / prod;
 | 
			
		||||
				bytes %= prod;
 | 
			
		||||
				s += std::to_string(res) + bytes_formats[i - 1] + "B ";
 | 
			
		||||
			}
 | 
			
		||||
			prod /= uint64_t(1)<<10;
 | 
			
		||||
		if(n == 0){
 | 
			
		||||
			sprintf(s, "0%s", format_prefix[0]);
 | 
			
		||||
			return s;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (s.back() == ' ')
 | 
			
		||||
			s.pop_back();
 | 
			
		||||
		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);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return s;
 | 
			
		||||
		/* Remove trailing character */
 | 
			
		||||
		s[j - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
		return std::string(s);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @brief Format the time in nanoseconds in human readable format.
 | 
			
		||||
	 * @brief Convert a given number of nanoseconds to a human readable format
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param time Time in nanoseconds
 | 
			
		||||
	 * @return std::string The formatted human readable string.
 | 
			
		||||
	 * @param time Number of nanoseconds
 | 
			
		||||
	 * @return Human readable formatted string
 | 
			
		||||
	 */
 | 
			
		||||
	std::string format_time_ns(uint64_t time) noexcept {
 | 
			
		||||
		if (time == 0)
 | 
			
		||||
			return "0ns";
 | 
			
		||||
		uint64_t prod = total_time;
 | 
			
		||||
		char s[STR_BUFFER_SIZE] = {0};
 | 
			
		||||
		size_t j = 0;
 | 
			
		||||
 | 
			
		||||
		std::string s = "";
 | 
			
		||||
		uint64_t res;
 | 
			
		||||
		for (size_t i = N_TIMES; i > 0; --i) {
 | 
			
		||||
			if (time >= prod) {
 | 
			
		||||
				res = time / prod;
 | 
			
		||||
				time %= prod;
 | 
			
		||||
				s += std::to_string(res) + time_formats[i - 1] + " ";
 | 
			
		||||
			}
 | 
			
		||||
			prod /= time_numbers[i - 1];
 | 
			
		||||
		if (time == 0){
 | 
			
		||||
			sprintf(s, "0%s", time_formats[0]);
 | 
			
		||||
			return s;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (s.back() == ' ')
 | 
			
		||||
			s.pop_back();
 | 
			
		||||
		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++] = ' ';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return s;
 | 
			
		||||
		/* Remove trailing character */
 | 
			
		||||
		s[j - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
		std::string ss(s);
 | 
			
		||||
 | 
			
		||||
		return ss;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -85,40 +135,65 @@ namespace asp {
 | 
			
		||||
	 *
 | 
			
		||||
	 */
 | 
			
		||||
	void toolbox_unit_test(void) noexcept {
 | 
			
		||||
		assert(std::string("0B")  == format_byte_size(uint64_t(0)));
 | 
			
		||||
		assert(std::string("1B")  == format_byte_size(uint64_t(1)));
 | 
			
		||||
		assert(std::string("1KB") == format_byte_size(uint64_t(1)<<10));
 | 
			
		||||
		assert(std::string("1MB") == format_byte_size(uint64_t(1)<<20));
 | 
			
		||||
		assert(std::string("1GB") == format_byte_size(uint64_t(1)<<30));
 | 
			
		||||
		assert(std::string("1PB") == format_byte_size(uint64_t(1)<<40));
 | 
			
		||||
		assert(std::string("1EB") == format_byte_size(uint64_t(1)<<50));
 | 
			
		||||
		assert(std::string("1ZB") == format_byte_size(uint64_t(1)<<60));
 | 
			
		||||
		//assert(std::string("1YB") == format_byte_size(uint64_t(1)<<70));
 | 
			
		||||
		// UINT64_MAX == 18446744073709551615I64u == -1
 | 
			
		||||
		assert(std::string("15ZB 1023EB 1023PB 1023GB 1023MB 1023KB 1023B") == format_byte_size(uint64_t(-1)));
 | 
			
		||||
		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));
 | 
			
		||||
 | 
			
		||||
		assert(std::string("0s") == format_time(uint64_t(0)));
 | 
			
		||||
		assert(std::string("1s") == format_time(uint64_t(1)));
 | 
			
		||||
		assert(std::string("1m") == format_time(uint64_t(60)));
 | 
			
		||||
		assert(std::string("1h") == format_time(uint64_t(3600)));
 | 
			
		||||
		assert(std::string("1j") == format_time(uint64_t(86400)));
 | 
			
		||||
		assert(std::string("1w") == format_time(uint64_t(604800)));
 | 
			
		||||
		assert(std::string("1M") == format_time(uint64_t(2419200)));
 | 
			
		||||
		assert(std::string("1y") == format_time(uint64_t(29030400)));
 | 
			
		||||
 | 
			
		||||
		assert(std::string("0ns") == format_time_ns(uint64_t(0)));
 | 
			
		||||
		assert(std::string("1ns") == format_time_ns(uint64_t(1)));
 | 
			
		||||
		assert(std::string("1us") == format_time_ns(uint64_t(1e3)));
 | 
			
		||||
		assert(std::string("1ms") == format_time_ns(uint64_t(1e6)));
 | 
			
		||||
		assert(std::string("1s") == format_time_ns(uint64_t(1e9)));
 | 
			
		||||
		assert(std::string("1m") == format_time_ns(uint64_t(6e10)));
 | 
			
		||||
		assert(std::string("1h") == format_time_ns(uint64_t(36e11)));
 | 
			
		||||
		assert(std::string("1j") == format_time_ns(uint64_t(864e11)));
 | 
			
		||||
		assert(std::string("1w") == format_time_ns(uint64_t(6048e11)));
 | 
			
		||||
		assert(std::string("1M") == format_time_ns(uint64_t(24192e11)));
 | 
			
		||||
		assert(std::string("1y") == format_time_ns(uint64_t(290304e11)));
 | 
			
		||||
		// UINT64_MAX == 18446744073709551615I64u == -1
 | 
			
		||||
		assert(std::string("635y 5M 3j 23h 34m 33s 709ms 551us 615ns") == format_time_ns(uint64_t(-1)));
 | 
			
		||||
		// 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 {
 | 
			
		||||
@@ -145,13 +220,4 @@ namespace asp {
 | 
			
		||||
	std::string thousand_sep(const uint64_t& k) noexcept {
 | 
			
		||||
		return thousand_sep(k, ',');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void print_separator(const char* const title) noexcept {
 | 
			
		||||
		#define S(N) std::string(N, '-').c_str()
 | 
			
		||||
		constexpr size_t SEPARATOR_SIZE = W_NAME + W_TIME + W_FTIME + 6 + 6;
 | 
			
		||||
		char separator[SEPARATOR_SIZE];
 | 
			
		||||
		sprintf(separator, "|%s|%s|%s|\n", S(W_NAME + 2), S(W_TIME + 2), S(W_FTIME + 2));
 | 
			
		||||
		printf("| %-" STR(W_NAME) "s | %-" STR(W_TIME) "s | %-" STR(W_FTIME) "s	| \n%s", title, "Time spent(ns)", "Formatted time spent", separator);
 | 
			
		||||
		#undef S
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user