From 0b34cadda2bc4da1cb0904989c8a5f2fe0236358 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sun, 21 May 2023 23:30:25 +0200 Subject: NB! Made cstr.h header-only by default. Now requires #define i_static, i_implement or i_extern (includes utf8code.c) to implement non-inline functions (or link with libstc). --- src/libstc.c | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/libstc.c (limited to 'src/libstc.c') diff --git a/src/libstc.c b/src/libstc.c new file mode 100644 index 00000000..bc61e37c --- /dev/null +++ b/src/libstc.c @@ -0,0 +1,4 @@ +#define i_extern +#include "../include/stc/cregex.h" +#define i_implement +#include "../include/stc/csview.h" -- cgit v1.2.3 From 72b0f0e7839b487a5df7c79ffe84511480cad251 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 9 Jun 2023 19:31:59 +0200 Subject: Fixed issues with linking params i_implement, i_extern. --- docs/cregex_api.md | 6 +-- include/c11/fmt.h | 1 + include/stc/cbits.h | 6 +-- include/stc/ccommon.h | 2 +- include/stc/cdeq.h | 2 +- include/stc/clist.h | 2 +- include/stc/cmap.h | 2 +- include/stc/cpque.h | 2 +- include/stc/cqueue.h | 2 +- include/stc/crand.h | 2 +- include/stc/cregex.h | 10 ++-- include/stc/csmap.h | 2 +- include/stc/cspan.h | 2 +- include/stc/cstr.h | 102 ++++++++++++++++++++-------------------- include/stc/csview.h | 36 +++++++------- include/stc/cvec.h | 2 +- include/stc/forward.h | 1 + include/stc/utf8.h | 16 +++++-- misc/examples/arc_containers.c | 2 +- misc/examples/astar.c | 1 + misc/examples/books.c | 1 + misc/examples/box.c | 1 + misc/examples/complex.c | 3 +- misc/examples/convert.c | 2 +- misc/examples/coread.c | 2 +- misc/examples/csmap_erase.c | 1 + misc/examples/csmap_find.c | 1 + misc/examples/csmap_insert.c | 1 + misc/examples/cstr_match.c | 1 + misc/examples/demos.c | 1 + misc/examples/forfilter.c | 1 + misc/examples/gauss2.c | 3 +- misc/examples/hashmap.c | 1 + misc/examples/inits.c | 2 +- misc/examples/list_splice.c | 1 - misc/examples/make.sh | 2 +- misc/examples/mapmap.c | 2 +- misc/examples/mmap.c | 1 + misc/examples/multimap.c | 1 + misc/examples/music_arc.c | 1 + misc/examples/new_map.c | 1 + misc/examples/new_smap.c | 1 + misc/examples/new_sptr.c | 1 + misc/examples/person_arc.c | 1 + misc/examples/phonebook.c | 2 +- misc/examples/printspan.c | 1 + misc/examples/rawptr_elements.c | 2 +- misc/examples/read.c | 1 + misc/examples/regex_match.c | 1 + misc/examples/replace.c | 1 + misc/examples/splitstr.c | 1 + misc/examples/sso_map.c | 1 + misc/examples/sso_substr.c | 2 + misc/examples/sview_split.c | 2 + misc/examples/unordered_set.c | 1 + misc/examples/utf8replace_c.c | 1 + misc/examples/vikings.c | 1 + src/cregex.c | 19 +++++++- src/libstc.c | 12 +++++ src/utf8code.c | 5 +- 60 files changed, 180 insertions(+), 107 deletions(-) (limited to 'src/libstc.c') diff --git a/docs/cregex_api.md b/docs/cregex_api.md index e702c47c..fc86cc63 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -44,15 +44,15 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); - // Replace count matches in input string-view. Optionally transform replacement with mfun. + // Replace count matches in input string-view. Optionally transform replacement. cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, - bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` diff --git a/include/c11/fmt.h b/include/c11/fmt.h index 7e85e4dd..45044e33 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -69,6 +69,7 @@ int main() { */ #include #include +#include #include #define fmt_OVERLOAD(name, ...) \ diff --git a/include/stc/cbits.h b/include/stc/cbits.h index fe422202..8a6558bf 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -161,9 +161,9 @@ STC_INLINE void cbits_resize(cbits* self, const int64_t size, const bool value) if (new_n >= old_n) { c_memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8); if (old_n > 0) { - uint64_t m = _cbits_bit(osize) - 1; /* mask */ - value ? (self->data64[old_n - 1] |= ~m) - : (self->data64[old_n - 1] &= m); + uint64_t mask = _cbits_bit(osize) - 1; + if (value) self->data64[old_n - 1] |= ~mask; + else self->data64[old_n - 1] &= mask; } } } diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 01ead57a..87522a6e 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -253,6 +253,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #if defined(STC_EXTERN) #define i_extern #endif -#if defined(i_static) || defined(STC_IMPLEMENT) || defined(i_extern) +#if defined(STC_IMPLEMENT) || defined(i_extern) #define i_implement #endif diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index b3714bf8..8bb62602 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -113,7 +113,7 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) #endif /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value) { diff --git a/include/stc/clist.h b/include/stc/clist.h index 128e848d..310db204 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -214,7 +214,7 @@ STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #endif // -------------------------- IMPLEMENTATION ------------------------- -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) #if !defined i_no_clone STC_DEF _cx_self diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 837631f8..f6c3eb07 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -261,7 +261,7 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) #ifndef i_max_load_factor #define i_max_load_factor 0.80f #endif diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 85002c67..31a53ece 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -108,7 +108,7 @@ STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) #endif // !i_no_emplace /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF void _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 571c1fe9..28515877 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -121,7 +121,7 @@ STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) { self->end = (self->end + n) & self->capmask; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n) { intptr_t len = _cx_memb(_size)(it._s); diff --git a/include/stc/crand.h b/include/stc/crand.h index f566c1cf..b9687c01 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -92,7 +92,7 @@ STC_INLINE double crand_f64(crand_t* rng) { } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) /* Global random() */ static crand_t crand_global = {{ diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 919f5474..e6180a31 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -135,7 +135,7 @@ STC_INLINE bool cregex_is_match(const cregex* re, const char* input) #define cregex_replace_sv_4(pattern, input, replace, count) \ cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*mfun)(int i, csview match, cstr* mstr), int rflags); + bool (*transform)(int group, csview match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) @@ -153,20 +153,20 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int i, csview match, cstr* mstr), int crflags); + bool (*transform)(int group, csview match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); -#endif // CREGEX_H_INCLUDED -#if defined i_extern || defined i_implement +#if defined i_implement # include "../../src/cregex.c" #endif #if defined i_extern # include "../../src/utf8code.c" #endif +#endif // CREGEX_H_INCLUDED #undef i_opt #undef i_header #undef i_static -#undef i_implement #undef i_extern +#undef i_implement diff --git a/include/stc/csmap.h b/include/stc/csmap.h index e8138926..7638b8f2 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -249,7 +249,7 @@ _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF void _cx_memb(_next)(_cx_iter *it) { diff --git a/include/stc/cspan.h b/include/stc/cspan.h index b07e75a8..5b592098 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -212,7 +212,7 @@ STC_API intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, int rank, const int32_t a[][2]); /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]) { intptr_t off = a[0]; diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 03eefd2f..ae80dab4 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -24,16 +24,12 @@ /* A string type with short string optimization in C99 with good small-string * optimization (22 characters with 24 bytes string). */ +#define _i_no_undef +#include "utf8.h" + #ifndef CSTR_H_INCLUDED #define CSTR_H_INCLUDED -#define i_header -#if defined i_extern || defined STC_EXTERN -# define _i_extern -#endif -#include "ccommon.h" -#include "forward.h" -#include "utf8.h" #include /* malloc */ #include #include /* vsnprintf */ @@ -65,8 +61,8 @@ enum { cstr_s_cap = sizeof(cstr_buf) - 2 }; #define cstr_l_drop(s) c_free((s)->lon.data) #define cstr_is_long(s) ((s)->sml.size > 127) -STC_API char* _cstr_init(cstr* self, intptr_t len, intptr_t cap); -STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); +extern char* _cstr_init(cstr* self, intptr_t len, intptr_t cap); +extern char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); /**************************** PUBLIC API **********************************/ @@ -74,19 +70,21 @@ STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); #define cstr_NULL (c_LITERAL(cstr){{{0}, 0}}) #define cstr_toraw(self) cstr_str(self) -STC_API char* cstr_reserve(cstr* self, intptr_t cap); -STC_API void cstr_shrink_to_fit(cstr* self); -STC_API char* cstr_resize(cstr* self, intptr_t size, char value); -STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); -STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); -STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); -STC_API void cstr_erase(cstr* self, intptr_t pos, intptr_t len); -STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); -STC_API cstr cstr_from_fmt(const char* fmt, ...); -STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); -STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +extern char* cstr_reserve(cstr* self, intptr_t cap); +extern void cstr_shrink_to_fit(cstr* self); +extern char* cstr_resize(cstr* self, intptr_t size, char value); +extern intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); +extern intptr_t cstr_find_sv(const cstr* self, csview search); +extern char* cstr_assign_n(cstr* self, const char* str, intptr_t len); +extern char* cstr_append_n(cstr* self, const char* str, intptr_t len); +extern bool cstr_getdelim(cstr *self, int delim, FILE *fp); +extern void cstr_erase(cstr* self, intptr_t pos, intptr_t len); +extern void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); +extern cstr cstr_from_fmt(const char* fmt, ...); +extern intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); +extern intptr_t cstr_printf(cstr* self, const char* fmt, ...); +extern cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +extern uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { return cstr_is_long(s) @@ -284,8 +282,6 @@ STC_INLINE intptr_t cstr_find(const cstr* self, const char* search) { return res ? (res - str) : c_NPOS; } -STC_API intptr_t cstr_find_sv(const cstr* self, csview search); - STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) { return cstr_find(self, cstr_str(&search)); } @@ -404,13 +400,15 @@ STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) { cstr_replace_at_sv(self, pos, 0, sv); } - STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } -STC_API uint64_t cstr_hash(const cstr *self); +#endif // CSTR_H_INCLUDED + +/* -------------------------- EXTERN ------------------------- */ +#if defined(i_extern) && !defined(CSTR_X_INCLUDED) +#define CSTR_X_INCLUDED -#ifdef _i_extern static struct { int (*conv_asc)(int); uint32_t (*conv_utf)(uint32_t); @@ -439,23 +437,25 @@ cstr cstr_tocase(csview sv, int k) { cstr_shrink_to_fit(&out); return out; } -#endif +#endif // i_extern /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#ifndef CSTR_C_INCLUDED +#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#define CSTR_C_INCLUDED -STC_DEF uint64_t cstr_hash(const cstr *self) { +uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); return cfasthash(sv.str, sv.size); } -STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { +intptr_t cstr_find_sv(const cstr* self, csview search) { csview sv = cstr_sv(self); char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; } -STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { +char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { cstr_buf r = cstr_buffer(self); if (pos1 != pos2) { const intptr_t newlen = (r.size + pos2 - pos1); @@ -467,7 +467,7 @@ STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_ return r.data; } -STC_DEF char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { +char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { if (cap > cstr_s_cap) { self->lon.data = (char *)c_malloc(cap + 1); cstr_l_set_size(self, len); @@ -478,7 +478,7 @@ STC_DEF char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { return self->sml.data; } -STC_DEF void cstr_shrink_to_fit(cstr* self) { +void cstr_shrink_to_fit(cstr* self) { cstr_buf r = cstr_buffer(self); if (r.size == r.cap) return; @@ -492,7 +492,7 @@ STC_DEF void cstr_shrink_to_fit(cstr* self) { } } -STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { +char* cstr_reserve(cstr* self, const intptr_t cap) { if (cstr_is_long(self)) { if (cap > cstr_l_cap(self)) { self->lon.data = (char *)c_realloc(self->lon.data, cap + 1); @@ -505,7 +505,7 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { char* data = (char *)c_malloc(cap + 1); const intptr_t len = cstr_s_size(self); /* copy full short buffer to emulate realloc() */ - c_memcpy(data, self->sml.data, cstr_s_cap + 2); + c_memcpy(data, self->sml.data, sizeof self->sml); self->lon.data = data; self->lon.size = (size_t)len; cstr_l_set_cap(self, cap); @@ -514,7 +514,7 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { return self->sml.data; } -STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { +char* cstr_resize(cstr* self, const intptr_t size, const char value) { cstr_buf r = cstr_buffer(self); if (size > r.size) { if (size > r.cap && !(r.data = cstr_reserve(self, size))) @@ -525,20 +525,20 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { return r.data; } -STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { +intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { csview sv = cstr_sv(self); if (pos > sv.size) return c_NPOS; const char* res = strstr((char*)sv.str + pos, search); return res ? (res - sv.str) : c_NPOS; } -STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { +char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { char* d = cstr_reserve(self, len); if (d) { c_memmove(d, str, len); _cstr_set_size(self, len); } return d; } -STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { +char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { cstr_buf r = cstr_buffer(self); if (r.size + len > r.cap) { const size_t off = (size_t)(str - r.data); @@ -551,7 +551,7 @@ STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { return r.data; } -STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { +bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { int c = fgetc(fp); if (c == EOF) return false; @@ -571,7 +571,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr +cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { cstr out = cstr_NULL; intptr_t from = 0; char* res; @@ -587,14 +587,14 @@ cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { return out; } -STC_DEF void cstr_erase(cstr* self, const intptr_t pos, intptr_t len) { +void cstr_erase(cstr* self, const intptr_t pos, intptr_t len) { cstr_buf r = cstr_buffer(self); if (len > r.size - pos) len = r.size - pos; c_memmove(&r.data[pos], &r.data[pos + len], r.size - (pos + len)); _cstr_set_size(self, r.size - len); } -STC_DEF void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { +void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { cstr_buf r = cstr_buffer(self); intptr_t len = utf8_pos(r.data + bytepos, u8len); c_memmove(&r.data[bytepos], &r.data[bytepos + len], r.size - (bytepos + len)); @@ -609,7 +609,7 @@ STC_DEF void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8 # pragma warning(disable: 4996) #endif -STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { +intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { va_list args2; va_copy(args2, args); const int n = vsnprintf(NULL, 0ULL, fmt, args); @@ -624,7 +624,7 @@ STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list # pragma warning(pop) #endif -STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { +cstr cstr_from_fmt(const char* fmt, ...) { cstr s = cstr_NULL; va_list args; va_start(args, fmt); @@ -633,7 +633,7 @@ STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { return s; } -STC_DEF intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { +intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { va_list args; va_start(args, fmt); const intptr_t n = cstr_vfmt(self, cstr_size(self), fmt, args); @@ -642,21 +642,21 @@ STC_DEF intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { } /* NB! self-data in args is UB */ -STC_DEF intptr_t cstr_printf(cstr* self, const char* fmt, ...) { +intptr_t cstr_printf(cstr* self, const char* fmt, ...) { va_list args; va_start(args, fmt); const intptr_t n = cstr_vfmt(self, 0, fmt, args); va_end(args); return n; } - #endif // i_implement +#endif // CSTR_C_INCLUDED + #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif -#endif // CSTR_H_INCLUDED #undef i_opt #undef i_header #undef i_static #undef i_implement -#undef _i_extern +#undef i_extern diff --git a/include/stc/csview.h b/include/stc/csview.h index e8a3ad9b..d38d5f59 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,12 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define _i_no_undef +#include "utf8.h" + #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#include "ccommon.h" -#include "utf8.h" - #define csview_NULL c_sv_1("") #define csview_init() csview_NULL #define csview_drop(p) c_default_drop(p) @@ -33,12 +33,12 @@ #define csview_lit(literal) c_sv_1(literal) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); -STC_API intptr_t csview_find_sv(csview sv, csview search); -STC_API uint64_t csview_hash(const csview *self); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); +extern csview_iter csview_advance(csview_iter it, intptr_t pos); +extern intptr_t csview_find_sv(csview sv, csview search); +extern uint64_t csview_hash(const csview *self); +extern csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +extern csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +extern csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } @@ -147,10 +147,14 @@ STC_INLINE int csview_icmp(const csview* x, const csview* y) STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } +#endif // CSVIEW_H_INCLUDED + /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#ifndef CSVIEW_C_INCLUDED +#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#define CSVIEW_C_INCLUDED -STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { +csview_iter csview_advance(csview_iter it, intptr_t pos) { int inc = -1; if (pos > 0) pos = -pos, inc = 1; while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; @@ -159,15 +163,15 @@ STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { return it; } -STC_DEF intptr_t csview_find_sv(csview sv, csview search) { +intptr_t csview_find_sv(csview sv, csview search) { char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; } -STC_DEF uint64_t csview_hash(const csview *self) +uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { +csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { if (pos < 0) { pos += sv.size; if (pos < 0) pos = 0; @@ -178,7 +182,7 @@ STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { return sv; } -STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { +csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { if (p1 < 0) { p1 += sv.size; if (p1 < 0) p1 = 0; @@ -189,7 +193,7 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { return sv; } -STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { +csview csview_token(csview sv, const char* sep, intptr_t* start) { intptr_t sep_size = c_strlen(sep); csview slice = {sv.str + *start, sv.size - *start}; const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 512dbf67..747c654d 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -264,7 +264,7 @@ _cx_memb(_sort)(_cx_self* self) { } #endif // !c_no_cmp /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF _cx_self _cx_memb(_init)(void) { diff --git a/include/stc/forward.h b/include/stc/forward.h index 9eafb857..484a8b63 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -24,6 +24,7 @@ #define STC_FORWARD_H_INCLUDED #include +#include #define forward_carc(CX, VAL) _c_carc_types(CX, VAL) #define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index a4cc3846..338f0db9 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,3 +1,4 @@ + #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED @@ -5,7 +6,6 @@ #include "forward.h" #include "ccommon.h" -// utf8 methods defined in src/utf8code.c: enum { U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl, U8G_Pc, U8G_Pd, U8G_Pf, U8G_Pi, @@ -16,6 +16,7 @@ enum { U8G_SIZE }; +// utf8 methods defined in src/utf8code.c: extern bool utf8_isgroup(int group, uint32_t c); extern bool utf8_isalpha(uint32_t c); extern uint32_t utf8_casefold(uint32_t c); @@ -112,9 +113,16 @@ STC_INLINE const char* utf8_at(const char *s, intptr_t index) { STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } - #endif // UTF8_H_INCLUDED -#if defined(i_extern) + +#if defined i_extern || (defined i_implement && !defined _i_no_undef) # include "../../src/utf8code.c" -# undef i_extern #endif +#ifndef _i_no_undef +#undef i_static +#undef i_header +#undef i_implement +#undef i_extern +#undef i_opt +#endif +#undef _i_no_undef diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index d6a0afa8..7038734e 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -1,6 +1,6 @@ // Create a stack and a list of shared pointers to maps, // and demonstrate sharing and cloning of maps. -#define i_static +#define i_implement #include #include #define i_type Map diff --git a/misc/examples/astar.c b/misc/examples/astar.c index dae6d609..db6bbd70 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -4,6 +4,7 @@ // This is a reimplementation of the CTL example to STC: // https://github.com/glouw/ctl/blob/master/examples/astar.c // https://www.redblobgames.com/pathfinding/a-star/introduction.html +#define i_implement #include #include #include diff --git a/misc/examples/books.c b/misc/examples/books.c index a62769b0..7f0660b8 100644 --- a/misc/examples/books.c +++ b/misc/examples/books.c @@ -1,4 +1,5 @@ // https://doc.rust-lang.org/std/collections/struct.HashMap.html +#define i_implement #include #define i_key_str #define i_val_str diff --git a/misc/examples/box.c b/misc/examples/box.c index 9954883c..e352aa2b 100644 --- a/misc/examples/box.c +++ b/misc/examples/box.c @@ -1,4 +1,5 @@ /* cbox: heap allocated boxed type */ +#define i_implement #include typedef struct { cstr name, last; } Person; diff --git a/misc/examples/complex.c b/misc/examples/complex.c index c730db33..2d8dbf62 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -5,10 +5,9 @@ // using StackList = std::stack; // using ListMap = std::unordered_map>; // using MapMap = std::unordered_map; - +#define i_implement #include - #define i_type FloatStack #define i_val float #include diff --git a/misc/examples/convert.c b/misc/examples/convert.c index c5649c55..318f09b8 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -1,3 +1,4 @@ +#define i_implement #include #include @@ -9,7 +10,6 @@ #include #define i_val_str -#define i_extern // define _clist_mergesort() once #include int main() diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 2585fb81..63162ba3 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -1,4 +1,4 @@ -#define i_static +#define i_implement #include #include #include diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c index 568dae29..9433d370 100644 --- a/misc/examples/csmap_erase.c +++ b/misc/examples/csmap_erase.c @@ -1,5 +1,6 @@ // map_erase.c // From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 +#define i_implement #include #include diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index 92dd0031..a8928410 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -1,5 +1,6 @@ // This implements the c++ std::map::find example at: // https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 +#define i_implement #include #define i_key int diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index 7708fdc9..f96cc08f 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -5,6 +5,7 @@ #define i_tag ii // Map of int => int #include +#define i_implement #include #define i_key int #define i_val_str diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c index 58cf8884..10a843cf 100644 --- a/misc/examples/cstr_match.c +++ b/misc/examples/cstr_match.c @@ -1,3 +1,4 @@ +#define i_implement #include #include #include diff --git a/misc/examples/demos.c b/misc/examples/demos.c index de92e378..8488dfb9 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -1,3 +1,4 @@ +#define i_implement #include void stringdemo1() diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index 8ea3e6a1..f9505aa9 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -1,6 +1,7 @@ #include #define i_extern #include +#define i_implement #include #include #include diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index e786824b..67586181 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -1,8 +1,9 @@ #include #include -#include +#define i_implement #include +#include // Declare int -> int sorted map. #define i_key int diff --git a/misc/examples/hashmap.c b/misc/examples/hashmap.c index 47a3bcff..cf11b7f7 100644 --- a/misc/examples/hashmap.c +++ b/misc/examples/hashmap.c @@ -1,4 +1,5 @@ // https://doc.rust-lang.org/rust-by-example/std/hash.html +#define i_implement #include #define i_key_str #define i_val_str diff --git a/misc/examples/inits.c b/misc/examples/inits.c index 1f01f88a..a3a6c4d2 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -1,3 +1,4 @@ +#define i_implement #include #define i_key int @@ -25,7 +26,6 @@ inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { #define i_val ipair_t #define i_cmp ipair_cmp #define i_tag ip -#define i_extern // define _clist_mergesort() once #include #define i_val float diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c index 73015454..e457694d 100644 --- a/misc/examples/list_splice.c +++ b/misc/examples/list_splice.c @@ -2,7 +2,6 @@ #define i_val int #define i_tag i -#define i_extern // define _clist_mergesort() once #include void print_ilist(const char* s, clist_i list) diff --git a/misc/examples/make.sh b/misc/examples/make.sh index d58ed0cb..61d9f879 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -6,7 +6,7 @@ if [ "$(uname)" = 'Linux' ]; then oflag='-o ' fi -cc=gcc; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" +cc=gcc; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" #cc=gcc; cflags="-DSTC_STATIC -std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" #cc=tcc; cflags="-DSTC_STATIC -std=c99 -Wall" #cc=clang; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c index 668da5de..d3065659 100644 --- a/misc/examples/mapmap.c +++ b/misc/examples/mapmap.c @@ -1,5 +1,5 @@ // create a structure like: std::map>: - +#define i_implement #include // People: std::map diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c index 0394a2df..63312e04 100644 --- a/misc/examples/mmap.c +++ b/misc/examples/mmap.c @@ -2,6 +2,7 @@ // https://en.cppreference.com/w/cpp/container/multimap/insert // Multimap entries +#define i_implement #include #define i_val_str #include diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index d8981a81..dc4a1ee0 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -1,3 +1,4 @@ +#define i_implement #include // Olympics multimap example diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 87a57783..9c7173ef 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -1,5 +1,6 @@ // shared_ptr-examples.cpp // based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 +#define i_implement #include typedef struct diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 1f50db83..277bcbc2 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -1,3 +1,4 @@ +#define i_implement #include #include diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index 2eaae836..77c4cdce 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -1,3 +1,4 @@ +#define i_implement #include #include diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index 1b72e4f5..aa8dd175 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -1,3 +1,4 @@ +#define i_implement #include typedef struct { cstr name, last; } Person; diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index c931089d..b4b926da 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -1,4 +1,5 @@ /* cbox: heap allocated boxed type */ +#define i_implement #include #include diff --git a/misc/examples/phonebook.c b/misc/examples/phonebook.c index 38a71089..faf7566e 100644 --- a/misc/examples/phonebook.c +++ b/misc/examples/phonebook.c @@ -20,7 +20,7 @@ // IN THE SOFTWARE. // Program to emulates the phone book. - +#define i_implement #include #define i_key_str diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index b9ec2476..b5099ed5 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -1,6 +1,7 @@ // printspan.c #include +#define i_implement #include #define i_val int #include diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c index 01bcdc44..8dd52aee 100644 --- a/misc/examples/rawptr_elements.c +++ b/misc/examples/rawptr_elements.c @@ -1,6 +1,6 @@ #include #include - +#define i_implement #include // Create cmap of cstr => long* diff --git a/misc/examples/read.c b/misc/examples/read.c index edc89f0e..545d706a 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -1,3 +1,4 @@ +#define i_implement #include #include #define i_val_str diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index e49ebd0b..b4932015 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -1,5 +1,6 @@ #define i_extern #include +#define i_implement #include #define i_val float diff --git a/misc/examples/replace.c b/misc/examples/replace.c index cf5b45cb..9ac26c07 100644 --- a/misc/examples/replace.c +++ b/misc/examples/replace.c @@ -1,3 +1,4 @@ +#define i_implement #include int main () diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 2bc6fc07..658c46a1 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -1,6 +1,7 @@ #include #define i_extern // cstr + utf8 functions #include +#define i_implement #include int main() diff --git a/misc/examples/sso_map.c b/misc/examples/sso_map.c index 70450e21..b78dcb2e 100644 --- a/misc/examples/sso_map.c +++ b/misc/examples/sso_map.c @@ -1,3 +1,4 @@ +#define i_implement #include #define i_key_str #define i_val_str diff --git a/misc/examples/sso_substr.c b/misc/examples/sso_substr.c index 4b2dbcc8..9b062eed 100644 --- a/misc/examples/sso_substr.c +++ b/misc/examples/sso_substr.c @@ -1,4 +1,6 @@ +#define i_implement #include +#define i_implement #include int main () diff --git a/misc/examples/sview_split.c b/misc/examples/sview_split.c index 31a28e51..782e4096 100644 --- a/misc/examples/sview_split.c +++ b/misc/examples/sview_split.c @@ -1,4 +1,6 @@ +#define i_implement #include +#define i_implement #include int main() diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c index 90c78521..006a1e80 100644 --- a/misc/examples/unordered_set.c +++ b/misc/examples/unordered_set.c @@ -1,5 +1,6 @@ // https://iq.opengenus.org/containers-cpp-stl/ // C program to demonstrate various function of stc cset +#define i_implement #include #include #define i_key_str diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c index 3cde8701..17352fee 100644 --- a/misc/examples/utf8replace_c.c +++ b/misc/examples/utf8replace_c.c @@ -1,3 +1,4 @@ +#define i_implement #include int main() diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c index abb909c3..cf087119 100644 --- a/misc/examples/vikings.c +++ b/misc/examples/vikings.c @@ -1,3 +1,4 @@ +#define i_implement #include typedef struct Viking { diff --git a/src/cregex.c b/src/cregex.c index 730d35a4..62a64b11 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -25,9 +25,24 @@ THE SOFTWARE. */ #ifndef CREGEX_C_INCLUDED #define CREGEX_C_INCLUDED -#include -#include // header only + #include +#ifdef i_extern +# define _i_extern +#endif +#ifndef CREGEX_H_INCLUDED +# include "../include/stc/cregex.h" +#endif +#ifdef _i_extern +# include "utf8code.c" +#endif +#ifdef _i_extern +# define i_implement +#else +# undef i_implement +#endif +#undef _i_extern +#include "../include/stc/cstr.h" typedef uint32_t _Rune; /* Utf8 code point */ typedef int32_t _Token; diff --git a/src/libstc.c b/src/libstc.c index bc61e37c..99611e05 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,4 +1,16 @@ +#include +#if 1 +#define i_extern +#include "../include/stc/utf8.h" +#define i_implement +#include "../include/stc/cstr.h" +#define i_implement +#include "../include/stc/cregex.h" +#define i_implement +#include "../include/stc/csview.h" +#else #define i_extern #include "../include/stc/cregex.h" #define i_implement #include "../include/stc/csview.h" +#endif diff --git a/src/utf8code.c b/src/utf8code.c index 496f5eef..6a133050 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -1,6 +1,9 @@ #ifndef UTF8_C_INCLUDED #define UTF8_C_INCLUDED -#include // header only + +#ifndef UTF8_H_INCLUDED +#include "../include/stc/utf8.h" /* header only */ +#endif #include "utf8tabs.inc" const uint8_t utf8_dtab[] = { -- cgit v1.2.3 From 5f935739d2ce280beda36c7a7ddb0e0ee34c8fb3 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 9 Jun 2023 22:37:15 +0200 Subject: Rename i_extern template flag to i_import. i_extern still available, but deprecated. --- README.md | 6 +++--- docs/clist_api.md | 1 - docs/cregex_api.md | 4 ++-- docs/csview_api.md | 4 ++-- include/stc/ccommon.h | 8 ++++---- include/stc/crand.h | 2 +- include/stc/cregex.h | 4 ++-- include/stc/cspan.h | 2 +- include/stc/cstr.h | 10 +++++----- include/stc/csview.h | 5 ++--- include/stc/priv/template2.h | 2 +- include/stc/utf8.h | 4 ++-- misc/examples/forfilter.c | 2 +- misc/examples/regex1.c | 2 +- misc/examples/regex2.c | 2 +- misc/examples/regex_match.c | 2 +- misc/examples/regex_replace.c | 2 +- misc/examples/splitstr.c | 2 +- misc/tests/cregex_test.c | 2 +- src/cregex.c | 2 +- src/libstc.c | 4 ++-- 21 files changed, 35 insertions(+), 37 deletions(-) (limited to 'src/libstc.c') diff --git a/README.md b/README.md index e63a56e4..f14858e7 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ After erasing the elements found: --- ## Installation +*NEEDS REWRITE!* Because it is headers-only, headers can simply be included in your program. By default, functions are static (some inlined). You may add the *include* folder to the **CPATH** environment variable to let GCC, Clang, and TinyC locate the headers. @@ -345,8 +346,7 @@ You may also cherry-pick shared linking mode on individual containers by `#defin `#define i_implement`, or force static symbols by `#define i_static` before container includes. As a special case, there may be non-templated functions in templated containers that should be implemented only -once and if needed. Currently, define `i_extern` before including **clist** for its sorting function, and before -**cregex** or **utf8** to implement them (global `STC_EXTERN` can alternatively be defined). +once and if needed. Currently, define `i_import` before including **cregex** or **utf8** to implement them. It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`. @@ -356,7 +356,7 @@ or define your own, e.g.: ```c // stc_libs.c #define STC_IMPLEMENT // implement all the following as shared objects - +#define i_implement #include #include "Point.h" diff --git a/docs/clist_api.md b/docs/clist_api.md index 36935c88..51b7af6a 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -118,7 +118,6 @@ Interleave *push_front()* / *push_back()* then *sort()*: ```c #define i_type DList #define i_val double -#define i_extern // link with sort() fn. #include #include diff --git a/docs/cregex_api.md b/docs/cregex_api.md index fc86cc63..ff69c549 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -99,7 +99,7 @@ If an error occurs ```cregex_compile``` returns a negative error code stored in [ [Run this code](https://godbolt.org/z/z434TMKfo) ] ```c -#define i_extern // include external cstr, utf8, cregex functions implementation. +#define i_import // include dependent cstr, utf8 and cregex function definitions. #include int main() { @@ -151,7 +151,7 @@ c_formatch (it, &re, input) ## Using cregex in a project -The easiest is to `#define i_extern` before `#include `. Make sure to do that in one translation unit only. +The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: - `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` diff --git a/docs/csview_api.md b/docs/csview_api.md index b697b7d6..879822d3 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -148,8 +148,8 @@ red Apples ### Example 2: UTF8 handling ```c -#define i_extern -#include // i_extern: implement cstr + dependencies (utf8) +#define i_import // include dependent cstr, utf8 and cregex function definitions. +#include int main() { diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 87522a6e..e491a567 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -241,6 +241,9 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #undef STC_API #undef STC_DEF +#ifdef i_extern +# define i_import +#endif #if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ defined(i_implement) || defined(STC_IMPLEMENT)) #define STC_API extern @@ -250,9 +253,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #define STC_API static inline #define STC_DEF static inline #endif -#if defined(STC_EXTERN) - #define i_extern -#endif -#if defined(STC_IMPLEMENT) || defined(i_extern) +#if defined(STC_IMPLEMENT) || defined(i_import) #define i_implement #endif diff --git a/include/stc/crand.h b/include/stc/crand.h index b9687c01..95a65fb0 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -158,4 +158,4 @@ STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { #undef i_static #undef i_header #undef i_implement -#undef i_extern +#undef i_import diff --git a/include/stc/cregex.h b/include/stc/cregex.h index e6180a31..43a7fcbf 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -161,12 +161,12 @@ void cregex_drop(cregex* re); #if defined i_implement # include "../../src/cregex.c" #endif -#if defined i_extern +#if defined i_import # include "../../src/utf8code.c" #endif #endif // CREGEX_H_INCLUDED #undef i_opt #undef i_header #undef i_static -#undef i_extern +#undef i_import #undef i_implement diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 5b592098..dd6cb1c0 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -265,4 +265,4 @@ STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ae80dab4..f47889b4 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -405,8 +405,8 @@ STC_INLINE bool cstr_getline(cstr *self, FILE *fp) #endif // CSTR_H_INCLUDED -/* -------------------------- EXTERN ------------------------- */ -#if defined(i_extern) && !defined(CSTR_X_INCLUDED) +/* -------------------------- UTF8 CASE CONVERSION ------------------------- */ +#if defined(i_import) && !defined(CSTR_X_INCLUDED) #define CSTR_X_INCLUDED static struct { @@ -437,11 +437,11 @@ cstr cstr_tocase(csview sv, int k) { cstr_shrink_to_fit(&out); return out; } -#endif // i_extern +#endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ #ifndef CSTR_C_INCLUDED -#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_no_undef) #define CSTR_C_INCLUDED uint64_t cstr_hash(const cstr *self) { @@ -659,4 +659,4 @@ intptr_t cstr_printf(cstr* self, const char* fmt, ...) { #undef i_header #undef i_static #undef i_implement -#undef i_extern +#undef i_import diff --git a/include/stc/csview.h b/include/stc/csview.h index d38d5f59..ee217e98 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -151,7 +151,7 @@ STC_INLINE bool csview_eq(const csview* x, const csview* y) /* -------------------------- IMPLEMENTATION ------------------------- */ #ifndef CSVIEW_C_INCLUDED -#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_no_undef) #define CSVIEW_C_INCLUDED csview_iter csview_advance(csview_iter it, intptr_t pos) { @@ -201,11 +201,10 @@ csview csview_token(csview sv, const char* sep, intptr_t* start) { *start += tok.size + sep_size; return tok; } - #endif #endif #undef i_opt #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index d7588ca0..75402150 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -59,7 +59,7 @@ #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import #undef i_allocator #undef i_malloc diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 338f0db9..e853263b 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -115,14 +115,14 @@ STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } #endif // UTF8_H_INCLUDED -#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_no_undef) # include "../../src/utf8code.c" #endif #ifndef _i_no_undef #undef i_static #undef i_header #undef i_implement -#undef i_extern +#undef i_import #undef i_opt #endif #undef _i_no_undef diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index f9505aa9..94a84065 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -1,5 +1,5 @@ #include -#define i_extern +#define i_import #include #define i_implement #include diff --git a/misc/examples/regex1.c b/misc/examples/regex1.c index 4a56b8ac..d8032358 100644 --- a/misc/examples/regex1.c +++ b/misc/examples/regex1.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include int main(int argc, char* argv[]) diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c index 3133f7c2..5718a1d8 100644 --- a/misc/examples/regex2.c +++ b/misc/examples/regex2.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include int main() diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index b4932015..ebda366f 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include #define i_implement #include diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c index cad195d5..2c7794af 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include #include #include diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 658c46a1..32b5f17f 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -1,5 +1,5 @@ #include -#define i_extern // cstr + utf8 functions +#define i_import // cstr + utf8 functions #include #define i_implement #include diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 301ecf4f..3ddcc608 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include #include #include diff --git a/src/cregex.c b/src/cregex.c index 62a64b11..1af719b4 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -27,7 +27,7 @@ THE SOFTWARE. #define CREGEX_C_INCLUDED #include -#ifdef i_extern +#ifdef i_import # define _i_extern #endif #ifndef CREGEX_H_INCLUDED diff --git a/src/libstc.c b/src/libstc.c index 99611e05..afc19a08 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,6 +1,6 @@ #include #if 1 -#define i_extern +#define i_import #include "../include/stc/utf8.h" #define i_implement #include "../include/stc/cstr.h" @@ -9,7 +9,7 @@ #define i_implement #include "../include/stc/csview.h" #else -#define i_extern +#define i_import #include "../include/stc/cregex.h" #define i_implement #include "../include/stc/csview.h" -- cgit v1.2.3 From f3529a2600141dc7f84c734ea3bf5db8f7090e56 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 11 Jun 2023 07:36:31 +0200 Subject: More internal structuring --- include/stc/cstr.h | 3 +++ include/stc/csview.h | 39 +++++++++++++++++++++------------------ include/stc/utf8.h | 3 ++- src/libstc.c | 16 ++++------------ 4 files changed, 30 insertions(+), 31 deletions(-) (limited to 'src/libstc.c') diff --git a/include/stc/cstr.h b/include/stc/cstr.h index f47889b4..0c5b67d8 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -655,8 +655,11 @@ intptr_t cstr_printf(cstr* self, const char* fmt, ...) { #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif +#ifndef _i_no_undef #undef i_opt #undef i_header #undef i_static #undef i_implement #undef i_import +#endif +#undef _i_no_undef diff --git a/include/stc/csview.h b/include/stc/csview.h index ee217e98..a1893063 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -114,6 +114,22 @@ STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c #define c_fortoken(it, input, sep) \ c_fortoken_sv(it, csview_from(input), sep) +/* ---- Container helper functions ---- */ + +STC_INLINE int csview_cmp(const csview* x, const csview* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_sv(*x, *y); } + +STC_INLINE bool csview_eq(const csview* x, const csview* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +#endif // CSVIEW_H_INCLUDED + /* csview interaction with cstr: */ #ifdef CSTR_H_INCLUDED @@ -131,23 +147,7 @@ STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } - #endif -/* ---- Container helper functions ---- */ - -STC_INLINE int csview_cmp(const csview* x, const csview* y) { - intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); - return c ? c : (int)(x->size - y->size); -} - -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_sv(*x, *y); } - -STC_INLINE bool csview_eq(const csview* x, const csview* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -#endif // CSVIEW_H_INCLUDED /* -------------------------- IMPLEMENTATION ------------------------- */ #ifndef CSVIEW_C_INCLUDED @@ -203,8 +203,11 @@ csview csview_token(csview sv, const char* sep, intptr_t* start) { } #endif #endif -#undef i_opt +#ifndef _i_no_undef +#undef i_static #undef i_header #undef i_implement -#undef i_static #undef i_import +#undef i_opt +#endif +#undef _i_no_undef diff --git a/include/stc/utf8.h b/include/stc/utf8.h index e853263b..d6c759eb 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,10 +1,11 @@ +#include "ccommon.h" + #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED #include #include "forward.h" -#include "ccommon.h" enum { U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl, diff --git a/src/libstc.c b/src/libstc.c index afc19a08..7b49540a 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,16 +1,8 @@ -#include -#if 1 #define i_import -#include "../include/stc/utf8.h" -#define i_implement -#include "../include/stc/cstr.h" -#define i_implement -#include "../include/stc/cregex.h" -#define i_implement -#include "../include/stc/csview.h" -#else -#define i_import -#include "../include/stc/cregex.h" +#include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement #include "../include/stc/csview.h" +#if __STDC_VERSION__ >= 201112L +# define i_implement +# include "../include/c11/fmt.h" #endif -- cgit v1.2.3 From f514c5128d62ad53623af4d45bd856b9564bce4f Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 6 Aug 2023 23:23:36 +0200 Subject: Improved Installation section in README.md --- README.md | 56 ++++++++++++++++++------------------------------------ include/stc/cstr.h | 2 +- src/libstc.c | 2 ++ 3 files changed, 21 insertions(+), 39 deletions(-) (limited to 'src/libstc.c') diff --git a/README.md b/README.md index 3ff00e52..69c51417 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ List of contents - **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers. - **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. -- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. +- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the [installation section](#installation). - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. - **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). - **Forward declaration** - Templated containers may be [forward declared](#forward-declarations) without including the full API/implementation. @@ -333,49 +333,29 @@ After erasing the elements found: --- ## Installation -*NEEDS REWRITE!* -Because it is headers-only, headers can simply be included in your program. By default, functions are static -(some inlined). You may add the *include* folder to the **CPATH** environment variable to -let GCC, Clang, and TinyC locate the headers. +STC is primarily a "headers-only" library, so most headers can simply be included in your program. By default, +all "templated" functions are static (many inlined). If you add the STC *include* folder to the **CPATH** +environment variable, GCC, Clang, and TinyC will locate the headers automatically. -If containers are used across several translation units with common instantiated container types, it is -recommended to build as a "library" with external linking to minimize executable size. To enable this, -specify `-DSTC_HEADER` as compiler option in your build environment. Next, place all the instantiations -of the containers used inside a single C-source file as in the example below, and `#define STC_IMPLEMENT` at top. -You may also cherry-pick shared linking mode on individual containers by `#define i_header` and -`#define i_implement`, or force static symbols by `#define i_static` before container includes. - -As a special case, there may be non-templated functions in templated containers that should be implemented only -once and if needed. Currently, define `i_import` before including **cregex** or **utf8** to implement them. - -It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`. - -Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**, -**cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, -or define your own, e.g.: +The templated container functions are defined with static linking by default, which is normally optimal +for both performance and compiled binary size. However, some common container type instances, e.g. `cvec_int` +may be used in several translation units. When they are used in more than 3-4, consider creating a separate +header file for them [as described here](#1-include-as-a-header-file). Now it will use shared +linking, so *one* c-file must implement the templated container, e.g.: ```c -// stc_libs.c -#define STC_IMPLEMENT // implement all the following as shared objects #define i_implement -#include -#include "Point.h" - -#define i_key int -#define i_val int -#define i_tag ii -#include // cmap_ii: int => int +#include "cvec_int.h" +``` +The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by +`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so +linking specifications and implementation are only needed for a few lesser used functions. -#define i_key int64_t -#define i_tag ix -#include // cset_ix +Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, +**csview**, **cregex**, **utf8**, and **crand**. -#define i_key int -#include // cvec_int +As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent +**utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. -#define i_key Point -#define i_tag pnt -#include // clist_pnt -``` --- ## Specifying template parameters diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 2648e267..f12d29b6 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -179,7 +179,7 @@ extern void cstr_lowercase(cstr* self); extern void cstr_uppercase(cstr* self); extern bool cstr_valid_utf8(const cstr* self); -// other utf8 +// utf8 functions not depending on src/utf8code.c: STC_INLINE intptr_t cstr_u8_size(const cstr* self) { return utf8_size(cstr_str(self)); } diff --git a/src/libstc.c b/src/libstc.c index 7b49540a..462c97c4 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -2,6 +2,8 @@ #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement #include "../include/stc/csview.h" +#define i_implement +#include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L # define i_implement # include "../include/c11/fmt.h" -- cgit v1.2.3 From 25dc58db206714dc02c1ae0548f6ba7dd3519d29 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 13 Aug 2023 23:15:45 +0200 Subject: API CHANGES: Changed csview: becomes a null-terminated string view. Added csubview: a null-terminated string view/span, like previous csview. Note that csview works like a csubview, so not much compability issues should arise. However, some functions have changed from _sv suffix to _ss. --- README.md | 30 ++-- docs/cmap_api.md | 2 +- docs/coroutine_api.md | 2 +- docs/cregex_api.md | 28 +-- docs/cstr_api.md | 44 +++-- docs/csubstr_api.md | 217 +++++++++++++++++++++++ docs/csview_api.md | 151 +++------------- include/stc/ccommon.h | 8 +- include/stc/cregex.h | 36 ++-- include/stc/cstr.h | 100 ++++++----- include/stc/csubstr.h | 208 ++++++++++++++++++++++ include/stc/csview.h | 155 ++++------------ include/stc/forward.h | 25 ++- include/stc/priv/template.h | 14 +- include/stc/utf8.h | 4 +- misc/benchmarks/various/string_bench_STC.cpp | 32 ++-- misc/examples/algorithms/forfilter.c | 12 +- misc/examples/regularexpressions/regex2.c | 2 +- misc/examples/regularexpressions/regex_match.c | 4 +- misc/examples/regularexpressions/regex_replace.c | 6 +- misc/examples/strings/cstr_match.c | 12 +- misc/examples/strings/replace.c | 4 +- misc/examples/strings/splitstr.c | 8 +- misc/examples/strings/sso_substr.c | 16 +- misc/examples/strings/sview_split.c | 14 +- misc/examples/strings/utf8replace_c.c | 4 +- misc/tests/cregex_test.c | 32 ++-- src/cregex.c | 28 +-- src/libstc.c | 2 +- src/singleupdate.sh | 2 +- src/utf8code.c | 2 +- 31 files changed, 733 insertions(+), 471 deletions(-) create mode 100644 docs/csubstr_api.md create mode 100644 include/stc/csubstr.h (limited to 'src/libstc.c') diff --git a/README.md b/README.md index d516f389..96479fa0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Containers - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) - [***cstack*** - **std::stack** alike type](docs/cstack_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) -- [***csview*** - **std::string_view** alike type](docs/csview_api.md) +- [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) - [***cspan*** - **std::span/std::mdspan** alike type](docs/cspan_api.md) - [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***cvec*** - **std::vector** alike type](docs/cvec_api.md) @@ -351,11 +351,11 @@ linking, so *one* c-file must implement the templated container, e.g.: #include "cvec_int.h" ``` The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by -`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so +`#define i_static`. Same for the string-view type **csubstr**, but most of its functions are static inlined, so linking specifications and implementation are only needed for a few lesser used functions. Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, -**csview**, **cregex**, **utf8**, and **crand**. +**csubstr**, **cregex**, **utf8**, and **crand**. As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent **utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. @@ -401,8 +401,8 @@ Only functions required by the container type is required to be defined. E.g.: - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. -- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csview\**. Defines both type convertion -`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csview\** as argument. +- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csubstr\**. Defines both type convertion +`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csubstr\** as argument. - `i_keyboxed` *Type* - Use when *Type* is a smart pointer **carc** or **cbox**. Defines *i_keyclass = Type*, and *i_keyraw = Type\**. NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. @@ -640,7 +640,7 @@ void maptest() STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. -- **csview**, 1 pointer, 1 intptr_t. Does not own data! +- **csubstr**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! - **clist**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. - **cdeq**, **cqueue**: Type size: 2 pointers, 2 intptr_t. Otherwise like *cvec*. @@ -654,7 +654,7 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Breaking changes: - - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - **cstr** and **csubstr** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - Renamed => `` - Moved => `` - Much improved with some new API and added features. @@ -686,7 +686,7 @@ STC is generally very memory efficient. Memory usage for the different container - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() -- Removed deprecated c_ARGSV(). Use c_SV() +- Removed deprecated c_ARGSV(). Use c_SS() - Removed c_PAIR ## Version 4.1.1 @@ -699,7 +699,7 @@ Major changes: - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. +- Renamed `c_ARGSV()` => `c_SS()`: **csubstr** print arg. Note `c_ss()` is shorthand for *csubstr_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. - Create single header container versions with python script. @@ -713,18 +713,18 @@ Major changes: - New + renamed loop iteration/scope macros: - `c_forlist`: macro replacing `c_forarray` and `c_apply`. Iterate a compound literal list. - `c_forrange`: macro replacing `c_forrange`. Iterate a `long long` type number sequence. -- Updated **cstr**, now always takes self as pointer, like all containers except csview. +- Updated **cstr**, now always takes self as pointer, like all containers except csubstr. - Updated **cvec**, **cdeq**, changed `*_range*` function names. ## Changes version 3.8 -- Overhauled some **cstr** and **csview** API: +- Overhauled some **cstr** and **csubstr** 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. + - Renamed `csubstr_*_u8()` => `csubstr_u8_*()` + - Added cstr_u8_slice() and csubstr_u8_slice(). + - Removed `csubstr_from_s()`: Use `cstr_ss(s)` instead. - Added back file coption.h - Simplified **cbits** usage: all inlined. - Updated docs. @@ -759,7 +759,7 @@ Major changes: - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. - Changed: the [**c_apply**](docs/algorithm_api.md) macros API. -- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. +- Replaced: *csubstr_first_token()* and *csubstr_next_token()* with one function: `csubstr_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 4e6da57d..65777221 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -282,7 +282,7 @@ typedef struct { cstr country; } Viking; -#define Viking_init() ((Viking){cstr_null, cstr_null}) +#define Viking_init() ((Viking){.name={0}, .country={0}}) static inline int Viking_cmp(const Viking* a, const Viking* b) { int c = cstr_cmp(&a->name, &b->name); diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index f7d81a34..c44f4a4d 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -237,7 +237,7 @@ cco_task_struct (produce_items, int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { - p->str = cstr_null; + p->str = cstr_init(); p->next.cco_func = next_value; while (true) { diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 52476e09..98161fe9 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -33,11 +33,11 @@ int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_ int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_find(const cregex* re, const char* input, csview match[], int mflags = CREG_DEFAULT); +int cregex_find(const cregex* re, const char* input, csubstr match[], int mflags = CREG_DEFAULT); // Search inside input string-view only -int cregex_find_sv(const cregex* re, csview input, csview match[]); +int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]); // All-in-one search (compile + find + drop) -int cregex_find_pattern(const char* pattern, const char* input, csview match[], int cmflags = CREG_DEFAULT); +int cregex_find_pattern(const char* pattern, const char* input, csubstr match[], int cmflags = CREG_DEFAULT); // Check if there are matches in input bool cregex_is_match(const cregex* re, const char* input); @@ -45,14 +45,14 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); // Replace count matches in input string-view. Optionally transform replacement. -cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); -cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, - bool(*transform)(int group, csview match, cstr* result), int rflags); +cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count = INT_MAX); +cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count, + bool(*transform)(int group, csubstr match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*transform)(int group, csview match, cstr* result), int rflags); + bool(*transform)(int group, csubstr match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -109,9 +109,9 @@ int main(void) { cregex re = cregex_from(pattern); // Lets find the first date in the string: - csview match[4]; // full-match, year, month, date. + csubstr match[4]; // full-match, year, month, date. if (cregex_find(&re, input, match) == CREG_OK) - printf("Found date: %.*s\n", c_SV(match[0])); + printf("Found date: %.*s\n", c_SS(match[0])); else printf("Could not find any date\n"); @@ -127,7 +127,7 @@ int main(void) { For a single match you may use the all-in-one function: ```c if (cregex_find_pattern(pattern, input, match)) - printf("Found date: %.*s\n", c_SV(match[0])); + printf("Found date: %.*s\n", c_SS(match[0])); ``` To use: `gcc first_match.c src/cregex.c src/utf8code.c`. @@ -137,16 +137,16 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c -csview match[5] = {0}; +csubstr match[5] = {0}; while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SV(match[k])); + printf("submatch %d: %.*s\n", k, c_SS(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); + printf("submatch %d: %.*s\n", k, c_SS(it.match[k])); ``` ## Using cregex in a project @@ -154,7 +154,7 @@ c_formatch (it, &re, input) The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: -- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` +- `stc/cregex.h`, `stc/utf8.h`, `stc/csubstr.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` - `src/cregex.c`, `src/utf8code.c`. ## Regex Cheatsheet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index dae5669f..36606b76 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -18,11 +18,11 @@ All cstr definitions and prototypes are available by including a single header f ## Methods ```c -cstr cstr_init(void); // constructor; same as cstr_null. +cstr cstr_init(void); // constructor; empty string cstr cstr_lit(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, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview sv); // construct cstr from csview +cstr cstr_from_ss(csubstr sv); // construct cstr from csubstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -34,7 +34,7 @@ void cstr_drop(cstr* self); // destructo 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 +csubstr cstr_ss(const cstr* self); // cast to string view cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity) intptr_t cstr_size(const cstr* self); @@ -48,13 +48,13 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_sv(cstr* self, csview sv); +char* cstr_assign_ss(cstr* self, csubstr 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* str); char* cstr_append_n(cstr* self, const char* str, intptr_t n); // append n first bytes of str -char* cstr_append_sv(cstr* self, csview str); +char* cstr_append_ss(cstr* self, csubstr str); char* cstr_append_s(cstr* self, cstr str); int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting char* cstr_append_uninit(cstr* self, intptr_t len); // return ptr to start of uninited data @@ -63,19 +63,19 @@ void cstr_push(cstr* self, const char* chr); // append on void cstr_pop(cstr* self); // pop one utf8 char void cstr_insert(cstr* self, intptr_t pos, const char* ins); -void cstr_insert_sv(cstr* self, intptr_t pos, csview ins); +void cstr_insert_ss(cstr* self, intptr_t pos, csubstr ins); void cstr_insert_s(cstr* self, intptr_t pos, cstr ins); void cstr_erase(cstr* self, intptr_t pos, intptr_t len); // erase len bytes from pos void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); -cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); +cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, unsigned count); void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl); // replace at a pos -void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl); +void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl); void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_sv(const cstr* self, csview sv); +bool cstr_equals_ss(const cstr* self, csubstr sv); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -83,11 +83,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_sv(const cstr* self, csview sv); +bool cstr_starts_with_ss(const cstr* self, csubstr sv); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_sv(const cstr* self, csview sv); +bool cstr_ends_with_ss(const cstr* self, csubstr sv); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -100,8 +100,8 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview -void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars +csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csubstr +void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos // iterate utf8 codepoints @@ -112,14 +112,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr +cstr cstr_casefold_ss(csubstr sv); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr +cstr cstr_tolower_ss(csubstr sv); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr +cstr cstr_toupper_ss(csubstr sv); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison @@ -132,11 +132,10 @@ Note that all methods with arguments `(..., const char* str, intptr_t n)`, `n` m #### Helper methods: ```c -int cstr_cmp(const cstr* s1, const cstr* s2); -bool cstr_eq(const cstr* s1, const cstr* s2); -bool cstr_hash(const cstr* self); - -char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); +int cstr_cmp(const cstr* s1, const cstr* s2); +bool cstr_eq(const cstr* s1, const cstr* s2); +bool cstr_hash(const cstr* self); +char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); ``` ## Types @@ -145,7 +144,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csview` | `struct { const char *str; intptr_t size; }` | String view type | +| `csubstr` | `struct { const char *str; intptr_t size; }` | String view type | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros @@ -153,7 +152,6 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt | Name | Value | |:------------------|:------------------| | `c_NPOS` | `INTPTR_MAX` | -| `cstr_null` | empty cstr value | ## Example ```c diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md new file mode 100644 index 00000000..925c69db --- /dev/null +++ b/docs/csubstr_api.md @@ -0,0 +1,217 @@ +# STC [csubstr](../include/stc/csubstr.h): String View +![String](pics/string.jpg) + +The type **csubstr** is a string view and can refer to a constant contiguous sequence of char-elements with the first +element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. + +**csubstr** is non-null terminated, and therefore not a replacent for `const char*` - see [csview](csview_api.md) for +that. **csubstr** never allocates memory, and therefore need not be destructed. +Its lifetime is limited by the source string storage. It keeps the length of the string, and does not need to call +*strlen()* to acquire the length. + +Note: a **csubstr** may ***not be null-terminated***, and must therefore be printed this way: +```c +printf("%.*s", c_SS(sstr)) +``` + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. + +## Header file + +All csubstr definitions and prototypes are available by including a single header file. + +```c +#define i_implement +#include +#include // after cstr.h: include extra cstr-csubstr functions +``` +## Methods + +```c +csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() +csubstr c_ss(const char* str, intptr_t n); // construct from str and length n +csubstr csubstr_from(const char* str); // construct from const char* +csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) + +intptr_t csubstr_size(csubstr sv); +bool csubstr_empty(csubstr sv); +void csubstr_clear(csubstr* self); + +bool csubstr_equals(csubstr sv, csubstr sv2); +intptr_t csubstr_find(csubstr sv, const char* str); +intptr_t csubstr_find_ss(csubstr sv, csubstr find); +bool csubstr_contains(csubstr sv, const char* str); +bool csubstr_starts_with(csubstr sv, const char* str); +bool csubstr_ends_with(csubstr sv, const char* str); + +csubstr csubstr_substr_ex(csubstr sv, intptr_t pos, intptr_t n); // negative pos count from end +csubstr csubstr_slice_ex(csubstr sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end +csubstr csubstr_token(csubstr sv, const char* sep, intptr_t* start); // *start > sv.size after last token +``` + +#### UTF8 methods +```c +intptr_t csubstr_u8_size(csubstr sv); +csubstr csubstr_u8_substr(csubstr sv, intptr_t bytepos, intptr_t u8len); +bool csubstr_valid_utf8(csubstr sv); // requires linking with src/utf8code.c + +csubstr_iter csubstr_begin(const csubstr* self); +csubstr_iter csubstr_end(const csubstr* self); +void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! +csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); +``` + +#### Extended cstr methods +```c +csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); +csubstr cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end +csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); + +csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); +csubstr cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end +``` +#### Iterate tokens with *c_fortoken*, *c_fortoken_ss* + +To iterate tokens in an input string separated by a string: +```c +c_fortoken (i, "hello, one, two, three", ", ") + printf("token: %.*s\n", c_SS(i.token)); +``` + +#### Helper methods +```c +int csubstr_cmp(const csubstr* x, const csubstr* y); +int csubstr_icmp(const csubstr* x, const csubstr* y); +bool csubstr_eq(const csubstr* x, const csubstr* y); +uint64_t csubstr_hash(const csubstr* x); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:----------------|:-------------------------------------------|:-------------------------| +| `csubstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `csubstr_value` | `char` | The string element type | +| `csubstr_iter` | `struct { csubstr_value *ref; }` | UTF8 iterator | + +## Constants and macros + +| Name | Value | Usage | +|:---------------|:---------------------|:---------------------------------------------| +| `c_SS(sv)` | printf argument | `printf("sv: %.*s\n", c_SS(sv));` | + +## Example +```c +#define i_implement +#include +#include + +int main(void) +{ + cstr str1 = cstr_lit("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) + + csubstr sv1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csubstr sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csubstr sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" + printf("%.*s %.*s %.*s\n", + c_SS(sv1), c_SS(sv2), c_SS(sv3)); + cstr s1 = cstr_lit("Apples are red"); + cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" + printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); + + c_drop(cstr, &str1, &s1, &s2, &s3); +} +``` +Output: +``` +think live details +red Apples +``` + +### Example 2: UTF8 handling +```c +#define i_import // include dependent cstr, utf8 and cregex function definitions. +#include + +int main(void) +{ + cstr s1 = cstr_lit("hell😀 w😀rld"); + + cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_ss("ø")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%.*s,", c_SS(i.u8.chr)); + + cstr_drop(&s1); +} +``` +Output: +``` +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, +``` + +### Example 3: csubstr tokenizer (string split) +Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, +and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. +```c +#include +#include + +void print_split(csubstr input, const char* sep) +{ + c_fortoken_ss (i, input, sep) + printf("[%.*s]\n", c_SS(i.token)); + puts(""); +} +#define i_implement +#include +#define i_key_str +#include + +cstack_str string_split(csubstr input, const char* sep) +{ + cstack_str out = cstack_str_init(); + + c_fortoken_ss (i, input, sep) + cstack_str_push(&out, cstr_from_ss(i.token)); + + return out; +} + +int main(void) +{ + print_split(c_ss("//This is a//double-slash//separated//string"), "//"); + print_split(c_ss("This has no matching separator"), "xx"); + + cstack_str s = string_split(c_ss("Split,this,,string,now,"), ","); + + c_foreach (i, cstack_str, s) + printf("[%s]\n", cstr_str(i.ref)); + puts(""); + + cstack_str_drop(&s); +} +``` +Output: +``` +[] +[This is a] +[double-slash] +[separated] +[string] + +[This has no matching separator] + +[Split] +[this] +[] +[string] +[now] +[] +``` diff --git a/docs/csview_api.md b/docs/csview_api.md index 49e4f9d1..4fdff0d1 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,19 +1,14 @@ # STC [csview](../include/stc/csview.h): String View ![String](pics/string.jpg) -The type **csview** is a string view and can refer to a constant contiguous sequence of char-elements with the first -element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. +The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two +members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** +string view/span type. -**csview** is an efficient replacent for `const char*`. It never allocates memory, and therefore need not be destructed. -Its lifetime is limited by the source string storage. It keeps the length of the string, and does not call *strlen()* -when passing it around. It is faster when using`csview` as convertion type (raw) than `const char*` in associative -containers with cstr keys. - -Note: a **csview** may ***not be null-terminated***, and must therefore be printed like: -`printf("%.*s", csview_ARG(sv))`. - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. +Because **csview** is null-terminated, it can be a more efficient replacent for `const char*`. It never +allocates memory, and need therefore not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, and does not call *strlen()* when passing it around. ## Header file @@ -42,17 +37,12 @@ intptr_t csview_find_sv(csview sv, csview find); bool csview_contains(csview sv, const char* str); bool csview_starts_with(csview sv, const char* str); bool csview_ends_with(csview sv, const char* str); - -csview csview_substr_ex(csview sv, intptr_t pos, intptr_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, const char* sep, intptr_t* start); // *start > sv.size after last token ``` #### UTF8 methods ```c intptr_t csview_u8_size(csview sv); -csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len); -bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c +bool csview_valid_utf8(csview sv); // depends on src/utf8code.c csview_iter csview_begin(const csview* self); csview_iter csview_end(const csview* self); @@ -74,27 +64,10 @@ uint32_t utf8_peek(const char* s); // codep uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) ``` -#### Extended cstr methods -```c -csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csview cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end -csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); - -csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); -csview cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end -``` -#### Iterate tokens with *c_fortoken*, *c_fortoken_sv* - -To iterate tokens in an input string separated by a string: -```c -c_fortoken (i, "hello, one, two, three", ", ") - printf("token: %.*s\n", c_SV(i.token)); -``` - #### Helper methods ```c int csview_cmp(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); +int csview_icmp(const csview* x, const csview* y); // depends on src/utf8code.c: bool csview_eq(const csview* x, const csview* y); uint64_t csview_hash(const csview* x); ``` @@ -107,46 +80,36 @@ uint64_t csview_hash(const csview* x); | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | - -## Example +## Example: UTF8 iteration and case conversion ```c -#define i_implement +#define i_import #include #include int main(void) { - cstr str1 = cstr_lit("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) - - csview sv1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csview sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csview sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", - c_SV(sv1), c_SV(sv2), c_SV(sv3)); - cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str1, &s1, &s2, &s3); + cstr str = cstr_from("Liberté, égalité, fraternité."); + csview sv = cstr_sv(&str); + + c_foreach (i, csview, sv) + printf("%.*s ", c_SS(i.u8.chr)); + puts(""); + + cstr_uppercase(&str); + printf("%s\n", cstr_str(&str)); + + cstr_drop(&str); } ``` Output: ``` -think live details -red Apples +L i b e r t é , é g a l i t é , f r a t e r n i t é . +LIBERTÉ, ÉGALITÉ, FRATERNITÉ. ``` -### Example 2: UTF8 handling +### Example 2: UTF8 replace ```c -#define i_import // include dependent cstr, utf8 and cregex function definitions. +#define i_import // include dependent utf8 definitions. #include int main(void) @@ -157,7 +120,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SV(i.u8.chr)); + printf("%.*s,", c_SS(i.u8.chr)); // u8.chr is a csubstr cstr_drop(&s1); } @@ -167,63 +130,3 @@ Output: hell😀 wørld h,e,l,l,😀, ,w,ø,r,l,d, ``` - -### Example 3: csview tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. -```c -#include -#include - -void print_split(csview input, const char* sep) -{ - c_fortoken_sv (i, input, sep) - printf("[%.*s]\n", c_SV(i.token)); - puts(""); -} -#define i_implement -#include -#define i_key_str -#include - -cstack_str string_split(csview input, const char* sep) -{ - cstack_str out = cstack_str_init(); - - c_fortoken_sv (i, input, sep) - cstack_str_push(&out, cstr_from_sv(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_sv("//This is a//double-slash//separated//string"), "//"); - print_split(c_sv("This has no matching separator"), "xx"); - - cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","); - - c_foreach (i, cstack_str, s) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - cstack_str_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 45fa01c6..24967a10 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -130,11 +130,15 @@ typedef const char* ccharptr; #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) +#define c_ss(...) c_MACRO_OVERLOAD(c_ss, __VA_ARGS__) +#define c_ss_1(literal) c_ss_2(literal, c_litstrlen(literal)) +#define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) +#define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); + #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) -#define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit)) +#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s" #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { diff --git a/include/stc/cregex.h b/include/stc/cregex.h index bce94b04..3aab3c8b 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -34,7 +34,7 @@ THE SOFTWARE. */ #include #include -#include "forward.h" // csview +#include "forward.h" // csubstr #include "ccommon.h" enum { @@ -82,7 +82,7 @@ typedef struct { typedef struct { const cregex* re; const char* input; - csview match[CREG_MAX_CAPTURES]; + csubstr match[CREG_MAX_CAPTURES]; } cregex_iter; #define c_formatch(it, Re, Input) \ @@ -115,11 +115,11 @@ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ #define cregex_find(...) c_MACRO_OVERLOAD(cregex_find, __VA_ARGS__) #define cregex_find_3(re, input, match) cregex_find_4(re, input, match, CREG_DEFAULT) -int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags); +int cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags); -/* find with csview as input. */ -STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { - csview *mp = NULL; +/* find with csubstr as input. */ +STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) { + csubstr *mp = NULL; if (match) { match[0] = input; mp = match; } return cregex_find(re, input.str, mp, CREG_STARTEND); } @@ -129,27 +129,27 @@ STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { #define cregex_find_pattern_3(pattern, input, match) \ cregex_find_pattern_4(pattern, input, match, CREG_DEFAULT) int cregex_find_pattern_4(const char* pattern, const char* input, - csview match[], int cmflags); + csubstr match[], int cmflags); STC_INLINE bool cregex_is_match(const cregex* re, const char* input) { return cregex_find_4(re, input, NULL, CREG_DEFAULT) == CREG_OK; } -/* replace csview input with replace using regular expression pattern */ -#define cregex_replace_sv(...) c_MACRO_OVERLOAD(cregex_replace_sv, __VA_ARGS__) -#define cregex_replace_sv_3(pattern, input, replace) \ - cregex_replace_sv_4(pattern, input, replace, INT32_MAX) -#define cregex_replace_sv_4(pattern, input, replace, count) \ - cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) -cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*transform)(int group, csview match, cstr* result), int rflags); +/* replace csubstr input with replace using regular expression pattern */ +#define cregex_replace_ss(...) c_MACRO_OVERLOAD(cregex_replace_ss, __VA_ARGS__) +#define cregex_replace_ss_3(pattern, input, replace) \ + cregex_replace_ss_4(pattern, input, replace, INT32_MAX) +#define cregex_replace_ss_4(pattern, input, replace, count) \ + cregex_replace_ss_6(pattern, input, replace, count, NULL, CREG_DEFAULT) +cstr cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, + bool (*transform)(int group, csubstr match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) #define cregex_replace_3(re, input, replace) cregex_replace_4(re, input, replace, INT32_MAX) STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char* replace, int count) { - csview sv = {input, c_strlen(input)}; - return cregex_replace_sv_4(re, sv, replace, count); + csubstr ss = {input, c_strlen(input)}; + return cregex_replace_ss_4(re, ss, replace, count); } /* replace + compile RE pattern, and extra arguments */ @@ -159,7 +159,7 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*transform)(int group, csview match, cstr* result), int crflags); + bool (*transform)(int group, csubstr match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index f12d29b6..47cf65da 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -75,7 +75,7 @@ STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API intptr_t cstr_find_sv(const cstr* self, csview search); +STC_API intptr_t cstr_find_ss(const cstr* self, csubstr search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_uninit(cstr *self, intptr_t len); @@ -85,7 +85,7 @@ STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +STC_API cstr cstr_replace_ss(csubstr sv, csubstr search, csubstr repl, int32_t count); STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { @@ -94,9 +94,11 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } STC_INLINE csview cstr_sv(const cstr* s) { - return cstr_is_long(s) ? c_LITERAL(csview){s->lon.data, cstr_l_size(s)} - : c_LITERAL(csview){s->sml.data, cstr_s_size(s)}; + return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) + : c_sv_2(s->sml.data, cstr_s_size(s)); } +STC_INLINE csubstr cstr_ss(const cstr* s) + { csview sv = cstr_sv(s); return c_ss_2(sv.str, sv.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -110,7 +112,10 @@ STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } -STC_INLINE cstr cstr_from_sv(csview sv) +STC_INLINE cstr cstr_from_ss(csubstr sv) + { return cstr_from_n(sv.str, sv.size); } + +STC_INLINE cstr cstr_from_v(csview sv) { return cstr_from_n(sv.str, sv.size); } STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { @@ -170,9 +175,9 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_casefold_sv(csview sv); -extern cstr cstr_tolower_sv(csview sv); -extern cstr cstr_toupper_sv(csview sv); +extern cstr cstr_casefold_ss(csubstr sv); +extern cstr cstr_tolower_ss(csubstr sv); +extern cstr cstr_toupper_ss(csubstr sv); extern cstr cstr_tolower(const char* str); extern cstr cstr_toupper(const char* str); extern void cstr_lowercase(cstr* self); @@ -193,9 +198,9 @@ STC_INLINE intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx) STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { +STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); - csview sv; + csubstr sv; sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; @@ -205,7 +210,7 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { STC_INLINE cstr_iter cstr_begin(const cstr* self) { csview sv = cstr_sv(self); - if (!sv.size) return c_LITERAL(cstr_iter){NULL}; + if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { @@ -244,6 +249,9 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } +STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) + { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } + STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } @@ -266,14 +274,14 @@ STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) STC_INLINE bool cstr_contains(const cstr* self, const char* search) { return strstr((char*)cstr_str(self), search) != NULL; } -STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) - { return cstr_find_sv(self, search) != c_NPOS; } +STC_INLINE bool cstr_contains_ss(const cstr* self, csubstr search) + { return cstr_find_ss(self, search) != c_NPOS; } STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) { return strstr((char*)cstr_str(self), cstr_str(&search)) != NULL; } -STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { +STC_INLINE bool cstr_starts_with_ss(const cstr* self, csubstr sub) { if (sub.size > cstr_size(self)) return false; return !c_memcmp(cstr_str(self), sub.str, sub.size); } @@ -285,26 +293,26 @@ STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { } STC_INLINE bool cstr_starts_with_s(const cstr* self, cstr sub) - { return cstr_starts_with_sv(self, cstr_sv(&sub)); } + { return cstr_starts_with_ss(self, cstr_ss(&sub)); } STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { - csview sv = cstr_sv(self); + csubstr sv = cstr_ss(self); intptr_t len = c_strlen(sub); - return len <= sv.size && !utf8_icmp_sv(sv, c_sv(sub, len)); + return len <= sv.size && !utf8_icmp_ss(sv, c_ss(sub, len)); } -STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { +STC_INLINE bool cstr_ends_with_ss(const cstr* self, csubstr sub) { csview sv = cstr_sv(self); if (sub.size > sv.size) return false; return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) - { return cstr_ends_with_sv(self, cstr_sv(&sub)); } + { return cstr_ends_with_ss(self, cstr_ss(&sub)); } STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) - { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } + { return cstr_ends_with_ss(self, c_ss(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { csview sv = cstr_sv(self); @@ -316,7 +324,7 @@ STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) +STC_INLINE char* cstr_assign_ss(cstr* self, csubstr sv) { return cstr_assign_n(self, sv.str, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { @@ -338,44 +346,42 @@ STC_INLINE void cstr_pop(cstr* self) { STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_append_sv(cstr* self, csview sv) +STC_INLINE char* cstr_append_ss(cstr* self, csubstr sv) { return cstr_append_n(self, sv.str, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) - { return cstr_append_sv(self, cstr_sv(&s)); } + { return cstr_append_ss(self, cstr_ss(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, int32_t count) { - cstr_take(self, cstr_replace_sv(cstr_sv(self), c_sv(search, c_strlen(search)), - c_sv(repl, c_strlen(repl)), count)); + cstr_take(self, cstr_replace_ss(cstr_ss(self), c_ss(search, c_strlen(search)), + c_ss(repl, c_strlen(repl)), count)); } -STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { +STC_INLINE void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); c_memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) - { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } + { cstr_replace_at_ss(self, pos, len, c_ss(repl, c_strlen(repl))); } STC_INLINE void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl) - { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } + { cstr_replace_at_ss(self, pos, len, cstr_ss(&repl)); } -STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl) - { cstr_replace_at_sv(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } +STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl) + { cstr_replace_at_ss(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str) - { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } + { cstr_replace_at_ss(self, pos, 0, c_ss(str, c_strlen(str))); } -STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv) - { cstr_replace_at_sv(self, pos, 0, sv); } +STC_INLINE void cstr_insert_ss(cstr* self, intptr_t pos, csubstr sv) + { cstr_replace_at_ss(self, pos, 0, sv); } -STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) { - csview sv = cstr_sv(&s); - cstr_replace_at_sv(self, pos, 0, sv); -} +STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) + { cstr_replace_at_ss(self, pos, 0, cstr_ss(&s)); } STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -394,7 +400,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -static cstr cstr_tocase(csview sv, int k) { +static cstr cstr_tocase(csubstr sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -415,26 +421,26 @@ static cstr cstr_tocase(csview sv, int k) { return out; } -cstr cstr_casefold_sv(csview sv) +cstr cstr_casefold_ss(csubstr sv) { return cstr_tocase(sv, 0); } -cstr cstr_tolower_sv(csview sv) +cstr cstr_tolower_ss(csubstr sv) { return cstr_tocase(sv, 1); } -cstr cstr_toupper_sv(csview sv) +cstr cstr_toupper_ss(csubstr sv) { return cstr_tocase(sv, 2); } cstr cstr_tolower(const char* str) - { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } + { return cstr_tolower_ss(c_ss(str, c_strlen(str))); } cstr cstr_toupper(const char* str) - { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } + { return cstr_toupper_ss(c_ss(str, c_strlen(str))); } void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } + { cstr_take(self, cstr_tolower_ss(cstr_ss(self))); } void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } + { cstr_take(self, cstr_toupper_ss(cstr_ss(self))); } bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } @@ -450,7 +456,7 @@ STC_DEF uint64_t cstr_hash(const cstr *self) { return cfasthash(sv.str, sv.size); } -STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { +STC_DEF intptr_t cstr_find_ss(const cstr* self, csubstr search) { csview sv = cstr_sv(self); char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; @@ -580,7 +586,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { +STC_DEF cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h new file mode 100644 index 00000000..152f7041 --- /dev/null +++ b/include/stc/csubstr.h @@ -0,0 +1,208 @@ +/* MIT License + * + * Copyright (c) 2023 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. + */ +#define i_header // external linkage by default. override with i_static. +#define _i_inc_utf8 +#include "utf8.h" + +#ifndef CSUBSTR_H_INCLUDED +#define CSUBSTR_H_INCLUDED + +#define csubstr_init() c_ss_1("") +#define csubstr_drop(p) c_default_drop(p) +#define csubstr_clone(ss) c_default_clone(ss) +#define csubstr_from_n(str, n) c_ss_2(str, n) + +STC_API csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos); +STC_API intptr_t csubstr_find_ss(csubstr ss, csubstr search); +STC_API uint64_t csubstr_hash(const csubstr *self); +STC_API csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2); +STC_API csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); +STC_API csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); + +STC_INLINE csubstr csubstr_from(const char* str) + { return c_LITERAL(csubstr){str, c_strlen(str)}; } +STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } +STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } +STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } + +STC_INLINE bool csubstr_equals(csubstr ss, const char* str) + { intptr_t n = c_strlen(str); return ss.size == n && !c_memcmp(ss.str, str, n); } + +STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) + { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } + +STC_INLINE bool csubstr_contains(csubstr ss, const char* str) + { return csubstr_find(ss, str) != c_NPOS; } + +STC_INLINE bool csubstr_starts_with(csubstr ss, const char* str) { + intptr_t n = c_strlen(str); + return n > ss.size ? false : !c_memcmp(ss.str, str, n); +} + +STC_INLINE bool csubstr_ends_with(csubstr ss, const char* str) { + intptr_t n = c_strlen(str); + return n > ss.size ? false : !c_memcmp(ss.str + ss.size - n, str, n); +} + +STC_INLINE csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n) { + if (pos + n > ss.size) n = ss.size - pos; + ss.str += pos, ss.size = n; + return ss; +} + +STC_INLINE csubstr csubstr_slice(csubstr ss, intptr_t p1, intptr_t p2) { + if (p2 > ss.size) p2 = ss.size; + ss.str += p1, ss.size = p2 > p1 ? p2 - p1 : 0; + return ss; +} + +/* utf8 iterator */ +STC_INLINE csubstr_iter csubstr_begin(const csubstr* self) { + if (!self->size) return c_LITERAL(csubstr_iter){NULL}; + return c_LITERAL(csubstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, + self->str + self->size}}; +} +STC_INLINE csubstr_iter csubstr_end(const csubstr* self) { + return c_LITERAL(csubstr_iter){.u8 = {{NULL}, self->str + self->size}}; +} +STC_INLINE void csubstr_next(csubstr_iter* it) { + it->ref += it->u8.chr.size; + it->u8.chr.size = utf8_chr_size(it->ref); + if (it->ref == it->u8.end) it->ref = NULL; +} + +/* utf8 */ +STC_INLINE intptr_t csubstr_u8_size(csubstr ss) + { return utf8_size_n(ss.str, ss.size); } + +STC_INLINE csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len) { + ss.str += bytepos; + ss.size = utf8_pos(ss.str, u8len); + return ss; +} + +STC_INLINE bool csubstr_valid_utf8(csubstr ss) // depends on src/utf8code.c + { return utf8_valid_n(ss.str, ss.size); } + +#define c_fortoken_ss(it, inputss, sep) \ + for (struct { csubstr _inp, token, *ref; const char *_sep; intptr_t pos; } \ + it = {._inp=inputss, .token=it._inp, .ref=&it.token, ._sep=sep} \ + ; it.pos <= it._inp.size && (it.token = csubstr_token(it._inp, it._sep, &it.pos)).str ; ) + +#define c_fortoken(it, input, sep) \ + c_fortoken_ss(it, csubstr_from(input), sep) + +/* ---- Container helper functions ---- */ + +STC_INLINE int csubstr_cmp(const csubstr* x, const csubstr* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE int csubstr_icmp(const csubstr* x, const csubstr* y) + { return utf8_icmp_ss(*x, *y); } + +STC_INLINE bool csubstr_eq(const csubstr* x, const csubstr* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +#endif // CSUBSTR_H_INCLUDED + +/* csubstr interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n) + { return csubstr_substr(cstr_ss(self), pos, n); } + +STC_INLINE csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) + { return csubstr_slice(cstr_ss(self), p1, p2); } + +STC_INLINE csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) + { return csubstr_substr_ex(cstr_ss(self), pos, n); } + +STC_INLINE csubstr cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) + { return csubstr_slice_ex(cstr_ss(self), p1, p2); } + +STC_INLINE csubstr cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) + { return csubstr_u8_substr(cstr_ss(self), bytepos, u8len); } +#endif + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement || defined i_static +#ifndef CSUBSTR_C_INCLUDED +#define CSUBSTR_C_INCLUDED + +STC_DEF csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + +STC_DEF intptr_t csubstr_find_ss(csubstr ss, csubstr search) { + char* res = cstrnstrn(ss.str, search.str, ss.size, search.size); + return res ? (res - ss.str) : c_NPOS; +} + +STC_DEF uint64_t csubstr_hash(const csubstr *self) + { return cfasthash(self->str, self->size); } + +STC_DEF csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n) { + if (pos < 0) { + pos += ss.size; + if (pos < 0) pos = 0; + } + if (pos > ss.size) pos = ss.size; + if (pos + n > ss.size) n = ss.size - pos; + ss.str += pos, ss.size = n; + return ss; +} + +STC_DEF csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += ss.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += ss.size; + if (p2 > ss.size) p2 = ss.size; + ss.str += p1, ss.size = (p2 > p1 ? p2 - p1 : 0); + return ss; +} + +STC_DEF csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start) { + intptr_t sep_size = c_strlen(sep); + csubstr slice = {ss.str + *start, ss.size - *start}; + const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); + csubstr tok = {slice.str, res ? (res - slice.str) : slice.size}; + *start += tok.size + sep_size; + return tok; +} +#endif // CSUBSTR_C_INCLUDED +#endif // i_implement +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt diff --git a/include/stc/csview.h b/include/stc/csview.h index bbf7cd8e..0d1ca36c 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,7 +20,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" @@ -32,25 +31,26 @@ #define csview_clone(sv) c_default_clone(sv) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); -STC_API intptr_t csview_find_sv(csview sv, csview search); -STC_API uint64_t csview_hash(const csview *self); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); - STC_INLINE csview csview_from(const char* str) - { return c_LITERAL(csview){str, c_strlen(str)}; } + { return csview_from_n(str, c_strlen(str)); } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } +STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } -STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } +STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } -STC_INLINE bool csview_equals(csview sv, const char* str) - { intptr_t n = c_strlen(str); return sv.size == n && !c_memcmp(sv.str, str, n); } +STC_INLINE bool csview_equals(csview sv, const char* str) { + intptr_t n = c_strlen(str); + return sv.size == n && !c_memcmp(sv.str, str, n); +} + +STC_INLINE intptr_t csview_find_v(csview sv, csview search) { + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; +} STC_INLINE intptr_t csview_find(csview sv, const char* str) - { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } + { return csview_find_v(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; } @@ -65,55 +65,40 @@ STC_INLINE bool csview_ends_with(csview sv, const char* str) { return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); } -STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { - if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; - return sv; -} - /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { - if (!self->size) return c_LITERAL(csview_iter){NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; + if (!self->size) return c_LITERAL(csview_iter){.ref = NULL}; + return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; } STC_INLINE csview_iter csview_end(const csview* self) { - return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; + (void)self; return c_LITERAL(csview_iter){.ref = NULL}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; it->u8.chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; + if (!*it->ref) it->ref = NULL; +} +STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (!*it.ref) it.ref = NULL; + return it; } -/* utf8 */ +/* utf8 size */ STC_INLINE intptr_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { - sv.str += bytepos; - sv.size = utf8_pos(sv.str, u8len); - return sv; -} - -STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c +/* utf8 validation: depends on src/utf8code.c */ +STC_INLINE bool csview_valid_utf8(csview sv) { return utf8_valid_n(sv.str, sv.size); } -#define c_fortoken_sv(it, inputsv, sep) \ - for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ - it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) - -#define c_fortoken(it, input, sep) \ - c_fortoken_sv(it, csview_from(input), sep) +/* utf8 ignore case cmp: depends on src/utf8code.c */ +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_ss(c_ss_2(x->str, x->size), c_ss_2(y->str, y->size)); } -/* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; @@ -121,87 +106,13 @@ STC_INLINE int csview_cmp(const csview* x, const csview* y) { return c ? c : (int)(x->size - y->size); } -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_sv(*x, *y); } - STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -#endif // CSVIEW_H_INCLUDED - -/* csview interaction with cstr: */ -#ifdef CSTR_H_INCLUDED - -STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n) - { return csview_substr(cstr_sv(self), pos, n); } - -STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) - { return csview_slice(cstr_sv(self), p1, p2); } - -STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t 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(cstr_sv(self), p1, p2); } - -STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) - { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement || defined i_static -#ifndef CSVIEW_C_INCLUDED -#define CSVIEW_C_INCLUDED - -STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - -STC_DEF intptr_t csview_find_sv(csview sv, csview search) { - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; -} - -STC_DEF uint64_t csview_hash(const csview *self) +STC_INLINE uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { - if (pos < 0) { - pos += sv.size; - if (pos < 0) pos = 0; - } - if (pos > sv.size) pos = sv.size; - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += sv.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += sv.size; - if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); - return sv; -} - -STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { - intptr_t sep_size = c_strlen(sep); - csview slice = {sv.str + *start, sv.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csview tok = {slice.str, res ? (res - slice.str) : slice.size}; - *start += tok.size + sep_size; - return tok; -} -#endif // CSVIEW_C_INCLUDED -#endif // i_implement +#endif // CSVIEW_H_INCLUDED #undef i_static #undef i_header #undef i_implement diff --git a/include/stc/forward.h b/include/stc/forward.h index 572a319f..5c9c4f4d 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -39,8 +39,21 @@ #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) -// csview -typedef const char csview_value; +// csubstr : non-null terminated string view +typedef const char csubstr_value; +typedef struct csubstr { + csubstr_value* str; + intptr_t size; +} csubstr; + +typedef union { + csubstr_value* ref; + struct { csubstr chr; csubstr_value* end; } u8; +} csubstr_iter; + + +// csview : null-terminated string view +typedef csubstr_value csview_value; typedef struct csview { csview_value* str; intptr_t size; @@ -48,10 +61,11 @@ typedef struct csview { typedef union { csview_value* ref; - struct { csview chr; csview_value* end; } u8; + struct { csubstr chr; } u8; } csview_iter; -// cstr + +// cstr : null-terminated string (short string optimized - sso) typedef char cstr_value; typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; typedef union cstr { @@ -61,9 +75,10 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csview chr; } u8; + struct { csubstr chr; } u8; } cstr_iter; + #define c_true(...) __VA_ARGS__ #define c_false(...) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 65dee203..47225ec8 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -114,10 +114,10 @@ #endif #elif defined i_key_ssv #define i_keyclass cstr - #define i_rawclass csview - #define i_keyfrom cstr_from_sv - #define i_keyto cstr_sv - #define i_eq csview_eq + #define i_rawclass csubstr + #define i_keyfrom cstr_from_ss + #define i_keyto cstr_ss + #define i_eq csubstr_eq #ifndef i_tag #define i_tag ssv #endif @@ -232,9 +232,9 @@ #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr - #define i_valraw csview - #define i_valfrom cstr_from_sv - #define i_valto cstr_sv + #define i_valraw csubstr + #define i_valfrom cstr_from_ss + #define i_valto cstr_ss #elif defined i_valboxed #define i_valclass i_valboxed #define i_valraw c_PASTE(i_valboxed, _raw) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 6d12856f..7d2adee0 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -48,7 +48,7 @@ extern uint32_t utf8_toupper(uint32_t c); extern bool utf8_iscased(uint32_t c); extern bool utf8_isword(uint32_t c); extern bool utf8_valid_n(const char* s, intptr_t nbytes); -extern int utf8_icmp_sv(csview s1, csview s2); +extern int utf8_icmp_ss(csubstr s1, csubstr s2); extern int utf8_encode(char *out, uint32_t c); extern uint32_t utf8_peek_off(const char *s, int offset); @@ -92,7 +92,7 @@ STC_INLINE uint32_t utf8_peek(const char* s) { /* case-insensitive utf8 string comparison */ STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); + return utf8_icmp_ss(c_ss(s1, INTPTR_MAX), c_ss(s2, INTPTR_MAX)); } STC_INLINE bool utf8_valid(const char* s) { diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index a5dfd901..9173d4b6 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -7,16 +7,16 @@ #define i_implement #include // string #define i_implement -#include // string_view +#include // string_view #include #define i_key_str #include // vec of cstr with const char* lookup -#define i_type cvec_sv // override default type name (cvec_csview) -#define i_key csview -#define i_cmp csview_cmp -#include // cvec_vs: vec of csview +#define i_type cvec_ss // override default type name (cvec_csubstr) +#define i_key csubstr +#define i_cmp csubstr_cmp +#include // cvec_vs: vec of csubstr #define i_key_str #define i_val size_t @@ -24,7 +24,7 @@ #define i_key_ssv #define i_val size_t -#include // sorted map of cstr, csview lookup +#include // sorted map of cstr, csubstr lookup #define i_key_str #define i_val size_t @@ -32,7 +32,7 @@ #define i_key_ssv #define i_val size_t -#include // unordered map of cstr, csview lookup +#include // unordered map of cstr, csubstr lookup cvec_str read_file(const char* name) @@ -67,7 +67,7 @@ private: std::chrono::high_resolution_clock::time_point begin; }; -void initShortStringVec(cvec_str* vs, cvec_sv* vsv) +void initShortStringVec(cvec_str* vs, cvec_ss* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -101,14 +101,14 @@ void initShortStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_sv(i.ref)); + cvec_sv_push_back(vsv, cstr_ss(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; std::cout << "avg str len: " << num / (float)cvec_sv_size(vsv) << std::endl; } -void initLongStringVec(cvec_str* vs, cvec_sv* vsv) +void initLongStringVec(cvec_str* vs, cvec_ss* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -147,7 +147,7 @@ void initLongStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_sv(i.ref)); + cvec_sv_push_back(vsv, cstr_ss(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; @@ -175,7 +175,7 @@ void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, void benchmark( const cvec_str* vec_string, - const cvec_sv* vec_stringview, + const cvec_ss* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -187,7 +187,7 @@ const size_t MAX_LOOP = 2000; int main(void) { c_auto (cvec_str, vec_string) - c_auto (cvec_sv, vec_stringview) + c_auto (cvec_ss, vec_stringview) c_auto (csmap_str, mapTrans) c_auto (csmap_ssv, mapSview) c_auto (cmap_str, unordmapTrans) @@ -229,7 +229,7 @@ int main(void) void benchmark( const cvec_str* vec_string, - const cvec_sv* vec_stringview, + const cvec_ss* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -258,7 +258,7 @@ void benchmark( stopwatch.start("Trans Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_sv, *vec_stringview) + c_foreach (j, cvec_ss, *vec_stringview) { const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); if (v) @@ -286,7 +286,7 @@ void benchmark( stopwatch.start("Trans Unord Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_sv, *vec_stringview) + c_foreach (j, cvec_ss, *vec_stringview) { const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); if (v) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index c1426045..d058660d 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -2,7 +2,7 @@ #define i_import #include #define i_implement -#include +#include #include #define i_type IVec @@ -82,7 +82,7 @@ fn main() { } */ #define i_type SVec -#define i_keyclass csview +#define i_keyclass csubstr #include void demo3(void) @@ -94,11 +94,11 @@ void demo3(void) SVec words_containing_i = {0}; c_forfilter (w, SVec, words, - csview_contains(*w.ref, "i")) + csubstr_contains(*w.ref, "i")) SVec_push(&words_containing_i, *w.ref); c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SV(*w.ref)); + printf(" %.*s", c_SS(*w.ref)); puts(""); c_drop(SVec, &words, &words_containing_i); @@ -107,10 +107,10 @@ void demo3(void) void demo4(void) { // Keep only uppercase letters and convert them to lowercase: - csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte + csubstr s = c_ss("ab123cReAghNGnΩoEp"); // Ω = multi-byte cstr out = {0}; - c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { + c_forfilter (i, csubstr, s, utf8_isupper(utf8_peek(i.ref))) { char chr[4]; utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); cstr_push(&out, chr); diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c index a798b1a1..85890070 100644 --- a/misc/examples/regularexpressions/regex2.c +++ b/misc/examples/regularexpressions/regex2.c @@ -27,7 +27,7 @@ int main(void) c_formatch (j, &re, s[i].input) { c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); + printf(" submatch %lld: %.*s\n", k, c_SS(j.match[k])); } } cregex_drop(&re); diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 11426d2d..6eaea781 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -1,7 +1,7 @@ #define i_import #include #define i_implement -#include +#include #define i_key float #include @@ -28,7 +28,7 @@ int main(void) printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); + cstr nums = cregex_replace_ss(&re, csubstr_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f1ea2711..f5fd8691 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -1,8 +1,8 @@ #define i_import #include -#include +#include -bool add_10_years(int i, csview match, cstr* out) { +bool add_10_years(int i, csubstr match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -47,7 +47,7 @@ int main(void) printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c index be03e981..3c41bd43 100644 --- a/misc/examples/strings/cstr_match.c +++ b/misc/examples/strings/cstr_match.c @@ -1,11 +1,11 @@ #define i_implement #include -#include +#include #include int main(void) { - cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); + cstr ss = cstr_from("The quick brown fox jumps over the lazy dog.JPG"); intptr_t pos = cstr_find_at(&ss, 0, "brown"); printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); @@ -16,11 +16,11 @@ int main(void) printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csview ch1 = cstr_u8_chr(&s1, 7); - csview ch2 = cstr_u8_chr(&s1, 10); + csubstr ch1 = cstr_u8_chr(&s1, 7); + csubstr ch2 = cstr_u8_chr(&s1, 10); printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SV(ch1)); - printf("ch2: %.*s\n", c_SV(ch2)); + printf("ch1: %.*s\n", c_SS(ch1)); + printf("ch2: %.*s\n", c_SS(ch2)); c_drop(cstr, &ss, &s1); } diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c index 59a56bf7..2411f1a7 100644 --- a/misc/examples/strings/replace.c +++ b/misc/examples/strings/replace.c @@ -20,13 +20,13 @@ int main(void) cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) + cstr_replace_at_ss(&s, 19, 6, c_ss(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) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) + cstr_replace_at_ss(&s, 8, 6, c_ss("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) diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c index ef7ed174..6fa76d34 100644 --- a/misc/examples/strings/splitstr.c +++ b/misc/examples/strings/splitstr.c @@ -2,20 +2,20 @@ #define i_import // cstr + utf8 functions #include #define i_implement -#include +#include int main(void) { - puts("Split with c_fortoken (csview):"); + puts("Split with c_fortoken (csubstr):"); c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SV(i.token)); + printf("'%.*s'\n", c_SS(i.token)); puts("\nSplit with c_formatch (regex):"); cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SV(i.match[0])); + printf("'%.*s'\n", c_SS(i.match[0])); cregex_drop(&re); } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 687658df..3c6b1046 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" - intptr_t pos = cstr_find(&str, "live"); // position of "live" - csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); + csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" + intptr_t pos = cstr_find(&str, "live"); // position of "live" + csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csubstr sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c index ac275da0..6abbf5e7 100644 --- a/misc/examples/strings/sview_split.c +++ b/misc/examples/strings/sview_split.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { // No memory allocations or string length calculations! - const csview date = c_sv("2021/03/12"); + const csubstr date = c_ss("2021/03/12"); intptr_t pos = 0; - const csview year = csview_token(date, "/", &pos); - const csview month = csview_token(date, "/", &pos); - const csview day = csview_token(date, "/", &pos); + const csubstr year = csubstr_token(date, "/", &pos); + const csubstr month = csubstr_token(date, "/", &pos); + const csubstr day = csubstr_token(date, "/", &pos); - printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); + printf("%.*s, %.*s, %.*s\n", c_SS(year), c_SS(month), c_SS(day)); - cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); + cstr y = cstr_from_ss(year), m = cstr_from_ss(month), d = cstr_from_ss(day); printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); c_drop(cstr, &y, &m, &d); } diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 1d54486f..03a0442f 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -10,12 +10,12 @@ int main(void) cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, - c_sv("🐨") + c_ss("🐨") ); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SV(c.u8.chr)); + printf("%.*s,", c_SS(c.u8.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 4e192de6..7cd03930 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,6 @@ #define i_import #include -#include +#include #include #include "ctest.h" @@ -14,7 +14,7 @@ CTEST(cregex, compile_match_char) cregex re = cregex_from("äsdf"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -32,7 +32,7 @@ CTEST(cregex, compile_match_anchors) cregex re = cregex_from(inp="^äs.f$"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -50,7 +50,7 @@ CTEST(cregex, compile_match_quantifiers1) re = cregex_from("ä+"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="ääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 4); @@ -70,7 +70,7 @@ CTEST(cregex, compile_match_quantifiers2) re = cregex_from("bä*"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="bääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -90,7 +90,7 @@ CTEST(cregex, compile_match_escaped_chars) cregex re = cregex_from("\\n\\r\\t\\{"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "\n\r\t", &match), CREG_NOMATCH); @@ -108,7 +108,7 @@ CTEST(cregex, compile_match_class_simple) re3 = cregex_from("\\D"); ASSERT_EQ(re3.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re1, " " , &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\r", &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\n", &match), CREG_OK); @@ -129,7 +129,7 @@ CTEST(cregex, compile_match_or) re = cregex_from("as|df"); ASSERT_EQ(re.error, 0); - csview match[4]; + csubstr match[4]; ASSERT_EQ(cregex_find(&re, "as", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "df", match), CREG_OK); @@ -146,7 +146,7 @@ CTEST(cregex, compile_match_class_complex_0) cregex re = cregex_from("[asdf]"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "s", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "d", &match), CREG_OK); @@ -160,7 +160,7 @@ CTEST(cregex, compile_match_class_complex_1) cregex re = cregex_from("[a-zä0-9öA-Z]"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "5", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "A", &match), CREG_OK); @@ -175,7 +175,7 @@ CTEST(cregex, compile_match_cap) cregex re = cregex_from("(abc)d"); ASSERT_EQ(re.error, 0); - csview match[4]; + csubstr match[4]; ASSERT_EQ(cregex_find(&re, "abcd", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "llljabcdkk", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "abc", match), CREG_NOMATCH); @@ -189,7 +189,7 @@ CTEST(cregex, search_all) c_auto (cregex, re) { re = cregex_from("ab"); - csview m = {0}; + csubstr m = {0}; int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; @@ -220,9 +220,9 @@ CTEST(cregex, captures_cap) re = cregex_from("(ab)((cd)+)"); ASSERT_EQ(cregex_captures(&re), 3); - csview cap[5]; + csubstr cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); - ASSERT_TRUE(csview_equals(cap[0], "abcdcd")); + ASSERT_TRUE(csubstr_equals(cap[0], "abcdcd")); ASSERT_EQ(M_END(cap[0]), 8); ASSERT_EQ(M_START(cap[1]), 2); @@ -235,7 +235,7 @@ CTEST(cregex, captures_cap) } } -static bool add_10_years(int i, csview match, cstr* out) { +static bool add_10_years(int i, csubstr match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index 975a5104..c045b9f3 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -100,7 +100,7 @@ typedef struct _Reprog /* * Sub expression matches */ -typedef csview _Resub; +typedef csubstr _Resub; /* * substitution list @@ -1215,8 +1215,8 @@ _regexec(const _Reprog *progp, /* program to run */ static void -_build_subst(const char* replace, int nmatch, const csview match[], - bool (*mfun)(int, csview, cstr*), cstr* subst) { +_build_subst(const char* replace, int nmatch, const csubstr match[], + bool (*mfun)(int, csubstr, cstr*), cstr* subst) { cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; @@ -1233,7 +1233,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } if (g < nmatch) { - csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; + csubstr m = mfun && mfun(g, match[g], &mstr) ? cstr_ss(&mstr) : match[g]; if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) @@ -1270,7 +1270,7 @@ cregex_captures(const cregex* self) { } int -cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { +cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) { int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; @@ -1281,7 +1281,7 @@ cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { int cregex_find_pattern_4(const char* pattern, const char* input, - csview match[], int cmflags) { + csubstr match[], int cmflags) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, cmflags); if (res != CREG_OK) return res; @@ -1291,16 +1291,16 @@ cregex_find_pattern_4(const char* pattern, const char* input, } cstr -cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*mfun)(int, csview, cstr*), int rflags) { +cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, + bool (*mfun)(int, csubstr, cstr*), int rflags) { cstr out = cstr_init(); cstr subst = cstr_init(); - csview match[CREG_MAX_CAPTURES]; + csubstr match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_STRIP); - while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { + while (count-- && cregex_find_ss(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); const intptr_t mpos = (match[0].str - input.str); if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); @@ -1308,19 +1308,19 @@ cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int cou input.str = match[0].str + match[0].size; input.size -= mpos + match[0].size; } - if (copy) cstr_append_sv(&out, input); + if (copy) cstr_append_ss(&out, input); cstr_drop(&subst); return out; } cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int, csview, cstr*), int crflags) { + bool (*mfun)(int, csubstr, cstr*), int crflags) { cregex re = cregex_init(); if (cregex_compile(&re, pattern, crflags) != CREG_OK) assert(0); - csview sv = {input, c_strlen(input)}; - cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags); + csubstr ss = c_ss(input, c_strlen(input)); + cstr out = cregex_replace_ss(&re, ss, replace, count, mfun, crflags); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index 462c97c4..b0d27350 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,7 +1,7 @@ #define i_import #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement -#include "../include/stc/csview.h" +#include "../include/stc/csubstr.h" #define i_implement #include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L diff --git a/src/singleupdate.sh b/src/singleupdate.sh index e706dd97..be99d4a7 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -17,12 +17,12 @@ python singleheader.py $d/include/stc/cqueue.h $d/../stcsingle/stc/cqueue.h python singleheader.py $d/include/stc/crand.h $d/../stcsingle/stc/crand.h python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h python singleheader.py $d/include/stc/cset.h $d/../stcsingle/stc/cset.h - python singleheader.py $d/include/stc/csmap.h $d/../stcsingle/stc/csmap.h python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h +python singleheader.py $d/include/stc/csubstr.h $d/../stcsingle/stc/csubstr.h python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h diff --git a/src/utf8code.c b/src/utf8code.c index 4abf10ea..ddc4cb97 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -101,7 +101,7 @@ uint32_t utf8_toupper(uint32_t c) { return c; } -int utf8_icmp_sv(const csview s1, const csview s2) { +int utf8_icmp_ss(const csubstr s1, const csubstr s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { -- cgit v1.2.3 From 78d8668e6d527070568a405408ed906e51055bf4 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 14 Aug 2023 16:46:24 +0200 Subject: Reverted csubstr => csview. Sorry about that! Added crawstr to become the null-terminated string view. --- README.md | 32 ++-- docs/crawstr_api.md | 130 +++++++++++++ docs/cregex_api.md | 28 +-- docs/cstr_api.md | 34 ++-- docs/csubstr_api.md | 221 ----------------------- docs/csview_api.md | 217 +++++++++++++++------- include/stc/ccommon.h | 13 +- include/stc/crawstr.h | 116 ++++++++++++ include/stc/cregex.h | 36 ++-- include/stc/cstr.h | 148 +++++++-------- include/stc/csubstr.h | 211 ---------------------- include/stc/csview.h | 159 ++++++++++++---- include/stc/forward.h | 34 ++-- include/stc/priv/template.h | 14 +- include/stc/utf8.h | 4 +- misc/benchmarks/various/string_bench_STC.cpp | 32 ++-- misc/examples/algorithms/forfilter.c | 12 +- misc/examples/regularexpressions/regex2.c | 2 +- misc/examples/regularexpressions/regex_match.c | 4 +- misc/examples/regularexpressions/regex_replace.c | 6 +- misc/examples/strings/cstr_match.c | 10 +- misc/examples/strings/replace.c | 4 +- misc/examples/strings/splitstr.c | 8 +- misc/examples/strings/sso_substr.c | 14 +- misc/examples/strings/sview_split.c | 14 +- misc/examples/strings/utf8replace_c.c | 4 +- misc/tests/cregex_test.c | 32 ++-- src/cregex.c | 28 +-- src/libstc.c | 2 +- src/singleupdate.sh | 2 +- src/utf8code.c | 2 +- 31 files changed, 786 insertions(+), 787 deletions(-) create mode 100644 docs/crawstr_api.md delete mode 100644 docs/csubstr_api.md create mode 100644 include/stc/crawstr.h delete mode 100644 include/stc/csubstr.h (limited to 'src/libstc.c') diff --git a/README.md b/README.md index 1c8c3878..d99d8a76 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ Containers - [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md) - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) -- [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) -- [***csview*** - null-terminated string view type](docs/csview_api.md) +- [***csview*** - **std::string_view** alike type](docs/csview_api.md) +- [***crawstr*** - null-terminated string view type](docs/crawstr_api.md) - [***cspan*** - **std::span** + **std::mdspan** alike type](docs/cspan_api.md) Algorithms @@ -352,11 +352,11 @@ linking, so *one* c-file must implement the templated container, e.g.: #include "cvec_int.h" ``` The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by -`#define i_static`. Same for the string-view type **csubstr**, but most of its functions are static inlined, so +`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so linking specifications and implementation are only needed for a few lesser used functions. Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, -**csubstr**, **cregex**, **utf8**, and **crand**. +**csview**, **cregex**, **utf8**, and **crand**. As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent **utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. @@ -402,8 +402,8 @@ Only functions required by the container type is required to be defined. E.g.: - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. -- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csubstr\**. Defines both type convertion -`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csubstr\** as argument. +- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csview\**. Defines both type convertion +`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csview\** as argument. - `i_keyboxed` *Type* - Use when *Type* is a smart pointer **carc** or **cbox**. Defines *i_keyclass = Type*, and *i_keyraw = Type\**. NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. @@ -641,7 +641,7 @@ void maptest() STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. -- **csubstr**, 1 pointer, 1 intptr_t. Does not own data! +- **csview**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! - **clist**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. - **cdeq**, **cqueue**: Type size: 2 pointers, 2 intptr_t. Otherwise like *cvec*. @@ -655,7 +655,7 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Breaking changes: - - **cstr** and **csubstr** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - Renamed => `` - Moved => `` - Much improved with some new API and added features. @@ -687,7 +687,7 @@ STC is generally very memory efficient. Memory usage for the different container - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() -- Removed deprecated c_ARGSV(). Use c_SS() +- Removed deprecated c_ARGSV(). Use c_SV() - Removed c_PAIR ## Version 4.1.1 @@ -700,7 +700,7 @@ Major changes: - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SS()`: **csubstr** print arg. Note `c_ss()` is shorthand for *csubstr_from()*. +- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. - Create single header container versions with python script. @@ -714,18 +714,18 @@ Major changes: - New + renamed loop iteration/scope macros: - `c_forlist`: macro replacing `c_forarray` and `c_apply`. Iterate a compound literal list. - `c_forrange`: macro replacing `c_forrange`. Iterate a `long long` type number sequence. -- Updated **cstr**, now always takes self as pointer, like all containers except csubstr. +- Updated **cstr**, now always takes self as pointer, like all containers except csview. - Updated **cvec**, **cdeq**, changed `*_range*` function names. ## Changes version 3.8 -- Overhauled some **cstr** and **csubstr** API: +- 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 `csubstr_*_u8()` => `csubstr_u8_*()` - - Added cstr_u8_slice() and csubstr_u8_slice(). - - Removed `csubstr_from_s()`: Use `cstr_ss(s)` instead. + - Renamed `csview_*_u8()` => `csview_u8_*()` + - Added cstr_u8_slice() and csview_u8_slice(). + - Removed `csview_from_s()`: Use `cstr_sv(s)` instead. - Added back file coption.h - Simplified **cbits** usage: all inlined. - Updated docs. @@ -760,7 +760,7 @@ Major changes: - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. - Changed: the [**c_apply**](docs/algorithm_api.md) macros API. -- Replaced: *csubstr_first_token()* and *csubstr_next_token()* with one function: `csubstr_token()`. +- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md new file mode 100644 index 00000000..d44c302d --- /dev/null +++ b/docs/crawstr_api.md @@ -0,0 +1,130 @@ +# STC [crawstr](../include/stc/crawstr.h): Null-terminated UTF8 String View +![String](pics/string.jpg) + +The type **crawstr** is a ***null-terminated*** string view and refers to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two +members: a pointer to constant char and a size. See [csview](csview_api.md) for a ***non null-terminated*** +string view/span type. + +Because **crawstr** is null-terminated, it can be an efficient replacent for `const char*`. It never +allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. + +## Header file + +All crawstr definitions and prototypes are available by including a single header file. + +```c +#define i_implement +#include +#include +``` +## Methods + +```c +crawstr crawstr_from(const char* str); // construct from const char* +crawstr c_rs(const char literal_only[]); // construct from literal, no strlen() + +intptr_t crawstr_size(crawstr rs); +bool crawstr_empty(crawstr rs); // check if size == 0 +void crawstr_clear(crawstr* self); +csview crawstr_sv(crawstr rs); // convert to csview type + +bool crawstr_equals(crawstr rs, const char* str); +intptr_t crawstr_find(crawstr rs, const char* str); +bool crawstr_contains(crawstr rs, const char* str); +bool crawstr_starts_with(crawstr rs, const char* str); +bool crawstr_ends_with(crawstr rs, const char* str); +``` + +#### UTF8 methods +```c +intptr_t crawstr_u8_size(crawstr rs); +bool crawstr_valid_utf8(crawstr rs); // depends on src/utf8code.c + +crawstr_iter crawstr_begin(const crawstr* self); +crawstr_iter crawstr_end(const crawstr* self); +void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte! +crawstr_iter crawstr_advance(crawstr_iter it, intptr_t n); + + // from utf8.h +intptr_t utf8_size(const char *s); +intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes +const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position +intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position +unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 + // implemented in src/utf8code.c: +bool utf8_valid(const char* s); +bool utf8_valid_n(const char* s, intptr_t nbytes); +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); // codepoint value of character at s +uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) +``` + +#### Helper methods +```c +int crawstr_cmp(const crawstr* x, const crawstr* y); +int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c: +bool crawstr_eq(const crawstr* x, const crawstr* y); +uint64_t crawstr_hash(const crawstr* x); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:----------------|:-------------------------------------------|:-------------------------| +| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `crawstr_value` | `char` | The string element type | +| `crawstr_iter` | `struct { crawstr_value *ref; }` | UTF8 iterator | + +## Example: UTF8 iteration and case conversion +```c +#define i_import +#include +#include + +int main(void) +{ + cstr str = cstr_from("Liberté, égalité, fraternité."); + crawstr rs = cstr_rs(&str); + + c_foreach (i, crawstr, rs) + printf("%.*s ", c_SV(i.u8.chr)); + puts(""); + + cstr_uppercase(&str); + printf("%s\n", cstr_str(&str)); + + cstr_drop(&str); +} +``` +Output: +``` +L i b e r t é , é g a l i t é , f r a t e r n i t é . +LIBERTÉ, ÉGALITÉ, FRATERNITÉ. +``` + +### Example 2: UTF8 replace +```c +#define i_import // include dependent utf8 definitions. +#include + +int main(void) +{ + cstr s1 = cstr_lit("hell😀 w😀rld"); + + cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_rs("ø")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%.*s,", c_SV(i.u8.chr)); // u8.chr is a csview + + cstr_drop(&s1); +} +``` +Output: +``` +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, +``` diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 98161fe9..52476e09 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -33,11 +33,11 @@ int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_ int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_find(const cregex* re, const char* input, csubstr match[], int mflags = CREG_DEFAULT); +int cregex_find(const cregex* re, const char* input, csview match[], int mflags = CREG_DEFAULT); // Search inside input string-view only -int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]); +int cregex_find_sv(const cregex* re, csview input, csview match[]); // All-in-one search (compile + find + drop) -int cregex_find_pattern(const char* pattern, const char* input, csubstr match[], int cmflags = CREG_DEFAULT); +int cregex_find_pattern(const char* pattern, const char* input, csview match[], int cmflags = CREG_DEFAULT); // Check if there are matches in input bool cregex_is_match(const cregex* re, const char* input); @@ -45,14 +45,14 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); // Replace count matches in input string-view. Optionally transform replacement. -cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count = INT_MAX); -cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count, - bool(*transform)(int group, csubstr match, cstr* result), int rflags); +cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); +cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, + bool(*transform)(int group, csview match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*transform)(int group, csubstr match, cstr* result), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -109,9 +109,9 @@ int main(void) { cregex re = cregex_from(pattern); // Lets find the first date in the string: - csubstr match[4]; // full-match, year, month, date. + csview match[4]; // full-match, year, month, date. if (cregex_find(&re, input, match) == CREG_OK) - printf("Found date: %.*s\n", c_SS(match[0])); + printf("Found date: %.*s\n", c_SV(match[0])); else printf("Could not find any date\n"); @@ -127,7 +127,7 @@ int main(void) { For a single match you may use the all-in-one function: ```c if (cregex_find_pattern(pattern, input, match)) - printf("Found date: %.*s\n", c_SS(match[0])); + printf("Found date: %.*s\n", c_SV(match[0])); ``` To use: `gcc first_match.c src/cregex.c src/utf8code.c`. @@ -137,16 +137,16 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c -csubstr match[5] = {0}; +csview match[5] = {0}; while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SS(match[k])); + printf("submatch %d: %.*s\n", k, c_SV(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SS(it.match[k])); + printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); ``` ## Using cregex in a project @@ -154,7 +154,7 @@ c_formatch (it, &re, input) The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: -- `stc/cregex.h`, `stc/utf8.h`, `stc/csubstr.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` +- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` - `src/cregex.c`, `src/utf8code.c`. ## Regex Cheatsheet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 07b9b4c8..1da57b0c 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -22,8 +22,8 @@ cstr cstr_init(void); // construct cstr cstr_lit(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, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview sv); // construct cstr from csview -cstr cstr_from_ss(csubstr ss); // construct cstr from csubstr +cstr cstr_from_sv(csview ss); // construct cstr from csview +cstr cstr_from_rs(crawstr rs); // construct cstr from crawstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -35,7 +35,7 @@ void cstr_drop(cstr* self); // destructo const char* cstr_str(const cstr* self); // to const char* csview cstr_sv(const cstr* self); // to csview -csubstr cstr_ss(const cstr* self); // to csubstr +crawstr cstr_rs(const cstr* self); // to crawstr char* cstr_data(cstr* self); // to mutable char* cstr_buf cstr_buffer(cstr* self); // to mutable buffer (with capacity) @@ -50,13 +50,13 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_ss(cstr* self, csubstr ss); +char* cstr_assign_sv(cstr* self, csview ss); 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* str); char* cstr_append_n(cstr* self, const char* str, intptr_t n); // append n first bytes of str -char* cstr_append_ss(cstr* self, csubstr str); +char* cstr_append_sv(cstr* self, csview str); char* cstr_append_s(cstr* self, cstr str); int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting char* cstr_append_uninit(cstr* self, intptr_t len); // return ptr to start of uninited data @@ -65,19 +65,19 @@ void cstr_push(cstr* self, const char* chr); // append on void cstr_pop(cstr* self); // pop one utf8 char void cstr_insert(cstr* self, intptr_t pos, const char* ins); -void cstr_insert_ss(cstr* self, intptr_t pos, csubstr ins); +void cstr_insert_sv(cstr* self, intptr_t pos, csview ins); void cstr_insert_s(cstr* self, intptr_t pos, cstr ins); void cstr_erase(cstr* self, intptr_t pos, intptr_t len); // erase len bytes from pos void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); -cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, unsigned count); +cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl); // replace at a pos -void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl); +void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl); void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_ss(const cstr* self, csubstr ss); +bool cstr_equals_sv(const cstr* self, csview ss); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -85,11 +85,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_ss(const cstr* self, csubstr ss); +bool cstr_starts_with_sv(const cstr* self, csview ss); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_ss(const cstr* self, csubstr ss); +bool cstr_ends_with_sv(const cstr* self, csview ss); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -102,8 +102,8 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csubstr -void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl); // replace u8len utf8 chars +csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview +void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos // iterate utf8 codepoints @@ -114,14 +114,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_ss(csubstr ss); // returns new casefolded utf8 cstr +cstr cstr_casefold_sv(csview ss); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_ss(csubstr ss); // returns new lowercase utf8 cstr +cstr cstr_tolower_sv(csview ss); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_ss(csubstr ss); // returns new uppercase utf8 cstr +cstr cstr_toupper_sv(csview ss); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison @@ -146,7 +146,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csubstr` | `struct { const char *str; intptr_t size; }` | String view type | +| `csview` | `struct { const char *str; intptr_t size; }` | String view type | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md deleted file mode 100644 index 7094cf82..00000000 --- a/docs/csubstr_api.md +++ /dev/null @@ -1,221 +0,0 @@ -# STC [csubstr](../include/stc/csubstr.h): Sub-string View -![String](pics/string.jpg) - -The type **csubstr** is a non-null terminated string view and can refer to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two members: -a pointer to constant char and a size. - -Because **csubstr** is non-null terminated, it is not a replacent view for `const char*` - see [csview](csview_api.md) -for that. **csubstr** never allocates memory, and therefore need not be destructed. Its lifetime is limited by -the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire -the length. - -- **csubstr** iterators works on UTF8 codepoints - like **cstr** and **csview** (see Example 2). -- Because it is null-terminated, it must be printed the following way: -```c -printf("%.*s", c_SS(sstr)); -``` - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. - -## Header file - -All csubstr definitions and prototypes are available by including a single header file. - -```c -#define i_implement -#include -#include // after cstr.h: include extra cstr-csubstr functions -``` -## Methods - -```c -csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() -csubstr c_ss(const char* str, intptr_t n); // construct from str and length n -csubstr csubstr_from(const char* str); // construct from const char* -csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) - -intptr_t csubstr_size(csubstr ss); -bool csubstr_empty(csubstr ss); -void csubstr_clear(csubstr* self); - -bool csubstr_equals(csubstr ss, const char* str); -intptr_t csubstr_equals_ss(csubstr ss, csubstr find); -intptr_t csubstr_find(csubstr ss, const char* str); -intptr_t csubstr_find_ss(csubstr ss, csubstr find); -bool csubstr_contains(csubstr ss, const char* str); -bool csubstr_starts_with(csubstr ss, const char* str); -bool csubstr_ends_with(csubstr ss, const char* str); -csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n); -csubstr csubstr_slice(csubstr ss, intptr_t pos1, intptr_t pos2); - -csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); // negative pos count from end -csubstr csubstr_slice_ex(csubstr ss, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end -csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); // *start > ss.size after last token -``` - -#### UTF8 methods -```c -intptr_t csubstr_u8_size(csubstr ss); -csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len); -bool csubstr_valid_utf8(csubstr ss); // requires linking with src/utf8code.c - -csubstr_iter csubstr_begin(const csubstr* self); -csubstr_iter csubstr_end(const csubstr* self); -void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! -csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); -``` - -#### cstr methods returning csubstr -```c -csubstr cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); -csubstr cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csubstr_slice_ex() -csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csubstr_substr_ex() -csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); -``` -#### Iterate tokens with *c_fortoken*, *c_fortoken_ss* - -To iterate tokens in an input string separated by a string: -```c -c_fortoken (i, "hello, one, two, three", ", ") - printf("token: %.*s\n", c_SS(i.token)); -``` - -#### Helper methods -```c -int csubstr_cmp(const csubstr* x, const csubstr* y); -int csubstr_icmp(const csubstr* x, const csubstr* y); -bool csubstr_eq(const csubstr* x, const csubstr* y); -uint64_t csubstr_hash(const csubstr* x); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:----------------|:-------------------------------------------|:-------------------------| -| `csubstr` | `struct { const char *str; intptr_t size; }` | The string view type | -| `csubstr_value` | `char` | The string element type | -| `csubstr_iter` | `struct { csubstr_value *ref; }` | UTF8 iterator | - -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_SS(ss)` | printf argument | `printf("ss: %.*s\n", c_SS(ss));` | - -## Example -```c -#define i_implement -#include -#include - -int main(void) -{ - cstr str1 = cstr_from("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) - - csubstr ss1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csubstr ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csubstr ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", - c_SS(ss1), c_SS(ss2), c_SS(ss3)); - cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str1, &s1, &s2, &s3); -} -``` -Output: -``` -think live details -red Apples -``` - -### Example 2: UTF8 handling -```c -#define i_import // include dependent cstr, utf8 and cregex function definitions. -#include - -int main(void) -{ - cstr s1 = cstr_lit("hell😀 w😀rld"); - - cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_ss("ø")); - printf("%s\n", cstr_str(&s1)); - - c_foreach (i, cstr, s1) - printf("%.*s,", c_SS(i.u8.chr)); - - cstr_drop(&s1); -} -``` -Output: -``` -hell😀 wørld -h,e,l,l,😀, ,w,ø,r,l,d, -``` - -### Example 3: csubstr tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. -```c -#include -#include - -void print_split(csubstr input, const char* sep) -{ - c_fortoken_ss (i, input, sep) - printf("[%.*s]\n", c_SS(i.token)); - puts(""); -} -#define i_implement -#include -#define i_key_str -#include - -cstack_str string_split(csubstr input, const char* sep) -{ - cstack_str out = cstack_str_init(); - - c_fortoken_ss (i, input, sep) - cstack_str_push(&out, cstr_from_ss(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_ss("//This is a//double-slash//separated//string"), "//"); - print_split(c_ss("This has no matching separator"), "xx"); - - cstack_str s = string_split(c_ss("Split,this,,string,now,"), ","); - - c_foreach (i, cstack_str, s) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - cstack_str_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/docs/csview_api.md b/docs/csview_api.md index d28e3ed2..eafc6854 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,14 +1,23 @@ -# STC [csview](../include/stc/csview.h): Null-terminated UTF8 String View +# STC [csview](../include/stc/csview.h): Sub-string View ![String](pics/string.jpg) -The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two -members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** -string view/span type. +The type **csview** is a non-null terminated string view and can refer to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two members: +a pointer to constant char and a size. -Because **csview** is null-terminated, it can be an efficient replacent for `const char*`. It never -allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string -storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. +Because **csview** is non-null terminated, it is not an ideal replacent view for `const char*` - see [crawstr](crawstr_api.md) +for that. **csview** never allocates memory, and therefore need not be destructed. Its lifetime is limited by +the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire +the length. + +- **csview** iterators works on UTF8 codepoints - like **cstr** and **crawstr** (see Example 2). +- Because it is null-terminated, it must be printed the following way: +```c +printf("%.*s", c_SV(sstr)); +``` + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. ## Header file @@ -22,52 +31,64 @@ All csview definitions and prototypes are available by including a single header ## Methods ```c -csview c_sv(const char literal_only[]); // construct from literal, no strlen() -csview csview_from(const char* str); // construct from const char* +csview c_sv(const char literal_only[]); // construct from literal, no strlen() +csview c_sv(const char* str, intptr_t n); // construct from str and length n +csview csview_from(const char* str); // construct from const char* +csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n) + +intptr_t csview_size(csview sv); +bool csview_empty(csview sv); +void csview_clear(csview* self); + +bool csview_equals(csview sv, const char* str); +intptr_t csview_equals_sv(csview sv, csview find); +intptr_t csview_find(csview sv, const char* str); +intptr_t csview_find_sv(csview sv, csview find); +bool csview_contains(csview sv, const char* str); +bool csview_starts_with(csview sv, const char* str); +bool csview_ends_with(csview sv, const char* str); +csview csview_substr(csview sv, intptr_t pos, intptr_t n); +csview csview_slice(csview sv, intptr_t pos1, intptr_t pos2); + +csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end +csview csview_slice_ex(csview sv, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end +csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token +``` -intptr_t csview_size(csview sv); -bool csview_empty(csview sv); // check if size == 0 -void csview_clear(csview* self); -csubstr csview_ss(csview sv); // convert to csubstr type +#### UTF8 methods +```c +intptr_t csview_u8_size(csview sv); +csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len); +bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c + +csview_iter csview_begin(const csview* self); +csview_iter csview_end(const csview* self); +void csview_next(csview_iter* it); // utf8 codepoint step, not byte! +csview_iter csview_advance(csview_iter it, intptr_t n); +``` -bool csview_equals(csview sv, const char* str); -intptr_t csview_find(csview sv, const char* str); -bool csview_contains(csview sv, const char* str); -bool csview_starts_with(csview sv, const char* str); -bool csview_ends_with(csview sv, const char* str); +#### cstr methods returning csview +```c +csview cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); +csview cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csview_slice_ex() +csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n); +csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csview_substr_ex() +csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); ``` +#### Iterate tokens with *c_fortoken*, *c_fortoken_sv* -#### UTF8 methods +To iterate tokens in an input string separated by a string: ```c -intptr_t csview_u8_size(csview sv); -bool csview_valid_utf8(csview sv); // depends on src/utf8code.c - -csview_iter csview_begin(const csview* self); -csview_iter csview_end(const csview* self); -void csview_next(csview_iter* it); // utf8 codepoint step, not byte! -csview_iter csview_advance(csview_iter it, intptr_t n); - - // from utf8.h -intptr_t utf8_size(const char *s); -intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes -const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position -intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position -unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 - // implemented in src/utf8code.c: -bool utf8_valid(const char* s); -bool utf8_valid_n(const char* s, intptr_t nbytes); -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); // codepoint value of character at s -uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) +c_fortoken (i, "hello, one, two, three", ", ") + printf("token: %.*s\n", c_SV(i.token)); ``` #### Helper methods ```c -int csview_cmp(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); // depends on src/utf8code.c: -bool csview_eq(const csview* x, const csview* y); -uint64_t csview_hash(const csview* x); +int csview_cmp(const csview* x, const csview* y); +int csview_icmp(const csview* x, const csview* y); +bool csview_eq(const csview* x, const csview* y); +uint64_t csview_hash(const csview* x); ``` ## Types @@ -78,36 +99,46 @@ uint64_t csview_hash(const csview* x); | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | -## Example: UTF8 iteration and case conversion +## Constants and macros + +| Name | Value | Usage | +|:---------------|:---------------------|:---------------------------------------------| +| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | + +## Example ```c -#define i_import +#define i_implement #include #include int main(void) { - cstr str = cstr_from("Liberté, égalité, fraternité."); - csview sv = cstr_sv(&str); - - c_foreach (i, csview, sv) - printf("%.*s ", c_SS(i.u8.chr)); - puts(""); - - cstr_uppercase(&str); - printf("%s\n", cstr_str(&str)); - - cstr_drop(&str); + cstr str1 = cstr_from("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) + + csview ss1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csview ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csview ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" + printf("%.*s %.*s %.*s\n", + c_SV(ss1), c_SV(ss2), c_SV(ss3)); + cstr s1 = cstr_lit("Apples are red"); + cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" + printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); + + c_drop(cstr, &str1, &s1, &s2, &s3); } ``` Output: ``` -L i b e r t é , é g a l i t é , f r a t e r n i t é . -LIBERTÉ, ÉGALITÉ, FRATERNITÉ. +think live details +red Apples ``` -### Example 2: UTF8 replace +### Example 2: UTF8 handling ```c -#define i_import // include dependent utf8 definitions. +#define i_import // include dependent cstr, utf8 and cregex function definitions. #include int main(void) @@ -118,7 +149,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SS(i.u8.chr)); // u8.chr is a csubstr + printf("%.*s,", c_SV(i.u8.chr)); cstr_drop(&s1); } @@ -128,3 +159,63 @@ Output: hell😀 wørld h,e,l,l,😀, ,w,ø,r,l,d, ``` + +### Example 3: csview tokenizer (string split) +Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, +and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. +```c +#include +#include + +void print_split(csview input, const char* sep) +{ + c_fortoken_sv (i, input, sep) + printf("[%.*s]\n", c_SV(i.token)); + puts(""); +} +#define i_implement +#include +#define i_key_str +#include + +cstack_str string_split(csview input, const char* sep) +{ + cstack_str out = cstack_str_init(); + + c_fortoken_sv (i, input, sep) + cstack_str_push(&out, cstr_from_sv(i.token)); + + return out; +} + +int main(void) +{ + print_split(c_sv("//This is a//double-slash//separated//string"), "//"); + print_split(c_sv("This has no matching separator"), "xx"); + + cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","); + + c_foreach (i, cstack_str, s) + printf("[%s]\n", cstr_str(i.ref)); + puts(""); + + cstack_str_drop(&s); +} +``` +Output: +``` +[] +[This is a] +[double-slash] +[separated] +[string] + +[This has no matching separator] + +[Split] +[this] +[] +[string] +[now] +[] +``` diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1b4a2277..e5422adc 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -130,14 +130,13 @@ typedef const char* ccharptr; #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) -#define c_ss(...) c_MACRO_OVERLOAD(c_ss, __VA_ARGS__) -#define c_ss_1(literal) c_ss_2(literal, c_litstrlen(literal)) -#define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) -#define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); - -#define c_sv(literal) c_sv_2(literal, c_litstrlen(literal)) +#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) +#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) c_SS(sv) // [deprecated] - unneeded +#define c_SV(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SV(ss)); + +#define c_rs(literal) c_rs_2(literal, c_litstrlen(literal)) +#define c_rs_2(str, n) (c_LITERAL(crawstr){str, n}) #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h new file mode 100644 index 00000000..7cf62e94 --- /dev/null +++ b/include/stc/crawstr.h @@ -0,0 +1,116 @@ +/* MIT License + * + * Copyright (c) 2023 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. + */ +#define _i_inc_utf8 +#include "utf8.h" + +#ifndef CRAWSTR_H_INCLUDED +#define CRAWSTR_H_INCLUDED + +#define crawstr_init() c_rs("") +#define crawstr_drop(p) c_default_drop(p) +#define crawstr_clone(rs) c_default_clone(rs) + +STC_INLINE crawstr crawstr_from(const char* str) + { return c_rs_2(str, c_strlen(str)); } +STC_INLINE void crawstr_clear(crawstr* self) { *self = crawstr_init(); } +STC_INLINE csview crawstr_sv(crawstr rs) { return c_sv_2(rs.str, rs.size); } + +STC_INLINE intptr_t crawstr_size(crawstr rs) { return rs.size; } +STC_INLINE bool crawstr_empty(crawstr rs) { return rs.size == 0; } + +STC_INLINE bool crawstr_equals(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return rs.size == n && !c_memcmp(rs.str, str, n); +} + +STC_INLINE intptr_t crawstr_find(crawstr rs, const char* search) { + char* res = cstrnstrn(rs.str, search, rs.size, c_strlen(search)); + return res ? (res - rs.str) : c_NPOS; +} + +STC_INLINE bool crawstr_contains(crawstr rs, const char* str) + { return crawstr_find(rs, str) != c_NPOS; } + +STC_INLINE bool crawstr_starts_with(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return n > rs.size ? false : !c_memcmp(rs.str, str, n); +} + +STC_INLINE bool crawstr_ends_with(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return n > rs.size ? false : !c_memcmp(rs.str + rs.size - n, str, n); +} + +/* utf8 iterator */ +STC_INLINE crawstr_iter crawstr_begin(const crawstr* self) { + if (!self->size) return c_LITERAL(crawstr_iter){.ref = NULL}; + return c_LITERAL(crawstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; +} +STC_INLINE crawstr_iter crawstr_end(const crawstr* self) { + (void)self; return c_LITERAL(crawstr_iter){.ref = NULL}; +} +STC_INLINE void crawstr_next(crawstr_iter* it) { + it->ref += it->u8.chr.size; + it->u8.chr.size = utf8_chr_size(it->ref); + if (!*it->ref) it->ref = NULL; +} +STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (!*it.ref) it.ref = NULL; + return it; +} + +/* utf8 size */ +STC_INLINE intptr_t crawstr_u8_size(crawstr rs) + { return utf8_size_n(rs.str, rs.size); } + +/* utf8 validation: depends on src/utf8code.c */ +STC_INLINE bool crawstr_valid_utf8(crawstr rs) + { return utf8_valid_n(rs.str, rs.size); } + +/* utf8 ignore case cmp: depends on src/utf8code.c */ +STC_INLINE int crawstr_icmp(const crawstr* x, const crawstr* y) + { return utf8_icmp_sv(c_sv_2(x->str, x->size), c_sv_2(y->str, y->size)); } + + +STC_INLINE int crawstr_cmp(const crawstr* x, const crawstr* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +STC_INLINE uint64_t crawstr_hash(const crawstr *self) + { return cfasthash(self->str, self->size); } + +#endif // CRAWSTR_H_INCLUDED +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 3aab3c8b..bce94b04 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -34,7 +34,7 @@ THE SOFTWARE. */ #include #include -#include "forward.h" // csubstr +#include "forward.h" // csview #include "ccommon.h" enum { @@ -82,7 +82,7 @@ typedef struct { typedef struct { const cregex* re; const char* input; - csubstr match[CREG_MAX_CAPTURES]; + csview match[CREG_MAX_CAPTURES]; } cregex_iter; #define c_formatch(it, Re, Input) \ @@ -115,11 +115,11 @@ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ #define cregex_find(...) c_MACRO_OVERLOAD(cregex_find, __VA_ARGS__) #define cregex_find_3(re, input, match) cregex_find_4(re, input, match, CREG_DEFAULT) -int cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags); +int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags); -/* find with csubstr as input. */ -STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) { - csubstr *mp = NULL; +/* find with csview as input. */ +STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { + csview *mp = NULL; if (match) { match[0] = input; mp = match; } return cregex_find(re, input.str, mp, CREG_STARTEND); } @@ -129,27 +129,27 @@ STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) #define cregex_find_pattern_3(pattern, input, match) \ cregex_find_pattern_4(pattern, input, match, CREG_DEFAULT) int cregex_find_pattern_4(const char* pattern, const char* input, - csubstr match[], int cmflags); + csview match[], int cmflags); STC_INLINE bool cregex_is_match(const cregex* re, const char* input) { return cregex_find_4(re, input, NULL, CREG_DEFAULT) == CREG_OK; } -/* replace csubstr input with replace using regular expression pattern */ -#define cregex_replace_ss(...) c_MACRO_OVERLOAD(cregex_replace_ss, __VA_ARGS__) -#define cregex_replace_ss_3(pattern, input, replace) \ - cregex_replace_ss_4(pattern, input, replace, INT32_MAX) -#define cregex_replace_ss_4(pattern, input, replace, count) \ - cregex_replace_ss_6(pattern, input, replace, count, NULL, CREG_DEFAULT) -cstr cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, - bool (*transform)(int group, csubstr match, cstr* result), int rflags); +/* replace csview input with replace using regular expression pattern */ +#define cregex_replace_sv(...) c_MACRO_OVERLOAD(cregex_replace_sv, __VA_ARGS__) +#define cregex_replace_sv_3(pattern, input, replace) \ + cregex_replace_sv_4(pattern, input, replace, INT32_MAX) +#define cregex_replace_sv_4(pattern, input, replace, count) \ + cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) +cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, + bool (*transform)(int group, csview match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) #define cregex_replace_3(re, input, replace) cregex_replace_4(re, input, replace, INT32_MAX) STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char* replace, int count) { - csubstr ss = {input, c_strlen(input)}; - return cregex_replace_ss_4(re, ss, replace, count); + csview sv = {input, c_strlen(input)}; + return cregex_replace_sv_4(re, sv, replace, count); } /* replace + compile RE pattern, and extra arguments */ @@ -159,7 +159,7 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*transform)(int group, csubstr match, cstr* result), int crflags); + bool (*transform)(int group, csview match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ce398628..7f4bad97 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -75,7 +75,7 @@ STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API intptr_t cstr_find_ss(const cstr* self, csubstr search); +STC_API intptr_t cstr_find_sv(const cstr* self, csview search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_uninit(cstr *self, intptr_t len); @@ -85,7 +85,7 @@ STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_ss(csubstr sv, csubstr search, csubstr repl, int32_t count); +STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { @@ -93,12 +93,12 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { ? c_LITERAL(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)} : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } -STC_INLINE csview cstr_sv(const cstr* s) { - return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) - : c_sv_2(s->sml.data, cstr_s_size(s)); +STC_INLINE crawstr cstr_rs(const cstr* s) { + return cstr_is_long(s) ? c_rs_2(s->lon.data, cstr_l_size(s)) + : c_rs_2(s->sml.data, cstr_s_size(s)); } -STC_INLINE csubstr cstr_ss(const cstr* s) - { csview sv = cstr_sv(s); return c_ss_2(sv.str, sv.size); } +STC_INLINE csview cstr_sv(const cstr* s) + { crawstr rs = cstr_rs(s); return c_sv_2(rs.str, rs.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -112,12 +112,12 @@ STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } -STC_INLINE cstr cstr_from_ss(csubstr sv) - { return cstr_from_n(sv.str, sv.size); } - STC_INLINE cstr cstr_from_sv(csview sv) { return cstr_from_n(sv.str, sv.size); } +STC_INLINE cstr cstr_from_rs(crawstr rs) + { return cstr_from_n(rs.str, rs.size); } + STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { cstr s; c_memset(_cstr_init(&s, size, size), value, size); @@ -144,8 +144,8 @@ STC_INLINE cstr cstr_move(cstr* self) { } STC_INLINE cstr cstr_clone(cstr s) { - csview sv = cstr_sv(&s); - return cstr_from_n(sv.str, sv.size); + crawstr rs = cstr_rs(&s); + return cstr_from_n(rs.str, rs.size); } STC_INLINE void cstr_drop(cstr* self) { @@ -175,9 +175,9 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_casefold_ss(csubstr sv); -extern cstr cstr_tolower_ss(csubstr sv); -extern cstr cstr_toupper_ss(csubstr sv); +extern cstr cstr_casefold_sv(csview sv); +extern cstr cstr_tolower_sv(csview sv); +extern cstr cstr_toupper_sv(csview sv); extern cstr cstr_tolower(const char* str); extern cstr cstr_toupper(const char* str); extern void cstr_lowercase(cstr* self); @@ -198,9 +198,9 @@ STC_INLINE intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx) STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { +STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); - csubstr sv; + csview sv; sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; @@ -209,9 +209,9 @@ STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { // utf8 iterator STC_INLINE cstr_iter cstr_begin(const cstr* self) { - csview sv = cstr_sv(self); - if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; - return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; + crawstr rs = cstr_rs(self); + if (!rs.size) return c_LITERAL(cstr_iter){.ref = NULL}; + return c_LITERAL(cstr_iter){.u8 = {{rs.str, utf8_chr_size(rs.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { (void)self; return c_LITERAL(cstr_iter){NULL}; @@ -241,7 +241,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) { return utf8_icmp(cstr_str(s1), cstr_str(s2)); } STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { - csview x = cstr_sv(s1), y = cstr_sv(s2); + crawstr x = cstr_rs(s1), y = cstr_rs(s2); return x.size == y.size && !c_memcmp(x.str, y.str, x.size); } @@ -249,7 +249,7 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } -STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) +STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } STC_INLINE bool cstr_equals_s(const cstr* self, cstr s) @@ -271,14 +271,14 @@ STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) STC_INLINE bool cstr_contains(const cstr* self, const char* search) { return strstr((char*)cstr_str(self), search) != NULL; } -STC_INLINE bool cstr_contains_ss(const cstr* self, csubstr search) - { return cstr_find_ss(self, search) != c_NPOS; } +STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) + { return cstr_find_sv(self, search) != c_NPOS; } STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) { return strstr((char*)cstr_str(self), cstr_str(&search)) != NULL; } -STC_INLINE bool cstr_starts_with_ss(const cstr* self, csubstr sub) { +STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { if (sub.size > cstr_size(self)) return false; return !c_memcmp(cstr_str(self), sub.str, sub.size); } @@ -290,43 +290,43 @@ STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { } STC_INLINE bool cstr_starts_with_s(const cstr* self, cstr sub) - { return cstr_starts_with_ss(self, cstr_ss(&sub)); } + { return cstr_starts_with_sv(self, cstr_sv(&sub)); } STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { - csubstr sv = cstr_ss(self); + csview sv = cstr_sv(self); intptr_t len = c_strlen(sub); - return len <= sv.size && !utf8_icmp_ss(sv, c_ss(sub, len)); + return len <= sv.size && !utf8_icmp_sv(sv, c_sv(sub, len)); } -STC_INLINE bool cstr_ends_with_ss(const cstr* self, csubstr sub) { - csview sv = cstr_sv(self); - if (sub.size > sv.size) return false; - return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); +STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { + crawstr rs = cstr_rs(self); + if (sub.size > rs.size) return false; + return !c_memcmp(rs.str + rs.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) - { return cstr_ends_with_ss(self, cstr_ss(&sub)); } + { return cstr_ends_with_sv(self, cstr_sv(&sub)); } STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) - { return cstr_ends_with_ss(self, c_ss(sub, c_strlen(sub))); } + { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { - csview sv = cstr_sv(self); + crawstr rs = cstr_rs(self); intptr_t n = c_strlen(sub); - return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); + return n <= rs.size && !utf8_icmp(rs.str + rs.size - n, sub); } STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_assign_ss(cstr* self, csubstr sv) +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); + crawstr rs = cstr_rs(&s); + return cstr_assign_n(self, rs.str, rs.size); } @@ -334,51 +334,51 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr) { return cstr_append_n(self, chr, utf8_chr_size(chr)); } STC_INLINE void cstr_pop(cstr* self) { - csview sv = cstr_sv(self); - const char* s = sv.str + sv.size; + crawstr rs = cstr_rs(self); + const char* s = rs.str + rs.size; while ((*--s & 0xC0) == 0x80) ; - _cstr_set_size(self, (s - sv.str)); + _cstr_set_size(self, (s - rs.str)); } STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_append_ss(cstr* self, csubstr sv) +STC_INLINE char* cstr_append_sv(cstr* self, csview sv) { return cstr_append_n(self, sv.str, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) - { return cstr_append_ss(self, cstr_ss(&s)); } + { return cstr_append_sv(self, cstr_sv(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, int32_t count) { - cstr_take(self, cstr_replace_ss(cstr_ss(self), c_ss(search, c_strlen(search)), - c_ss(repl, c_strlen(repl)), count)); + cstr_take(self, cstr_replace_sv(cstr_sv(self), c_sv(search, c_strlen(search)), + c_sv(repl, c_strlen(repl)), count)); } -STC_INLINE void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl) { +STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); c_memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) - { cstr_replace_at_ss(self, pos, len, c_ss(repl, c_strlen(repl))); } + { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } STC_INLINE void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl) - { cstr_replace_at_ss(self, pos, len, cstr_ss(&repl)); } + { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } -STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl) - { cstr_replace_at_ss(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } +STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl) + { cstr_replace_at_sv(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str) - { cstr_replace_at_ss(self, pos, 0, c_ss(str, c_strlen(str))); } + { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } -STC_INLINE void cstr_insert_ss(cstr* self, intptr_t pos, csubstr sv) - { cstr_replace_at_ss(self, pos, 0, sv); } +STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv) + { cstr_replace_at_sv(self, pos, 0, sv); } STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) - { cstr_replace_at_ss(self, pos, 0, cstr_ss(&s)); } + { cstr_replace_at_sv(self, pos, 0, cstr_sv(&s)); } STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -397,7 +397,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -static cstr cstr_tocase(csubstr sv, int k) { +static cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -418,26 +418,26 @@ static cstr cstr_tocase(csubstr sv, int k) { return out; } -cstr cstr_casefold_ss(csubstr sv) +cstr cstr_casefold_sv(csview sv) { return cstr_tocase(sv, 0); } -cstr cstr_tolower_ss(csubstr sv) +cstr cstr_tolower_sv(csview sv) { return cstr_tocase(sv, 1); } -cstr cstr_toupper_ss(csubstr sv) +cstr cstr_toupper_sv(csview sv) { return cstr_tocase(sv, 2); } cstr cstr_tolower(const char* str) - { return cstr_tolower_ss(c_ss(str, c_strlen(str))); } + { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } cstr cstr_toupper(const char* str) - { return cstr_toupper_ss(c_ss(str, c_strlen(str))); } + { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_ss(cstr_ss(self))); } + { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_ss(cstr_ss(self))); } + { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } @@ -449,14 +449,14 @@ bool cstr_valid_utf8(const cstr* self) #define CSTR_C_INCLUDED STC_DEF uint64_t cstr_hash(const cstr *self) { - csview sv = cstr_sv(self); - return cfasthash(sv.str, sv.size); + crawstr rs = cstr_rs(self); + return cfasthash(rs.str, rs.size); } -STC_DEF intptr_t cstr_find_ss(const cstr* self, csubstr search) { - csview sv = cstr_sv(self); - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; +STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { + crawstr rs = cstr_rs(self); + char* res = cstrnstrn(rs.str, search.str, rs.size, search.size); + return res ? (res - rs.str) : c_NPOS; } STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { @@ -530,10 +530,10 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { } STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { - csview sv = cstr_sv(self); - if (pos > sv.size) return c_NPOS; - const char* res = strstr((char*)sv.str + pos, search); - return res ? (res - sv.str) : c_NPOS; + crawstr rs = cstr_rs(self); + if (pos > rs.size) return c_NPOS; + const char* res = strstr((char*)rs.str + pos, search); + return res ? (res - rs.str) : c_NPOS; } STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { @@ -583,7 +583,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, int32_t count) { +STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h deleted file mode 100644 index c7a43052..00000000 --- a/include/stc/csubstr.h +++ /dev/null @@ -1,211 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 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. - */ -#define i_header // external linkage by default. override with i_static. -#define _i_inc_utf8 -#include "utf8.h" - -#ifndef CSUBSTR_H_INCLUDED -#define CSUBSTR_H_INCLUDED - -#define csubstr_init() c_ss_1("") -#define csubstr_drop(p) c_default_drop(p) -#define csubstr_clone(ss) c_default_clone(ss) -#define csubstr_from_n(str, n) c_ss_2(str, n) - -STC_API csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos); -STC_API intptr_t csubstr_find_ss(csubstr ss, csubstr search); -STC_API uint64_t csubstr_hash(const csubstr *self); -STC_API csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2); -STC_API csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); -STC_API csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); - -STC_INLINE csubstr csubstr_from(const char* str) - { return c_LITERAL(csubstr){str, c_strlen(str)}; } -STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } -STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } -STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } - -STC_INLINE bool csubstr_equals_ss(csubstr ss1, csubstr ss2) - { return ss1.size == ss2.size && !c_memcmp(ss1.str, ss2.str, ss1.size); } - -STC_INLINE bool csubstr_equals(csubstr ss, const char* str) - { return csubstr_equals_ss(ss, c_ss_2(str, c_strlen(str))); } - -STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) - { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } - -STC_INLINE bool csubstr_contains(csubstr ss, const char* str) - { return csubstr_find(ss, str) != c_NPOS; } - -STC_INLINE bool csubstr_starts_with(csubstr ss, const char* str) { - intptr_t n = c_strlen(str); - return n > ss.size ? false : !c_memcmp(ss.str, str, n); -} - -STC_INLINE bool csubstr_ends_with(csubstr ss, const char* str) { - intptr_t n = c_strlen(str); - return n > ss.size ? false : !c_memcmp(ss.str + ss.size - n, str, n); -} - -STC_INLINE csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n) { - if (pos + n > ss.size) n = ss.size - pos; - ss.str += pos, ss.size = n; - return ss; -} - -STC_INLINE csubstr csubstr_slice(csubstr ss, intptr_t p1, intptr_t p2) { - if (p2 > ss.size) p2 = ss.size; - ss.str += p1, ss.size = p2 > p1 ? p2 - p1 : 0; - return ss; -} - -/* utf8 iterator */ -STC_INLINE csubstr_iter csubstr_begin(const csubstr* self) { - if (!self->size) return c_LITERAL(csubstr_iter){NULL}; - return c_LITERAL(csubstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; -} -STC_INLINE csubstr_iter csubstr_end(const csubstr* self) { - return c_LITERAL(csubstr_iter){.u8 = {{NULL}, self->str + self->size}}; -} -STC_INLINE void csubstr_next(csubstr_iter* it) { - it->ref += it->u8.chr.size; - it->u8.chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; -} - -/* utf8 */ -STC_INLINE intptr_t csubstr_u8_size(csubstr ss) - { return utf8_size_n(ss.str, ss.size); } - -STC_INLINE csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len) { - ss.str += bytepos; - ss.size = utf8_pos(ss.str, u8len); - return ss; -} - -STC_INLINE bool csubstr_valid_utf8(csubstr ss) // depends on src/utf8code.c - { return utf8_valid_n(ss.str, ss.size); } - -#define c_fortoken_ss(it, inputss, sep) \ - for (struct { csubstr _inp, token, *ref; const char *_sep; intptr_t pos; } \ - it = {._inp=inputss, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csubstr_token(it._inp, it._sep, &it.pos)).str ; ) - -#define c_fortoken(it, input, sep) \ - c_fortoken_ss(it, csubstr_from(input), sep) - -/* ---- Container helper functions ---- */ - -STC_INLINE int csubstr_cmp(const csubstr* x, const csubstr* y) { - intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); - return c ? c : (int)(x->size - y->size); -} - -STC_INLINE int csubstr_icmp(const csubstr* x, const csubstr* y) - { return utf8_icmp_ss(*x, *y); } - -STC_INLINE bool csubstr_eq(const csubstr* x, const csubstr* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -#endif // CSUBSTR_H_INCLUDED - -/* csubstr interaction with cstr: */ -#ifdef CSTR_H_INCLUDED - -STC_INLINE csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n) - { return csubstr_substr(cstr_ss(self), pos, n); } - -STC_INLINE csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) - { return csubstr_slice(cstr_ss(self), p1, p2); } - -STC_INLINE csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) - { return csubstr_substr_ex(cstr_ss(self), pos, n); } - -STC_INLINE csubstr cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) - { return csubstr_slice_ex(cstr_ss(self), p1, p2); } - -STC_INLINE csubstr cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) - { return csubstr_u8_substr(cstr_ss(self), bytepos, u8len); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement || defined i_static -#ifndef CSUBSTR_C_INCLUDED -#define CSUBSTR_C_INCLUDED - -STC_DEF csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - -STC_DEF intptr_t csubstr_find_ss(csubstr ss, csubstr search) { - char* res = cstrnstrn(ss.str, search.str, ss.size, search.size); - return res ? (res - ss.str) : c_NPOS; -} - -STC_DEF uint64_t csubstr_hash(const csubstr *self) - { return cfasthash(self->str, self->size); } - -STC_DEF csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n) { - if (pos < 0) { - pos += ss.size; - if (pos < 0) pos = 0; - } - if (pos > ss.size) pos = ss.size; - if (pos + n > ss.size) n = ss.size - pos; - ss.str += pos, ss.size = n; - return ss; -} - -STC_DEF csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += ss.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += ss.size; - if (p2 > ss.size) p2 = ss.size; - ss.str += p1, ss.size = (p2 > p1 ? p2 - p1 : 0); - return ss; -} - -STC_DEF csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start) { - intptr_t sep_size = c_strlen(sep); - csubstr slice = {ss.str + *start, ss.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csubstr tok = {slice.str, res ? (res - slice.str) : slice.size}; - *start += tok.size + sep_size; - return tok; -} -#endif // CSUBSTR_C_INCLUDED -#endif // i_implement -#undef i_static -#undef i_header -#undef i_implement -#undef i_import -#undef i_opt diff --git a/include/stc/csview.h b/include/stc/csview.h index 367258e4..2a051ddd 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,33 +20,39 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#define csview_init() c_sv("") +#define csview_init() c_sv_1("") #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) +#define csview_from_n(str, n) c_sv_2(str, n) + +STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); +STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API uint64_t csview_hash(const csview *self); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) - { return c_sv_2(str, c_strlen(str)); } + { return c_LITERAL(csview){str, c_strlen(str)}; } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } -STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } - STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } -STC_INLINE bool csview_equals(csview sv, const char* str) { - intptr_t n = c_strlen(str); - return sv.size == n && !c_memcmp(sv.str, str, n); -} +STC_INLINE bool csview_equals_sv(csview sv1, csview sv2) + { return sv1.size == sv2.size && !c_memcmp(sv1.str, sv2.str, sv1.size); } -STC_INLINE intptr_t csview_find(csview sv, const char* search) { - char* res = cstrnstrn(sv.str, search, sv.size, c_strlen(search)); - return res ? (res - sv.str) : c_NPOS; -} +STC_INLINE bool csview_equals(csview sv, const char* str) + { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); } + +STC_INLINE intptr_t 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; } @@ -61,40 +67,55 @@ STC_INLINE bool csview_ends_with(csview sv, const char* str) { return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); } +STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + return sv; +} + /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { - if (!self->size) return c_LITERAL(csview_iter){.ref = NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; + if (!self->size) return c_LITERAL(csview_iter){NULL}; + return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, + self->str + self->size}}; } STC_INLINE csview_iter csview_end(const csview* self) { - (void)self; return c_LITERAL(csview_iter){.ref = NULL}; + return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; it->u8.chr.size = utf8_chr_size(it->ref); - if (!*it->ref) it->ref = NULL; -} -STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (!*it.ref) it.ref = NULL; - return it; + if (it->ref == it->u8.end) it->ref = NULL; } -/* utf8 size */ +/* utf8 */ STC_INLINE intptr_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -/* utf8 validation: depends on src/utf8code.c */ -STC_INLINE bool csview_valid_utf8(csview sv) +STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { + sv.str += bytepos; + sv.size = utf8_pos(sv.str, u8len); + return sv; +} + +STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } -/* utf8 ignore case cmp: depends on src/utf8code.c */ -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_ss(c_ss_2(x->str, x->size), c_ss_2(y->str, y->size)); } +#define c_fortoken_sv(it, inputsv, sep) \ + for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ + it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ + ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) +#define c_fortoken(it, input, sep) \ + c_fortoken_sv(it, csview_from(input), sep) + +/* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; @@ -102,13 +123,87 @@ STC_INLINE int csview_cmp(const csview* x, const csview* y) { return c ? c : (int)(x->size - y->size); } +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_sv(*x, *y); } + STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -STC_INLINE uint64_t csview_hash(const csview *self) +#endif // CSVIEW_H_INCLUDED + +/* csview interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n) + { return csview_substr(cstr_sv(self), pos, n); } + +STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) + { return csview_slice(cstr_sv(self), p1, p2); } + +STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t 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(cstr_sv(self), p1, p2); } + +STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) + { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } +#endif + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement || defined i_static +#ifndef CSVIEW_C_INCLUDED +#define CSVIEW_C_INCLUDED + +STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + +STC_DEF intptr_t csview_find_sv(csview sv, csview search) { + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; +} + +STC_DEF uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -#endif // CSVIEW_H_INCLUDED +STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { + if (pos < 0) { + pos += sv.size; + if (pos < 0) pos = 0; + } + if (pos > sv.size) pos = sv.size; + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += sv.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += sv.size; + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); + return sv; +} + +STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { + intptr_t sep_size = c_strlen(sep); + csview slice = {sv.str + *start, sv.size - *start}; + const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); + csview tok = {slice.str, res ? (res - slice.str) : slice.size}; + *start += tok.size + sep_size; + return tok; +} +#endif // CSVIEW_C_INCLUDED +#endif // i_implement #undef i_static #undef i_header #undef i_implement diff --git a/include/stc/forward.h b/include/stc/forward.h index 5c9c4f4d..839be012 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -39,21 +39,8 @@ #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) -// csubstr : non-null terminated string view -typedef const char csubstr_value; -typedef struct csubstr { - csubstr_value* str; - intptr_t size; -} csubstr; - -typedef union { - csubstr_value* ref; - struct { csubstr chr; csubstr_value* end; } u8; -} csubstr_iter; - - -// csview : null-terminated string view -typedef csubstr_value csview_value; +// csview : non-null terminated string view +typedef const char csview_value; typedef struct csview { csview_value* str; intptr_t size; @@ -61,10 +48,23 @@ typedef struct csview { typedef union { csview_value* ref; - struct { csubstr chr; } u8; + struct { csview chr; csview_value* end; } u8; } csview_iter; +// crawstr : null-terminated string view +typedef csview_value crawstr_value; +typedef struct crawstr { + crawstr_value* str; + intptr_t size; +} crawstr; + +typedef union { + crawstr_value* ref; + struct { csview chr; } u8; +} crawstr_iter; + + // cstr : null-terminated string (short string optimized - sso) typedef char cstr_value; typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; @@ -75,7 +75,7 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csubstr chr; } u8; + struct { csview chr; } u8; } cstr_iter; diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 47225ec8..65dee203 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -114,10 +114,10 @@ #endif #elif defined i_key_ssv #define i_keyclass cstr - #define i_rawclass csubstr - #define i_keyfrom cstr_from_ss - #define i_keyto cstr_ss - #define i_eq csubstr_eq + #define i_rawclass csview + #define i_keyfrom cstr_from_sv + #define i_keyto cstr_sv + #define i_eq csview_eq #ifndef i_tag #define i_tag ssv #endif @@ -232,9 +232,9 @@ #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr - #define i_valraw csubstr - #define i_valfrom cstr_from_ss - #define i_valto cstr_ss + #define i_valraw csview + #define i_valfrom cstr_from_sv + #define i_valto cstr_sv #elif defined i_valboxed #define i_valclass i_valboxed #define i_valraw c_PASTE(i_valboxed, _raw) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 7d2adee0..6d12856f 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -48,7 +48,7 @@ extern uint32_t utf8_toupper(uint32_t c); extern bool utf8_iscased(uint32_t c); extern bool utf8_isword(uint32_t c); extern bool utf8_valid_n(const char* s, intptr_t nbytes); -extern int utf8_icmp_ss(csubstr s1, csubstr s2); +extern int utf8_icmp_sv(csview s1, csview s2); extern int utf8_encode(char *out, uint32_t c); extern uint32_t utf8_peek_off(const char *s, int offset); @@ -92,7 +92,7 @@ STC_INLINE uint32_t utf8_peek(const char* s) { /* case-insensitive utf8 string comparison */ STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icmp_ss(c_ss(s1, INTPTR_MAX), c_ss(s2, INTPTR_MAX)); + return utf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); } STC_INLINE bool utf8_valid(const char* s) { diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index 9173d4b6..a5dfd901 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -7,16 +7,16 @@ #define i_implement #include // string #define i_implement -#include // string_view +#include // string_view #include #define i_key_str #include // vec of cstr with const char* lookup -#define i_type cvec_ss // override default type name (cvec_csubstr) -#define i_key csubstr -#define i_cmp csubstr_cmp -#include // cvec_vs: vec of csubstr +#define i_type cvec_sv // override default type name (cvec_csview) +#define i_key csview +#define i_cmp csview_cmp +#include // cvec_vs: vec of csview #define i_key_str #define i_val size_t @@ -24,7 +24,7 @@ #define i_key_ssv #define i_val size_t -#include // sorted map of cstr, csubstr lookup +#include // sorted map of cstr, csview lookup #define i_key_str #define i_val size_t @@ -32,7 +32,7 @@ #define i_key_ssv #define i_val size_t -#include // unordered map of cstr, csubstr lookup +#include // unordered map of cstr, csview lookup cvec_str read_file(const char* name) @@ -67,7 +67,7 @@ private: std::chrono::high_resolution_clock::time_point begin; }; -void initShortStringVec(cvec_str* vs, cvec_ss* vsv) +void initShortStringVec(cvec_str* vs, cvec_sv* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -101,14 +101,14 @@ void initShortStringVec(cvec_str* vs, cvec_ss* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_ss(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; std::cout << "avg str len: " << num / (float)cvec_sv_size(vsv) << std::endl; } -void initLongStringVec(cvec_str* vs, cvec_ss* vsv) +void initLongStringVec(cvec_str* vs, cvec_sv* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -147,7 +147,7 @@ void initLongStringVec(cvec_str* vs, cvec_ss* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_ss(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; @@ -175,7 +175,7 @@ void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, void benchmark( const cvec_str* vec_string, - const cvec_ss* vec_stringview, + const cvec_sv* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -187,7 +187,7 @@ const size_t MAX_LOOP = 2000; int main(void) { c_auto (cvec_str, vec_string) - c_auto (cvec_ss, vec_stringview) + c_auto (cvec_sv, vec_stringview) c_auto (csmap_str, mapTrans) c_auto (csmap_ssv, mapSview) c_auto (cmap_str, unordmapTrans) @@ -229,7 +229,7 @@ int main(void) void benchmark( const cvec_str* vec_string, - const cvec_ss* vec_stringview, + const cvec_sv* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -258,7 +258,7 @@ void benchmark( stopwatch.start("Trans Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_ss, *vec_stringview) + c_foreach (j, cvec_sv, *vec_stringview) { const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); if (v) @@ -286,7 +286,7 @@ void benchmark( stopwatch.start("Trans Unord Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_ss, *vec_stringview) + c_foreach (j, cvec_sv, *vec_stringview) { const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); if (v) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index d058660d..c1426045 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -2,7 +2,7 @@ #define i_import #include #define i_implement -#include +#include #include #define i_type IVec @@ -82,7 +82,7 @@ fn main() { } */ #define i_type SVec -#define i_keyclass csubstr +#define i_keyclass csview #include void demo3(void) @@ -94,11 +94,11 @@ void demo3(void) SVec words_containing_i = {0}; c_forfilter (w, SVec, words, - csubstr_contains(*w.ref, "i")) + csview_contains(*w.ref, "i")) SVec_push(&words_containing_i, *w.ref); c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SS(*w.ref)); + printf(" %.*s", c_SV(*w.ref)); puts(""); c_drop(SVec, &words, &words_containing_i); @@ -107,10 +107,10 @@ void demo3(void) void demo4(void) { // Keep only uppercase letters and convert them to lowercase: - csubstr s = c_ss("ab123cReAghNGnΩoEp"); // Ω = multi-byte + csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte cstr out = {0}; - c_forfilter (i, csubstr, s, utf8_isupper(utf8_peek(i.ref))) { + c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { char chr[4]; utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); cstr_push(&out, chr); diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c index 85890070..a798b1a1 100644 --- a/misc/examples/regularexpressions/regex2.c +++ b/misc/examples/regularexpressions/regex2.c @@ -27,7 +27,7 @@ int main(void) c_formatch (j, &re, s[i].input) { c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SS(j.match[k])); + printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); } } cregex_drop(&re); diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 6eaea781..11426d2d 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -1,7 +1,7 @@ #define i_import #include #define i_implement -#include +#include #define i_key float #include @@ -28,7 +28,7 @@ int main(void) printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_ss(&re, csubstr_from(str), " $0,", 0, NULL, CREG_STRIP); + cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f5fd8691..f1ea2711 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -1,8 +1,8 @@ #define i_import #include -#include +#include -bool add_10_years(int i, csubstr match, cstr* out) { +bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -47,7 +47,7 @@ int main(void) printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c index 3c41bd43..80013019 100644 --- a/misc/examples/strings/cstr_match.c +++ b/misc/examples/strings/cstr_match.c @@ -1,6 +1,6 @@ #define i_implement #include -#include +#include #include int main(void) @@ -16,11 +16,11 @@ int main(void) printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csubstr ch1 = cstr_u8_chr(&s1, 7); - csubstr ch2 = cstr_u8_chr(&s1, 10); + csview ch1 = cstr_u8_chr(&s1, 7); + csview ch2 = cstr_u8_chr(&s1, 10); printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SS(ch1)); - printf("ch2: %.*s\n", c_SS(ch2)); + printf("ch1: %.*s\n", c_SV(ch1)); + printf("ch2: %.*s\n", c_SV(ch2)); c_drop(cstr, &ss, &s1); } diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c index 2411f1a7..59a56bf7 100644 --- a/misc/examples/strings/replace.c +++ b/misc/examples/strings/replace.c @@ -20,13 +20,13 @@ int main(void) cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at_ss(&s, 19, 6, c_ss(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) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at_ss(&s, 8, 6, c_ss("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) diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c index 6fa76d34..ef7ed174 100644 --- a/misc/examples/strings/splitstr.c +++ b/misc/examples/strings/splitstr.c @@ -2,20 +2,20 @@ #define i_import // cstr + utf8 functions #include #define i_implement -#include +#include int main(void) { - puts("Split with c_fortoken (csubstr):"); + puts("Split with c_fortoken (csview):"); c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SS(i.token)); + printf("'%.*s'\n", c_SV(i.token)); puts("\nSplit with c_formatch (regex):"); cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SS(i.match[0])); + printf("'%.*s'\n", c_SV(i.match[0])); cregex_drop(&re); } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 2262e349..70d34440 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { cstr str = cstr_from("We think in generalities, but we live in details."); - csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" + csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" intptr_t pos = cstr_find(&str, "live"); // position of "live" - csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csubstr sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); + csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c index 6abbf5e7..ac275da0 100644 --- a/misc/examples/strings/sview_split.c +++ b/misc/examples/strings/sview_split.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { // No memory allocations or string length calculations! - const csubstr date = c_ss("2021/03/12"); + const csview date = c_sv("2021/03/12"); intptr_t pos = 0; - const csubstr year = csubstr_token(date, "/", &pos); - const csubstr month = csubstr_token(date, "/", &pos); - const csubstr day = csubstr_token(date, "/", &pos); + const csview year = csview_token(date, "/", &pos); + const csview month = csview_token(date, "/", &pos); + const csview day = csview_token(date, "/", &pos); - printf("%.*s, %.*s, %.*s\n", c_SS(year), c_SS(month), c_SS(day)); + printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); - cstr y = cstr_from_ss(year), m = cstr_from_ss(month), d = cstr_from_ss(day); + cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); c_drop(cstr, &y, &m, &d); } diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 03a0442f..1d54486f 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -10,12 +10,12 @@ int main(void) cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, - c_ss("🐨") + c_sv("🐨") ); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SS(c.u8.chr)); + printf("%.*s,", c_SV(c.u8.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 7cd03930..4e192de6 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,6 @@ #define i_import #include -#include +#include #include #include "ctest.h" @@ -14,7 +14,7 @@ CTEST(cregex, compile_match_char) cregex re = cregex_from("äsdf"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -32,7 +32,7 @@ CTEST(cregex, compile_match_anchors) cregex re = cregex_from(inp="^äs.f$"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -50,7 +50,7 @@ CTEST(cregex, compile_match_quantifiers1) re = cregex_from("ä+"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="ääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 4); @@ -70,7 +70,7 @@ CTEST(cregex, compile_match_quantifiers2) re = cregex_from("bä*"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="bääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -90,7 +90,7 @@ CTEST(cregex, compile_match_escaped_chars) cregex re = cregex_from("\\n\\r\\t\\{"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "\n\r\t", &match), CREG_NOMATCH); @@ -108,7 +108,7 @@ CTEST(cregex, compile_match_class_simple) re3 = cregex_from("\\D"); ASSERT_EQ(re3.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re1, " " , &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\r", &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\n", &match), CREG_OK); @@ -129,7 +129,7 @@ CTEST(cregex, compile_match_or) re = cregex_from("as|df"); ASSERT_EQ(re.error, 0); - csubstr match[4]; + csview match[4]; ASSERT_EQ(cregex_find(&re, "as", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "df", match), CREG_OK); @@ -146,7 +146,7 @@ CTEST(cregex, compile_match_class_complex_0) cregex re = cregex_from("[asdf]"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "s", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "d", &match), CREG_OK); @@ -160,7 +160,7 @@ CTEST(cregex, compile_match_class_complex_1) cregex re = cregex_from("[a-zä0-9öA-Z]"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "5", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "A", &match), CREG_OK); @@ -175,7 +175,7 @@ CTEST(cregex, compile_match_cap) cregex re = cregex_from("(abc)d"); ASSERT_EQ(re.error, 0); - csubstr match[4]; + csview match[4]; ASSERT_EQ(cregex_find(&re, "abcd", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "llljabcdkk", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "abc", match), CREG_NOMATCH); @@ -189,7 +189,7 @@ CTEST(cregex, search_all) c_auto (cregex, re) { re = cregex_from("ab"); - csubstr m = {0}; + csview m = {0}; int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; @@ -220,9 +220,9 @@ CTEST(cregex, captures_cap) re = cregex_from("(ab)((cd)+)"); ASSERT_EQ(cregex_captures(&re), 3); - csubstr cap[5]; + csview cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); - ASSERT_TRUE(csubstr_equals(cap[0], "abcdcd")); + ASSERT_TRUE(csview_equals(cap[0], "abcdcd")); ASSERT_EQ(M_END(cap[0]), 8); ASSERT_EQ(M_START(cap[1]), 2); @@ -235,7 +235,7 @@ CTEST(cregex, captures_cap) } } -static bool add_10_years(int i, csubstr match, cstr* out) { +static bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index c045b9f3..e6da66b2 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -100,7 +100,7 @@ typedef struct _Reprog /* * Sub expression matches */ -typedef csubstr _Resub; +typedef csview _Resub; /* * substitution list @@ -1215,8 +1215,8 @@ _regexec(const _Reprog *progp, /* program to run */ static void -_build_subst(const char* replace, int nmatch, const csubstr match[], - bool (*mfun)(int, csubstr, cstr*), cstr* subst) { +_build_subst(const char* replace, int nmatch, const csview match[], + bool (*mfun)(int, csview, cstr*), cstr* subst) { cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; @@ -1233,7 +1233,7 @@ _build_subst(const char* replace, int nmatch, const csubstr match[], if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } if (g < nmatch) { - csubstr m = mfun && mfun(g, match[g], &mstr) ? cstr_ss(&mstr) : match[g]; + csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) @@ -1270,7 +1270,7 @@ cregex_captures(const cregex* self) { } int -cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) { +cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; @@ -1281,7 +1281,7 @@ cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) int cregex_find_pattern_4(const char* pattern, const char* input, - csubstr match[], int cmflags) { + csview match[], int cmflags) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, cmflags); if (res != CREG_OK) return res; @@ -1291,16 +1291,16 @@ cregex_find_pattern_4(const char* pattern, const char* input, } cstr -cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, - bool (*mfun)(int, csubstr, cstr*), int rflags) { +cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, + bool (*mfun)(int, csview, cstr*), int rflags) { cstr out = cstr_init(); cstr subst = cstr_init(); - csubstr match[CREG_MAX_CAPTURES]; + csview match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_STRIP); - while (count-- && cregex_find_ss(re, input, match) == CREG_OK) { + while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); const intptr_t mpos = (match[0].str - input.str); if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); @@ -1308,19 +1308,19 @@ cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int co input.str = match[0].str + match[0].size; input.size -= mpos + match[0].size; } - if (copy) cstr_append_ss(&out, input); + if (copy) cstr_append_sv(&out, input); cstr_drop(&subst); return out; } cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int, csubstr, cstr*), int crflags) { + bool (*mfun)(int, csview, cstr*), int crflags) { cregex re = cregex_init(); if (cregex_compile(&re, pattern, crflags) != CREG_OK) assert(0); - csubstr ss = c_ss(input, c_strlen(input)); - cstr out = cregex_replace_ss(&re, ss, replace, count, mfun, crflags); + csview sv = c_sv(input, c_strlen(input)); + cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index b0d27350..462c97c4 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,7 +1,7 @@ #define i_import #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement -#include "../include/stc/csubstr.h" +#include "../include/stc/csview.h" #define i_implement #include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L diff --git a/src/singleupdate.sh b/src/singleupdate.sh index be99d4a7..8c2bba45 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -22,8 +22,8 @@ python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h -python singleheader.py $d/include/stc/csubstr.h $d/../stcsingle/stc/csubstr.h python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h +python singleheader.py $d/include/stc/crawstr.h $d/../stcsingle/stc/crawstr.h python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h python singleheader.py $d/include/stc/forward.h $d/../stcsingle/stc/forward.h diff --git a/src/utf8code.c b/src/utf8code.c index ddc4cb97..4abf10ea 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -101,7 +101,7 @@ uint32_t utf8_toupper(uint32_t c) { return c; } -int utf8_icmp_ss(const csubstr s1, const csubstr s2) { +int utf8_icmp_sv(const csview s1, const csview s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { -- cgit v1.2.3 From 80cd2adc2cd008aeee9f799f2dd5042f42b4ec82 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 30 Aug 2023 17:16:03 +0200 Subject: Smaller updates. --- include/stc/cspan.h | 20 ++++++---------- misc/benchmarks/various/cspan_bench.c | 43 ++++++++++++++++++----------------- misc/examples/spans/matmult.c | 22 +++++++++--------- src/libstc.c | 5 ++-- 4 files changed, 42 insertions(+), 48 deletions(-) (limited to 'src/libstc.c') diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 3f2b300f..e72bb97a 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -63,12 +63,6 @@ int demo2() { #include "priv/linkage.h" #include "ccommon.h" -#ifdef i_ndebug - #define cspan_assert(x) ((void)0) -#else - #define cspan_assert(x) c_assert(x) -#endif - #define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__) #define using_cspan_2(Self, T) \ using_cspan_3(Self, T, 1); \ @@ -91,7 +85,7 @@ int demo2() { const int rank, const int32_t a[][2]) { \ Self s; int outrank; \ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ - cspan_assert(outrank == RANK); \ + c_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ @@ -193,7 +187,7 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { intptr_t sz = shape[0]; - while (--rank > 0) sz *= shape[rank]; + while (--rank) sz *= shape[rank]; return sz; } @@ -207,14 +201,15 @@ STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { - cspan_assert(c_LTu(a[rank], shape[rank])); + c_assert(c_LTu(a[rank], shape[rank])); off += stride[rank]*a[rank]; } return off; } -STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); #define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) +STC_API intptr_t + _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -270,13 +265,13 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { - case 0: cspan_assert(c_LTu(a[i][0], shape[i])); continue; + case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; default: end = a[i][1]; } oshape[oi] = end - a[i][0]; ostride[oi] = stride[i]; - cspan_assert(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); + c_assert((oshape[oi] > 0) & !c_LTu(shape[i], end)); ++oi; } *orank = oi; @@ -284,7 +279,6 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, } #endif -#undef i_ndebug #undef i_opt #undef i_header #undef i_implement diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index 3b1c3132..bfc0ead3 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -42,7 +42,7 @@ static void Traditional_for_loop(intptr_t n) printf("forloop : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } -static void MDRanges_nested_loop(intptr_t n) +static void MDRanges_loop_over_joined(intptr_t n) { clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); @@ -52,22 +52,20 @@ static void MDRanges_nested_loop(intptr_t n) double sum = 0; for (intptr_t s = 0; s < n; ++s) { - for (int x = 0; x < r_in.shape[0]; ++x) { - for (int y = 0; y < r_in.shape[1]; ++y) { - for (int z = 0; z < r_in.shape[2]; ++z) - { - double d = *cspan_at(&r_in, x,y,z); - *cspan_at(&r_out, x,y,z) += d; - sum += d; - } - } + MD3_iter i = MD3_begin(&r_in); + MD3_iter o = MD3_begin(&r_out); + + for (; i.ref; MD3_next(&i), MD3_next(&o)) + { + *o.ref += *i.ref; + sum += *i.ref; } } t = clock() - t; - printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); + printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } -static void MDRanges_loop_over_joined(intptr_t n) +static void MDRanges_nested_loop(intptr_t n) { clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); @@ -77,19 +75,22 @@ static void MDRanges_loop_over_joined(intptr_t n) double sum = 0; for (intptr_t s = 0; s < n; ++s) { - MD3_iter i = MD3_begin(&r_in); - MD3_iter o = MD3_begin(&r_out); - - for (; i.ref; MD3_next(&i), MD3_next(&o)) - { - *o.ref += *i.ref; - sum += *i.ref; + for (int x = 0; x < r_in.shape[0]; ++x) { + for (int y = 0; y < r_in.shape[1]; ++y) { + for (int z = 0; z < r_in.shape[2]; ++z) + { + double d = *cspan_at(&r_in, x,y,z); + *cspan_at(&r_out, x,y,z) += d; + sum += d; + } + } } } t = clock() - t; - printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); + printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } + int main(void) { intptr_t n = 100000; @@ -97,6 +98,6 @@ int main(void) Vin[i] = i + 1.23; Traditional_for_loop(n); - MDRanges_nested_loop(n); MDRanges_loop_over_joined(n); + MDRanges_nested_loop(n); } diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c index 266fa121..ec992ff9 100644 --- a/misc/examples/spans/matmult.c +++ b/misc/examples/spans/matmult.c @@ -37,7 +37,7 @@ void base_case_matrix_product(Mat2 A, Mat2 B, OutMat C) void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C) { // Some hardware-dependent constant - enum {recursion_threshold = 16}; + enum {recursion_threshold = 32}; if (C.shape[0] <= recursion_threshold || C.shape[1] <= recursion_threshold) { base_case_matrix_product(A, B, C); } else { @@ -63,28 +63,28 @@ void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C) int main(void) { - enum {N = 10, D1 = 256, D2 = D1}; + enum {N = 10, D = 256}; Values values = {0}; - for (int i=0; i < N*D1*D2; ++i) + for (int i=0; i < N*D*D; ++i) Values_push(&values, (crandf() - 0.5)*4.0); - double out[D1*D2]; - Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D1, D2); - OutMat c = cspan_md_layout(c_ROWMAJOR, out, D1, D2); + double out[D*D]; + Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D, D); + OutMat c = cspan_md_layout(c_COLMAJOR, out, D, D); Mat2 a = cspan_submd3(&data, 0); - double sum = 0.0; - clock_t t = clock(); + clock_t t = clock(); for (int i=1; i= 201112L -# define i_implement # include "../include/c11/fmt.h" #endif -- cgit v1.2.3