Sat, 22 Apr 2023 13:06:18 +0200
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) {