Sun, 28 Dec 2025 15:45:39 +0100
full generic support for cx_strsubs() and cx_strsubsl()
relates to #792
| src/cx/string.h | file | annotate | diff | comparison | revisions | |
| src/string.c | file | annotate | diff | comparison | revisions | |
| tests/test_string.c | file | annotate | diff | comparison | revisions |
--- a/src/cx/string.h Sun Dec 28 14:47:36 2025 +0100 +++ b/src/cx/string.h Sun Dec 28 15:45:39 2025 +0100 @@ -395,6 +395,19 @@ #endif /** + * Casts away constness and converts a cxstring to a cxmutstr. + * For internal use only! + * @param str + * @return + */ +CX_INLINE cxmutstr cx_mutstrcast(cxstring str) { + cxmutstr s; + s.ptr = (char*)str.ptr; + s.length = str.length; + return s; +} + +/** * Passes the pointer in this string to the cxDefaultAllocator's @c free() function. * * The pointer in the struct is set to @c NULL, and the length is set to zero, @@ -530,22 +543,74 @@ cx_strcat_a(cxDefaultAllocator, str, count, __VA_ARGS__) /** - * Returns a substring starting at the specified location. + * Returns a substring. + * + * Internal function - do not use. * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. + * @param string input string + * @param start start location of the substring + * @param length the maximum length of the returned string + * @return a substring of @p string starting at @p start + * @see cx_strsubsl() + */ +cx_attr_nodiscard +CX_EXPORT cxstring cx_strsubsl_(cxstring string, size_t start, size_t length); + +/** + * Returns a substring. + * + * Internal function - do not use. * * @param string input string * @param start start location of the substring * @return a substring of @p string starting at @p start + * @see cx_strsubs() + */ +cx_attr_nodiscard +CX_EXPORT cxstring cx_strsubs_(cxstring string, size_t start); + +CX_INLINE cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) { + return cx_mutstrcast(cx_strsubs_(cx_strcast(string), start)); +} + +CX_INLINE cxmutstr cx_strsubsl_m_(cxmutstr string, size_t start, size_t length) { + return cx_mutstrcast(cx_strsubsl_(cx_strcast(string), start, length)); +} + +#ifdef __cplusplus +} // extern "C" +CX_CPPDECL cxstring cx_strsubs_cpp_(cxstring string, size_t start) { + return cx_strsubs_(string, start); +} +CX_CPPDECL cxstring cx_strsubsl_cpp_(cxstring string, size_t start, size_t length) { + return cx_strsubsl_(string, start, length); +} +CX_CPPDECL cxmutstr cx_strsubs_cpp_(cxmutstr string, size_t start) { + return cx_strsubs_m_(string, start); +} +CX_CPPDECL cxmutstr cx_strsubsl_cpp_(cxmutstr string, size_t start, size_t length) { + return cx_strsubsl_m_(string, start, length); +} +#define cx_strsubs(string, start) cx_strsubs_cpp_(cx_strcast_m(string), start) +#define cx_strsubsl(string, start, length) cx_strsubsl_cpp_(cx_strcast_m(string), start, length) +extern "C" { +#else +/** + * Returns a substring starting at the specified location. + * + * @attention the new string references the same memory area as the + * input string and is @em not zero-terminated. + * Use cx_strdup() to get a copy. + * + * @param string input string + * @param start (@c size_t) start location of the substring + * @return (@c cxstring or @c cxmutstr) a substring of @p string starting at @p start * * @see cx_strsubsl() - * @see cx_strsubs_m() - * @see cx_strsubsl_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubs(cxstring string, size_t start); +#define cx_strsubs(string, start) _Generic(cx_strcast_m(string), \ + cxstring: cx_strsubs_, \ + cxmutstr: cx_strsubs_m_)(cx_strcast_m(string), start) /** * Returns a substring starting at the specified location. @@ -563,51 +628,11 @@ * @return a substring of @p string starting at @p start * * @see cx_strsubs() - * @see cx_strsubs_m() - * @see cx_strsubsl_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubsl(cxstring string, size_t start, size_t length); - -/** - * Returns a substring starting at the specified location. - * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @return a substring of @p string starting at @p start - * - * @see cx_strsubsl_m() - * @see cx_strsubs() - * @see cx_strsubsl() - */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start); - -/** - * Returns a substring starting at the specified location. - * - * The returned string will be limited to @p length bytes or the number - * of bytes available in @p string, whichever is smaller. - * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @param length the maximum length of the returned string - * @return a substring of @p string starting at @p start - * - * @see cx_strsubs_m() - * @see cx_strsubs() - * @see cx_strsubsl() - */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strsubsl_m(cxmutstr string, size_t start, size_t length); +#define cx_strsubsl(string, start, length) _Generic(cx_strcast_m(string), \ + cxstring: cx_strsubsl_, \ + cxmutstr: cx_strsubsl_m_)(cx_strcast_m(string), start, length) +#endif /** * Returns the character at the specified index offset.
--- a/src/string.c Sun Dec 28 14:47:36 2025 +0100 +++ b/src/string.c Sun Dec 28 15:45:39 2025 +0100 @@ -154,21 +154,14 @@ return str; } -cxstring cx_strsubs( +cxstring cx_strsubs_( cxstring string, size_t start ) { - return cx_strsubsl(string, start, string.length - start); + return cx_strsubsl_(string, start, string.length); } -cxmutstr cx_strsubs_m( - cxmutstr string, - size_t start -) { - return cx_strsubsl_m(string, start, string.length - start); -} - -cxstring cx_strsubsl( +cxstring cx_strsubsl_( cxstring string, size_t start, size_t length @@ -185,15 +178,6 @@ return (cxstring) {string.ptr + start, length}; } -cxmutstr cx_strsubsl_m( - cxmutstr string, - size_t start, - size_t length -) { - cxstring result = cx_strsubsl(cx_strcast(string), start, length); - return (cxmutstr) {(char *) result.ptr, result.length}; -} - cxstring cx_strchr( cxstring string, int chr
--- a/tests/test_string.c Sun Dec 28 14:47:36 2025 +0100 +++ b/tests/test_string.c Sun Dec 28 15:45:39 2025 +0100 @@ -226,34 +226,115 @@ } } -CX_TEST(test_strsubs) { +CX_TEST(test_strsubs_cxs) { cxstring str = cx_str("A test string"); + cxstring sub; CX_TEST_DO { - cxstring sub = cx_strsubs(str, 0); + sub = cx_strsubs(str, 0); + CX_TEST_ASSERT(0 == cx_strcmp(sub, str)); + + sub = cx_strsubs(str, 2); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test string")); + + sub = cx_strsubs(str, 7); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); + + sub = cx_strsubs(str, 15); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "")); + + sub = cx_strsubsl(str, 2, 4); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test")); + + sub = cx_strsubsl(str, 7, 3); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "str")); + + sub = cx_strsubsl(str, 7, 20); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); + } +} + +CX_TEST(test_strsubs_cc) { + const char *str = "A test string"; + cxstring sub; + + CX_TEST_DO { + sub = cx_strsubs(str, 0); CX_TEST_ASSERT(0 == cx_strcmp(sub, str)); sub = cx_strsubs(str, 2); - CX_TEST_ASSERT(0 == cx_strcmp(sub, cx_str("test string"))); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test string")); sub = cx_strsubs(str, 7); - CX_TEST_ASSERT(0 == cx_strcmp(sub, cx_str("string"))); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); sub = cx_strsubs(str, 15); - CX_TEST_ASSERT(0 == cx_strcmp(sub, cx_str(""))); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "")); sub = cx_strsubsl(str, 2, 4); - CX_TEST_ASSERT(0 == cx_strcmp(sub, cx_str("test"))); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test")); sub = cx_strsubsl(str, 7, 3); - CX_TEST_ASSERT(0 == cx_strcmp(sub, cx_str("str"))); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "str")); sub = cx_strsubsl(str, 7, 20); - CX_TEST_ASSERT(0 == cx_strcmp(sub, cx_str("string"))); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); + } +} + +CX_TEST(test_strsubs_cxms) { + cxmutstr str = cx_mutstr((char*)"A test string"); + cxmutstr sub; + + CX_TEST_DO { + sub = cx_strsubs(str, 0); + CX_TEST_ASSERT(0 == cx_strcmp(sub, str)); + + sub = cx_strsubs(str, 2); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test string")); + + sub = cx_strsubs(str, 7); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); + + sub = cx_strsubs(str, 15); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "")); + + sub = cx_strsubsl(str, 2, 4); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test")); + + sub = cx_strsubsl(str, 7, 3); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "str")); - // just for coverage, call the _m variant - cxmutstr m = cx_strsubs_m(cx_mutstrn(NULL, 0), 0); - CX_TEST_ASSERT(0 == cx_strcmp(m, "")); + sub = cx_strsubsl(str, 7, 20); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); + } +} + +CX_TEST(test_strsubs_c) { + char *str = "A test string"; + cxmutstr sub; + + CX_TEST_DO { + sub = cx_strsubs(str, 0); + CX_TEST_ASSERT(0 == cx_strcmp(sub, str)); + + sub = cx_strsubs(str, 2); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test string")); + + sub = cx_strsubs(str, 7); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); + + sub = cx_strsubs(str, 15); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "")); + + sub = cx_strsubsl(str, 2, 4); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "test")); + + sub = cx_strsubsl(str, 7, 3); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "str")); + + sub = cx_strsubsl(str, 7, 20); + CX_TEST_ASSERT(0 == cx_strcmp(sub, "string")); } } @@ -1566,7 +1647,10 @@ cx_test_register(suite, test_strdup_shortened); cx_test_register(suite, test_strcpy); cx_test_register(suite, test_strlen); - cx_test_register(suite, test_strsubs); + cx_test_register(suite, test_strsubs_cxs); + cx_test_register(suite, test_strsubs_cxms); + cx_test_register(suite, test_strsubs_cc); + cx_test_register(suite, test_strsubs_c); cx_test_register(suite, test_strat); cx_test_register(suite, test_strchr); cx_test_register(suite, test_strrchr);