add full generic support for cx_strchr() and cx_strrchr()

Sun, 28 Dec 2025 18:30:25 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 28 Dec 2025 18:30:25 +0100
changeset 1676
f889ffd07c86
parent 1675
36c0fb2b60b2
child 1677
1d73c7302fbc

add full generic support for cx_strchr() and cx_strrchr()

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 17:31:20 2025 +0100
+++ b/src/cx/string.h	Sun Dec 28 18:30:25 2025 +0100
@@ -674,19 +674,59 @@
 #define cx_strat(str, index) cx_strat_(cx_strcast(str), index)
 
 /**
- * Returns a substring starting at the location of the first occurrence of the
- * specified character.
- *
- * If the string does not contain the character, an empty string is returned.
- *
- * @param string the string where to locate the character
- * @param chr    the character to locate
- * @return       a substring starting at the first location of @p chr
- *
- * @see cx_strchr_m()
+ * Searches for a character in a string.
+ * Internal function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ * @see cx_strchr()
+ */
+CX_EXTERN CX_NODISCARD
+cxstring cx_strchr_(cxstring string, int chr);
+
+/**
+ * Searches for a character in a string.
+ * Internal function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ * @see cx_strrchr()
  */
 CX_EXTERN CX_NODISCARD
-cxstring cx_strchr(cxstring string, int chr);
+cxstring cx_strrchr_(cxstring string, int chr);
+
+#ifdef __cplusplus
+CX_CPPDECL cxstring cx_strchr(cxstring string, int chr) {
+    return cx_strchr_(string, chr);
+}
+CX_CPPDECL cxmutstr cx_strchr(cxmutstr string, int chr) {
+    return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr));
+}
+CX_CPPDECL cxstring cx_strrchr(cxstring string, int chr) {
+    return cx_strrchr_(string, chr);
+}
+CX_CPPDECL cxmutstr cx_strrchr(cxmutstr string, int chr) {
+    return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr));
+}
+#else
+/**
+ * Internal conversion function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ */
+CX_INLINE cxmutstr cx_strchr_m_(cxmutstr string, int chr) {
+    return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr));
+}
+/**
+ * Internal conversion function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ */
+CX_INLINE  cxmutstr cx_strrchr_m_(cxmutstr string, int chr) {
+    return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr));
+}
 
 /**
  * Returns a substring starting at the location of the first occurrence of the
@@ -697,11 +737,10 @@
  * @param string the string where to locate the character
  * @param chr    the character to locate
  * @return       a substring starting at the first location of @p chr
- *
- * @see cx_strchr()
  */
-CX_EXTERN CX_NODISCARD
-cxmutstr cx_strchr_m(cxmutstr string, int chr);
+#define cx_strchr(string, chr) _Generic(cx_strcast_m(string), \
+        cxstring: cx_strchr_, \
+        cxmutstr: cx_strchr_m_)(cx_strcast_m(string), chr)
 
 /**
  * Returns a substring starting at the location of the last occurrence of the
@@ -712,26 +751,11 @@
  * @param string the string where to locate the character
  * @param chr    the character to locate
  * @return       a substring starting at the last location of @p chr
- *
- * @see cx_strrchr_m()
  */
-CX_EXTERN CX_NODISCARD
-cxstring cx_strrchr(cxstring string, int chr);
-
-/**
- * Returns a substring starting at the location of the last occurrence of the
- * specified character.
- *
- * If the string does not contain the character, an empty string is returned.
- *
- * @param string the string where to locate the character
- * @param chr    the character to locate
- * @return       a substring starting at the last location of @p chr
- *
- * @see cx_strrchr()
- */
-CX_EXTERN CX_NODISCARD
-cxmutstr cx_strrchr_m(cxmutstr string, int chr);
+#define cx_strrchr(string, chr) _Generic(cx_strcast_m(string), \
+        cxstring: cx_strrchr_, \
+        cxmutstr: cx_strrchr_m_)(cx_strcast_m(string), chr)
+#endif
 
 /**
  * Searches for a specific substring.
--- a/src/string.c	Sun Dec 28 17:31:20 2025 +0100
+++ b/src/string.c	Sun Dec 28 18:30:25 2025 +0100
@@ -178,7 +178,7 @@
     return (cxstring) {string.ptr + start, length};
 }
 
-cxstring cx_strchr(
+cxstring cx_strchr_(
         cxstring string,
         int chr
 ) {
@@ -187,15 +187,7 @@
     return (cxstring) {ret, string.length - (ret - string.ptr)};
 }
 
-cxmutstr cx_strchr_m(
-        cxmutstr string,
-        int chr
-) {
-    cxstring result = cx_strchr(cx_strcast(string), chr);
-    return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
-cxstring cx_strrchr(
+cxstring cx_strrchr_(
     cxstring string,
     int chr
 ) {
@@ -216,14 +208,6 @@
 #endif
 }
 
-cxmutstr cx_strrchr_m(
-        cxmutstr string,
-        int chr
-) {
-    cxstring result = cx_strrchr(cx_strcast(string), chr);
-    return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
 #ifndef CX_STRSTR_SBO_SIZE
 #define CX_STRSTR_SBO_SIZE 128
 #endif
--- a/tests/test_string.c	Sun Dec 28 17:31:20 2025 +0100
+++ b/tests/test_string.c	Sun Dec 28 18:30:25 2025 +0100
@@ -373,10 +373,19 @@
         cxstring result = cx_strchr(str, 'w');
         CX_TEST_ASSERT(result.length == 35);
         CX_TEST_ASSERT(0 == strcmp(result.ptr, "will find you - and I will kill you"));
+    }
+}
 
-        // just for coverage, call the _m variant
-        cxmutstr m = cx_strchr_m(cx_mutstrn(NULL, 0), 'a');
-        CX_TEST_ASSERT(0 == cx_strcmp(m, ""));
+CX_TEST(test_strchr_m) {
+    cxmutstr str = cx_mutstr((char*)"I will find you - and I will kill you");
+
+    CX_TEST_DO {
+        cxmutstr notfound = cx_strchr(str, 'x');
+        CX_TEST_ASSERT(notfound.length == 0);
+
+        cxmutstr result = cx_strchr(str, 'w');
+        CX_TEST_ASSERT(result.length == 35);
+        CX_TEST_ASSERT(0 == strcmp(result.ptr, "will find you - and I will kill you"));
     }
 }
 
@@ -397,10 +406,26 @@
 
         result = cx_strrchr(str, 'X');
         CX_TEST_ASSERT(0 == cx_strcmp(result, str));
+    }
+}
 
-        // just for coverage, call the _m variant
-        cxmutstr m = cx_strrchr_m(cx_mutstrn(NULL, 0), 'a');
-        CX_TEST_ASSERT(0 == cx_strcmp(m, ""));
+CX_TEST(test_strrchr_m) {
+    cxmutstr str = cx_mutstr((char*)"X will find you - and I will kill you");
+
+    CX_TEST_DO {
+        cxmutstr notfound = cx_strrchr(str, 'x');
+        CX_TEST_ASSERT(notfound.length == 0);
+
+        cxmutstr result = cx_strrchr(str, 'w');
+        CX_TEST_ASSERT(result.length == 13);
+        CX_TEST_ASSERT(0 == strcmp(result.ptr, "will kill you"));
+
+        result = cx_strrchr(str, 'u');
+        CX_TEST_ASSERT(result.length == 1);
+        CX_TEST_ASSERT(0 == strcmp(result.ptr, "u"));
+
+        result = cx_strrchr(str, 'X');
+        CX_TEST_ASSERT(0 == cx_strcmp(result, str));
     }
 }
 
@@ -1653,7 +1678,9 @@
     cx_test_register(suite, test_strsubs_c);
     cx_test_register(suite, test_strat);
     cx_test_register(suite, test_strchr);
+    cx_test_register(suite, test_strchr_m);
     cx_test_register(suite, test_strrchr);
+    cx_test_register(suite, test_strrchr_m);
     cx_test_register(suite, test_strstr);
     cx_test_register(suite, test_strcmp);
     cx_test_register(suite, test_strcasecmp);

mercurial