libguf/src/guf_str.h
2025-12-23 14:11:04 +01:00

143 lines
5.1 KiB
C

#ifndef GUF_STR_H
#define GUF_STR_H
#include "guf_common.h"
#include "guf_alloc.h"
#if defined(GUF_STATIC) || defined(GUF_IMPL_STATIC)
#define GUF_FN_KEYWORDS static
#else
#define GUF_FN_KEYWORDS
#endif
typedef enum guf_str_state {
GUF_STR_STATE_INIT = 0,
GUF_STR_STATE_SHORT = 1,
GUF_STR_STATE_VIEW = 2,
GUF_STR_STATE_ALLOC_ERR = 4
} guf_str_state;
typedef struct guf_str {
union {
struct heap {
char *c_str;
size_t len, capacity; // len and capacity do not include the null-terminator.
} heap;
struct stack { // Short-string optimisation.
#define GUF_STR_SSO_BUFSIZE (sizeof(struct heap) - sizeof(unsigned char))
#define GUF_STR_SSO_BUFCAP (GUF_STR_SSO_BUFSIZE - 1)
char c_str[GUF_STR_SSO_BUFSIZE];
unsigned char len;
} stack;
} data;
guf_allocator *allocator;
guf_str_state state;
} guf_str;
typedef struct guf_str_view {
const char *str;
ptrdiff_t len;
} guf_str_view;
#define GUF_CSTR_TO_VIEW(CSTR) ((guf_str_view){.str = (CSTR), .len = strlen((CSTR))})
#define GUF_STR_TO_VIEW(GUF_STR_PTR) ((guf_str_view){.str = guf_str_const_cstr((GUF_STR_PTR)), .len = guf_str_len((GUF_STR_PTR))})
#define GUF_CSTR_TO_READONLY_STR(CSTR) ((guf_str){.state = GUF_STR_STATE_VIEW, .allocator = NULL, .data.heap.c_str = CSTR, .data.heap.len = strlen(CSTR), .data.heap.capacity = 0})
// Creation:
GUF_FN_KEYWORDS guf_str *guf_str_init(guf_str *str, guf_str_view str_view);
GUF_FN_KEYWORDS guf_str *guf_str_init_from_cstr(guf_str *str, const char* c_str);
GUF_FN_KEYWORDS guf_str *guf_str_init_empty_with_capacity(guf_str *str, size_t capacity);
// guf_str_new functions return GUF_DICT_UNINITIALISED or GUF_STR_UNINITIALISED_FAILED_ALLOC on failure (can be checked with guf_str_alloc_success)
GUF_FN_KEYWORDS guf_str guf_str_new(guf_str_view str_view);
GUF_FN_KEYWORDS guf_str guf_str_new_substr(guf_str_view str_view, ptrdiff_t pos, ptrdiff_t len);
GUF_FN_KEYWORDS guf_str guf_str_new_from_cstr(const char *c_str);
GUF_FN_KEYWORDS guf_str guf_str_new_empty_with_capacity(size_t capacity);
// Destruction:
GUF_FN_KEYWORDS void guf_str_free(guf_str *str);
// Modification:
GUF_FN_KEYWORDS guf_str *guf_str_append(guf_str *str, guf_str_view to_append);
GUF_FN_KEYWORDS guf_str *guf_str_append_cstr(guf_str *str, const char *cstr_to_append); // Not necessary
GUF_FN_KEYWORDS guf_str *guf_str_substr(guf_str* str, size_t pos, size_t count);
GUF_FN_KEYWORDS guf_str *guf_str_reserve(guf_str *str, size_t bufsize);
GUF_FN_KEYWORDS guf_str *guf_str_shrink_capacity(guf_str *str, size_t shrink_trigger_fac, bool shrink_exact);
GUF_FN_KEYWORDS char guf_str_pop_back(guf_str *str);
GUF_FN_KEYWORDS char guf_str_pop_front(guf_str *str);
// Copying and viewing:
GUF_FN_KEYWORDS guf_str guf_str_substr_cpy(guf_str_view str, size_t pos, size_t count); // not necessary
GUF_FN_KEYWORDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count);
// Indexing:
GUF_FN_KEYWORDS char *guf_str_at(guf_str *str, size_t idx);
GUF_FN_KEYWORDS char *guf_str_back(guf_str *str);
GUF_FN_KEYWORDS char *guf_str_front(guf_str *str);
GUF_FN_KEYWORDS const char *guf_str_const_cstr(const guf_str *str);
// Metadata retrieval:
GUF_FN_KEYWORDS size_t guf_str_len(const guf_str *str); // The size (in chars) without the final zero-terminator (size - 1).
GUF_FN_KEYWORDS size_t guf_str_capacity(const guf_str *str);
GUF_FN_KEYWORDS bool guf_str_is_stack_allocated(const guf_str *str);
GUF_FN_KEYWORDS bool guf_str_is_valid(const guf_str *str);
GUF_FN_KEYWORDS bool guf_str_alloc_success(const guf_str *str);
// Comparison:
GUF_FN_KEYWORDS bool guf_str_view_equal(const guf_str_view* a, const guf_str_view* b);
GUF_FN_KEYWORDS bool guf_str_equal(const guf_str *a, const guf_str *b);
GUF_FN_KEYWORDS bool guf_str_equals_cstr(const guf_str *a, const char *c_str);
GUF_FN_KEYWORDS bool guf_str_equals_strview(const guf_str *a, guf_str_view b);
GUF_FN_KEYWORDS int guf_str_view_cmp(const void *str_view_a, const void *str_view_b); // For qsort etc.
#endif
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
#include <string.h>
#ifndef GUF_FN_KEYWORDS
#define GUF_FN_KEYWORDS
#endif
// TODO: find_first_of and tokenise -> for parsing, see aoclib.
GUF_FN_KEYWORDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count)
{
GUF_ASSERT(str.str);
GUF_ASSERT(pos >= 0);
GUF_ASSERT(count >= 0);
if (str.len == 0 || count == 0 || pos >= str.len || str.str == NULL) {
return (guf_str_view){.str = str.str, .len = 0};
}
const ptrdiff_t substr_len = pos + count > str.len ? str.len - pos : count;
GUF_ASSERT(substr_len >= 0);
GUF_ASSERT(substr_len <= str.len);
return (guf_str_view){.str = str.str + pos, .len = substr_len};
}
// Comparison:
GUF_FN_KEYWORDS bool guf_str_view_equal(const guf_str_view* a, const guf_str_view* b)
{
GUF_ASSERT_RELEASE(a && b);
GUF_ASSERT_RELEASE(a->str && b->str);
if (a->len != b->len) {
return false;
}
GUF_ASSERT_RELEASE(a->len >= 0);
return 0 == memcmp(a->str, b->str, a->len);
}
#undef GUF_IMPL
#undef GUF_IMPL_STATIC
#undef GUF_STATIC
#undef GUF_FN_KEYWORDS
#endif /* end impl */