add cx_strcat_m() and cx_strcat_ma() for in-place concatenation

Sat, 22 Apr 2023 13:06:18 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 22 Apr 2023 13:06:18 +0200
changeset 697
ebdce4bf262b
parent 696
1ba4ec2e7a89
child 698
7345ee0a0301

add cx_strcat_m() and cx_strcat_ma() for in-place concatenation

src/cx/string.h file | annotate | diff | comparison | revisions
src/string.c file | annotate | diff | comparison | revisions
tests/test_string.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/cx/string.h	Sat Apr 22 12:29:00 2023 +0200
     1.2 +++ b/src/cx/string.h	Sat Apr 22 13:06:18 2023 +0200
     1.3 @@ -296,28 +296,50 @@
     1.4  );
     1.5  
     1.6  /**
     1.7 - * Concatenates two or more strings.
     1.8 + * Concatenates strings.
     1.9   *
    1.10   * The resulting string will be allocated by the specified allocator.
    1.11 -  * So developers \em must pass the return value to cx_strfree() eventually.
    1.12 -  *
    1.13 -  * \note It is guaranteed that there is only one allocation.
    1.14 -  * It is also guaranteed that the returned string is zero-terminated.
    1.15 + * So developers \em must pass the return value to cx_strfree_a() eventually.
    1.16 + *
    1.17 + * If \p str already contains a string, the memory will be reallocated and
    1.18 + * the other strings are appended. Otherwise, new memory is allocated.
    1.19 + *
    1.20 + * \note It is guaranteed that there is only one allocation.
    1.21 + * It is also guaranteed that the returned string is zero-terminated.
    1.22   *
    1.23   * @param alloc the allocator to use
    1.24 - * @param count   the total number of strings to concatenate
    1.25 - * @param ...     all strings
    1.26 + * @param str   the string the other strings shall be concatenated to
    1.27 + * @param count the number of the other following strings to concatenate
    1.28 + * @param ...   all other strings
    1.29   * @return the concatenated string
    1.30   */
    1.31  __attribute__((__warn_unused_result__, __nonnull__))
    1.32 -cxmutstr cx_strcat_a(
    1.33 +cxmutstr cx_strcat_ma(
    1.34          CxAllocator const *alloc,
    1.35 +        cxmutstr str,
    1.36          size_t count,
    1.37          ...
    1.38  );
    1.39  
    1.40  /**
    1.41 - * Concatenates two or more strings.
    1.42 + * Concatenates strings and returns a new string.
    1.43 + *
    1.44 + * The resulting string will be allocated by the specified allocator.
    1.45 + * So developers \em must pass the return value to cx_strfree_a() eventually.
    1.46 + *
    1.47 + * \note It is guaranteed that there is only one allocation.
    1.48 + * It is also guaranteed that the returned string is zero-terminated.
    1.49 + *
    1.50 + * @param alloc the allocator to use
    1.51 + * @param count the number of the other following strings to concatenate
    1.52 + * @param ...   all other strings
    1.53 + * @return the concatenated string
    1.54 + */
    1.55 +#define cx_strcat_a(alloc, count, ...) \
    1.56 +cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
    1.57 +
    1.58 +/**
    1.59 + * Concatenates strings and returns a new string.
    1.60   *
    1.61   * The resulting string will be allocated by standard \c malloc().
    1.62   * So developers \em must pass the return value to cx_strfree() eventually.
    1.63 @@ -325,12 +347,32 @@
    1.64   * \note It is guaranteed that there is only one allocation.
    1.65   * It is also guaranteed that the returned string is zero-terminated.
    1.66   *
    1.67 - * @param count   the total number of strings to concatenate
    1.68 - * @param ...     all strings
    1.69 + * @param count   the number of the other following strings to concatenate
    1.70 + * @param ...     all other strings
    1.71   * @return the concatenated string
    1.72   */
    1.73  #define cx_strcat(count, ...) \
    1.74 -cx_strcat_a(cxDefaultAllocator, count, __VA_ARGS__)
    1.75 +cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
    1.76 +
    1.77 +/**
    1.78 + * Concatenates strings.
    1.79 + *
    1.80 + * The resulting string will be allocated by standard \c malloc().
    1.81 + * So developers \em must pass the return value to cx_strfree() eventually.
    1.82 + *
    1.83 + * If \p str already contains a string, the memory will be reallocated and
    1.84 + * the other strings are appended. Otherwise, new memory is allocated.
    1.85 + *
    1.86 + * \note It is guaranteed that there is only one allocation.
    1.87 + * It is also guaranteed that the returned string is zero-terminated.
    1.88 + *
    1.89 + * @param str     the string the other strings shall be concatenated to
    1.90 + * @param count   the number of the other following strings to concatenate
    1.91 + * @param ...     all other strings
    1.92 + * @return the concatenated string
    1.93 + */
    1.94 +#define cx_strcat_m(str, count, ...) \
    1.95 +cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
    1.96  
    1.97  /**
    1.98   * Returns a substring starting at the specified location.
     2.1 --- a/src/string.c	Sat Apr 22 12:29:00 2023 +0200
     2.2 +++ b/src/string.c	Sat Apr 22 13:06:18 2023 +0200
     2.3 @@ -98,11 +98,14 @@
     2.4      return size;
     2.5  }
     2.6  
     2.7 -cxmutstr cx_strcat_a(
     2.8 +cxmutstr cx_strcat_ma(
     2.9          CxAllocator const *alloc,
    2.10 +        cxmutstr str,
    2.11          size_t count,
    2.12          ...
    2.13  ) {
    2.14 +    if (count == 0) return str;
    2.15 +
    2.16      cxstring *strings = calloc(count, sizeof(cxstring));
    2.17      if (!strings) abort();
    2.18  
    2.19 @@ -110,34 +113,38 @@
    2.20      va_start(ap, count);
    2.21  
    2.22      // get all args and overall length
    2.23 -    size_t slen = 0;
    2.24 +    size_t slen = str.length;
    2.25      cx_for_n(i, count) {
    2.26          cxstring s = va_arg (ap, cxstring);
    2.27          strings[i] = s;
    2.28          slen += s.length;
    2.29      }
    2.30 +    va_end(ap);
    2.31  
    2.32 -    // create new string
    2.33 -    cxmutstr result;
    2.34 -    result.ptr = cxMalloc(alloc, slen + 1);
    2.35 -    result.length = slen;
    2.36 -    if (result.ptr == NULL) abort();
    2.37 +    // reallocate or create new string
    2.38 +    if (str.ptr == NULL) {
    2.39 +        str.ptr = cxMalloc(alloc, slen + 1);
    2.40 +    } else {
    2.41 +        str.ptr = cxRealloc(alloc, str.ptr, slen + 1);
    2.42 +    }
    2.43 +    if (str.ptr == NULL) abort();
    2.44  
    2.45      // concatenate strings
    2.46 -    size_t pos = 0;
    2.47 +    size_t pos = str.length;
    2.48 +    str.length = slen;
    2.49      cx_for_n(i, count) {
    2.50          cxstring s = strings[i];
    2.51 -        memcpy(result.ptr + pos, s.ptr, s.length);
    2.52 +        memcpy(str.ptr + pos, s.ptr, s.length);
    2.53          pos += s.length;
    2.54      }
    2.55  
    2.56      // terminate string
    2.57 -    result.ptr[result.length] = '\0';
    2.58 +    str.ptr[str.length] = '\0';
    2.59  
    2.60      // free temporary array
    2.61      free(strings);
    2.62  
    2.63 -    return result;
    2.64 +    return str;
    2.65  }
    2.66  
    2.67  cxstring cx_strsubs(
     3.1 --- a/tests/test_string.cpp	Sat Apr 22 12:29:00 2023 +0200
     3.2 +++ b/tests/test_string.cpp	Sat Apr 22 13:06:18 2023 +0200
     3.3 @@ -273,6 +273,13 @@
     3.4      EXPECT_EQ(cx_strcmp(cx_strcast(t5), CX_STR("561234")), 0);
     3.5      EXPECT_ZERO_TERMINATED(t5);
     3.6      cx_strfree(&t5);
     3.7 +
     3.8 +    // use an initial string
     3.9 +    cxmutstr t6 = cx_strdup(CX_STR("Hello"));
    3.10 +    t6 = cx_strcat_m(t6, 2, CX_STR(", "), CX_STR("World!"));
    3.11 +    EXPECT_EQ(cx_strcmp(cx_strcast(t6), CX_STR("Hello, World!")), 0);
    3.12 +    EXPECT_ZERO_TERMINATED(t6);
    3.13 +    cx_strfree(&t6);
    3.14  }
    3.15  
    3.16  TEST(String, strsplit) {

mercurial