Add bt_common_sep_digits()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 11 Jun 2019 14:59:56 +0000 (10:59 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 17 Jun 2019 20:56:59 +0000 (16:56 -0400)
This new utility function adds digit separators to a string representing
a number. For example, `1983291832` can become `1,983,291,832`.

See the function's comment for more details.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I39dedc69fbc76b31252a64c68261a35d8ac7c7a8
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1411
Tested-by: jenkins
src/common/common.c
src/common/common.h

index a81f8e79acd7a9a86de1fb271fb6c2f2af3374fe..4aa8fcd2a70e3ec9a890182fbf7f89350c97936f 100644 (file)
@@ -1567,3 +1567,106 @@ void bt_common_custom_snprintf(char *buf, size_t buf_size,
                priv_data, fmt, &args);
        va_end(args);
 }
+
+BT_HIDDEN
+void bt_common_sep_digits(char *str, unsigned int digits_per_group, char sep)
+{
+       const char *rd;
+       char *wr;
+       uint64_t i = 0;
+       uint64_t orig_len;
+       uint64_t sep_count;
+       uint64_t new_len;
+
+       BT_ASSERT(digits_per_group > 0);
+       BT_ASSERT(sep != '\0');
+
+       /* Compute new length of `str` */
+       orig_len = strlen(str);
+       BT_ASSERT(orig_len > 0);
+       sep_count = (orig_len - 1) / digits_per_group;
+       new_len = strlen(str) + sep_count;
+
+       /*
+        * Do the work in place. Have the reading pointer `rd` start at
+        * the end of the original string, and the writing pointer `wr`
+        * start at the end of the new string, making sure to also put a
+        * null character there.
+        */
+       rd = str + orig_len - 1;
+       wr = str + new_len;
+       *wr = '\0';
+       wr--;
+
+       /*
+        * Here's what the process looks like (3 digits per group):
+        *
+        *     Source:      12345678
+        *                         ^
+        *     Destination: 12345678#8
+        *                           ^
+        *
+        *     Source:      12345678
+        *                        ^
+        *     Destination: 1234567878
+        *                          ^
+        *
+        *     Source:      12345678
+        *                       ^
+        *     Destination: 1234567678
+        *                         ^
+        *
+        *     Source:      12345678
+        *                      ^
+        *     Destination: 123456,678
+        *                        ^
+        *
+        *     Source:      12345678
+        *                      ^
+        *     Destination: 123455,678
+        *                       ^
+        *
+        *     Source:      12345678
+        *                     ^
+        *     Destination: 123445,678
+        *                      ^
+        *
+        *     Source:      12345678
+        *                    ^
+        *     Destination: 123345,678
+        *                     ^
+        *
+        *     Source:      12345678
+        *                   ^
+        *     Destination: 12,345,678
+        *                    ^
+        *
+        *     Source:      12345678
+        *                   ^
+        *     Destination: 12,345,678
+        *                   ^
+        *
+        *     Source:      12345678
+        *                  ^
+        *     Destination: 12,345,678
+        *                  ^
+        */
+       while (rd != str - 1) {
+               if (i == digits_per_group) {
+                       /*
+                        * Time to append the separator: decrement `wr`,
+                        * but keep `rd` as is.
+                        */
+                       i = 0;
+                       *wr = sep;
+                       wr--;
+                       continue;
+               }
+
+               /* Copy read-side character to write-side character */
+               *wr = *rd;
+               wr--;
+               rd--;
+               i++;
+       }
+}
index d5f2d096e89dd8f1b48754c9205ef7c9b636bd38..ef9a715fed9871aeb8c4310eb713f41993c0dc8f 100644 (file)
@@ -311,6 +311,22 @@ void bt_common_custom_snprintf(char *buf, size_t buf_size,
 BT_HIDDEN
 size_t bt_common_get_page_size(void);
 
+/*
+ * Adds the digit separator `sep` as many times as needed to form groups
+ * of `digits_per_group` digits within `str`. `str` must have enough
+ * room to accomodate the new separators, that is:
+ *
+ *     strlen(str) + (strlen(str) / digits_per_group) + 1
+ *
+ * Example: with `str` `1983198398213`, `digits_per_group` 3, and `sep`
+ * `,`, `str` becomes `1,983,198,398,213`.
+ *
+ * `strlen(str)` must not be 0. `digits_per_group` must not be 0. `sep`
+ * must not be `\0`.
+ */
+BT_HIDDEN
+void bt_common_sep_digits(char *str, unsigned int digits_per_group, char sep);
+
 /*
  * Wraps read() function to handle EINTR and partial reads.
  * On success, it returns `count` received as parameter. On error, it returns a
@@ -643,4 +659,5 @@ enum bt_self_message_iterator_status bt_common_message_iterator_status_to_self(
 {
        return (int) status;
 }
+
 #endif /* BABELTRACE_COMMON_INTERNAL_H */
This page took 0.026568 seconds and 4 git commands to generate.