#include #include #include #include #include #include void fx_rope_init_char(struct fx_rope *rope, char c) { memset(rope, 0x0, sizeof *rope); rope->r_flags = FX_ROPE_F_CHAR; rope->r_len_left = rope->r_len_total = 1; rope->r_v.v_char = c; } void fx_rope_init_cstr(struct fx_rope *rope, const char *s) { memset(rope, 0x0, sizeof *rope); rope->r_flags = FX_ROPE_F_CSTR; rope->r_v.v_cstr.hash = fx_hash_cstr_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 fx_rope_init_cstr_borrowed(struct fx_rope *rope, const char *s) { memset(rope, 0x0, sizeof *rope); rope->r_flags = FX_ROPE_F_CSTR_BORROWED; rope->r_v.v_cstr.s = s; rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total); rope->r_len_left = rope->r_len_total; } void fx_rope_init_cstr_static(struct fx_rope *rope, const char *s) { memset(rope, 0x0, sizeof *rope); rope->r_flags = FX_ROPE_F_CSTR_STATIC; rope->r_v.v_cstr.s = s; rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total); rope->r_len_left = rope->r_len_total; } void fx_rope_init_int(struct fx_rope *rope, intptr_t v) { memset(rope, 0x0, sizeof *rope); rope->r_flags = FX_ROPE_F_INT; rope->r_len_left = rope->r_len_total = fx_int_length(v); rope->r_v.v_int = v; } void fx_rope_init_uint(struct fx_rope *rope, uintptr_t v) { memset(rope, 0x0, sizeof *rope); rope->r_flags = FX_ROPE_F_UINT; rope->r_len_left = rope->r_len_total = fx_uint_length(v); rope->r_v.v_uint = v; } void fx_rope_destroy(struct fx_rope *rope) { unsigned int type = FX_ROPE_TYPE(rope->r_flags); switch (type) { case FX_ROPE_F_CSTR: free((char *)rope->r_v.v_cstr.s); break; 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); break; default: break; } if (rope->r_flags & FX_ROPE_F_MALLOC) { free(rope); } } void fx_rope_iterate( const struct fx_rope *rope, void (*func)(const fx_rope *, void *), void *arg) { if (FX_ROPE_TYPE(rope->r_flags) != FX_ROPE_F_COMPOSITE) { func(rope, arg); return; } if (rope->r_v.v_composite.r_left) { fx_rope_iterate(rope->r_v.v_composite.r_left, func, arg); } if (rope->r_v.v_composite.r_right) { fx_rope_iterate(rope->r_v.v_composite.r_right, func, arg); } } size_t fx_rope_get_size(const struct fx_rope *rope) { return rope->r_len_total; } void fx_rope_concat( struct fx_rope *result, const struct fx_rope *left, const struct fx_rope *right) { memset(result, 0x0, sizeof *result); result->r_flags = FX_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 fx_rope *create_composite_node(void) { struct fx_rope *out = malloc(sizeof *out); if (!out) { return NULL; } memset(out, 0x0, sizeof *out); out->r_flags = FX_ROPE_F_COMPOSITE | FX_ROPE_F_MALLOC; return out; } void fx_rope_join(fx_rope *result, const fx_rope **ropes, size_t nr_ropes) { if (nr_ropes == 0) { return; } if (nr_ropes == 1) { *result = *ropes[0]; return; } struct fx_rope *prev = NULL; for (size_t i = 0; i < nr_ropes - 1; i++) { const struct fx_rope *left = ropes[i]; const struct fx_rope *right = ropes[i + 1]; if (prev) { left = prev; } struct fx_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 &= ~FX_ROPE_F_MALLOC; free(prev); } static void rope_iterate( const struct fx_rope *rope, void (*callback)(const struct fx_rope *, void *), void *arg) { unsigned int type = FX_ROPE_TYPE(rope->r_flags); switch (type) { 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: callback(rope, arg); break; case FX_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; } } static void to_bstr(const struct fx_rope *rope, void *arg) { fx_bstr *str = arg; unsigned int type = FX_ROPE_TYPE(rope->r_flags); switch (type) { case FX_ROPE_F_CHAR: fx_bstr_write_char(str, rope->r_v.v_char); break; 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); break; case FX_ROPE_F_INT: fx_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int); break; case FX_ROPE_F_UINT: fx_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint); break; default: break; } } static void to_stream(const struct fx_rope *rope, void *arg) { fx_stream *out = arg; unsigned int type = FX_ROPE_TYPE(rope->r_flags); switch (type) { case FX_ROPE_F_CHAR: fx_stream_write_char(out, rope->r_v.v_char); break; 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); break; case FX_ROPE_F_INT: fx_stream_write_fmt(out, NULL, "%" PRIdPTR, rope->r_v.v_int); break; case FX_ROPE_F_UINT: fx_stream_write_fmt(out, NULL, "%" PRIuPTR, rope->r_v.v_uint); break; default: break; } } fx_status fx_rope_to_cstr(const struct fx_rope *rope, char *out, size_t max) { fx_bstr str; fx_bstr_begin(&str, out, max); rope_iterate(rope, to_bstr, &str); return FX_SUCCESS; } fx_status fx_rope_to_bstr(const struct fx_rope *rope, fx_bstr *str) { rope_iterate(rope, to_bstr, str); return FX_SUCCESS; } fx_status fx_rope_to_string(const struct fx_rope *rope, fx_stream *out) { rope_iterate(rope, to_stream, out); return FX_SUCCESS; }