2026-03-16 10:35:43 +00:00
|
|
|
#include <fx/core/bstr.h>
|
|
|
|
|
#include <fx/core/rope.h>
|
2025-04-11 13:53:48 +01:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_init_char(struct fx_rope *rope, char c)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(rope, 0x0, sizeof *rope);
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_flags = FX_ROPE_F_CHAR;
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_len_left = rope->r_len_total = 1;
|
|
|
|
|
rope->r_v.v_char = c;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_init_cstr(struct fx_rope *rope, const char *s)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(rope, 0x0, sizeof *rope);
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_flags = FX_ROPE_F_CSTR;
|
|
|
|
|
rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total);
|
2025-04-11 13:53:48 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_init_cstr_borrowed(struct fx_rope *rope, const char *s)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(rope, 0x0, sizeof *rope);
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_flags = FX_ROPE_F_CSTR_BORROWED;
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_v.v_cstr.s = s;
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total);
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_len_left = rope->r_len_total;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_init_cstr_static(struct fx_rope *rope, const char *s)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(rope, 0x0, sizeof *rope);
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_flags = FX_ROPE_F_CSTR_STATIC;
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_v.v_cstr.s = s;
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total);
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_len_left = rope->r_len_total;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_init_int(struct fx_rope *rope, intptr_t v)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(rope, 0x0, sizeof *rope);
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_flags = FX_ROPE_F_INT;
|
|
|
|
|
rope->r_len_left = rope->r_len_total = fx_int_length(v);
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_v.v_int = v;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_init_uint(struct fx_rope *rope, uintptr_t v)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(rope, 0x0, sizeof *rope);
|
2026-03-16 10:35:43 +00:00
|
|
|
rope->r_flags = FX_ROPE_F_UINT;
|
|
|
|
|
rope->r_len_left = rope->r_len_total = fx_uint_length(v);
|
2025-04-11 13:53:48 +01:00
|
|
|
rope->r_v.v_uint = v;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_destroy(struct fx_rope *rope)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
|
2025-04-11 13:53:48 +01:00
|
|
|
|
|
|
|
|
switch (type) {
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_CSTR:
|
2025-04-11 13:53:48 +01:00
|
|
|
free((char *)rope->r_v.v_cstr.s);
|
|
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_COMPOSITE:
|
|
|
|
|
fx_rope_destroy((struct fx_rope *)rope->r_v.v_composite.r_left);
|
|
|
|
|
fx_rope_destroy((struct fx_rope *)rope->r_v.v_composite.r_right);
|
2025-04-11 13:53:48 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
if (rope->r_flags & FX_ROPE_F_MALLOC) {
|
2025-04-11 13:53:48 +01:00
|
|
|
free(rope);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_iterate(
|
|
|
|
|
const struct fx_rope *rope, void (*func)(const fx_rope *, void *), void *arg)
|
2026-02-03 14:39:33 +00:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
if (FX_ROPE_TYPE(rope->r_flags) != FX_ROPE_F_COMPOSITE) {
|
2026-02-03 14:39:33 +00:00
|
|
|
func(rope, arg);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rope->r_v.v_composite.r_left) {
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_rope_iterate(rope->r_v.v_composite.r_left, func, arg);
|
2026-02-03 14:39:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rope->r_v.v_composite.r_right) {
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_rope_iterate(rope->r_v.v_composite.r_right, func, arg);
|
2026-02-03 14:39:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
size_t fx_rope_get_size(const struct fx_rope *rope)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
return rope->r_len_total;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_concat(
|
|
|
|
|
struct fx_rope *result, const struct fx_rope *left, const struct fx_rope *right)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
memset(result, 0x0, sizeof *result);
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
result->r_flags = FX_ROPE_F_COMPOSITE;
|
2025-04-11 13:53:48 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static struct fx_rope *create_composite_node(void)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_rope *out = malloc(sizeof *out);
|
2025-04-11 13:53:48 +01:00
|
|
|
if (!out) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
out->r_flags = FX_ROPE_F_COMPOSITE | FX_ROPE_F_MALLOC;
|
2025-04-11 13:53:48 +01:00
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
void fx_rope_join(fx_rope *result, const fx_rope **ropes, size_t nr_ropes)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
|
|
|
|
if (nr_ropes == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nr_ropes == 1) {
|
|
|
|
|
*result = *ropes[0];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_rope *prev = NULL;
|
2025-04-11 13:53:48 +01:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nr_ropes - 1; i++) {
|
2026-03-16 10:35:43 +00:00
|
|
|
const struct fx_rope *left = ropes[i];
|
|
|
|
|
const struct fx_rope *right = ropes[i + 1];
|
2025-04-11 13:53:48 +01:00
|
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
|
left = prev;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
struct fx_rope *composite = create_composite_node();
|
2025-04-11 13:53:48 +01:00
|
|
|
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;
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
result->r_flags &= ~FX_ROPE_F_MALLOC;
|
2025-04-11 13:53:48 +01:00
|
|
|
free(prev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void rope_iterate(
|
2026-03-16 10:35:43 +00:00
|
|
|
const struct fx_rope *rope,
|
|
|
|
|
void (*callback)(const struct fx_rope *, void *), void *arg)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
|
2025-04-11 13:53:48 +01:00
|
|
|
|
|
|
|
|
switch (type) {
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_CHAR:
|
|
|
|
|
case FX_ROPE_F_CSTR:
|
|
|
|
|
case FX_ROPE_F_CSTR_BORROWED:
|
|
|
|
|
case FX_ROPE_F_CSTR_STATIC:
|
|
|
|
|
case FX_ROPE_F_INT:
|
|
|
|
|
case FX_ROPE_F_UINT:
|
2025-04-11 13:53:48 +01:00
|
|
|
callback(rope, arg);
|
|
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_COMPOSITE:
|
2025-04-11 13:53:48 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static void to_bstr(const struct fx_rope *rope, void *arg)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_bstr *str = arg;
|
2025-04-11 13:53:48 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
|
2025-04-11 13:53:48 +01:00
|
|
|
|
2026-02-03 14:39:33 +00:00
|
|
|
switch (type) {
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_CHAR:
|
|
|
|
|
fx_bstr_write_char(str, rope->r_v.v_char);
|
2026-02-03 14:39:33 +00:00
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_CSTR:
|
|
|
|
|
case FX_ROPE_F_CSTR_BORROWED:
|
|
|
|
|
case FX_ROPE_F_CSTR_STATIC:
|
|
|
|
|
fx_bstr_write_cstr(str, rope->r_v.v_cstr.s, NULL);
|
2026-02-03 14:39:33 +00:00
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_INT:
|
|
|
|
|
fx_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int);
|
2026-02-03 14:39:33 +00:00
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_UINT:
|
|
|
|
|
fx_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint);
|
2026-02-03 14:39:33 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
static void to_stream(const struct fx_rope *rope, void *arg)
|
2026-02-03 14:39:33 +00:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_stream *out = arg;
|
2026-02-03 14:39:33 +00:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
|
2025-04-11 13:53:48 +01:00
|
|
|
|
|
|
|
|
switch (type) {
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_CHAR:
|
|
|
|
|
fx_stream_write_char(out, rope->r_v.v_char);
|
2025-04-11 13:53:48 +01:00
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_CSTR:
|
|
|
|
|
case FX_ROPE_F_CSTR_BORROWED:
|
|
|
|
|
case FX_ROPE_F_CSTR_STATIC:
|
|
|
|
|
fx_stream_write_string(out, rope->r_v.v_cstr.s, NULL);
|
2025-04-11 13:53:48 +01:00
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_INT:
|
|
|
|
|
fx_stream_write_fmt(out, NULL, "%" PRIdPTR, rope->r_v.v_int);
|
2025-04-11 13:53:48 +01:00
|
|
|
break;
|
2026-03-16 10:35:43 +00:00
|
|
|
case FX_ROPE_F_UINT:
|
|
|
|
|
fx_stream_write_fmt(out, NULL, "%" PRIuPTR, rope->r_v.v_uint);
|
2025-04-11 13:53:48 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-02-03 14:39:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_status fx_rope_to_cstr(const struct fx_rope *rope, char *out, size_t max)
|
2026-02-03 14:39:33 +00:00
|
|
|
{
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_bstr str;
|
|
|
|
|
fx_bstr_begin(&str, out, max);
|
2026-02-03 14:39:33 +00:00
|
|
|
rope_iterate(rope, to_bstr, &str);
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_SUCCESS;
|
2026-02-03 14:39:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_status fx_rope_to_bstr(const struct fx_rope *rope, fx_bstr *str)
|
2026-02-03 14:39:33 +00:00
|
|
|
{
|
|
|
|
|
rope_iterate(rope, to_bstr, str);
|
2025-04-11 13:53:48 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_SUCCESS;
|
2025-04-11 13:53:48 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
fx_status fx_rope_to_string(const struct fx_rope *rope, fx_stream *out)
|
2025-04-11 13:53:48 +01:00
|
|
|
{
|
2026-02-03 14:39:33 +00:00
|
|
|
rope_iterate(rope, to_stream, out);
|
2025-04-11 13:53:48 +01:00
|
|
|
|
2026-03-16 10:35:43 +00:00
|
|
|
return FX_SUCCESS;
|
2025-04-11 13:53:48 +01:00
|
|
|
}
|