From 5e2777a8e4b075d11f14ef7135626ce48b9775e7 Mon Sep 17 00:00:00 2001 From: steven-na Date: Sat, 15 Aug 2026 16:16:28 -0700 Subject: Added a ton of string view procs --- src/string.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 282 insertions(+), 11 deletions(-) (limited to 'src/string.c') diff --git a/src/string.c b/src/string.c index 2185a81..41119e9 100644 --- a/src/string.c +++ b/src/string.c @@ -3,6 +3,7 @@ #include "log.h" #include "string.h" +#include #include #include @@ -125,19 +126,289 @@ void strng_clear(strng_t *string) { strng_view_t sv_from_chars(char const* c) { u64 l = strlen(c); return (strng_view_t){ .start=0, - .end=l, - .max=l, + .end=l-1, + .max=l-1, .string=c, }; } -void sv_trim_left(strng_view_t *sv) { - while (sv->start <= sv->end && isspace(*(sv->string+sv->start))) sv->start++; - if (sv->start > sv->end) sv->start = sv->end; +void sv_trimws_left(strng_view_t *sv) { + while (sv->start <= sv->end && isspace((unsigned char)*(sv->string+sv->start))) sv->start++; } -void sv_trim_right(strng_view_t *sv) { - while (sv->end >= sv->start && isspace(*(sv->string+sv->end))) sv->end--; - if (sv->end < sv->start) sv->end = sv->start; + +void sv_trimws_right(strng_view_t *sv) { + while (sv->end >= sv->start && isspace((unsigned char)*(sv->string+sv->end))) sv->end--; +} + +void sv_trimws(strng_view_t *sv) { + sv_trimws_left(sv); + sv_trimws_right(sv); +} + +void sv_trim_pastc_left(strng_view_t *sv, char n) { + while (sv->start <= sv->end) { + if (*(sv->string+sv->start) == n) { + sv->start++; + return; + } + sv->start++; + } +} + +void sv_trim_pastc_right(strng_view_t *sv, char n) { + while (sv->end >= sv->start) { + if (*(sv->string+sv->end) == n) { + sv->end--; + return; + } + sv->end--; + } +} + +void sv_trim_end_nextc(strng_view_t *sv, char n) { + if (sv->start > sv->end) return; + + i32 i = sv_contains_c_simd(sv, n); + + if (i > -1) { + if (i == 0) { + sv->end = sv->start - 1; + } else { + sv->end = sv->start + i - 1; + } + } +} + +void sv_trim_strt_prvc(strng_view_t *sv, char n) { + if (sv->start > sv->end) return; + + for (i64 i = (i64)sv->end; i >= (i64)sv->start; i--) { + if (*(sv->string + i) == n) { + sv->start = i + 1; + return; + } + } +} + +void sv_set_len_left(strng_view_t *sv, u64 n) { + if (sv->start > sv->end) return; + + if (n == 0) { + sv->end = sv->start - 1; + return; + } + u64 target_end = sv->start + n - 1; + if (target_end < (u64)sv->end) { + sv->end = (u64)target_end; + } } -void sv_trim(strng_view_t *sv) { sv_trim_left(sv); - sv_trim_right(sv); } -void sv_reset(strng_view_t *sv) { sv->end=sv->max; sv->start=0; } +void sv_set_len_right(strng_view_t *sv, u64 n) { + if (sv->start > sv->end) return; + + if (n == 0) { + sv->start = sv->end + 1; + return; + } + + if (n >= sv_len(sv)) return; + + sv->start = sv->end - n + 1; +} + +i32 sv_contains_simd(strng_view_t const *sv, char const *_needle) { + u64 nlen = strlen(_needle); + u64 hlen = sv_len(sv); + + if ((nlen > hlen) || !hlen) return -1; + if (nlen == hlen && memcmp(sv->string+sv->start, _needle, hlen) == 0) return 0; + + char const *restrict haystack = sv->string+sv->start; + char const *restrict needle = _needle; + + __m256i first_vec = _mm256_set1_epi8(*needle); + + u64 end_idx = hlen - nlen + 1; + u64 i = 0; + + for (; i + 32 <= end_idx; i += 32) { + __m256i hay_vec = _mm256_loadu_si256((const __m256i*)(haystack+i)); + __m256i cmp = _mm256_cmpeq_epi8(hay_vec, first_vec); + u32 mask = _mm256_movemask_epi8(cmp); + + while (mask != 0) { + i32 offset = __builtin_ctz(mask); + if (strncmp(haystack+i+offset, needle, nlen) == 0) return i+offset; + mask &= (mask - 1); + } + } + + for (; i < end_idx; i++) { if (strncmp(haystack + i, needle, nlen) == 0) return i; } + + return -1; +} + +i32 sv_contains_c_simd(strng_view_t const *sv, char n) { + u64 hlen = sv_len(sv); + + char const *restrict haystack = SV_TO(*sv); + + if (hlen == 0) return -1; + if (hlen == 1 && *haystack == n) return 0; + + + __m256i needle_vec = _mm256_set1_epi8(n); + u64 i = 0; + + for (; i + 32 <= hlen; i += 32) { + __m256i hay_vec = _mm256_loadu_si256((const __m256i*)(haystack+i)); + __m256i cmp = _mm256_cmpeq_epi8(hay_vec, needle_vec); + u32 mask = _mm256_movemask_epi8(cmp); + + if (mask) { + i32 offset = __builtin_ctz(mask); + return (i32)(i+offset); + } + } + + for (; i < hlen; i++) { if (haystack[i] == n) return i; } + + return -1; +} + +b32 sv_starts_with(strng_view_t const *sv, char const *prefix) { + u64 plen = strlen(prefix); + u64 hlen = sv_len(sv); + if (plen > hlen || hlen == 0) return false; + return memcmp(SV_TO(*sv), prefix, plen) == 0; +} + +b32 sv_ends_with(strng_view_t const *sv, char const *suffix) { + u64 slen = strlen(suffix); + u64 hlen = sv_len(sv); + if (slen > hlen || hlen == 0) return false; + return memcmp(SV_TO(*sv)+(hlen-slen), suffix, slen) == 0; +} + +b32 sv_eq_case_insensitive(strng_view_t const *sv1, strng_view_t const *sv2) { + u64 len1 = sv_len(sv1); + u64 len2 = sv_len(sv2); + if (len1 != len2) return false; + + char const *restrict c1 = SV_TO(*sv1); + char const *restrict c2 = SV_TO(*sv2); + + __m256i Av = _mm256_set1_epi8('A'-1); + __m256i Zv = _mm256_set1_epi8('Z'+1); + __m256i subV = _mm256_set1_epi8(0x20); + + u64 i = 0; + for (; i + 32 <= len1; i += 32) { + __m256i v1 = _mm256_loadu_si256((const __m256i*)(c1+i)); + __m256i v2 = _mm256_loadu_si256((const __m256i*)(c2+i)); + + // Get chars which are 'A'<=c<='Z' + __m256i A1 = _mm256_cmpgt_epi8(v1, Av); + __m256i Z1 = _mm256_cmpgt_epi8(v1, Zv); + __m256i u1 = _mm256_and_si256(subV, _mm256_andnot_si256(Z1, A1)); + v1 = _mm256_or_si256(v1, u1); + + // Same for v2 + __m256i A2 = _mm256_cmpgt_epi8(v2, Av); + __m256i Z2 = _mm256_cmpgt_epi8(v2, Zv); + __m256i u2 = _mm256_and_si256(subV, _mm256_andnot_si256(Z2, A2)); + v2 = _mm256_or_si256(v2, u2); + + + __m256i cmp = _mm256_cmpeq_epi8(v1, v2); + u32 mask = _mm256_movemask_epi8(cmp); + + if (mask != 0xFFFFFFFF) return false; + } + + for (; i < len1; i++) { if (tolower(c1[i]) != tolower(c2[i])) return false; } + + return true; +} + +strng_view_t sv_split_once(strng_view_t *sv, char const *needle) { + u64 nlen = strlen(needle); + u64 hlen = sv_len(sv); + if (hlen == 0) return *sv; + + i32 i = sv_contains_simd(sv, needle); + if (nlen == 0 || i == -1) { + strng_view_t out = *sv; + sv->start = sv->end+1; + return out; + } + + strng_view_t out = *sv; + if (i == 0) { + out.end = out.start - 1; + } else { + out.end = out.start + i - 1; + } + sv->start += (i + nlen); + return out; +} + +strng_view_t sv_split_once_c(strng_view_t *sv, char n) { + u64 hlen = sv_len(sv); + if (hlen == 0) return *sv; + + i32 i = sv_contains_c_simd(sv, n); + if (i == -1) { + strng_view_t out = *sv; + sv->start = sv->end+1; + return out; + } + + strng_view_t out = *sv; + if (i == 0) { + out.end = out.start - 1; + } else { + out.end = out.start + i - 1; + } + sv->start += (i + 1); + return out; +} + + +i32 sv_to_i64(strng_view_t const *sv, i64 *value_o) { + char const *origin_ptr = SV_TO(*sv); + + strng_view_t a = sv_dup(sv); + sv_trimws(&a); + + char const *digit = SV_TO(a); + char const *end_ptr = a.string + a.end; + + i64 mod = 1; + if (*digit == '-') { + mod = -1; + digit++; + } else if (*digit == '+') { + digit++; + } + + if (digit > end_ptr || !(*digit >= '0' && *digit <= '9')) return -1; + i64 result = 0; + while (digit <= end_ptr && *digit >= '0' && *digit <= '9') { + i64 d = *digit - '0'; + + if (mod == 1) { + if (result > (INT64_MAX / 10) || (result == (INT64_MAX / 10) && d > (INT64_MAX % 10))) { + return -1; + } + result = (result * 10) + d; + } else { + if (result < (INT64_MIN / 10) || (result == (INT64_MIN / 10) && -d < (INT64_MIN % 10))) { + return -1; + } + result = (result * 10) - d; + } + digit++; + } + + *value_o = result; + return (i32)(digit - origin_ptr); +} -- cgit v1.2.3