summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2019-11-03 16:42:31 +0200
committerOran Agra <oran@redislabs.com>2019-11-03 16:42:31 +0200
commit779aebc91cd8d3043ab172e0bc5b8c988df88e33 (patch)
tree803c68ed0f77f8b9abd01e200022a310876d9712 /src/util.c
parentfdaea2a7a7eed1499f46bb98552f8d8bb8dc7e9d (diff)
downloadredis-779aebc91cd8d3043ab172e0bc5b8c988df88e33.tar.gz
Module API for loading and saving long double
looks like each platform implements long double differently (different bit count) so we can't save them as binary, and we also want to avoid creating a new RDB format version, so we save these are hex strings using "%La". This commit includes a change in the arguments of ld2string to support this. as well as tests for coverage and short reads. coded by @guybe7
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c60
1 files changed, 36 insertions, 24 deletions
diff --git a/src/util.c b/src/util.c
index 783bcf83b..062a572d4 100644
--- a/src/util.c
+++ b/src/util.c
@@ -510,15 +510,17 @@ int d2string(char *buf, size_t len, double value) {
return len;
}
-/* Convert a long double into a string. If humanfriendly is non-zero
- * it does not use exponential format and trims trailing zeroes at the end,
- * however this results in loss of precision. Otherwise exp format is used
- * and the output of snprintf() is not modified.
+/* Create a string object from a long double.
+ * If mode is humanfriendly it does not use exponential format and trims trailing
+ * zeroes at the end (may result in loss of precision).
+ * If mode is default exp format is used and the output of snprintf()
+ * is not modified (may result in loss of precision).
+ * If mode is hex hexadecimal format is used (no loss of precision)
*
* The function returns the length of the string or zero if there was not
* enough buffer room to store it. */
-int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
- size_t l;
+int ld2string(char *buf, size_t len, long double value, ld2string_mode mode) {
+ size_t l = 0;
if (isinf(value)) {
/* Libc in odd systems (Hi Solaris!) will format infinite in a
@@ -531,26 +533,36 @@ int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
memcpy(buf,"-inf",4);
l = 4;
}
- } else if (humanfriendly) {
- /* We use 17 digits precision since with 128 bit floats that precision
- * after rounding is able to represent most small decimal numbers in a
- * way that is "non surprising" for the user (that is, most small
- * decimal numbers will be represented in a way that when converted
- * back into a string are exactly the same as what the user typed.) */
- l = snprintf(buf,len,"%.17Lf", value);
- if (l+1 > len) return 0; /* No room. */
- /* Now remove trailing zeroes after the '.' */
- if (strchr(buf,'.') != NULL) {
- char *p = buf+l-1;
- while(*p == '0') {
- p--;
- l--;
+ } else {
+ switch (mode) {
+ case LD_STR_AUTO:
+ l = snprintf(buf,len,"%.17Lg",value);
+ if (l+1 > len) return 0; /* No room. */
+ break;
+ case LD_STR_HEX:
+ l = snprintf(buf,len,"%La",value);
+ if (l+1 > len) return 0; /* No room. */
+ break;
+ case LD_STR_HUMAN:
+ /* We use 17 digits precision since with 128 bit floats that precision
+ * after rounding is able to represent most small decimal numbers in a
+ * way that is "non surprising" for the user (that is, most small
+ * decimal numbers will be represented in a way that when converted
+ * back into a string are exactly the same as what the user typed.) */
+ l = snprintf(buf,len,"%.17Lf",value);
+ if (l+1 > len) return 0; /* No room. */
+ /* Now remove trailing zeroes after the '.' */
+ if (strchr(buf,'.') != NULL) {
+ char *p = buf+l-1;
+ while(*p == '0') {
+ p--;
+ l--;
+ }
+ if (*p == '.') l--;
}
- if (*p == '.') l--;
+ break;
+ default: return 0; /* Invalid mode. */
}
- } else {
- l = snprintf(buf,len,"%.17Lg", value);
- if (l+1 > len) return 0; /* No room. */
}
buf[l] = '\0';
return l;