diff options
| -rw-r--r-- | README.md | 14 | ||||
| -rw-r--r-- | benchmarks/misc/string_bench_STC.cpp | 4 | ||||
| -rw-r--r-- | docs/cstr_api.md | 75 | ||||
| -rw-r--r-- | docs/csview_api.md | 53 | ||||
| -rw-r--r-- | examples/cstr_match.c | 8 | ||||
| -rw-r--r-- | examples/demos.c | 2 | ||||
| -rw-r--r-- | examples/regex_replace.c | 2 | ||||
| -rw-r--r-- | examples/replace.c | 18 | ||||
| -rw-r--r-- | examples/utf8replace_c.c | 11 | ||||
| -rw-r--r-- | include/stc/alt/cstr.h | 70 | ||||
| -rw-r--r-- | include/stc/ccommon.h | 5 | ||||
| -rw-r--r-- | include/stc/cstr.h | 147 | ||||
| -rw-r--r-- | include/stc/csview.h | 62 |
13 files changed, 246 insertions, 225 deletions
@@ -3,7 +3,7 @@ STC - Smart Template Containers for C ===================================== -News: Version 3.7 released (July 2022) +News: Version 3.8 released (July 2022) --------------------------------------- - [See changes version 3](#version-3). Note some code-breaking API changes! @@ -457,6 +457,18 @@ Memory efficiency # Version 3 +## Changes version 3.8 +- Overhauled some **cstr** and **csview** API: + - Changed cstr_replace*() => `cstr_replace_at*(self, pos, len, repl)`: Replace at specific position. + - Changed `cstr_replace_all() cstr_replace*(self, search, repl, count)`: Replace count occurences. + - Renamed `cstr_find_from()` => `cstr_find_at()` + - Renamed `cstr_*_u8()` => `cstr_u8_*()` + - Renamed `csview_*_u8()` => `csview_u8_*()` + - Added cstr_u8_slice() and csview_u8_slice(). + - Removed `csview_from_s()`: Use `cstr_sv(s)` instead. + - Removed `csview_from_n()`: Use `c_sv(str, n)` instead. + - Updated cstr and csview docs. + ## Changes version 3.7 - NB! Changed self argument from value to const pointer on containers (does not apply to **cstr**): - `CNT_size(const CNT *self)` diff --git a/benchmarks/misc/string_bench_STC.cpp b/benchmarks/misc/string_bench_STC.cpp index 9fc861ea..648cb1f3 100644 --- a/benchmarks/misc/string_bench_STC.cpp +++ b/benchmarks/misc/string_bench_STC.cpp @@ -100,7 +100,7 @@ void initShortStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, csview_from_s(i.ref)); + cvec_sv_push_back(vsv, cstr_sv(i.ref)); num += cstr_size(*i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; @@ -146,7 +146,7 @@ void initLongStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, csview_from_s(i.ref)); + cvec_sv_push_back(vsv, cstr_sv(i.ref)); num += cstr_size(*i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 7afdcf77..a05dc1ae 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -3,16 +3,16 @@ A **cstr** object represent sequences of characters. It supports an interface similar to that of a standard container of bytes, but adding features specifically designed to operate with strings of single-byte characters, terminated by the null character. -**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and efficient functions for handling case-foldings and comparisons of UTF strings. The **cstr** type uses short strings optimization (sso), which eliminates heap memory allocation for strings shorter than 24 bytes (sizeof(cstr) is also 24). +**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and efficient functions for handling case-foldings and comparisons of UTF strings. -See the c++ class [std::basic_string](https://en.cppreference.com/w/cpp/string/basic_string) for a functional description. +**cstr** uses short strings optimization (sso), which eliminates heap memory allocation for string capacity less than 24 bytes. `sizeof(cstr)` is also 24. In comparison, c++ `sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes. ## Header file All cstr definitions and prototypes are available by including a single header file. ```c -#define i_implement // optional: define in one source file only for shared symbols linking! +#define i_implement // define this to implement many functions as shared symbols! #include <stc/cstr.h> ``` @@ -21,61 +21,70 @@ All cstr definitions and prototypes are available by including a single header f cstr cstr_init(void); // constructor; same as cstr_null. cstr cstr_new(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() -cstr cstr_from_n(const char* str, size_t len); // constructor with specified length +cstr cstr_from_n(const char* str, size_t n); // constructor with n first bytes of str +cstr cstr_from_sv(csview sv); // construct cstr from csview cstr cstr_with_capacity(size_t cap); cstr cstr_with_size(size_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting cstr cstr_clone(cstr s); -cstr* cstr_take(cstr* self, cstr s); // take the constructed or moved string -cstr cstr_move(cstr* self); // move string to caller, leave empty string +cstr* cstr_take(cstr* self, cstr s); // take ownership of s, i.e. don't drop s. +cstr cstr_move(cstr* self); // move string to caller, leave self empty void cstr_drop(cstr *self); // destructor -const char* cstr_str(const cstr* self); // access to const char* -char* cstr_data(cstr* self); // access to char* -csview cstr_sv(const cstr* self); // access to string view -cstr_buf cstr_buffer(cstr* self); // access to mutable buffer (with capacity) +const char* cstr_str(const cstr* self); // cast to const char* +char* cstr_data(cstr* self); // cast to mutable char* +csview cstr_sv(const cstr* self); // cast to string view +cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity) size_t cstr_size(cstr s); size_t cstr_capacity(cstr s); bool cstr_empty(cstr s); -size_t cstr_reserve(cstr* self, size_t capacity); +char* cstr_reserve(cstr* self, size_t capacity); // return pointer to buffer void cstr_resize(cstr* self, size_t len, char fill); void cstr_shrink_to_fit(cstr* self); char* cstr_append_uninit(cstr* self, size_t len); // return ptr to uninit data void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); -char* cstr_assign_s(cstr* self, cstr s); -char* cstr_assign_n(cstr* self, const char* str, size_t len); // assign n first chars of str -int cstr_printf(cstr* self, const char* fmt, ...); // printf() formatting +char* cstr_assign_n(cstr* self, const char* str, size_t n); // assign n first bytes of str +char* cstr_assign_sv(cstr* self, csview sv) +char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr +int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. -char* cstr_append(cstr* self, const char* app); -char* cstr_append_s(cstr* self, cstr app); -char* cstr_append_n(cstr* self, const char* app, size_t len); +char* cstr_append(cstr* self, const char* str); +char* cstr_append_n(cstr* self, const char* str, size_t n); // append n first bytes of str +char* cstr_append_sv(cstr* self, csview str); +char* cstr_append_s(cstr* self, cstr str); +char* cstr_append_uninit(cstr *self, size_t len); // append len uninitialized bytes void cstr_insert(cstr* self, size_t pos, const char* ins); +void cstr_insert_sv(cstr* self, size_t pos, csview ins); void cstr_insert_s(cstr* self, size_t pos, cstr ins); -void cstr_insert_n(cstr* self, size_t pos, const char* ins, size_t len); void cstr_erase(cstr* self, size_t pos); -void cstr_erase_n(cstr* self, size_t pos, size_t len); +void cstr_erase_n(cstr* self, size_t pos, size_t n); // erase n bytes from pos -size_t cstr_replace(cstr* self, const char* search, const char* repl); -size_t cstr_replace_from(cstr* self, size_t pos, const char* search, const char* repl); -void cstr_replace_at(cstr* self, size_t pos, size_t len, const char* repl); -void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr repl); -void cstr_replace_with_n(cstr* self, size_t pos, size_t len, const char* repl, size_t rlen); -void cstr_replace_all(cstr* self, const char* search, const char* repl); +void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count); // count==0: replace all. +cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); +void cstr_replace_at(cstr* self, size_t pos, size_t len, const char* repl); // replace at a position +void cstr_replace_at_sv(cstr* self, size_t pos, size_t len, const csview repl); +void cstr_replace_at_s(cstr* self, size_t pos, size_t len, cstr repl); bool cstr_equals(cstr s, const char* str); bool cstr_equals_s(cstr s, cstr s2); size_t cstr_find(cstr s, const char* search); -size_t cstr_find_from(cstr s, size_t pos, const char* search); +size_t cstr_find_at(cstr s, size_t pos, const char* search); // search from pos bool cstr_contains(cstr s, const char* search); + bool cstr_starts_with(cstr s, const char* str); +bool cstr_starts_with_sv(cstr s, csview sv); +bool cstr_starts_with_s(cstr s, cstr s); + bool cstr_ends_with(cstr s, const char* str); +bool cstr_ends_with_sv(cstr s, csview sv); +bool cstr_ends_with_s(cstr s, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) bool cstr_getdelim(cstr *self, int delim, FILE *stream); // does not append delim to result @@ -83,11 +92,12 @@ bool cstr_getdelim(cstr *self, int delim, FILE *stream); // does no #### UTF8 methods ```c -size_t cstr_u8size(cstr s); // number of utf8 codepoints -size_t cstr_u8size_n(cstr s, size_t nbytes); // utf8 size within n bytes -size_t cstr_pos_u8(cstr s, size_t u8idx); // byte pos offset at utf8 index -const char* cstr_at_u8(const cstr* self, size_t u8idx); // char* position at utf8 index -csview cstr_chr_u8(const cstr* self, size_t u8idx); // utf8 character at utf8 pos as csview +size_t cstr_u8_size(cstr s); // number of utf8 codepoints +size_t cstr_u8_size_n(cstr s, size_t nbytes); // utf8 size within n bytes +size_t cstr_u8_to_pos(cstr s, size_t u8idx); // byte pos offset at utf8 codepoint index +const char* cstr_u8_at(const cstr* self, size_t u8idx); // char* position at utf8 codepoint index +csview cstr_u8_chr(const cstr* self, size_t u8idx); // get utf8 character as a csview +void cstr_u8_replace_at(cstr* self, size_t u8pos, size_t u8len, csview repl); // replace at utf8 indices // iterate utf8 codepoints cstr_iter cstr_begin(const cstr* self); @@ -150,8 +160,7 @@ int main() { cstr_erase_n(&s1, 7, 5); // -nine printf("%s\n", cstr_str(&s1)); - //cstr_replace_at(&s1, cstr_find(s1, "seven"), 5, "four"); - cstr_replace(&s1, "seven", "four"); + cstr_replace(&s1, "seven", "four", 1); printf("%s\n", cstr_str(&s1)); // reassign: diff --git a/docs/csview_api.md b/docs/csview_api.md index 49f7cb70..e6a89d5e 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -27,22 +27,21 @@ All csview definitions and prototypes are available by including a single header ```c csview c_sv(const char literal_only[]); // alias for csview_new +csview c_sv(const char* str, size_t n); // overloaded csview constructor. csview csview_new(const char literal_only[]); // construct from literal, no strlen() csview csview_from(const char* str); // construct from const char* -csview csview_from_s(const cstr* s); // construct from cstr -csview csview_from_n(const char* str, size_t n); // construct void csview_clear(csview* self); size_t csview_size(csview sv); bool csview_empty(csview sv); bool csview_equals(csview sv, csview sv2); -size_t csview_find(csview sv, csview needle); -bool csview_contains(csview sv, csview needle); +size_t csview_find(csview sv, csview search); +bool csview_contains(csview sv, csview search); bool csview_starts_with(csview sv, csview sub); bool csview_ends_with(csview sv, csview sub); -// requires i_implement defined before one include of csview.h +// requires i_implement defined before inclusion of csview.h csview csview_substr_ex(csview sv, intptr_t pos, size_t n); // negative pos count from end csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end csview csview_token(csview sv, csview sep, size_t* start); // see split example below. @@ -50,8 +49,9 @@ csview csview_token(csview sv, csview sep, size_t* start); // see sp #### UTF8 methods ```c -size_t csview_u8size(csview sv); -csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len); +size_t csview_u8_size(csview sv); +csview csview_u8_substr(csview sv, size_t u8pos, size_t u8len); +csview csview_u8_slice(csview sv, size_t u8p1, size_t u8p2); csview_iter csview_begin(const csview* self); csview_iter csview_end(const csview* self); @@ -60,14 +60,14 @@ void csview_next(csview_iter* it); // utf8 c // requires linking with src/utf8code.c: bool csview_valid_utf8(csview sv); -// from utf8.h/utf8code.c: +// from utf8.h, linking src/utf8code.c: bool utf8_valid(const char* s); bool utf8_valid_n(const char* s, size_t nbytes); size_t utf8_size(const char *s); size_t utf8_size_n(const char *s, size_t nbytes); // 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 -unsigned utf8_chr_size(const char* s); // 0-4 (0 if s[0] is illegal utf8) +unsigned utf8_chr_size(const char* s); // 0-4 (0 if s[0] means illegal utf8) uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state. unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer uint32_t utf8_peek(const char* s, int pos); // codepoint value at utf8 pos (may be negative) @@ -75,22 +75,13 @@ uint32_t utf8_peek(const char* s, int pos); // codepoint #### Extended cstr methods ```c -cstr cstr_from_sv(csview sv); // construct cstr from csview -csview cstr_sv(const cstr* self); // convert to csview from const cstr* - -csview cstr_substr(const cstr* s, intptr_t pos, size_t n); // negative pos count from end -csview cstr_slice(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end - -csview cstr_assign_sv(cstr* self, csview sv); // return csview of assigned cstr -void cstr_append_sv(cstr* self, csview sv); -void cstr_insert_sv(cstr* self, size_t pos, csview sv); -void cstr_replace_sv(cstr* self, size_t pos, size_t len, csview sv); - -bool cstr_equals_sv(cstr s, csview sv); -size_t cstr_find_sv(cstr s, csview needle); -bool cstr_contains_sv(cstr s, csview needle); -bool cstr_starts_with_sv(cstr s, csview sub); -bool cstr_ends_with_sv(cstr s, csview sub); +csview cstr_substr(const cstr* self, size_t pos, size_t n); +csview cstr_substr_ex(const cstr* s, intptr_t pos, size_t n); // negative pos count from end +csview cstr_u8_substr(const cstr* self, size_t u8pos, size_t u8len); + +csview cstr_slice(const cstr* self, size_t p1, size_t p2); +csview cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end +csview cstr_u8_slice(const cstr* self, size_t u8p1, size_t u8p2); ``` #### Helper methods @@ -115,8 +106,8 @@ uint64_t csview_hash(const csview* x); |:---------------|:---------------------|:---------------------------------------------| | `csview_null` | same as `c_sv("")` | `sview = csview_null;` | | `csview_npos` | same as `cstr_npos` | | -| `c_PRIsv` | printf format | | -| `c_ARGsv(sv)` | printf argument | `printf("sv: %" c_PRIsv "\n", c_ARGsv(sv));` | +| `c_PRIsv` | `".*s"` | `printf("sv: %" c_PRIsv "\n", c_ARGsv(sv));` | +| `c_ARGsv(sv)` | printf argument | `printf("sv: %.*s\n", c_ARGsv(sv));` | ## Example ```c @@ -157,18 +148,18 @@ int main() { c_auto (cstr, s1) { s1 = cstr_new("hell😀 w😀rld"); - cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("x")); + cstr_u8_replace_at(&s1, 7, 1, c_sv("ø")); printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%" c_PRIsv ",", c_ARGsv(i.chr)); + printf("%.*s,", c_ARGsv(i.chr)); } } ``` Output: ``` -hell😀 wxrld -h,e,l,l,😀, ,w,x,r,l,d, +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, ``` ### Example 3: csview tokenizer (string split) diff --git a/examples/cstr_match.c b/examples/cstr_match.c index fd420f62..9c4fa2d3 100644 --- a/examples/cstr_match.c +++ b/examples/cstr_match.c @@ -5,7 +5,7 @@ int main() { c_autovar (cstr ss = cstr_new("The quick brown fox jumps over the lazy dog.JPG"), cstr_drop(&ss)) { - size_t pos = cstr_find_from(ss, 0, "brown"); + size_t pos = cstr_find_at(ss, 0, "brown"); printf("%" PRIuMAX " [%s]\n", pos, pos == cstr_npos ? "<NULL>" : cstr_str(&ss) + pos); printf("equals: %d\n", cstr_equals(ss, "The quick brown fox jumps over the lazy dog.JPG")); printf("contains: %d\n", cstr_contains(ss, "umps ove")); @@ -14,9 +14,9 @@ int main() printf("ends_with: %d\n", cstr_ends_with(ss, ".JPG")); cstr s1 = cstr_new("hell😀 w😀rl🐨"); - csview ch1 = cstr_chr_u8(&s1, 7); - csview ch2 = cstr_chr_u8(&s1, 10); - printf("%s\nsize: %" PRIuMAX ", %" PRIuMAX "\n", cstr_str(&s1), cstr_u8size(s1), cstr_size(s1)); + csview ch1 = cstr_u8_chr(&s1, 7); + csview ch2 = cstr_u8_chr(&s1, 10); + printf("%s\nsize: %" PRIuMAX ", %" PRIuMAX "\n", cstr_str(&s1), cstr_u8_size(s1), cstr_size(s1)); 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 4cb50082..052c4e32 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(&cs, "seven", "four"); + cstr_replace(&cs, "seven", "four", 1); printf("%s.\n", cstr_str(&cs)); cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); diff --git a/examples/regex_replace.c b/examples/regex_replace.c index 21252236..3dcb965d 100644 --- a/examples/regex_replace.c +++ b/examples/regex_replace.c @@ -41,7 +41,7 @@ int main() cregex_drop(&re); printf("euros: %s\n", cstr_str(&str)); - /* Wrap all words in {} */ + /* Wrap all words in ${} */ cstr_take(&str, cregex_replace_p("[52] apples and [31] mangoes", "[a-z]+", "$${$0}")); printf("curly: %s\n", cstr_str(&str)); } diff --git a/examples/replace.c b/examples/replace.c index 2926977c..13b6eaaf 100644 --- a/examples/replace.c +++ b/examples/replace.c @@ -8,23 +8,27 @@ int main () // replace signatures used in the same order as described above: - // Ustring positions: 0123456789*123456789*12345 - cstr s = cstr_from(base); // "this is a test string." + // Ustring positions: 0123456789*123456789*12345 + cstr s = cstr_from(base); // "this is a test string." cstr m = cstr_clone(s); c_autodefer (cstr_drop(&s), cstr_drop(&m)) { cstr_append(&m, cstr_str(&m)); cstr_append(&m, cstr_str(&m)); printf("%s\n", cstr_str(&m)); - cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) + cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_with_n(&s, 19, 6, s3+7, 6); // "this is an example phrase." (2) + + cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) printf("(2) %s\n", cstr_str(&s)); - cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) + + cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_with_n(&s, 8, 6,"a shorty", 7); // "this is a short phrase." (4) + + cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) printf("(4) %s\n", cstr_str(&s)); - cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) + + cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) printf("(5) %s\n", cstr_str(&s)); } } diff --git a/examples/utf8replace_c.c b/examples/utf8replace_c.c index c38b37e4..86d8bd69 100644 --- a/examples/utf8replace_c.c +++ b/examples/utf8replace_c.c @@ -1,3 +1,4 @@ +#define i_implement #include <stc/cstr.h> #include <stc/csview.h> @@ -6,14 +7,12 @@ int main() { hello = cstr_new("hell😀 w😀rld"); printf("%s\n", cstr_str(&hello)); - cstr_replace_sv( - &hello, - csview_substr_u8(cstr_sv(&hello), 7, 1), - c_sv("🐨") - ); + /* replace second smiley at utf8 codepoint pos 7 */ + cstr_u8_replace_at(&hello, 7, 1, c_sv("🐨")); + printf("%s\n", cstr_str(&hello)); - cstr_replace(&hello, "🐨", "ø"); + cstr_replace(&hello, "🐨", "ø", 1); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) diff --git a/include/stc/alt/cstr.h b/include/stc/alt/cstr.h index 77067740..82ab585a 100644 --- a/include/stc/alt/cstr.h +++ b/include/stc/alt/cstr.h @@ -48,21 +48,19 @@ typedef struct { size_t size, cap; char chr[1]; } cstr_priv; STC_API cstr cstr_from_n(const char* str, size_t n); STC_API cstr cstr_from_fmt(const char* fmt, ...); -STC_API cstr cstr_from_replace_all(const char* str, size_t str_len, - const char* find, size_t find_len, - const char* repl, size_t repl_len); +STC_API cstr cstr_from_replace(csview str, csview find, csview repl, unsigned count); STC_API char* cstr_reserve(cstr* self, size_t cap); STC_API void cstr_resize(cstr* self, size_t len, char fill); STC_API cstr* cstr_assign_n(cstr* self, const char* str, size_t n); STC_API int cstr_printf(cstr* self, const char* fmt, ...); STC_API cstr* cstr_append_n(cstr* self, const char* str, size_t n); -STC_API void cstr_replace_with_n(cstr* self, size_t pos, size_t len, const char* str, size_t n); -STC_API void cstr_replace_all(cstr* self, const char* find, const char* replace); +STC_API void MyExt(cstr* self, size_t pos, size_t len, const char* str, size_t n); +STC_API void cstr_replace(cstr* self, const char* find, const char* replace); +STC_DEF void cstr_replace_at_sv(cstr* self, const size_t pos, size_t len, csview repl); STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n); STC_API size_t cstr_find(cstr s, const char* needle); -STC_API size_t cstr_find_from(cstr s, size_t pos, const char* needle); +STC_API size_t cstr_find_at(cstr s, size_t pos, const char* needle); STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream); -STC_API void cstr_replace_all(cstr* self, const char* find, const char* repl); STC_INLINE cstr cstr_init() { return cstr_null; } STC_INLINE const char* cstr_str(const cstr* self) { return self->str; } @@ -96,15 +94,15 @@ STC_INLINE void cstr_push_back(cstr* self, char value) STC_INLINE void cstr_pop_back(cstr* self) { self->str[ --_cstr_p(self)->size ] = '\0'; } STC_INLINE void cstr_insert_n(cstr* self, const size_t pos, const char* str, const size_t n) - { cstr_replace_with_n(self, pos, 0, str, n); } + { cstr_replace_at_sv(self, pos, 0, c_sv(str, n)); } STC_INLINE void cstr_insert(cstr* self, const size_t pos, const char* str) - { cstr_replace_with_n(self, pos, 0, str, strlen(str)); } + { cstr_replace_at_sv(self, pos, 0, c_sv(str, strlen(str))); } STC_INLINE void cstr_insert_s(cstr* self, const size_t pos, cstr s) - { cstr_replace_with_n(self, pos, 0, s.str, _cstr_p(&s)->size); } + { cstr_replace_at_sv(self, pos, 0, c_sv(s.str, _cstr_p(&s)->size)); } STC_INLINE void cstr_replace_at(cstr* self, const size_t pos, const size_t len, const char* str) - { cstr_replace_with_n(self, pos, len, str, strlen(str)); } + { cstr_replace_at_sv(self, pos, len, c_sv(str, strlen(str))); } STC_INLINE void cstr_replace_s(cstr* self, const size_t pos, const size_t len, cstr s) - { cstr_replace_with_n(self, pos, len, s.str, _cstr_p(&s)->size); } + { cstr_replace_at_sv(self, pos, len, c_sv(s.str, _cstr_p(&s)->size)); } STC_INLINE void cstr_erase(cstr* self, const size_t pos) { cstr_erase_n(self, pos, 1); } STC_INLINE char* cstr_front(cstr* self) { return self->str; } @@ -184,6 +182,17 @@ STC_INLINE uint64_t cstr_hash(const cstr *self) { return c_fasthash(self->str, _cstr_p(self)->size); } +STC_INLINE void +cstr_replace_sv(cstr* self, csview find, csview repl, unsigned count) { + cstr_take(self, cstr_from_replace(c_sv(self->str, _cstr_p(self)->size), + find, repl, count); +} + +STC_INLINE void +cstr_replace(cstr* self, const char* find, const char* repl, unsigned count) { + cstr_replace_sv(self, c_sv(find, strlen(find)), + c_sv(repl, strlen(repl)), count); +} /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) @@ -306,40 +315,33 @@ STC_INLINE void _cstr_internal_move(cstr* self, const size_t pos1, const size_t } STC_DEF void -cstr_replace_with_n(cstr* self, const size_t pos, size_t len, const char* str, const size_t n) { +cstr_replace_at_sv(cstr* self, const size_t pos, size_t len, csview repl) { const size_t sz = cstr_size(*self); if (len > sz - pos) len = sz - pos; - c_autobuf (xstr, char, n) { - memcpy(xstr, str, n); - _cstr_internal_move(self, pos + len, pos + n); - memcpy(&self->str[pos], xstr, n); + c_autobuf (xstr, char, repl.size) { + memcpy(xstr, repl.str, repl.size); + _cstr_internal_move(self, pos + len, pos + repl.size); + memcpy(&self->str[pos], xstr, repl.size); } } STC_DEF cstr -cstr_from_replace_all(const char* str, const size_t str_len, - const char* find, const size_t find_len, - const char* repl, const size_t repl_len) { +cstr_from_replace(csview str, csview find, csview repl, unsigned count) { cstr out = cstr_null; size_t from = 0; char* res; - if (find_len) - while ((res = c_strnstrn(str + from, find, str_len - from, find_len))) { - const size_t pos = res - str; - cstr_append_n(&out, str + from, pos - from); - cstr_append_n(&out, repl, repl_len); - from = pos + find_len; + if (count == 0) count = ~0; + if (find.size) + while (count-- && (res = c_strnstrn(str + from, find.str, str.size - from, find.size))) { + const size_t pos = res - str.str; + cstr_append_n(&out, str.str + from, pos - from); + cstr_append_n(&out, repl.str, repl_len); + from = pos + find.size; } - cstr_append_n(&out, str + from, str_len - from); + cstr_append_n(&out, str.str + from, str.size - from); return out; } STC_DEF void -cstr_replace_all(cstr* self, const char* find, const char* repl) { - cstr_take(self, cstr_from_replace_all(self->str, _cstr_p(self)->size, - find, strlen(find), repl, strlen(repl))); -} - -STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t n) { const size_t len = _cstr_p(self)->size; if (n > len - pos) n = len - pos; @@ -377,7 +379,7 @@ cstr_find(cstr s, const char* needle) { } STC_DEF size_t -cstr_find_from(cstr s, const size_t pos, const char* needle) { +cstr_find_at(cstr s, const size_t pos, const char* needle) { if (pos > _cstr_p(&s)->size) return cstr_npos; char* res = strstr(s.str + pos, needle); return res ? res - s.str : cstr_npos; diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index e87e7678..9624909e 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -111,8 +111,11 @@ typedef const char* crawstr; #define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp)) #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_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) +#define c_sv1(lit) (c_make(csview){lit, c_strlen_lit(lit)}) +#define c_sv2(str, n) (c_make(csview){str, n}) #define c_PRIsv ".*s" #define c_ARGsv(sv) (int)(sv).size, (sv).str diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 6db5ef49..92f49d92 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -80,14 +80,15 @@ STC_API char* _cstr_internal_move(cstr* self, size_t pos1, size_t pos2); STC_API char* cstr_reserve(cstr* self, size_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API void cstr_resize(cstr* self, size_t size, char value); -STC_API size_t cstr_find_from(cstr s, size_t pos, const char* search); +STC_API size_t cstr_find_at(cstr s, size_t pos, const char* search); STC_API char* cstr_assign_n(cstr* self, const char* str, size_t len); STC_API char* cstr_append_n(cstr* self, const char* str, size_t len); STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); STC_API void cstr_erase_n(cstr* self, size_t pos, size_t len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API int cstr_printf(cstr* self, const char* fmt, ...); -STC_API void cstr_replace_all(cstr* self, const char* search, const char* repl); +STC_API void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count); +STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, unsigned count); STC_INLINE cstr_buf cstr_buffer(cstr* s) { return cstr_is_long(s) @@ -183,21 +184,22 @@ STC_INLINE bool cstr_valid_utf8(const cstr* self) // other utf8 -STC_INLINE size_t cstr_u8size(cstr s) +STC_INLINE size_t cstr_u8_size(cstr s) { return utf8_size(cstr_str(&s)); } -STC_INLINE size_t cstr_u8size_n(cstr s, size_t nbytes) +STC_INLINE size_t cstr_u8_size_n(cstr s, size_t nbytes) { return utf8_size_n(cstr_str(&s), nbytes); } -STC_INLINE size_t cstr_pos_u8(const cstr* self, size_t u8idx) +STC_INLINE size_t cstr_u8_to_pos(const cstr* self, size_t u8idx) { return utf8_pos(cstr_str(self), u8idx); } -STC_INLINE const char* cstr_at_u8(const cstr* self, size_t u8idx) +STC_INLINE const char* cstr_u8_at(const cstr* self, size_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csview cstr_chr_u8(const cstr* self, size_t u8idx) { - csview sv = cstr_sv(self); - sv.str = utf8_at(sv.str, u8idx); +STC_INLINE csview cstr_u8_chr(const cstr* self, size_t u8idx) { + const char* str = cstr_str(self); + csview sv; + sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; } @@ -240,110 +242,138 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { return x.size == y.size && !memcmp(x.str, y.str, x.size); } + STC_INLINE bool cstr_equals(cstr s1, const char* str) { return !strcmp(cstr_str(&s1), str); } -STC_INLINE bool cstr_iequals(cstr s1, const char* str) - { return !utf8_icmp(cstr_str(&s1), str); } +STC_INLINE bool cstr_equals_sv(cstr s, csview sv) + { return sv.size == cstr_size(s) && !memcmp(cstr_str(&s), sv.str, sv.size); } STC_INLINE bool cstr_equals_s(cstr s1, cstr s2) { return !cstr_cmp(&s1, &s2); } +STC_INLINE bool cstr_iequals(cstr s1, const char* str) + { return !utf8_icmp(cstr_str(&s1), str); } + + STC_INLINE size_t cstr_find(cstr s, const char* search) { const char *str = cstr_str(&s), *res = strstr((char*)str, search); return res ? res - str : cstr_npos; } +STC_INLINE size_t cstr_find_sv(cstr s, csview search) { + char* res = c_strnstrn(cstr_str(&s), search.str, cstr_size(s), search.size); + return res ? res - cstr_str(&s) : cstr_npos; +} + STC_INLINE size_t cstr_find_s(cstr s, cstr search) { return cstr_find(s, cstr_str(&search)); } + STC_INLINE bool cstr_contains(cstr s, const char* search) { return strstr(cstr_data(&s), search) != NULL; } +STC_INLINE bool cstr_contains_sv(cstr s, csview search) + { return c_strnstrn(cstr_str(&s), search.str, cstr_size(s), search.size) != NULL; } + STC_INLINE bool cstr_contains_s(cstr s, cstr search) { return strstr(cstr_data(&s), cstr_str(&search)) != NULL; } + +STC_INLINE bool cstr_starts_with_sv(cstr s, csview sub) { + if (sub.size > cstr_size(s)) return false; + return !memcmp(cstr_str(&s), sub.str, sub.size); +} + STC_INLINE bool cstr_starts_with(cstr s, const char* sub) { const char* str = cstr_str(&s); while (*sub && *str == *sub) ++str, ++sub; return !*sub; } + +STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub) + { return cstr_starts_with_sv(s, cstr_sv(&sub)); } + STC_INLINE bool cstr_istarts_with(cstr s, const char* sub) { csview sv = cstr_sv(&s); size_t len = strlen(sub); return len <= sv.size && !utf8_icmp_n(cstr_npos, sv.str, sv.size, sub, len); } -STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub) - { return cstr_starts_with(s, cstr_str(&sub)); } -STC_INLINE bool cstr_ends_with(cstr s, const char* sub) { +STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) { csview sv = cstr_sv(&s); - size_t n = strlen(sub); - return n <= sv.size && !memcmp(sv.str + sv.size - n, sub, n); + if (sub.size > sv.size) return false; + return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); } +STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub) + { return cstr_ends_with_sv(s, cstr_sv(&sub)); } + +STC_INLINE bool cstr_ends_with(cstr s, const char* sub) + { return cstr_ends_with_sv(s, c_sv(sub, strlen(sub))); } + STC_INLINE bool cstr_iends_with(cstr s, const char* sub) { csview sv = cstr_sv(&s); size_t n = strlen(sub); return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); } -STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub) - { return cstr_ends_with(s, cstr_str(&sub)); } STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, strlen(str)); } -STC_INLINE char* cstr_assign_s(cstr* self, cstr s) { +STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) + { return cstr_assign_n(self, sv.str, sv.size); } + +STC_INLINE char* cstr_copy(cstr* self, cstr s) { csview sv = cstr_sv(&s); return cstr_assign_n(self, sv.str, sv.size); } + STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, strlen(str)); } +STC_INLINE void cstr_append_sv(cstr* self, csview sv) + { cstr_append_n(self, sv.str, sv.size); } + STC_INLINE char* cstr_append_s(cstr* self, cstr s) { csview sv = cstr_sv(&s); return cstr_append_n(self, sv.str, sv.size); } -STC_INLINE void cstr_replace_with_n(cstr* self, size_t pos, size_t len, const char* repl, size_t rlen) { - char* d = _cstr_internal_move(self, pos + len, pos + rlen); - memcpy(d + pos, repl, rlen); + +STC_INLINE void cstr_replace_at_sv(cstr* self, size_t pos, size_t len, const csview repl) { + char* d = _cstr_internal_move(self, pos + len, pos + repl.size); + memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, size_t pos, size_t len, const char* repl) - { cstr_replace_with_n(self, pos, len, repl, strlen(repl)); } + { cstr_replace_at_sv(self, pos, len, c_sv(repl, strlen(repl))); } -STC_INLINE size_t cstr_replace_from(cstr* self, size_t pos, const char* search, const char* repl) { - pos = cstr_find_from(*self, pos, search); - if (pos == cstr_npos) - return pos; - const size_t rlen = strlen(repl); - cstr_replace_with_n(self, pos, strlen(search), repl, rlen); - return pos + rlen; -} +STC_INLINE void cstr_replace_at_s(cstr* self, size_t pos, size_t len, cstr repl) + { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } -STC_INLINE size_t cstr_replace(cstr* self, const char* search, const char* repl) - { return cstr_replace_from(self, 0, search, repl); } - -STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) { - csview sv = cstr_sv(&s); - cstr_replace_with_n(self, pos, len, sv.str, sv.size); +STC_INLINE void cstr_u8_replace_at(cstr* self, size_t u8pos, size_t u8len, csview repl) { + csview sv = cstr_sv(self); + const char* p = utf8_at(sv.str, u8pos); + cstr_replace_at_sv(self, p - sv.str, utf8_pos(p, u8len), repl); } -STC_INLINE void cstr_insert_n(cstr* self, size_t pos, const char* str, size_t len) - { cstr_replace_with_n(self, pos, 0, str, len); } STC_INLINE void cstr_insert(cstr* self, size_t pos, const char* str) - { cstr_replace_with_n(self, pos, 0, str, strlen(str)); } + { cstr_replace_at_sv(self, pos, 0, c_sv(str, strlen(str))); } + +STC_INLINE void cstr_insert_sv(cstr* self, size_t pos, csview sv) + { cstr_replace_at_sv(self, pos, 0, sv); } STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) { csview sv = cstr_sv(&s); - cstr_replace_with_n(self, pos, 0, sv.str, sv.size); + cstr_replace_at_sv(self, pos, 0, sv); } + STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -360,7 +390,7 @@ STC_DEF char* _cstr_internal_move(cstr* self, const size_t pos1, const size_t po if (pos1 != pos2) { const size_t newlen = r.size + pos2 - pos1; if (newlen > r.cap) - r.data = cstr_reserve(self, (r.size*3 >> 1) + pos2 - pos1); + r.data = cstr_reserve(self, r.size*3/2 + pos2 - pos1); memmove(&r.data[pos2], &r.data[pos1], r.size - pos1); _cstr_set_size(self, newlen); } @@ -422,7 +452,7 @@ STC_DEF void cstr_resize(cstr* self, const size_t size, const char value) { _cstr_set_size(self, size); } -STC_DEF size_t cstr_find_from(cstr s, const size_t pos, const char* search) { +STC_DEF size_t cstr_find_at(cstr s, const size_t pos, const char* search) { csview sv = cstr_sv(&s); if (pos > sv.size) return cstr_npos; const char* res = strstr((char*)sv.str + pos, search); @@ -440,7 +470,7 @@ STC_DEF char* cstr_append_n(cstr* self, const char* str, const size_t len) { cstr_buf r = cstr_buffer(self); if (r.size + len > r.cap) { const size_t off = (size_t)(str - r.data); - r.data = cstr_reserve(self, (r.size*3 >> 1) + len); + r.data = cstr_reserve(self, r.size*3/2 + len); if (off <= r.size) str = r.data + off; /* handle self append */ } memcpy(r.data + r.size, str, len); @@ -461,7 +491,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } if (pos == r.cap) { _cstr_set_size(self, pos); - r.data = cstr_reserve(self, (r.cap = (r.cap*3 >> 1) + 16)); + r.data = cstr_reserve(self, (r.cap = r.cap*3/2 + 16)); } r.data[pos++] = (char) c; c = fgetc(fp); @@ -469,27 +499,26 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } STC_DEF cstr -cstr_from_replace_all(const char* str, const size_t str_len, - const char* search, const size_t search_len, - const char* repl, const size_t repl_len) { +cstr_replace_sv(csview in, csview search, csview repl, unsigned count) { cstr out = cstr_null; size_t from = 0; char* res; - if (search_len) - while ((res = c_strnstrn(str + from, search, str_len - from, search_len))) { - const size_t pos = res - str; - cstr_append_n(&out, str + from, pos - from); - cstr_append_n(&out, repl, repl_len); - from = pos + search_len; + if (!count) count = ~0; + if (search.size) + while (count-- && (res = c_strnstrn(in.str + from, search.str, in.size - from, search.size))) { + const size_t pos = res - in.str; + cstr_append_n(&out, in.str + from, pos - from); + cstr_append_n(&out, repl.str, repl.size); + from = pos + search.size; } - cstr_append_n(&out, str + from, str_len - from); + cstr_append_n(&out, in.str + from, in.size - from); return out; } STC_DEF void -cstr_replace_all(cstr* self, const char* search, const char* repl) { - csview sv = cstr_sv(self); - cstr_take(self, cstr_from_replace_all(sv.str, sv.size, search, strlen(search), - repl, strlen(repl))); +cstr_replace(cstr* self, const char* search, const char* repl, unsigned count) { + csview in = cstr_sv(self); + cstr_take(self, cstr_replace_sv(in, c_sv(search, strlen(search)), + c_sv(repl, strlen(repl)), count)); } STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t len) { diff --git a/include/stc/csview.h b/include/stc/csview.h index 39bfa354..ec40a8be 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -38,8 +38,6 @@ STC_API csview csview_token(csview sv, csview sep, size_t* start); STC_INLINE csview csview_init() { return csview_null; } STC_INLINE csview csview_from(const char* str) { return c_make(csview){str, strlen(str)}; } -STC_INLINE csview csview_from_n(const char* str, size_t n) - { return c_make(csview){str, n}; } STC_INLINE void csview_clear(csview* self) { *self = csview_null; } STC_INLINE size_t csview_size(csview sv) { return sv.size; } @@ -48,13 +46,13 @@ STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } STC_INLINE bool csview_equals(csview sv, csview sv2) { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); } -STC_INLINE size_t csview_find(csview sv, csview needle) { - char* res = c_strnstrn(sv.str, needle.str, sv.size, needle.size); +STC_INLINE size_t csview_find(csview sv, csview search) { + char* res = c_strnstrn(sv.str, search.str, sv.size, search.size); return res ? res - sv.str : csview_npos; } -STC_INLINE bool csview_contains(csview sv, csview needle) - { return c_strnstrn(sv.str, needle.str, sv.size, needle.size) != NULL; } +STC_INLINE bool csview_contains(csview sv, csview search) + { return c_strnstrn(sv.str, search.str, sv.size, search.size) != NULL; } STC_INLINE bool csview_starts_with(csview sv, csview sub) { if (sub.size > sv.size) return false; @@ -89,15 +87,18 @@ STC_INLINE void csview_next(csview_iter* it) { it->ref += it->chr.size; it->chr.size = utf8_chr_size(it->ref); } /* utf8 */ -STC_INLINE size_t csview_u8size(csview sv) +STC_INLINE size_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -STC_INLINE csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len) { +STC_INLINE csview csview_u8_substr(csview sv, size_t u8pos, size_t u8len) { sv.str = utf8_at(sv.str, u8pos); sv.size = utf8_pos(sv.str, u8len); return sv; } +STC_INLINE csview csview_u8_slice(csview sv, size_t u8p1, size_t u8p2) + { return csview_u8_substr(sv, u8p1, u8p2 - u8p1); } + STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } @@ -105,53 +106,24 @@ STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c /* csview interaction with cstr: */ #ifdef CSTR_H_INCLUDED -STC_INLINE csview csview_from_s(const cstr* self) - { return c_make(csview){cstr_str(self), cstr_size(*self)}; } - STC_INLINE csview cstr_substr(const cstr* self, size_t pos, size_t n) - { return csview_substr(csview_from_s(self), pos, n); } + { return csview_substr(cstr_sv(self), pos, n); } STC_INLINE csview cstr_slice(const cstr* self, size_t p1, size_t p2) - { return csview_slice(csview_from_s(self), p1, p2); } + { return csview_slice(cstr_sv(self), p1, p2); } STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, size_t n) - { return csview_substr_ex(csview_from_s(self), pos, n); } + { return csview_substr_ex(cstr_sv(self), pos, n); } STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) - { return csview_slice_ex(csview_from_s(self), p1, p2); } - -STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) - { return cstr_assign_n(self, sv.str, sv.size); } + { return csview_slice_ex(cstr_sv(self), p1, p2); } -STC_INLINE void cstr_append_sv(cstr* self, csview sv) - { cstr_append_n(self, sv.str, sv.size); } +STC_INLINE csview cstr_u8_substr(const cstr* self , size_t u8pos, size_t u8len) + { return csview_u8_substr(cstr_sv(self), u8pos, u8len); } -STC_INLINE void cstr_insert_sv(cstr* self, size_t pos, csview sv) - { cstr_replace_with_n(self, pos, 0, sv.str, sv.size); } +STC_INLINE csview cstr_u8_slice(const cstr* self , size_t u8p1, size_t u8p2) + { return csview_u8_substr(cstr_sv(self), u8p1, u8p2 - u8p1); } -STC_INLINE void cstr_replace_sv(cstr* self, csview sub, csview with) - { cstr_replace_with_n(self, sub.str - cstr_str(self), sub.size, with.str, with.size); } - -STC_INLINE bool cstr_equals_sv(cstr s, csview sv) - { return sv.size == cstr_size(s) && !memcmp(cstr_str(&s), sv.str, sv.size); } - -STC_INLINE size_t cstr_find_sv(cstr s, csview needle) { - char* res = c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size); - return res ? res - cstr_str(&s) : cstr_npos; -} - -STC_INLINE bool cstr_contains_sv(cstr s, csview needle) - { return c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size) != NULL; } - -STC_INLINE bool cstr_starts_with_sv(cstr s, csview sub) { - if (sub.size > cstr_size(s)) return false; - return !memcmp(cstr_str(&s), sub.str, sub.size); -} - -STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) { - if (sub.size > cstr_size(s)) return false; - return !memcmp(cstr_str(&s) + cstr_size(s) - sub.size, sub.str, sub.size); -} #endif /* ---- Container helper functions ---- */ |
