_insert(), _pop_substitute(), _erase_substitute() + INSTANTIATION for SetT template

This commit is contained in:
Андреев Григорий 2025-09-20 00:15:46 +03:00
parent 6b7a67cb1f
commit bcc20b2f6e
7 changed files with 201 additions and 74 deletions

View File

@ -55,7 +55,5 @@ add_executable(codegen_l1_5 src/l1_5/anne/codegen.c)
#add_executable(0_play_test src/l3/tests/p0.c)
#target_link_libraries(0_play_test -lncurses)
#
## Recursively collect all .h files in the src directory.
#file(GLOB_RECURSE HEADER_FILES "${CMAKE_SOURCE_DIR}/src/*.h")
## Do not build utku
#add_executable(utka src/l1/tests/t0.c ${HEADER_FILES})
add_executable(l2t0 src/l2/tests/data_structures/t0.c)

View File

@ -3,12 +3,14 @@
#include "../codegen/util_template_inst.h"
// todo: split VecAndSpan_int_primitives into multiple files (one file per integer type)
/* These headers are guarded */
void generate_util_temp_very_base_headers() {
{
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_int_primitives.h"));
VecU8_append_span(&head.result, cstr("#include \"../../src/l1/core/util.h\"\n\n"));
SpanU8 T[4] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")};
SpanU8 T[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")};
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
.T = T[i],
@ -22,7 +24,7 @@ void generate_util_temp_very_base_headers() {
{
GeneratedHeader head = begin_header(cstr("l1/Option_int_primitives.h"));
VecU8_append_span(&head.result, cstr("#include \"../../src/l1/core/util.h\"\n\n"));
SpanU8 T[4] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")};
SpanU8 T[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")};
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
VecU8_append_vec(&head.result, generate_OptionT_struct_and_methods((option_template_instantiation_op){
.T = T[i], .t_integer = true, .t_primitive = true
@ -33,7 +35,7 @@ void generate_util_temp_very_base_headers() {
{
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_Vec_int_primitives.h"));
VecU8_append_span(&head.result, cstr("#include \"VecAndSpan_int_primitives.h\"\n\n"));
SpanU8 T[4] = {cstr("VecU8"), cstr("VecU16"), cstr("VecU32"), cstr("VecU64")};
SpanU8 T[] = {cstr("VecU8"), cstr("VecU16"), cstr("VecU32"), cstr("VecU64")};
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
.T = T[i], .t_clonable = true, .vec = true, .vec_extended = true,

View File

@ -71,4 +71,18 @@ NODISCARD VecU8 codegen_T_ref_less_T_ref(SpanU8 T, bool t_integer, VecU8 a, VecU
return VecU8_fmt("%s_equal_%s(%v, %v)", T, T, a, b);
}
NODISCARD VecU8 prepend_spaces_to_SpanU8_lines(SpanU8 lines, int tabulation){
VecU8 res = VecU8_new();
if (lines.len > 0)
for (int j = 0; j < tabulation; j++)
VecU8_append_span(&res, cstr(SPACE));
for (size_t i = 0; i < lines.len; i++) {
VecU8_append(&res, lines.data[i]);
if (lines.data[i] == '\n' && i + 1 < lines.len)
for (int j = 0; j < tabulation; j++)
VecU8_append_span(&res, cstr(SPACE));
}
return res;
}
#endif

View File

@ -1,8 +1,18 @@
#ifndef prototype1_src_l1_5_anne_l1_5_templ_very_base_h
#define prototype1_src_l1_5_anne_l1_5_templ_very_base_h
void generate_l1_5_template_instantiation_for_base_types(){
#include "../codegen/rb_tree_set_map_template_inst.h"
void generate_l1_5_template_instantiation_for_base_types(){
SpanU8 l = cstr("l1_5");
SpanU8 ns = cstr("");
SpanU8 dep = cstr(
"#include \"../l1/VecAndSpan_int_primitives.h\"\n"
"#include \"../l1/Option_int_primitives.h\""
);
// todo: split VecAndSpan_int_primitives into multiple files (one file per integer type)
generate_rb_tree_Set_templ_inst_guarded_header(l, ns, dep, (set_instantiation_op){.T = cstr("U64"), .t_integer = true});
generate_rb_tree_Set_templ_inst_guarded_header(l, ns, dep, (set_instantiation_op){.T = cstr("S64"), .t_integer = true});
}
#endif
#endif

View File

@ -48,27 +48,109 @@ NODISCARD VecU8 codegen_rb_tree_set_some_ref_t(set_instantiation_op op, SpanU8 i
}
/* Suppose some method returns pointer to key (ofc wrapped in option). But this time we found nothing */
NODISCARD VecU8 codegen_rb_tree_set_none_ref_t(set_instantiation_op op, SpanU8 index_var_name){
NODISCARD VecU8 codegen_rb_tree_set_none_ref_t(set_instantiation_op op){
if (op.t_integer)
return VecU8_fmt("Some_%s()", op.T, index_var_name);
return VecU8_fmt("Some_Ref%s()", op.T, index_var_name);
return VecU8_fmt("Some_%s()", op.T);
return VecU8_fmt("Some_Ref%s()", op.T);
}
NODISCARD VecU8 codegen_rb_tree_set_option_returned_value_t(set_instantiation_op op){
return VecU8_fmt("Option%s", op.T);
}
/* Suppose some method returns an owned key (by value, ofc wrapped in option). If we DID found something,
* we construct Option_Some */
NODISCARD VecU8 codegen_rb_tree_some_t(set_instantiation_op op, SpanU8 val_giving_expr){
NODISCARD VecU8 codegen_rb_tree_set_some_t(set_instantiation_op op, SpanU8 val_giving_expr){
return VecU8_fmt("Some_%s(%s)", op.T, val_giving_expr);
}
/* Suppose some method returns an owned key (by value, ofc wrapped in option). But this time we found nothing */
NODISCARD VecU8 codegen_rb_tree_none_t(set_instantiation_op op, SpanU8 val_giving_expr){
return VecU8_fmt("None_%s(%s)", op.T, val_giving_expr);
NODISCARD VecU8 codegen_rb_tree_set_none_t(set_instantiation_op op){
return VecU8_fmt("None_%s()", op.T);
}
/* Suppose some method (like _erase() or _pop(), or _find(), or _at(), takes constant reference to key T
* This function tells how to write type of this argument. Basically it is needed to take into account that
* integer is better than pointer to integer. (Though, notice that _pop family of methods don't exist for
* sets of integers
*/
NODISCARD VecU8 codegen_rb_tree_set_taking_ref_t_argument(set_instantiation_op op){
return !op.t_integer ? VecU8_fmt("const %s*", op.T) : VecU8_from_span(op.T);
}
/* Generates methods _insert() _pop_substitute() _erase_substitute() for SetT
* Takes ownership of strings Tc, Fc */
void codegen_append_rb_tree_set_insert_kind_method(
VecU8* result, set_instantiation_op op, SpanU8 set, SpanU8 method_name, VecU8 RT, VecU8 Tc, VecU8 Fc
){
VecU8 Tc_root = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc), 2);
VecU8 Tc_on_left = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc), 4);
VecU8 Tc_on_right = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc), 4);
VecU8 Fc_exists = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Fc), 1);
VecU8_drop(Tc);
VecU8_drop(Fc);
VecU8_append_vec(result, VecU8_fmt(
"%v %s_%s(%s* self, %s key) {\n" /* set, set, op.T */
SPACE "if (self->root == 0) {\n"
SPACE SPACE "assert(self->tree.len == 1);\n"
SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.color = RBTree_black});\n"
SPACE SPACE "Vec%s_append(&self->el, key);\n" /* op.T */
SPACE SPACE "self->root = 1;\n"
"%v" /* Tc_root */
/* Should have returned by now in Tc*/
SPACE "}\n"
SPACE "U64 cur = self->root;\n"
SPACE "while (%v) {\n" /* el[cur] != key */
SPACE SPACE "if (%v) {\n" /* key < el[cur] */
SPACE SPACE SPACE "if (self->tree.buf[cur].left != 0) {\n"
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
SPACE SPACE SPACE "} else { \n"
/* We are inserting to the left of cur */
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
SPACE SPACE SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.parent = cur, .color = RBTree_red});\n"
SPACE SPACE SPACE SPACE "self->tree.buf[cur].left = n;\n"
SPACE SPACE SPACE SPACE "RBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
SPACE SPACE SPACE SPACE "Vec%s_append(&self->el, key);\n" /* op.T */
"%v" /* Tc_on_left */
/* Should have returned by now in Tc*/
SPACE SPACE SPACE "}\n"
SPACE SPACE "} else {\n"
SPACE SPACE SPACE "if (self->tree.buf[cur].right != 0) {\n"
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
SPACE SPACE SPACE "} else {\n"
/* We are inserting to the right of cur */
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
SPACE SPACE SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.parent = cur, .color = RBTree_red});\n"
SPACE SPACE SPACE SPACE "self->tree.buf[cur].right = n;\n"
SPACE SPACE SPACE SPACE "RBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
SPACE SPACE SPACE SPACE "Vec%s_append(&self->el, key);\n" /* op.T */
"%v" /* Tc_on_right */
/* Should have returned by now in Tc*/
SPACE SPACE SPACE "}\n"
SPACE SPACE "}\n"
SPACE "}\n"
"%v" /* Fc_exists */
/* Should have returned by now in Tc*/
"}\n\n",
RT, set, method_name, set, op.T, op.T, Tc_root,
codegen_rb_tree_set_key_value_NOT_EQUAL_element(op),
codegen_rb_tree_set_key_value_LESS_element(op),
op.T, Tc_on_left, op.T, Tc_on_right, Fc_exists
));
}
void codegen_append_rb_tree_set_erase_kind_method(
VecU8* result, set_instantiation_op op, SpanU8 set, SpanU8 method_name,
VecU8 Fc, VecU8 Tc_z_available, VecU8 Tc_returning
){
// todo: move deletion here
}
/* src/l1_5/core/rb_tree_node.h is a dependency of all instantiations of rb_tree_set template
* Don't forget to include them
*/
NODISCARD VecU8 generate_rb_tree_set_template_instantiation(set_instantiation_op op){
NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op op){
set_instantiation_op_fix(&op);
VecU8 res = VecU8_new();
VecU8 g_set = VecU8_fmt("BuffRBTree_Set%s", op.T);
@ -77,61 +159,51 @@ NODISCARD VecU8 generate_rb_tree_set_template_instantiation(set_instantiation_op
"typedef struct {\n"
SPACE "VecRBTreeNode tree;\n"
SPACE "U64 root;\n"
SPACE "Vec%s"
"} %s\n\n", op.T, set));
SPACE "Vec%s el;\n"
"} %s;\n\n", op.T, set));
VecU8_append_vec(&res, VecU8_fmt(
"void %s_drop(%s self) {\n"
SPACE "VecRBTreeNode_drop(self->tree);\n"
SPACE "Vec%s_drop(self->el);\n"
SPACE "VecRBTreeNode_drop(self.tree);\n"
SPACE "Vec%s_drop(self.el);\n"
"}\n\n", set, set, op.T));
/* Method insert does not try to replace the existing element with equal key,
* it returns true if insertion was done, false it collision happened and key was not inserted */
VecU8_append_vec(&res, VecU8_fmt(
"bool %s_insert(%s* self, %s key) {\n"
SPACE "if (self->root == 0) {\n"
SPACE SPACE "assert(self->tree.len == 1);\n"
SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.color = RBTree_black});\n"
SPACE SPACE "Vec%s_append(&self->el, key);\n"
SPACE SPACE "self->root = 1;\n"
SPACE SPACE "return true;\n"
SPACE "}\n"
SPACE "U64 cur = self->root;\n"
SPACE "while (%v) {\n"
SPACE SPACE "if (%v) {\n"
SPACE SPACE SPACE "if (self->tree.buf[cur].left != 0) {\n"
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].left\n"
SPACE SPACE SPACE "} else { \n"
/* We are inserting to the left of cur */
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
SPACE SPACE SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeeNode){.parent = cur, .color = RBTree_red});\n"
SPACE SPACE SPACE SPACE "self->tree.buf[cur].left = n;\n"
SPACE SPACE SPACE SPACE "RBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
SPACE SPACE SPACE SPACE "return true;\n"
SPACE SPACE SPACE "}\n"
SPACE SPACE "} else {\n"
SPACE SPACE SPACE "if (self->tree.buf[cur].right != 0) {\n"
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].right\n"
SPACE SPACE SPACE "} else {\n"
/* We are inserting to the right of cur */
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
SPACE SPACE SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeeNode){.parent = cur, .color = RBTree_red});\n"
SPACE SPACE SPACE SPACE "self->tree.buf[cur].right = n;\n"
SPACE SPACE SPACE SPACE "RBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
SPACE SPACE SPACE SPACE "return true;\n"
SPACE SPACE SPACE "}\n"
SPACE SPACE "}\n"
SPACE "}\n"
SPACE "return false;\n"
"}\n\n",
set, set, op.T,
codegen_rb_tree_set_key_value_NOT_EQUAL_element(op),
codegen_rb_tree_set_key_value_LESS_element(op)
));
/* Method _insert() does not try to replace the existing element with equal key,
* it returns true if insertion was done, false if collision happened and key was not inserted */
codegen_append_rb_tree_set_insert_kind_method(&res, op, set, cstr("insert"), vcstr("bool"),
vcstr("return true;\n"),
op.t_integer ?
vcstr("return false;\n") :
VecU8_fmt(
"%s_drop(key);\n" /* op.T */
"return false;\n",
op.T));
/* Method _erase_substitute() is a mole bald version of _insert() method. It will substitute
* previous element with equal key it it was found. It still returns true if no conflict has happened, though */
codegen_append_rb_tree_set_insert_kind_method(&res, op, set, cstr("erase_substitute"), vcstr("bool"),
vcstr("return true;\n"),
op.t_integer ?
vcstr("return false;\n") :
VecU8_fmt(
"%s_drop(self->el.buf[cur - 1]);\n"
"self->el.buf[cur - 1] = key;\n"
"return false;\n"
));
if (!op.t_integer) {
codegen_append_rb_tree_set_insert_kind_method(&res, op, set, cstr("pop_substitute"),
codegen_rb_tree_set_option_returned_value_t(op),
VecU8_fmt("return %v;\n", codegen_rb_tree_set_none_t(op)),
VecU8_fmt(
"%s old = self->el.buf[cur - 1];\n" /* op.T */
"self->el.buf[cur - 1] = key;\n"
"return %v;", /* Some_T(old) */
op.T, codegen_rb_tree_set_some_t(op, cstr("old"))));
}
VecU8_append_vec(&res, VecU8_fmt(
"bool %s_erase(%s* self, const %s* key) {\n"
"bool %s_erase(%s* self, %v key) {\n" /* set, codegen_rb_tree_set_taking_ref_t_argument */
SPACE "U64 cur = self->root;\n"
SPACE "while (true){\n"
SPACE SPACE "if (cur == 0)\n"
@ -144,10 +216,10 @@ NODISCARD VecU8 generate_rb_tree_set_template_instantiation(set_instantiation_op
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
SPACE "}\n"
SPACE "U64 z = cur;\n"
SPACE "U64 y = (self->tree.buf[z].left == 0 || ) ? z : RBTree_minimum_in_subtree(&self->tree);\n"
SPACE "U64 x = self->tree.buf[y].left != 0 ? self->tree.buf[y].left : self->tree.buf[y].z;\n"
SPACE "U64 py = self->tree[y].parent;\n" // May be null
SPACE "self->tree.buf[x] = self->tree.buf[y].parent;\n"
SPACE "U64 y = (self->tree.buf[z].left == 0 || self->tree.buf[z].right == 0) ? z : RBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[z].right);\n"
SPACE "U64 x = self->tree.buf[y].left != 0 ? self->tree.buf[y].left : self->tree.buf[y].right;\n"
SPACE "U64 py = self->tree.buf[y].parent;\n" // May be null
SPACE "self->tree.buf[x].parent = self->tree.buf[y].parent;\n"
SPACE "if (py == 0)\n"
SPACE SPACE "self->root = x;\n"
SPACE "else if (self->tree.buf[py].left == y)\n"
@ -156,9 +228,9 @@ NODISCARD VecU8 generate_rb_tree_set_template_instantiation(set_instantiation_op
SPACE SPACE "self->tree.buf[py].right = x;\n"
SPACE "RBTreeColor y_org_clr = self->tree.buf[y].color;\n"
SPACE "if (z != y)\n"
SPACE SPACE "RBTree_steal_neighbours(z, y);\n"
SPACE SPACE "RBTree_steal_neighbours(self->tree.buf, &self->root, z, y);\n"
SPACE "U64 L = self->el.len;\n" /* self->tree.len - 1 */
SPACE "RBTree_steal_neighbours(L, z);\n"
SPACE "RBTree_steal_neighbours(self->tree.buf, &self->root, L, z);\n"
SPACE "self->tree.len--;\n"
SPACE "self->el.buf[z-1] = self->el.buf[L-1];\n"
SPACE "self->el.len--;\n"
@ -166,7 +238,7 @@ NODISCARD VecU8 generate_rb_tree_set_template_instantiation(set_instantiation_op
SPACE SPACE "RBTree_fix_after_delete(self->tree.buf, &self->root, x);\n"
SPACE "return true;\n"
"}\n\n",
set, set, op.T,
set, set, codegen_rb_tree_set_taking_ref_t_argument(op),
codegen_rb_tree_set_key_ref_EQUAL_element(op),
codegen_rb_tree_set_key_ref_LESS_element(op)
));
@ -180,4 +252,33 @@ NODISCARD VecU8 generate_rb_tree_set_template_instantiation(set_instantiation_op
return res;
}
void generate_rb_tree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, option_template_instantiation_op op) {
VecU8 text = VecU8_from_cstr("/* Automatically generated file. Do not edit it.\n"
" * Do not include it in more than one place */\n\n");
VecU8_append_vec(&text, generate_OptionT_struct_and_methods(op));
VecU8 nt_path = VecU8_fmt("%s/eve/%s/BuffRBTree_Set%s%c", layer, bonus_ns, op.T, 0);
write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text));
VecU8_drop(nt_path);
VecU8_drop(text);
}
void generate_rb_tree_Set_templ_inst_guarded_header(
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, set_instantiation_op op
){
assert(layer.len > 1);
VecU8 path = VecU8_fmt("%s/%s%sBuffRBTree_Set%s.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), op.T);
GeneratedHeader head = begin_header(VecU8_to_span(&path));
VecU8_drop(path);
VecU8_append_span(&head.result, cstr("#include \"../../"));
int to_my_layer = get_number_of_parts_in_header_namespace(bonus_ns);
for (int i = 0; i < to_my_layer; i++)
VecU8_append_span(&head.result, cstr("../"));
VecU8_append_span(&head.result, cstr("src/l1_5/core/rb_tree_node.h\"\n"));
VecU8_append_span(&head.result, dependencies);
VecU8_append_span(&head.result, cstr("\n\n"));
VecU8_append_vec(&head.result, generate_rb_tree_Set_template_instantiation(op));
finish_header(head);
}
#endif

View File

@ -0,0 +1,5 @@
#include "../../../../gen/l1_5/BuffRBTree_SetS64.h"
int main() {
return 0;
}

View File

@ -1,3 +0,0 @@
int main(){
}