Skip to content

Commit 851610b

Browse files
committed
libutil: add encode_size()
Problem: There is no equivalent to parse_size() which turns a number into a human readable string using the same SI prefix characters defined in parse_size(). Add an encode_size() function which returns a human readable string representation of a number. While the result of encode_size() will always be valid input to parse_size(), loss of precision when creating the human readable string means that parse_size() of a string returned from encode_size() may not return the exact original value. Instead this function is mainly intended for creating human readable output.
1 parent 5a61b34 commit 851610b

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/common/libutil/parse_size.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <stdint.h>
1616
#include <errno.h>
1717
#include <stdlib.h>
18+
#include <stdio.h>
1819
#include <string.h>
1920
#include <stdbool.h>
2021
#include <math.h>
@@ -132,4 +133,29 @@ int parse_size (const char *s, uint64_t *vp)
132133
return 0;
133134
}
134135

136+
const char *encode_size (uint64_t size)
137+
{
138+
/* Allocate a thread-local buffer to make this function easy to use
139+
* in output formats (its intended use case).
140+
*
141+
* Note: The maximum printable digits for a double is 15 (DBL_DIG).
142+
* We also account for an optional decimal point, suffix, and required
143+
* space for NUL to get a buffer size of 18. (We ignore the fact that
144+
* a precision is specified in the %g format below for safety).
145+
*/
146+
static __thread char buf[18];
147+
const char* suffix[] = {"", "K", "M", "G", "T", "P", "E"};
148+
int i = 0;
149+
double value = size;
150+
while (value >= 1024) {
151+
value /= 1024;
152+
i++;
153+
}
154+
/* Note: UINT64_MAX is 16E so there is no possibility that 'i' will
155+
* overflow the suffix array.
156+
*/
157+
(void) snprintf (buf, sizeof (buf), "%.8g%s", value, suffix[i]);
158+
return buf;
159+
}
160+
135161
// vi:ts=4 sw=4 expandtab

src/common/libutil/parse_size.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@
3131
*/
3232
int parse_size (const char *s, uint64_t *vp);
3333

34+
/* Format 'size' as a human readable string using suffixes documented
35+
* above for parse_size(). Note that due to use of double precision
36+
* arithmetic and because the result is rounded to 8 significant figures
37+
* the returned string may be imprecise. Passing the result of encode_size()
38+
* to parse_size() may not result in the same value for 'size'.
39+
*
40+
* The result is only good until the next call to encode_size() from the
41+
* current thread.
42+
*/
43+
const char *encode_size (uint64_t size);
44+
3445
#endif /* !_UTIL_PARSE_SIZE_H */
3546

3647
// vi:ts=4 sw=4 expandtab

0 commit comments

Comments
 (0)