improve human_friendly_bytesize to cope with sizes up to 16 exibytes

This commit is contained in:
Vincent Sanders 2019-10-19 18:20:00 +01:00
parent a54cbb5aea
commit e01c24cef7
4 changed files with 87 additions and 29 deletions

View File

@ -119,6 +119,7 @@ nl.all.FrameDrag:frames aan het aanpassen
# Units # Units
# ===== # =====
# #
# Decimal prefix
en.all.Bytes: B en.all.Bytes: B
de.all.Bytes: B de.all.Bytes: B
fr.all.Bytes: octets fr.all.Bytes: octets
@ -139,7 +140,13 @@ de.all.GBytes: GB
fr.all.GBytes: Go fr.all.GBytes: Go
it.all.GBytes: GB it.all.GBytes: GB
nl.all.GBytes: GB nl.all.GBytes: GB
# Binary prefix
en.all.KiBytes: KiB
en.all.MiBytes: MiB
en.all.GiBytes: GiB
en.all.TiBytes: TiB
en.all.PiBytes: PiB
en.all.EiBytes: EiB
# Content Forms # Content Forms
# ============= # =============

View File

@ -37,22 +37,31 @@
#define SLEN(x) (sizeof((x)) - 1) #define SLEN(x) (sizeof((x)) - 1)
struct test_pairs { struct test_pairs {
const unsigned long test; const unsigned long long int test;
const char* res; const char* res;
}; };
static const struct test_pairs human_friendly_bytesize_test_vec[] = { static const struct test_pairs human_friendly_bytesize_test_vec[] = {
{ 0, "0.00Bytes" }, { 0ULL, "0Bytes" },
{ 1024, "1024.00Bytes" }, { 0x2AULL, "42Bytes" },
{ 1025, "1.00kBytes" }, { 0x400ULL, "1024Bytes" },
{ 1048576, "1024.00kBytes" }, { 0x401ULL, "1.00KiBytes" },
{ 1048577, "1.00MBytes" }, { 0xA9AEULL, "42.42KiBytes" },
{ 1073741824, "1024.00MBytes" }, { 0x100000ULL, "1024.00KiBytes" },
{ 1073741888, "1024.00MBytes" }, /* spot the rounding error */ { 0x100001ULL, "1.00MiBytes" },
{ 1073741889, "1.00GBytes" }, { 0x2A6B852ULL, "42.42MiBytes" },
{ 2147483648, "2.00GBytes" }, { 0x40000000ULL, "1024.00MiBytes" },
{ 3221225472, "3.00GBytes" }, { 0x40000001ULL, "1.00GiBytes" },
{ 4294967295, "4.00GBytes" }, { 0x80000000ULL, "2.00GiBytes" },
{ 0xC0000000ULL, "3.00GiBytes" },
{ 0x100000000ULL, "4.00GiBytes" },
{ 0x10000000000ULL, "1024.00GiBytes" },
{ 0x10000000001ULL, "1.00TiBytes" },
{ 0x4000000000000ULL, "1024.00TiBytes" },
{ 0x4000000000001ULL, "1.00PiBytes" },
{ 0x1000000000000000ULL, "1024.00PiBytes" },
{ 0x1000000000000100ULL, "1.00EiBytes" }, /* precision loss */
{ 0xFFFFFFFFFFFFFFFFULL, "16.00EiBytes" },
}; };
/** /**

View File

@ -64,7 +64,7 @@ char *cnv_space2nbsp(const char *s);
* @param bytesize The size in bytes. * @param bytesize The size in bytes.
* @return A human readable string representing the size. * @return A human readable string representing the size.
*/ */
char *human_friendly_bytesize(unsigned long bytesize); char *human_friendly_bytesize(unsigned long long int bytesize);
/** /**

View File

@ -192,26 +192,43 @@ nserror snstrjoin(char **str, size_t *size, char sep, size_t nelm, ...)
/** /**
* The size of buffers within human_friendly_bytesize. * The size of buffers within human_friendly_bytesize.
* *
* We can have a fairly good estimate of how long the buffer needs to * We can have a fairly good estimate of the output buffers maximum length.
* be. The unsigned long can store a value representing a maximum *
* size of around 4 GB. Therefore the greatest space required is to * The unsigned long long int can store a value representing a maximum
* represent 1023MB. Currently that would be represented as "1023MB" * size of 16 EiB (exibytes). Therefore the greatest space required is to
* so 12 including a null terminator. Ideally we would be able to * represent 1023 PiB.
* know this value for sure, in the mean time the following should * Currently that would be represented as "1023.00PiBytes" in english
* suffice. * giving a 15 byte length including a null terminator.
* Ideally we would be able to accurately know this length for other
* languages, in the mean time a largeish buffer size is selected
* and should suffice.
*/ */
#define BYTESIZE_BUFFER_SIZE 20 #define BYTESIZE_BUFFER_SIZE 32
/* exported interface documented in utils/string.h */ /* exported interface documented in utils/string.h */
char *human_friendly_bytesize(unsigned long bsize) { char *human_friendly_bytesize(unsigned long long int bsize) {
static char buffer1[BYTESIZE_BUFFER_SIZE]; static char buffer1[BYTESIZE_BUFFER_SIZE];
static char buffer2[BYTESIZE_BUFFER_SIZE]; static char buffer2[BYTESIZE_BUFFER_SIZE];
static char buffer3[BYTESIZE_BUFFER_SIZE]; static char buffer3[BYTESIZE_BUFFER_SIZE];
static char *curbuffer = buffer3; static char *curbuffer = buffer3;
enum {bytes, kilobytes, megabytes, gigabytes} unit = bytes; enum {
static char units[][7] = {"Bytes", "kBytes", "MBytes", "GBytes"}; bytes,
kilobytes,
float bytesize = (float)bsize; megabytes,
gibibytes,
tebibytes,
pebibytes,
exbibytes } unit = bytes;
static const char *const units[] = {
"Bytes",
"KiBytes",
"MiBytes",
"GiBytes",
"TiBytes",
"PiBytes",
"EiBytes" };
double bytesize = (double)bsize;
const char *fmt;
if (curbuffer == buffer1) if (curbuffer == buffer1)
curbuffer = buffer2; curbuffer = buffer2;
@ -232,10 +249,35 @@ char *human_friendly_bytesize(unsigned long bsize) {
if (bytesize > 1024) { if (bytesize > 1024) {
bytesize /= 1024; bytesize /= 1024;
unit = gigabytes; unit = gibibytes;
} }
snprintf(curbuffer, BYTESIZE_BUFFER_SIZE, "%3.2f%s", bytesize, messages_get(units[unit])); if (bytesize > 1024) {
bytesize /= 1024;
unit = tebibytes;
}
if (bytesize > 1024) {
bytesize /= 1024;
unit = pebibytes;
}
if (bytesize > 1024) {
bytesize /= 1024;
unit = exbibytes;
}
if (unit == bytes) {
fmt = "%.0f%s";
} else {
fmt = "%3.2f%s";
}
snprintf(curbuffer,
BYTESIZE_BUFFER_SIZE,
fmt,
bytesize,
messages_get(units[unit]));
return curbuffer; return curbuffer;
} }