From a341dbc0ce456198d5773c7260e93e8433228ee2 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sun, 29 May 2022 00:36:08 +0200 Subject: Renamed cstr_replace_first() => cstr_replace_one(). cstr.h now #include "utf8.h". Added iterator (utf8) to cstr and other utf8 functions postfixed by _u8(). Also renamed some utf8 functions in csview to better names. --- docs/cstr_api.md | 9 +++++++++ docs/csview_api.md | 22 ++++++++++----------- examples/cstr_match.c | 7 +++++++ examples/demos.c | 2 +- examples/replace.c | 1 - examples/utf8replace_c.c | 16 +++++++++------- include/stc/ccommon.h | 2 ++ include/stc/cstr.h | 50 +++++++++++++++++++++++++++++++++++++++++++++++- include/stc/csview.h | 19 ++++++++---------- include/stc/forward.h | 9 ++++++--- include/stc/utf8.h | 29 +++++++++++++++------------- 11 files changed, 118 insertions(+), 48 deletions(-) diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 5570df8e..4d68807c 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -38,6 +38,15 @@ size_t cstr_length(cstr s); size_t cstr_capacity(cstr s); bool cstr_empty(cstr s); +// utf8: +size_t cstr_size_u8(cstr s); // utf8 size +size_t cstr_size_n_u8(cstr s, size_t nbytes); // utf8 size within n bytes +csview cstr_at(const cstr* self, size_t bytepos); // utf8 character as a csview +csview cstr_at_u8(const cstr* self, size_t u8idx); // utf8 character at utf8 pos +size_t cstr_pos_u8(const cstr* self, size_t u8idx); // byte position at utf8 index +bool cstr_valid_u8(const cstr* self); // check if str is valid utf8 +utf8_decode_t cstr_peek(const cstr* self, size_t bytepos); + size_t cstr_reserve(cstr* self, size_t capacity); void cstr_resize(cstr* self, size_t len, char fill); void cstr_shrink_to_fit(cstr* self); diff --git a/docs/csview_api.md b/docs/csview_api.md index 112ca0eb..4c92a1e5 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -57,20 +57,21 @@ void csview_next(csview_iter* it); // NB: UTF8 #### UTF8 methods ``` -bool utf8_valid_sv(csview sv); -size_t utf8_size_sv(csview sv); -csview utf8_substr(const char* str, size_t pos, size_t n); +bool csview_valid_u8(csview sv); +size_t csview_size_u8(csview sv); +csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len); bool utf8_valid(const char* s); +bool utf8_valid_n(const char* s, size_t n); size_t utf8_size(const char *s); size_t utf8_size_n(const char *s, size_t n); // number of UTF8 codepoints within n bytes const char* utf8_at(const char *s, size_t index); // from UTF8 index to char* position size_t utf8_pos(const char* s, size_t index); // from UTF8 index to byte index position -const char* utf8_next(const char *s); // next codepoint as char*; NULL if *s == 0 -uint32_t utf8_peek(const char *s); // next codepoint as uint32_t - -size_t utf8_codep_size(const char* s); // 1-4 (0 if s[0] is illegal first cp char) -uint32_t utf8_decode(uint32_t *state, uint32_t *codep, const uint32_t byte); // decode next utf8 codepoint. +unsigned utf8_codep_size(const char* s); // 0-4 (0 if s[0] is illegal utf8) +void utf8_peek(const char *s, utf8_decode_t* d); // next codepoint as uint32_t +uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte, // d holds state, size and unicode point + const uint32_t byte); // decode next utf8 codepoint. +unsigned utf8_encode(char *out, uint32_t cp); // encode unicode cp into out ``` #### Extended cstr methods @@ -159,9 +160,8 @@ int main() cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("x")); printf("%s\n", cstr_str(&s1)); - csview sv = csview_from_s(&s1); - c_foreach (i, csview, sv) - printf("%" c_PRIsv ",", c_ARGsv(i.codep)); + c_foreach (i, cstr, s1) + printf("%" c_PRIsv ",", c_ARGsv(i.chr)); } } ``` diff --git a/examples/cstr_match.c b/examples/cstr_match.c index cd3f04be..637fa7f9 100644 --- a/examples/cstr_match.c +++ b/examples/cstr_match.c @@ -1,4 +1,5 @@ #include +#include #include int main() @@ -11,5 +12,11 @@ int main() printf("starts_with: %d\n", cstr_starts_with(ss, "The quick brown")); printf("ends_with: %d\n", cstr_ends_with(ss, ".jpg")); printf("ends_with: %d\n", cstr_ends_with(ss, ".JPG")); + + cstr s1 = cstr_new("hell😀 w😀rl🐨"); + csview ch1 = cstr_at(&s1, 10); + csview ch2 = cstr_at_u8(&s1, 10); + printf("ch1: %" c_PRIsv "\n", c_ARGsv(ch1)); + printf("ch2: %" c_PRIsv "\n", c_ARGsv(ch2)); } } diff --git a/examples/demos.c b/examples/demos.c index 99b9e570..c0cecac2 100644 --- a/examples/demos.c +++ b/examples/demos.c @@ -13,7 +13,7 @@ void stringdemo1() cstr_erase_n(&cs, 7, 5); // -nine printf("%s.\n", cstr_str(&cs)); - cstr_replace_first(&cs, 0, "seven", "four"); + cstr_replace_one(&cs, 0, "seven", "four"); printf("%s.\n", cstr_str(&cs)); cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); diff --git a/examples/replace.c b/examples/replace.c index a5bcf4d3..f658fb3c 100644 --- a/examples/replace.c +++ b/examples/replace.c @@ -1,6 +1,5 @@ #include -#include int main () { diff --git a/examples/utf8replace_c.c b/examples/utf8replace_c.c index 6b3fcebe..89d5375f 100644 --- a/examples/utf8replace_c.c +++ b/examples/utf8replace_c.c @@ -1,21 +1,23 @@ #include #include -#include int main() { c_auto (cstr, hello) { - hello = cstr_new("hell😀 world"); + hello = cstr_new("hell😀 w😀rld"); printf("%s\n", cstr_str(&hello)); cstr_replace_sv( - &hello, - utf8_substr(cstr_str(&hello), 4, 1), + &hello, + csview_substr_u8(cstr_sv(&hello), 7, 1), c_sv("🐨") ); printf("%s\n", cstr_str(&hello)); - csview sv = csview_from_s(&hello); - c_foreach (c, csview, sv) - printf("%" c_PRIsv ",", c_ARGsv(c.codep)); + cstr_replace_one(&hello, 0, "🐨", "ø"); + printf("%s\n", cstr_str(&hello)); + + c_foreach (c, cstr, hello) + printf("%" c_PRIsv ",", c_ARGsv(c.chr)); + puts(""); } } diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index a0fa58fb..46d53bc1 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -117,6 +117,8 @@ typedef const char* crawstr; #define crawstr_hash(p) c_strhash(*(p)) #define c_strlen_lit(literal) (sizeof "" literal - 1U) #define c_sv(lit) c_make(csview){lit, c_strlen_lit(lit)} +#define c_PRIsv ".*s" +#define c_ARGsv(sv) (int)(sv).size, (sv).str #define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ca6d9392..1d57437e 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -32,6 +32,7 @@ #include "ccommon.h" #include "forward.h" +#include "utf8.h" #include /* malloc */ #include #include /* vsnprintf */ @@ -168,6 +169,53 @@ STC_INLINE size_t cstr_length(cstr s) STC_INLINE size_t cstr_capacity(cstr s) { return cstr_is_long(&s) ? cstr_l_cap(&s) : cstr_s_cap; } +// utf8: + +STC_INLINE size_t cstr_size_u8(cstr s) + { return utf8_size(cstr_str(&s)); } + +STC_INLINE size_t cstr_size_n_u8(cstr s, size_t nbytes) + { return utf8_size_n(cstr_str(&s), nbytes); } + +STC_INLINE csview cstr_at(const cstr* self, size_t bytepos) { + csview sv = cstr_sv(self); + sv.str += bytepos; + sv.size = utf8_codep_size(sv.str); + return sv; +} +STC_INLINE csview cstr_at_u8(const cstr* self, size_t u8idx) { + csview sv = cstr_sv(self); + sv.str = utf8_at(sv.str, u8idx); + sv.size = utf8_codep_size(sv.str); + return sv; +} + +STC_INLINE size_t cstr_pos_u8(const cstr* self, size_t u8idx) + { return utf8_pos(cstr_str(self), u8idx); } + +STC_INLINE bool cstr_valid_u8(const cstr* self) + { return utf8_valid(cstr_str(self)); } + +STC_INLINE utf8_decode_t cstr_peek(const cstr* self, size_t bytepos) { + utf8_decode_t d = {UTF8_OK}; + utf8_peek(cstr_str(self) + bytepos, &d); + return d; +} + +STC_INLINE cstr_iter cstr_begin(const cstr* self) { + const char* str = cstr_str(self); + return c_make(cstr_iter){.chr = {str, utf8_codep_size(str)}}; +} +STC_INLINE cstr_iter cstr_end(const cstr* self) { + csview sv = cstr_sv(self); + return c_make(cstr_iter){sv.str + sv.size}; +} +STC_INLINE void cstr_next(cstr_iter* it) { + it->ref += it->chr.size; + it->chr.size = utf8_codep_size(it->ref); +} + + STC_INLINE void cstr_clear(cstr* self) { _cstr_set_size(self, 0); } @@ -250,7 +298,7 @@ STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* r STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* repl) { cstr_replace_n(self, pos, len, repl, strlen(repl)); } -STC_INLINE size_t cstr_replace_first(cstr* self, size_t pos, const char* search, const char* repl) { +STC_INLINE size_t cstr_replace_one(cstr* self, size_t pos, const char* search, const char* repl) { pos = cstr_find_from(*self, pos, search); if (pos == cstr_npos) return pos; diff --git a/include/stc/csview.h b/include/stc/csview.h index 5bc25215..270a79f8 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -30,8 +30,6 @@ #define csview_null c_sv("") #define csview_new(literal) c_sv(literal) #define csview_npos (SIZE_MAX >> 1) -#define c_PRIsv ".*s" -#define c_ARGsv(sv) (int)(sv).size, (sv).str STC_API csview csview_substr(csview sv, intptr_t pos, size_t n); STC_API csview csview_slice(csview sv, intptr_t p1, intptr_t p2); @@ -64,23 +62,22 @@ STC_INLINE bool csview_ends_with(csview sv, csview sub) { if (sub.size > sv.size) return false; return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); } STC_INLINE csview_iter csview_begin(const csview* self) - { return c_make(csview_iter){.codep = {self->str, utf8_codep_size(self->str)}}; } + { return c_make(csview_iter){.chr = {self->str, utf8_codep_size(self->str)}}; } STC_INLINE csview_iter csview_end(const csview* self) { return c_make(csview_iter){self->str + self->size}; } STC_INLINE void csview_next(csview_iter* it) - { it->ref += it->codep.size; it->codep.size = utf8_codep_size(it->ref); } + { it->ref += it->chr.size; it->chr.size = utf8_codep_size(it->ref); } /* utf8 */ -STC_INLINE bool utf8_valid_sv(csview sv) - { return utf8_size_n(sv.str, sv.size) != SIZE_MAX; } +STC_INLINE bool csview_valid_u8(csview sv) + { return utf8_valid_n(sv.str, sv.size); } -STC_INLINE size_t utf8_size_sv(csview sv) +STC_INLINE size_t csview_size_u8(csview sv) { return utf8_size_n(sv.str, sv.size); } -STC_INLINE csview utf8_substr(const char* str, size_t pos, size_t n) { - csview sv; - sv.str = utf8_at(str, pos); - sv.size = utf8_pos(sv.str, n); +STC_INLINE csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len) { + sv.str = utf8_at(sv.str, u8pos); + sv.size = utf8_pos(sv.str, u8len); return sv; } diff --git a/include/stc/forward.h b/include/stc/forward.h index 635c63df..67f5f0f2 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -45,7 +45,7 @@ typedef struct { char* data; size_t size, cap; } cstr_buf; typedef char cstr_value; #if defined STC_CSTR_V1 - typedef struct cstr { char* str; } cstr; + typedef struct { char* str; } cstr; #else typedef union { struct { char data[sizeof(cstr_buf) - 1]; unsigned char last; } sml; @@ -53,9 +53,12 @@ typedef char cstr_value; } cstr; #endif -typedef struct csview { const char* str; size_t size; } csview; -typedef union csview_iter { const char *ref; csview codep; } csview_iter; +typedef struct { const char* str; size_t size; } csview; typedef char csview_value; +typedef union { + const char *ref; + csview chr; +} csview_iter, cstr_iter; #define c_true(...) __VA_ARGS__ #define c_false(...) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 02f24711..f11af046 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -13,9 +13,8 @@ int main() cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("🐨")); printf("%s\n", cstr_str(&s1)); - csview sv = csview_from_s(s1); - c_foreach (i, csview, sv) - printf("%" c_PRIsv ",", c_ARGsv(i.codep)); + c_foreach (i, cstr, s1) + printf("%" c_PRIsv ",", c_ARGsv(i.chr)); } } // Output: @@ -54,19 +53,16 @@ STC_INLINE const char* utf8_at(const char *s, size_t index) { return s; } -STC_INLINE size_t utf8_pos(const char* s, size_t index) +STC_INLINE size_t utf8_pos(const char* s, size_t index) { return utf8_at(s, index) - s; } -STC_INLINE uint32_t utf8_peek(const char *s, unsigned* codep_size) { - utf8_decode_t d = {UTF8_OK}; - utf8_decode(&d, (uint8_t)*s++); - switch (d.size) { - case 4: utf8_decode(&d, (uint8_t)*s++); - case 3: utf8_decode(&d, (uint8_t)*s++); - case 2: utf8_decode(&d, (uint8_t)*s++); +STC_INLINE void utf8_peek(const char *s, utf8_decode_t* d) { + utf8_decode(d, (uint8_t)*s++); + switch (d->size) { + case 4: utf8_decode(d, (uint8_t)*s++); + case 3: utf8_decode(d, (uint8_t)*s++); + case 2: utf8_decode(d, (uint8_t)*s++); } - *codep_size = d.size; - return d.codep; } STC_INLINE unsigned utf8_codep_size(const char *s) { @@ -82,6 +78,13 @@ STC_INLINE bool utf8_valid(const char* s) { return d.state == UTF8_OK; } +STC_INLINE bool utf8_valid_n(const char* s, size_t n) { + utf8_decode_t d = {UTF8_OK}; + while ((n-- != 0) & (*s != 0)) + utf8_decode(&d, (uint8_t)*s++); + return d.state == UTF8_OK; +} + // --------------------------- IMPLEMENTATION --------------------------------- #ifdef i_implement // https://news.ycombinator.com/item?id=15423674 -- cgit v1.2.3