Added files
This commit is contained in:
39
format_bytes/Makefile
Normal file
39
format_bytes/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
CXX := g++
|
||||
CFLAGS := -std=c++11 -m64 -Wall -Werror -Wextra -O3
|
||||
|
||||
.PHONY: all
|
||||
all: bin/format_bytes
|
||||
|
||||
bin:
|
||||
@mkdir -v bin
|
||||
|
||||
bin/format_bytes: src/format_bytes.cpp src/toolbox.cpp | check-cxx-works bin
|
||||
@echo Compiling $<
|
||||
@${CXX} ${CFLAGS} $^ -o $@
|
||||
|
||||
bin/format_bytes_test: src/format_bytes.cpp src/toolbox.cpp src/unit_test.cpp | check-cxx-works bin
|
||||
@echo Compiling $^
|
||||
@${CXX} ${CFLAGS} -DTEST $^ -o $@
|
||||
|
||||
.PHONY: install
|
||||
install: bin/format_bytes
|
||||
@cp -v $^ /usr/bin
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall: /usr/bin/format_bytes
|
||||
@rm -v $^
|
||||
|
||||
.PHONY: test
|
||||
test: bin/format_bytes_test
|
||||
@./$^
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rfv bin
|
||||
|
||||
.PHONY: mrproper
|
||||
mrproper: clean
|
||||
|
||||
.PHONY: check-cxx-works
|
||||
check-cxx-works:
|
||||
@${CXX} --version >/dev/null 2>&1 || (echo 'Please install a C++ compiler.' && exit 1)
|
66
format_bytes/src/format_bytes.cpp
Normal file
66
format_bytes/src/format_bytes.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <stdint.h>
|
||||
#include "toolbox.hpp"
|
||||
|
||||
static constexpr const size_t STRING_BUFFER_SIZE = 64;
|
||||
static constexpr const std::array<const char[3], 7> 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_bytes(uint64_t n) noexcept {
|
||||
char s[STRING_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);
|
||||
}
|
||||
|
||||
#ifndef TEST
|
||||
int32_t main(const int32_t argc, const char* const* argv) noexcept {
|
||||
|
||||
uint64_t n = 0;
|
||||
if (argc > 2) return fprintf(stderr, "Invalid usage : (%s $NUMBER) or (echo $NUMBER | %s)\n", argv[0], argv[0]);
|
||||
else if (argc == 2){
|
||||
if(sstrtoull(argv[1], n) == EXIT_FAILURE)
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
size_t i = 0;
|
||||
char c, BUFFER[STRING_BUFFER_SIZE];
|
||||
for(; i < STRING_BUFFER_SIZE && (c = fgetc(stdin)) != EOF; ++i)
|
||||
BUFFER[i] = c;
|
||||
if(i == STRING_BUFFER_SIZE){
|
||||
fprintf(stderr, "Error while converting to integer : invalid stdin input (too large)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(sstrtoull(BUFFER, n) == EXIT_FAILURE)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("%s\n", format_bytes(n).c_str());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
11
format_bytes/src/format_bytes.hpp
Normal file
11
format_bytes/src/format_bytes.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @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_bytes(uint64_t n) noexcept;
|
85
format_bytes/src/toolbox.cpp
Normal file
85
format_bytes/src/toolbox.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Convert a given string to an unsigned 64 bit integer
|
||||
*
|
||||
* @param str Input string to convert
|
||||
* @param n Integer output
|
||||
* @return EXIT_SUCCESS if succesful otherwise EXIT_FAILURE
|
||||
*/
|
||||
int32_t sstrtoull(const char* str, uint64_t& n) noexcept {
|
||||
errno = 0;
|
||||
char* endptr = nullptr;
|
||||
const uint64_t a = strtoull(str, &endptr, 10);
|
||||
|
||||
switch(errno){
|
||||
case 0:
|
||||
n = a;
|
||||
return EXIT_SUCCESS;
|
||||
case ERANGE:
|
||||
fprintf(stderr, "Error while converting to integer : numerical result out of range (");
|
||||
if(a == 0)
|
||||
fprintf(stderr, "underflow occurred");
|
||||
else if(a == ULLONG_MAX)
|
||||
fprintf(stderr, "overflow occurred");
|
||||
else
|
||||
fprintf(stderr, "unspecified");
|
||||
fprintf(stderr, ")\n");
|
||||
return EXIT_FAILURE;
|
||||
default:
|
||||
fprintf(stderr, "Unspecified error occurred while converting to integer: %s\n", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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>
|
||||
inline 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
|
||||
*/
|
||||
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 Convert a given number to string
|
||||
*
|
||||
* @param num Number to convert
|
||||
* @param str String to append the number to
|
||||
* @return number of written bytes
|
||||
*/
|
||||
size_t ullstr(uint64_t num, char* const str) noexcept {
|
||||
return ullstr(num, 0, str);
|
||||
}
|
126
format_bytes/src/toolbox.hpp
Normal file
126
format_bytes/src/toolbox.hpp
Normal file
@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a given string to an unsigned 64 bit integer
|
||||
*
|
||||
* @param str Input string to convert
|
||||
* @param n Integer output
|
||||
* @return EXIT_SUCCESS if successful otherwise EXIT_FAILURE
|
||||
*/
|
||||
int32_t sstrtoull(const char* const str, uint64_t& n) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Swap two given memory values
|
||||
*
|
||||
* @tparam T Type of memory placeholder
|
||||
* @param a Firat memory pointer
|
||||
* @param b Second memory pointer
|
||||
*/
|
||||
inline void swap(char* const a, char* const b) noexcept;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
size_t ullstr(uint64_t num, const size_t offset, char* const str) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Convert a given number to string
|
||||
*
|
||||
* @param num Number to convert
|
||||
* @param str String to append the number to
|
||||
* @return number of written bytes
|
||||
*/
|
||||
size_t ullstr(uint64_t num, char* const str) noexcept;
|
||||
|
||||
namespace AnsiColor {
|
||||
constexpr const char* const Reset = "\e[0m";
|
||||
|
||||
// Regular
|
||||
constexpr const char* const Black = "\e[0;30m";
|
||||
constexpr const char* const Red = "\e[0;31m";
|
||||
constexpr const char* const Green = "\e[0;32m";
|
||||
constexpr const char* const Yellow = "\e[0;33m";
|
||||
constexpr const char* const Blue = "\e[0;34m";
|
||||
constexpr const char* const Purple = "\e[0;35m";
|
||||
constexpr const char* const Cyan = "\e[0;36m";
|
||||
constexpr const char* const White = "\e[0;37m";
|
||||
|
||||
// Bold
|
||||
constexpr const char* const BoldBlack = "\e[1;30m";
|
||||
constexpr const char* const BoldRed = "\e[1;31m";
|
||||
constexpr const char* const BoldGreen = "\e[1;32m";
|
||||
constexpr const char* const BoldYellow = "\e[1;33m";
|
||||
constexpr const char* const BoldBlue = "\e[1;34m";
|
||||
constexpr const char* const BoldPurple = "\e[1;35m";
|
||||
constexpr const char* const BoldCyan = "\e[1;36m";
|
||||
constexpr const char* const BoldWhite = "\e[1;37m";
|
||||
|
||||
// Underline
|
||||
constexpr const char* const UnderBlack = "\e[4;30m";
|
||||
constexpr const char* const UnderRed = "\e[4;31m";
|
||||
constexpr const char* const UnderGreen = "\e[4;32m";
|
||||
constexpr const char* const UnderYellow = "\e[4;33m";
|
||||
constexpr const char* const UnderBlue = "\e[4;34m";
|
||||
constexpr const char* const UnderPurple = "\e[4;35m";
|
||||
constexpr const char* const UnderCyan = "\e[4;36m";
|
||||
constexpr const char* const UnderWhite = "\e[4;37m";
|
||||
|
||||
// Background
|
||||
constexpr const char* const BgBlack = "\e[40m";
|
||||
constexpr const char* const BgRed = "\e[41m";
|
||||
constexpr const char* const BgGreen = "\e[42m";
|
||||
constexpr const char* const BgYellow = "\e[43m";
|
||||
constexpr const char* const BgBlue = "\e[44m";
|
||||
constexpr const char* const BgPurple = "\e[45m";
|
||||
constexpr const char* const BgCyan = "\e[46m";
|
||||
constexpr const char* const BgWhite = "\e[47m";
|
||||
|
||||
// High Intensity
|
||||
constexpr const char* const HIBlack = "\e[0;90m";
|
||||
constexpr const char* const HIRed = "\e[0;91m";
|
||||
constexpr const char* const HIGreen = "\e[0;92m";
|
||||
constexpr const char* const HIYellow = "\e[0;93m";
|
||||
constexpr const char* const HIBlue = "\e[0;94m";
|
||||
constexpr const char* const HIPurple = "\e[0;95m";
|
||||
constexpr const char* const HICyan = "\e[0;96m";
|
||||
constexpr const char* const HIWhite = "\e[0;97m";
|
||||
|
||||
// Bold High Intensity
|
||||
constexpr const char* const BoldHIBlack = "\e[1;90m";
|
||||
constexpr const char* const BoldHIRed = "\e[1;91m";
|
||||
constexpr const char* const BoldHIGreen = "\e[1;92m";
|
||||
constexpr const char* const BoldHIYellow = "\e[1;93m";
|
||||
constexpr const char* const BoldHIBlue = "\e[1;94m";
|
||||
constexpr const char* const BoldHIPurple = "\e[1;95m";
|
||||
constexpr const char* const BoldHICyan = "\e[1;96m";
|
||||
constexpr const char* const BoldHIWhite = "\e[1;97m";
|
||||
|
||||
// High Intensity Background
|
||||
constexpr const char* const HIBgBlack = "\e[0;100m";
|
||||
constexpr const char* const HIBgRed = "\e[0;101m";
|
||||
constexpr const char* const HIBgGreen = "\e[0;102m";
|
||||
constexpr const char* const HIBgYellow = "\e[0;103m";
|
||||
constexpr const char* const HIBgBlue = "\e[0;104m";
|
||||
constexpr const char* const HIBgPurple = "\e[0;105m";
|
||||
constexpr const char* const HIBgCyan = "\e[0;106m";
|
||||
constexpr const char* const HIBgWhite = "\e[0;107m";
|
||||
};
|
46
format_bytes/src/unit_test.cpp
Normal file
46
format_bytes/src/unit_test.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <iostream>
|
||||
#include "toolbox.hpp"
|
||||
#include "format_bytes.hpp"
|
||||
|
||||
/**
|
||||
* @brief Test if a given result is equal of the expected one and log result
|
||||
*
|
||||
* @tparam T type of returning values
|
||||
* @param name of the unit test
|
||||
* @param expected result of the function call
|
||||
* @param result of the function
|
||||
*/
|
||||
template<typename T>
|
||||
void Assert(const char* const name, const T& expected, const T& result) noexcept {
|
||||
if (expected != result)
|
||||
std::cerr << AnsiColor::Red << "[ ] - " << name << AnsiColor::Reset << " - Expected '" << expected << "' but got '" << result << "' instead\n";
|
||||
else
|
||||
std::cout << AnsiColor::Green << "[✓] - " << name << AnsiColor::Reset << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test suite for the format_byte output
|
||||
*/
|
||||
void format_byte_test(void) noexcept {
|
||||
std::cout << AnsiColor::BoldWhite << "\tTesting format_byte_size str suite" << AnsiColor::Reset << "\n";
|
||||
|
||||
Assert("format_bytes str null", std::string("0B"), format_bytes(u64(0)));
|
||||
Assert("format_bytes str byte", std::string("1B"), format_bytes(u64(1)));
|
||||
Assert("format_bytes str kilobyte", std::string("1KB"), format_bytes(u64(1) << 10));
|
||||
Assert("format_bytes str megabyte", std::string("1MB"), format_bytes(u64(1) << 20));
|
||||
Assert("format_bytes str gigabyte", std::string("1GB"), format_bytes(u64(1) << 30));
|
||||
Assert("format_bytes str terabyte", std::string("1TB"), format_bytes(u64(1) << 40));
|
||||
Assert("format_bytes str petabyte", std::string("1PB"), format_bytes(u64(1) << 50));
|
||||
Assert("format_bytes str exabyte", std::string("1EB"), format_bytes(u64(1) << 60));
|
||||
// Unsupported due to number of byte bigger than currently supported by ISO c++
|
||||
// Assert("format_bytes zettabyte", std::string("1ZB"), format_bytes(u64(1)<<70));
|
||||
// Assert("format_bytes yottabyte", std::string("1YB"), format_bytes(u64(1)<<80));
|
||||
// uint64_t_MAX == 2**64 == 18446744073709551615 == -1
|
||||
Assert("format_bytes str max", std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B"), format_bytes(u64(-1)));
|
||||
Assert("format_bytes str max", std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B"), format_bytes(18446744073709551615ull));
|
||||
Assert("format_bytes str longest", std::string("10EB 1000PB 1000TB 1000GB 1000MB 1000KB 1000B"), format_bytes(12656215539330294760ull));
|
||||
}
|
||||
|
||||
int32_t main(void) noexcept {
|
||||
format_byte_test();
|
||||
}
|
Reference in New Issue
Block a user