diff --git a/src/guf_str.h b/src/guf_str.h index 3f67e63..f678ae0 100644 --- a/src/guf_str.h +++ b/src/guf_str.h @@ -90,15 +90,13 @@ GUF_STR_KWRDS void guf_str_free(guf_str *str, void *ctx); GUF_STR_KWRDS guf_str *guf_str_copy(guf_str *dst, const guf_str *src, void *ctx); GUF_STR_KWRDS guf_str *guf_str_move(guf_str *dst, guf_str *src, void *ctx); +GUF_STR_KWRDS bool guf_str_equal(const guf_str *a, const guf_str *b); +GUF_STR_KWRDS int guf_str_cmp(const guf_str *a, const guf_str *b); + // TODO: GUF_STR_KWRDS guf_str guf_str_try_new_substr(guf_str_view str_view, ptrdiff_t pos, ptrdiff_t len, guf_allocator *alloc, guf_err *err); GUF_STR_KWRDS guf_str guf_str_new_substr(guf_str_view str_view, ptrdiff_t pos, ptrdiff_t len, guf_allocator *alloc); -// TODO: -GUF_STR_KWRDS bool guf_str_equal(const guf_str *a, const guf_str *b); -GUF_STR_KWRDS bool guf_str_equals_cstr(const guf_str *a, const char *c_str); -GUF_STR_KWRDS bool guf_str_equals_strview(const guf_str *a, guf_str_view b); - // DONE: GUF_STR_KWRDS guf_str *guf_str_try_append_char(guf_str *str, char c, ptrdiff_t times, guf_err *err); GUF_STR_KWRDS guf_str *guf_str_append_char(guf_str *str, char c, ptrdiff_t times); @@ -363,7 +361,7 @@ GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t new_cap_min, if (guf_str_is_short_internal_(str)) { // a.) Was short string -> need initial allocation. char *c_str_new = str->allocator->alloc(new_cap_min_with_null, str->allocator->ctx); if (!c_str_new) { - guf_err_set_or_panic(err, GUF_ERR_ALLOC_FAIL, "in guf_str_try_grow_if_necessary: Initial allocation failed."); + guf_err_set_or_panic(err, GUF_ERR_ALLOC_FAIL, "in guf_str_try_reserve: Initial allocation failed."); return NULL; } memcpy(c_str_new, str->data.shrt.c_str, len_with_null); @@ -372,7 +370,7 @@ GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t new_cap_min, } else { // b) Was long string -> need re-allocation char *c_str_new = str->allocator->realloc(str->data.lng.c_str, old_cap_with_null, new_cap_min_with_null, str->allocator->ctx); if (!c_str_new) { - guf_err_set_or_panic(err, GUF_ERR_ALLOC_FAIL, "in guf_str_try_grow_if_necessary: re-allocation failed."); + guf_err_set_or_panic(err, GUF_ERR_ALLOC_FAIL, "in guf_str_try_reserve: re-allocation failed."); return NULL; } str->data.lng.c_str = c_str_new; @@ -557,7 +555,8 @@ GUF_STR_KWRDS guf_str *guf_str_copy(guf_str *dst, const guf_str *src, void *ctx) (void)ctx; GUF_ASSERT_RELEASE(dst); GUF_ASSERT_RELEASE(guf_str_is_valid(src)); - + GUF_ASSERT_RELEASE(!guf_str_is_readonly(src)); // // Doesn't make sense to deep-cpy in readonly mode (I think). + guf_str_init_empty(dst, src->allocator); GUF_ASSERT(guf_str_is_short_internal_(dst)); @@ -593,13 +592,40 @@ GUF_STR_KWRDS guf_str *guf_str_move(guf_str *dst, guf_str *src, void *ctx) (void)ctx; GUF_ASSERT_RELEASE(dst); GUF_ASSERT_RELEASE(guf_str_is_valid(src)); + GUF_ASSERT_RELEASE(!guf_str_is_readonly(src)); // Doesn't make sense to move in readonly mode (I think). + *dst = *src; *src = guf_str_new_uninitialised(); return dst; } +GUF_STR_KWRDS bool guf_str_equal(const guf_str *a, const guf_str *b) +{ + GUF_ASSERT_RELEASE(guf_str_is_valid(a) && guf_str_is_valid(b)); + if (guf_str_len(a) != guf_str_len(b)) { + return false; + } + const char *a_cstr = guf_str_const_cstr(a); + const char *b_cstr = guf_str_const_cstr(b); + GUF_ASSERT(a_cstr && b_cstr); + return 0 == memcmp(a_cstr, b_cstr, guf_str_len(a)); +} + +GUF_STR_KWRDS int guf_str_cmp(const guf_str *a, const guf_str *b) +{ + GUF_ASSERT_RELEASE(guf_str_is_valid(a) && guf_str_is_valid(b)); + GUF_ASSERT_RELEASE(guf_str_is_valid(a) && guf_str_is_valid(b)); + + + const ptrdiff_t shorter_len = guf_min_ptrdiff_t(guf_str_len(a), guf_str_len(b)); + const char *a_cstr = guf_str_const_cstr(a); + const char *b_cstr = guf_str_const_cstr(b); + GUF_ASSERT(a_cstr && b_cstr); + + return memcmp(a_cstr, b_cstr, shorter_len); +} GUF_STR_KWRDS guf_str *guf_str_try_append_char(guf_str *str, char c, ptrdiff_t times, guf_err *err) { @@ -622,8 +648,9 @@ GUF_STR_KWRDS guf_str *guf_str_try_append_char(guf_str *str, char c, ptrdiff_t t const size_t old_cap = guf_str_cap_internal_(str); const size_t old_len = guf_str_len_internal_(str); + const size_t new_len = old_len + (size_t)times; - if (new_len <= old_len || new_len > (size_t)PTRDIFF_MAX) { // Handle overflow. + if (new_len <= old_len || new_len >= (size_t)PTRDIFF_MAX) { // Handle overflow. guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_char: new length would overflow ptrdiff_t"); return NULL; } else if (new_len > old_cap) { // Need to grow capacity. @@ -686,7 +713,7 @@ GUF_STR_KWRDS guf_str *guf_str_try_append(guf_str *str, guf_str_view sv, guf_err const size_t old_cap = guf_str_cap_internal_(str); const size_t old_len = guf_str_len_internal_(str); const size_t new_len = old_len + (size_t)sv.len; - if (new_len <= old_len || new_len > (size_t)PTRDIFF_MAX) { // Handle overflow. + if (new_len <= old_len || new_len >= (size_t)PTRDIFF_MAX) { // Handle overflow. guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_view: new length would overflow ptrdiff_t"); return NULL; } else if (new_len > old_cap) { // Growth necessary. @@ -739,7 +766,11 @@ GUF_STR_KWRDS guf_str *guf_str_try_append_cstr(guf_str *str, const char *c_str, GUF_ASSERT(len <= cap); if (len == cap) { // Grow if necessary. - guf_str_try_reserve(str, cap < PTRDIFF_MAX ? cap + 1 : PTRDIFF_MAX, err); + if (cap == PTRDIFF_MAX) { + guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_cstr: cannot grow (capacity is PTRDIFF_MAX)"); + return NULL; + } + guf_str_try_reserve(str, cap + 1, err); if (err && *err != GUF_ERR_NONE) { guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_cstr: failed to reserve"); return NULL;