/* MIT License * * Copyright (c) 2025 Tyge Løvset * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // csview is a non-zero-terminated string view. #ifndef STC_CSVIEW_H_INCLUDED #define STC_CSVIEW_H_INCLUDED #include "common.h" #include "types.h" #include "priv/utf8_prv.h" #define csview_init() c_sv_1("") #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) csview_iter csview_advance(csview_iter it, isize u8pos); csview csview_subview_pro(csview sv, isize pos, isize n); csview csview_token(csview sv, const char* sep, isize* pos); csview csview_u8_subview(csview sv, isize u8pos, isize u8len); csview csview_u8_tail(csview sv, isize u8len); csview_iter csview_u8_at(csview sv, isize u8pos); STC_INLINE csview csview_from(const char* str) { return c_literal(csview){str, c_strlen(str)}; } STC_INLINE csview csview_from_n(const char* str, isize n) { return c_literal(csview){str, n}; } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } STC_INLINE isize csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_is_empty(csview sv) { return sv.size == 0; } STC_INLINE bool csview_equals_sv(csview sv1, csview sv2) { return sv1.size == sv2.size && !c_memcmp(sv1.buf, sv2.buf, sv1.size); } STC_INLINE bool csview_equals(csview sv, const char* str) { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE size_t csview_hash(const csview *self) { return c_basehash_n(self->buf, self->size); } STC_INLINE isize csview_find_sv(csview sv, csview search) { char* res = c_strnstrn(sv.buf, sv.size, search.buf, search.size); return res ? (res - sv.buf) : c_NPOS; } STC_INLINE isize csview_find(csview sv, const char* str) { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } STC_INLINE bool csview_starts_with(csview sv, const char* str) { isize n = c_strlen(str); return n <= sv.size && !c_memcmp(sv.buf, str, n); } STC_INLINE bool csview_ends_with(csview sv, const char* str) { isize n = c_strlen(str); return n <= sv.size && !c_memcmp(sv.buf + sv.size - n, str, n); } STC_INLINE csview csview_subview(csview sv, isize pos, isize len) { c_assert(((size_t)pos <= (size_t)sv.size) & (len >= 0)); if (pos + len > sv.size) len = sv.size - pos; sv.buf += pos, sv.size = len; return sv; } STC_INLINE csview csview_slice(csview sv, isize p1, isize p2) { c_assert(((size_t)p1 <= (size_t)p2) & ((size_t)p1 <= (size_t)sv.size)); if (p2 > sv.size) p2 = sv.size; sv.buf += p1, sv.size = p2 - p1; return sv; } STC_INLINE csview csview_trim_start(csview sv) { while (sv.size && *sv.buf <= ' ') ++sv.buf, --sv.size; return sv; } STC_INLINE csview csview_trim_end(csview sv) { while (sv.size && sv.buf[sv.size - 1] <= ' ') --sv.size; return sv; } STC_INLINE csview csview_trim(csview sv) { return csview_trim_end(csview_trim_start(sv)); } STC_INLINE csview csview_tail(csview sv, isize len) { return csview_subview(sv, sv.size - len, len); } /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { csview_iter it = {.u8 = {{self->buf, utf8_chr_size(self->buf)}, self->buf + self->size}}; return it; } STC_INLINE csview_iter csview_end(const csview* self) { (void)self; csview_iter it = {0}; return it; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->chr.size; it->chr.size = utf8_chr_size(it->ref); if (it->ref == it->u8.end) it->ref = NULL; } /* utf8 */ STC_INLINE csview csview_u8_from(const char* str, isize u8pos, isize u8len) { return utf8_subview(str, u8pos, u8len); } STC_INLINE isize csview_u8_size(csview sv) { return utf8_count_n(sv.buf, sv.size); } STC_INLINE bool csview_u8_valid(csview sv) // requires linking with utf8 symbols { return utf8_valid_n(sv.buf, sv.size); } #define c_fortoken(...) for (c_token(__VA_ARGS__)) // [deprecated] #define c_token_sv(it, separator, sv) \ struct { csview input, token; const char* sep; isize pos; } \ it = {.input=sv, .sep=separator} ; \ it.pos <= it.input.size && (it.token = csview_token(it.input, it.sep, &it.pos)).buf ; #define c_token(it, separator, str) \ c_token_sv(it, separator, csview_from(str)) /* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { isize n = x->size < y->size ? x->size : y->size; int c = c_memcmp(x->buf, y->buf, n); return c ? c : c_default_cmp(&x->size, &y->size); } STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->buf, y->buf, x->size); } /* ---- case insensitive ---- */ STC_INLINE bool csview_iequals_sv(csview sv1, csview sv2) { return sv1.size == sv2.size && !utf8_icompare(sv1, sv2); } STC_INLINE bool csview_iequals(csview sv, const char* str) { return csview_iequals_sv(sv, c_sv(str, c_strlen(str))); } STC_INLINE bool csview_ieq(const csview* x, const csview* y) { return csview_iequals_sv(*x, *y); } STC_INLINE int csview_icmp(const csview* x, const csview* y) { return utf8_icompare(*x, *y); } STC_INLINE bool csview_istarts_with(csview sv, const char* str) { isize n = c_strlen(str); return n <= sv.size && !utf8_icompare(sv, c_sv(str, n)); } STC_INLINE bool csview_iends_with(csview sv, const char* str) { isize n = c_strlen(str); return n <= sv.size && !utf8_icmp(sv.buf + sv.size - n, str); } #endif // STC_CSVIEW_H_INCLUDED /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined STC_IMPLEMENT || defined i_implement #ifndef STC_CSVIEW_C_INCLUDED #define STC_CSVIEW_C_INCLUDED csview_iter csview_advance(csview_iter it, isize u8pos) { int inc = 1; if (u8pos < 0) u8pos = -u8pos, inc = -1; while (u8pos && it.ref != it.u8.end) u8pos -= (*(it.ref += inc) & 0xC0) != 0x80; if (it.ref == it.u8.end) it.ref = NULL; else it.chr.size = utf8_chr_size(it.ref); return it; } csview csview_subview_pro(csview sv, isize pos, isize len) { if (pos < 0) { pos += sv.size; if (pos < 0) pos = 0; } if (pos > sv.size) pos = sv.size; if (pos + len > sv.size) len = sv.size - pos; sv.buf += pos, sv.size = len; return sv; } csview csview_token(csview sv, const char* sep, isize* pos) { isize sep_size = c_strlen(sep); csview slice = {sv.buf + *pos, sv.size - *pos}; const char* res = c_strnstrn(slice.buf, slice.size, sep, sep_size); csview tok = {slice.buf, res ? (res - slice.buf) : slice.size}; *pos += tok.size + sep_size; return tok; } csview csview_u8_subview(csview sv, isize u8pos, isize u8len) { const char* s, *end = &sv.buf[sv.size]; while ((u8pos > 0) & (sv.buf != end)) u8pos -= (*++sv.buf & 0xC0) != 0x80; s = sv.buf; while ((u8len > 0) & (s != end)) u8len -= (*++s & 0xC0) != 0x80; sv.size = s - sv.buf; return sv; } csview csview_u8_tail(csview sv, isize u8len) { const char* p = &sv.buf[sv.size]; while (u8len && p != sv.buf) u8len -= (*--p & 0xC0) != 0x80; sv.size -= p - sv.buf, sv.buf = p; return sv; } csview_iter csview_u8_at(csview sv, isize u8pos) { const char *end = &sv.buf[sv.size]; while ((u8pos > 0) & (sv.buf != end)) u8pos -= (*++sv.buf & 0xC0) != 0x80; sv.size = utf8_chr_size(sv.buf); c_assert(sv.buf != end); return c_literal(csview_iter){.u8 = {sv, end}}; } #endif // STC_CSVIEW_C_INCLUDED #endif // i_implement #if defined i_import #include "priv/utf8_prv.c" #endif