Files
bluelib/core/rope.c

237 lines
5.0 KiB
C
Raw Normal View History

#include <blue/core/rope.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void b_rope_init_char(struct b_rope *rope, char c)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = B_ROPE_F_CHAR;
rope->r_len_left = rope->r_len_total = 1;
rope->r_v.v_char = c;
}
void b_rope_init_cstr(struct b_rope *rope, const char *s)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = B_ROPE_F_CSTR;
rope->r_v.v_cstr.hash = b_hash_string_ex(s, &rope->r_len_total);
rope->r_len_left = rope->r_len_total;
char *s2 = malloc(rope->r_len_total + 1);
if (!s2) {
return;
}
strcpy(s2, s);
s2[rope->r_len_total] = '\0';
rope->r_v.v_cstr.s = s2;
}
void b_rope_init_cstr_borrowed(struct b_rope *rope, const char *s)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = B_ROPE_F_CSTR_BORROWED;
rope->r_v.v_cstr.s = s;
rope->r_v.v_cstr.hash = b_hash_string_ex(s, &rope->r_len_total);
rope->r_len_left = rope->r_len_total;
}
void b_rope_init_cstr_static(struct b_rope *rope, const char *s)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = B_ROPE_F_CSTR_STATIC;
rope->r_v.v_cstr.s = s;
rope->r_v.v_cstr.hash = b_hash_string_ex(s, &rope->r_len_total);
rope->r_len_left = rope->r_len_total;
}
void b_rope_init_int(struct b_rope *rope, intptr_t v)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = B_ROPE_F_INT;
rope->r_len_left = rope->r_len_total = b_int_length(v);
rope->r_v.v_int = v;
}
void b_rope_init_uint(struct b_rope *rope, uintptr_t v)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = B_ROPE_F_UINT;
rope->r_len_left = rope->r_len_total = b_uint_length(v);
rope->r_v.v_uint = v;
}
void b_rope_destroy(struct b_rope *rope)
{
unsigned int type = B_ROPE_TYPE(rope->r_flags);
switch (type) {
case B_ROPE_F_CSTR:
free((char *)rope->r_v.v_cstr.s);
break;
case B_ROPE_F_COMPOSITE:
b_rope_destroy((struct b_rope *)rope->r_v.v_composite.r_left);
b_rope_destroy((struct b_rope *)rope->r_v.v_composite.r_right);
break;
default:
break;
}
if (rope->r_flags & B_ROPE_F_MALLOC) {
free(rope);
}
}
size_t b_rope_get_size(const struct b_rope *rope)
{
return rope->r_len_total;
}
void b_rope_concat(
struct b_rope *result, const struct b_rope *left, const struct b_rope *right)
{
memset(result, 0x0, sizeof *result);
result->r_flags = B_ROPE_F_COMPOSITE;
result->r_len_left = left->r_len_total;
result->r_len_total = left->r_len_total + right->r_len_total;
result->r_v.v_composite.r_left = left;
result->r_v.v_composite.r_right = right;
}
static struct b_rope *create_composite_node(void)
{
struct b_rope *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->r_flags = B_ROPE_F_COMPOSITE | B_ROPE_F_MALLOC;
return out;
}
void b_rope_join(b_rope *result, const b_rope **ropes, size_t nr_ropes)
{
if (nr_ropes == 0) {
return;
}
if (nr_ropes == 1) {
*result = *ropes[0];
return;
}
struct b_rope *prev = NULL;
for (size_t i = 0; i < nr_ropes - 1; i++) {
const struct b_rope *left = ropes[i];
const struct b_rope *right = ropes[i + 1];
if (prev) {
left = prev;
}
struct b_rope *composite = create_composite_node();
if (!composite) {
return;
}
composite->r_len_left = left->r_len_total;
composite->r_len_total = left->r_len_total + right->r_len_total;
composite->r_v.v_composite.r_left = left;
composite->r_v.v_composite.r_right = right;
prev = composite;
}
*result = *prev;
result->r_flags &= ~B_ROPE_F_MALLOC;
free(prev);
}
static void rope_iterate(
const struct b_rope *rope,
void (*callback)(const struct b_rope *, void *), void *arg)
{
unsigned int type = B_ROPE_TYPE(rope->r_flags);
switch (type) {
case B_ROPE_F_CHAR:
case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC:
case B_ROPE_F_INT:
case B_ROPE_F_UINT:
callback(rope, arg);
break;
case B_ROPE_F_COMPOSITE:
rope_iterate(rope->r_v.v_composite.r_left, callback, arg);
rope_iterate(rope->r_v.v_composite.r_right, callback, arg);
break;
default:
break;
}
}
struct to_cstr_args {
char *str;
size_t max;
size_t ptr;
};
static void to_cstr(const struct b_rope *rope, void *arg)
{
struct to_cstr_args *str = arg;
if (str->ptr >= str->max) {
return;
}
unsigned int type = B_ROPE_TYPE(rope->r_flags);
char *dest = str->str + str->ptr;
size_t capacity = str->max - str->ptr;
size_t nr_written = 0;
switch (type) {
case B_ROPE_F_CHAR:
nr_written = snprintf(dest, capacity, "%c", rope->r_v.v_char);
break;
case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC:
nr_written = snprintf(dest, capacity, "%s", rope->r_v.v_cstr.s);
break;
case B_ROPE_F_INT:
nr_written
= snprintf(dest, capacity, "%" PRIdPTR, rope->r_v.v_int);
break;
case B_ROPE_F_UINT:
nr_written
= snprintf(dest, capacity, "%" PRIuPTR, rope->r_v.v_uint);
break;
default:
break;
}
str->ptr += nr_written;
}
void b_rope_to_cstr(const struct b_rope *rope, char *out, size_t max)
{
struct to_cstr_args args = {
.str = out,
.max = max,
.ptr = 0,
};
rope_iterate(rope, to_cstr, &args);
}