#include #include #include #include #include #include #include "apfl.h" #include "alloc.h" #include "gc.h" #include "resizable.h" #include "strings.h" 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, .cap = 0 }; } void apfl_string_deinit(struct apfl_allocator allocator, struct apfl_string *string) { FREE_BYTES(allocator, string->bytes, string->cap); *string = apfl_string_blank(); } bool apfl_string_copy(struct apfl_allocator allocator, struct apfl_string *dst, struct apfl_string_view src) { apfl_string_deinit(allocator, dst); if ((dst->bytes = ALLOC_BYTES(allocator, src.len)) == NULL) { return false; } memcpy(dst->bytes, src.bytes, src.len); dst->len = src.len; dst->cap = 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; } static void builder_reset(struct apfl_string_builder *builder) { apfl_resizable_init((void **)&(builder->bytes), &(builder->len), &(builder->cap)); } struct apfl_string_builder apfl_string_builder_init(struct apfl_allocator allocator) { struct apfl_string_builder builder; builder.allocator = allocator; builder_reset(&builder); return builder; } void apfl_string_builder_deinit(struct apfl_string_builder *builder) { FREE_BYTES(builder->allocator, builder->bytes, builder->cap); builder_reset(builder); } bool apfl_string_builder_append_bytes(struct apfl_string_builder *builder, const char *bytes, size_t len) { return apfl_resizable_append( builder->allocator, sizeof(char), APFL_RESIZABLE_ARGS(*builder, bytes), bytes, len ); } bool apfl_string_builder_prealloc(struct apfl_string_builder *builder, size_t newcap) { return apfl_resizable_ensure_cap( builder->allocator, sizeof(char), (void **)&builder->bytes, &builder->cap, newcap ); } bool apfl_string_builder_append(struct apfl_string_builder *builder, struct apfl_string_view view) { return apfl_string_builder_append_bytes(builder, view.bytes, view.len); } bool apfl_string_builder_append_byte(struct apfl_string_builder *builder, char byte) { return apfl_string_builder_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; str.cap = builder->cap; builder_reset(builder); return str; } struct apfl_string * apfl_string_move_into_new_gc_string(struct gc *gc, struct apfl_string *in) { struct apfl_string *str = apfl_gc_new_string(gc); if (str == NULL) { return NULL; } *str = apfl_string_move(in); return str; } struct apfl_string_view apfl_string_view_offset(struct apfl_string_view sv, size_t off) { if (off >= sv.len) { return (struct apfl_string_view) { .bytes = NULL, .len = 0, }; } sv.bytes += off; sv.len -= off; return sv; } struct apfl_string_view apfl_string_view_trunc(struct apfl_string_view sv, size_t newlen) { if (newlen < sv.len) { sv.len = newlen; } return sv; } struct apfl_string_view apfl_string_view_substr(struct apfl_string_view sv, size_t off, size_t newlen) { sv = apfl_string_view_offset(sv, off); sv = apfl_string_view_trunc(sv, newlen); return sv; } ptrdiff_t apfl_string_view_search(const struct apfl_string_view haystack, const struct apfl_string_view needle) { // TODO: This is not very efficient. Use a faster algorithm here. if (needle.len == 0) { return 0; } if (needle.len > haystack.len || haystack.len == 0) { return -1; } size_t lim = haystack.len - needle.len; if (lim > PTRDIFF_MAX) { return -1; } for (size_t i = 0; i <= lim; i++) { if (memcmp(haystack.bytes + i, needle.bytes, needle.len) == 0) { return (ptrdiff_t)i; } } return -1; } struct apfl_string_view apfl_string_view_ltrim(struct apfl_string_view sv) { while (sv.len > 0 && isspace(sv.bytes[0])) { sv.len--; sv.bytes++; } return sv; } struct apfl_string_view apfl_string_view_rtrim(struct apfl_string_view sv) { while (sv.len > 0 && isspace(sv.bytes[sv.len - 1])) { sv.len--; } return sv; } struct apfl_string_view apfl_string_view_trim(struct apfl_string_view sv) { return apfl_string_view_ltrim(apfl_string_view_rtrim(sv)); }