]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: *_strsplit() - implement more efficient version for a single separator char
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 3 Nov 2017 23:40:24 +0000 (01:40 +0200)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Mon, 6 Nov 2017 07:34:31 +0000 (09:34 +0200)
src/lib/strfuncs.c
src/lib/test-strfuncs.c

index 05c3c7f5e41a598bb1df186eb7e03828ae1d8f11..eec9027977abb0468359ddbb8beac7250c2fa23d 100644 (file)
@@ -525,14 +525,12 @@ bool mem_equals_timing_safe(const void *p1, const void *p2, size_t size)
 }
 
 static char **
-split_str(pool_t pool, const char *data, const char *separators, bool spaces)
+split_str_slow(pool_t pool, const char *data, const char *separators, bool spaces)
 {
         char **array;
        char *str;
         unsigned int count, alloc_count, new_alloc_count;
 
-       i_assert(*separators != '\0');
-
        if (spaces) {
                /* skip leading separators */
                while (*data != '\0' && strchr(separators, *data) != NULL)
@@ -582,6 +580,51 @@ split_str(pool_t pool, const char *data, const char *separators, bool spaces)
         return array;
 }
 
+static char **
+split_str_fast(pool_t pool, const char *data, char sep)
+{
+       char **array, *str;
+       unsigned int count, alloc_count, new_alloc_count;
+
+       if (*data == '\0')
+               return p_new(pool, char *, 1);
+
+       str = p_strdup(pool, data);
+
+       alloc_count = 32;
+       array = p_new(pool, char *, alloc_count);
+
+       array[0] = str; count = 1;
+       while ((str = strchr(str, sep)) != NULL) {
+               /* separator found */
+               if (count+1 >= alloc_count) {
+                       new_alloc_count = nearest_power(alloc_count+1);
+                       array = p_realloc(pool, array,
+                                         sizeof(char *) * alloc_count,
+                                         sizeof(char *) *
+                                         new_alloc_count);
+                       alloc_count = new_alloc_count;
+               }
+               *str++ = '\0';
+               array[count++] = str;
+       }
+       i_assert(count < alloc_count);
+       i_assert(array[count] == NULL);
+
+       return array;
+}
+
+static char **
+split_str(pool_t pool, const char *data, const char *separators, bool spaces)
+{
+       i_assert(*separators != '\0');
+
+       if (separators[1] == '\0' && !spaces)
+               return split_str_fast(pool, data, separators[0]);
+       else
+               return split_str_slow(pool, data, separators, spaces);
+}
+
 const char **t_strsplit(const char *data, const char *separators)
 {
        return (const char **)split_str(unsafe_data_stack_pool, data,
index 2fa5bf45e091e18292ea1ecbe7e95bae4fe4e4c1..d7ac4bf6ce6bc91a166ad5eba0287eb5714aaed2 100644 (file)
@@ -104,8 +104,9 @@ static void test_t_strsplit(void)
        test_begin("t_strsplit");
 
        for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
+               /* split_str_fast() with single separator */
                args = t_strsplit(tests[i].input, "\n");
-               /* test also with a secondary nonexistent separator */
+               /* split_str_slow() with a secondary separator */
                args2 = t_strsplit(tests[i].input, "\r\n");
                /* also as suffix */
                args3 = t_strsplit(tests[i].input, "\n\r");