#include #include #include #include #include "apfl.h" #include "internal.h" #include "resizable.h" struct apfl_refcounted_string_data { unsigned refcount; struct apfl_string string; }; struct apfl_string_view apfl_string_view_from_view(struct apfl_string_view view) { return view; } struct apfl_string_view apfl_string_view_from_cstr(char *cstr) { return (struct apfl_string_view) { .bytes = cstr, .len = strlen(cstr), }; } struct apfl_string_view apfl_string_view_from_const_cstr(const char *cstr) { return (struct apfl_string_view) { .bytes = cstr, .len = strlen(cstr), }; } struct apfl_string_view apfl_string_view_from_string(struct apfl_string string) { return (struct apfl_string_view) { .bytes = string.bytes, .len = string.len, }; } int apfl_string_view_cmp(struct apfl_string_view a, struct apfl_string_view b) { size_t n = a.len > b.len ? b.len : a.len; int cmp = memcmp(a.bytes, b.bytes, n); if (cmp != 0) { return cmp; } if (a.len == b.len) { return 0; } return a.len > b.len ? 1 : -1; } struct apfl_string apfl_string_blank(void) { return (struct apfl_string) { .bytes = NULL, .len = 0, }; } void apfl_string_deinit(struct apfl_string *string) { free(string->bytes); *string = apfl_string_blank(); } bool apfl_string_copy(struct apfl_string *dst, struct apfl_string_view src) { apfl_string_deinit(dst); if ((dst->bytes = malloc(src.len)) == NULL) { return false; } memcpy(dst->bytes, src.bytes, src.len); dst->len = src.len; return true; } struct apfl_string apfl_string_move(struct apfl_string *src) { struct apfl_string out = *src; *src = apfl_string_blank(); return out; } void apfl_string_builder_init(struct apfl_string_builder *builder) { apfl_resizable_init((void **)&(builder->bytes), &(builder->len), &(builder->cap)); } void apfl_string_builder_deinit(struct apfl_string_builder *builder) { free(builder->bytes); apfl_string_builder_init(builder); } static bool append_bytes(struct apfl_string_builder *builder, const char *bytes, size_t len) { return apfl_resizable_append( sizeof(char), APFL_RESIZABLE_ARGS(*builder, bytes), bytes, len ); } bool apfl_string_builder_append(struct apfl_string_builder *builder, struct apfl_string_view view) { return append_bytes(builder, view.bytes, view.len); } bool apfl_string_builder_append_byte(struct apfl_string_builder *builder, char byte) { return append_bytes(builder, &byte, 1); } struct apfl_string apfl_string_builder_move_string(struct apfl_string_builder *builder) { struct apfl_string str; str.bytes = builder->bytes; str.len = builder->len; apfl_string_builder_init(builder); return str; } struct apfl_string_view apfl_string_view_from_refcounted_string(apfl_refcounted_string rcstring) { if (rcstring == NULL) { return apfl_string_view_from(apfl_string_blank()); } return apfl_string_view_from(rcstring->string); } apfl_refcounted_string apfl_string_copy_into_new_refcounted(struct apfl_string_view sv) { struct apfl_string str = apfl_string_blank(); if (!apfl_string_copy(&str, sv)) { return NULL; } apfl_refcounted_string rcstring = apfl_string_move_into_new_refcounted(&str); if (rcstring == NULL) { apfl_string_deinit(&str); return NULL; } return rcstring; } apfl_refcounted_string apfl_string_move_into_new_refcounted(struct apfl_string *src) { apfl_refcounted_string dst = ALLOC(struct apfl_refcounted_string_data); if (dst == NULL) { // TODO: Or should we free src here? return NULL; } *dst = (struct apfl_refcounted_string_data) { .refcount = 1, .string = apfl_string_move(src), }; return dst; } apfl_refcounted_string apfl_refcounted_string_incref(apfl_refcounted_string rcstring) { if (rcstring != NULL) { rcstring->refcount++; } return rcstring; } void apfl_refcounted_string_unref(apfl_refcounted_string rcstring) { if (rcstring != NULL && apfl_refcount_dec(&rcstring->refcount)) { apfl_string_deinit(&rcstring->string); free(rcstring); } } void apfl_refcounted_string_unref_ptr(apfl_refcounted_string *rcstring_ptr) { apfl_refcounted_string_unref(*rcstring_ptr); *rcstring_ptr = NULL; }