]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: implement trimming of floating point numbers
authorWilly Tarreau <w@1wt.eu>
Sat, 8 May 2021 08:28:53 +0000 (10:28 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 8 May 2021 08:42:11 +0000 (10:42 +0200)
When using "%f" to print a float, it automatically gets 6 digits after
the decimal point and there's no way to automatically adjust to the
required ones by dropping trailing zeroes. This function does exactly
this and automatically drops the decimal point if all digits after it
were zeroes. This will make numbers more friendly in stats and makes
outputs shorter (e.g. JSON where everything is just a "number").

The function is designed to be easy to use with snprint() and chunks:

  snprintf:
    flt_trim(buf, 0, snprintf(buf, sizeof(buf), "%f", x));

  chunk_printf:
    out->data = flt_trim(out->area, 0, chunk_printf(out, "%f", x));

  chunk_appendf:
    size_t prev_data = out->data;
    out->data = flt_trim(out->area, prev_data, chunk_appendf(out, "%f", x));

include/haproxy/tools.h
src/tools.c

index 92d5b7081241ced53eee67e06fa64d36457df630..948207a38ad2d579065c88bf84837d1c95bbd63a 100644 (file)
@@ -74,6 +74,7 @@ extern char *ultoa_r(unsigned long n, char *buffer, int size);
 extern char *lltoa_r(long long int n, char *buffer, int size);
 extern char *sltoa_r(long n, char *buffer, int size);
 extern const char *ulltoh_r(unsigned long long n, char *buffer, int size);
+size_t flt_trim(char *buffer, size_t num_start, size_t len);
 static inline const char *ultoa(unsigned long n)
 {
        return ultoa_r(n, itoa_str[0], sizeof(itoa_str[0]));
index c45358570bfbabf8fa7977205330316676b8da5a..e94fed7e7283b5da7a175069f9181b272290ea5c 100644 (file)
@@ -535,6 +535,39 @@ const char *limit_r(unsigned long n, char *buffer, int size, const char *alt)
        return (n) ? ultoa_r(n, buffer, size) : (alt ? alt : "");
 }
 
+/* Trims the first "%f" float in a string to its minimum number of digits after
+ * the decimal point by trimming trailing zeroes, even dropping the decimal
+ * point if not needed. The string is in <buffer> of length <len>, and the
+ * number is expected to start at or after position <num_start> (the first
+ * point appearing there is considered). A NUL character is always placed at
+ * the end if some trimming occurs. The new buffer length is returned.
+ */
+size_t flt_trim(char *buffer, size_t num_start, size_t len)
+{
+       char *end = buffer + len;
+       char *p = buffer + num_start;
+       char *trim;
+
+       do {
+               if (p >= end)
+                       return len;
+               trim = p++;
+       } while (*trim != '.');
+
+       /* For now <trim> is on the decimal point. Let's look for any other
+        * meaningful digit after it.
+        */
+       while (p < end) {
+               if (*p++ != '0')
+                       trim = p;
+       }
+
+       if (trim < end)
+               *trim = 0;
+
+       return trim - buffer;
+}
+
 /* returns a locally allocated string containing the quoted encoding of the
  * input string. The output may be truncated to QSTR_SIZE chars, but it is
  * guaranteed that the string will always be properly terminated. Quotes are