apfl/src/strings.c

256 lines
5.3 KiB
C
Raw Normal View History

#include <ctype.h>
2021-12-10 20:22:16 +00:00
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
2021-12-10 20:22:16 +00:00
#include <stdlib.h>
#include <string.h>
#include "apfl.h"
#include "alloc.h"
#include "gc.h"
2021-12-10 20:22:16 +00:00
#include "resizable.h"
2022-04-22 21:17:28 +00:00
#include "strings.h"
2021-12-10 20:22:16 +00:00
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
};
}
2021-12-10 20:22:16 +00:00
void
apfl_string_deinit(struct apfl_allocator allocator, struct apfl_string *string)
2021-12-10 20:22:16 +00:00
{
FREE_BYTES(allocator, string->bytes, string->cap);
*string = apfl_string_blank();
2021-12-10 20:22:16 +00:00
}
bool
apfl_string_copy(struct apfl_allocator allocator, struct apfl_string *dst, struct apfl_string_view src)
2021-12-10 20:22:16 +00:00
{
apfl_string_deinit(allocator, dst);
if ((dst->bytes = ALLOC_BYTES(allocator, src.len)) == NULL) {
2021-12-10 20:22:16 +00:00
return false;
}
memcpy(dst->bytes, src.bytes, src.len);
dst->len = src.len;
dst->cap = src.len;
2021-12-10 20:22:16 +00:00
return true;
}
struct apfl_string
apfl_string_move(struct apfl_string *src)
{
struct apfl_string out = *src;
*src = apfl_string_blank();
2021-12-10 20:22:16 +00:00
return out;
}
static void
builder_reset(struct apfl_string_builder *builder)
2021-12-10 20:22:16 +00:00
{
apfl_resizable_init((void **)&(builder->bytes), &(builder->len), &(builder->cap));
}
void
apfl_string_builder_init(struct apfl_allocator allocator, struct apfl_string_builder *builder)
{
builder->allocator = allocator;
builder_reset(builder);
}
2021-12-10 20:22:16 +00:00
void
apfl_string_builder_deinit(struct apfl_string_builder *builder)
{
FREE_BYTES(builder->allocator, builder->bytes, builder->cap);
builder_reset(builder);
2021-12-10 20:22:16 +00:00
}
bool
apfl_string_builder_append_bytes(struct apfl_string_builder *builder, const char *bytes, size_t len)
2021-12-10 20:22:16 +00:00
{
return apfl_resizable_append(
builder->allocator,
2021-12-10 20:22:16 +00:00
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 apfl_string_builder_append_bytes(builder, view.bytes, view.len);
2021-12-10 20:22:16 +00:00
}
bool
apfl_string_builder_append_byte(struct apfl_string_builder *builder, char byte)
{
return apfl_string_builder_append_bytes(builder, &byte, 1);
2021-12-10 20:22:16 +00:00
}
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;
2021-12-10 20:22:16 +00:00
builder_reset(builder);
2021-12-10 20:22:16 +00:00
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));
}