diff --git a/CMakeLists.txt b/CMakeLists.txt index f6b2ec8..56c754b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) #target_link_libraries(3_render_test -lwayland-client -lm -lvulkan -lxkbcommon) #add_executable(l2t0_2 src/l2/tests/data_structures/t0_2.c) // todo: I will get back +add_executable(l2t0_3 src/l2/tests/data_structures/t0_3.c) add_executable(l2t2 src/l2/tests/data_structures/t2.c) #add_executable(l2t0 src/l2/tests/data_structures/t0.c) diff --git a/Makefile b/Makefile index f32ad7a..e4215fc 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,6 @@ out/l2/t0: src/l2/tests/data_structures/t0.c $(HEADERS_gen_l1_5) .PHONY: run_l2_t0 run_l2_t0: out/l2/t0 - mkdir -p src/l2/tests/data_structures/GRAPHS cd src/l2/tests/data_structures && ../../../../out/l2/t0 out/l2/r0: src/l2/tests/r0/r0.c $(HEADERS_src_l2) $(l_wl_protocols) diff --git a/src/l1/anne/codegen.c b/src/l1/anne/codegen.c index d4a4c06..61e876d 100644 --- a/src/l1/anne/codegen.c +++ b/src/l1/anne/codegen.c @@ -10,7 +10,7 @@ #include "margaret/margaret_misc.h" #include "marie/graphics_geom.h" #include "liza.h" -#include "codegen_from_l1_5.h" +#include "embassy_l1_5.h" #include "margaret/png_pixel_masses.h" int main() { diff --git a/src/l1/anne/codegen_from_l1_5.h b/src/l1/anne/embassy_l1_5.h similarity index 85% rename from src/l1/anne/codegen_from_l1_5.h rename to src/l1/anne/embassy_l1_5.h index 0982eeb..9862c88 100644 --- a/src/l1/anne/codegen_from_l1_5.h +++ b/src/l1/anne/embassy_l1_5.h @@ -10,7 +10,7 @@ void generate_l1_headers_for_l1_5() { SpanU8 ns = cstr("embassy_l1_5"); generate_eve_span_company_for_primitive(l, ns, cstr("NamedVariableRecordRef"), false, true); generate_eve_span_company_for_primitive(l, ns, cstr("NamedMethodSignatureRecordRef"), false, true); - generate_eve_span_company_for_primitive(l, ns, cstr("BuffRBTreeNode"), true, false); + generate_eve_span_company_for_primitive(l, ns, cstr("BufRBTreeNode"), true, false); } #endif \ No newline at end of file diff --git a/src/l1/anne/some_tests.h b/src/l1/anne/some_tests.h index aa18468..117e59a 100644 --- a/src/l1/anne/some_tests.h +++ b/src/l1/anne/some_tests.h @@ -38,6 +38,10 @@ void generate_headers_for_r0_r1_r2_r3() { generate_eve_span_company_for_primitive(l, ns, cstr("I_FishNode"), true, false); generate_eve_span_company_for_primitive(l, ns, cstr("J_AlphaVertex"), true, false); } + // mkdir_nofail("l1/eve/ds_test"); + // { /* This structure is needed for testing purposes only */ + // generate_eve_span_company_for_primitive(l, cstr("ds_test"), cstr("RefRBTreeNode_S64"), true, false); + // } } #endif \ No newline at end of file diff --git a/src/l1/codegen/codegen.h b/src/l1/codegen/codegen.h index 8bcf248..6f39f36 100644 --- a/src/l1/codegen/codegen.h +++ b/src/l1/codegen/codegen.h @@ -85,6 +85,35 @@ NODISCARD VecU8 prepend_spaces_to_SpanU8_lines(SpanU8 lines, int tabulation){ return res; } -#define EVE_MESSAGE "/* Automatically generated file. Don't edit it.\n * Don't include it in more than one place */\n\n" +void generate_SOME_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, VecU8 body, VecU8 name){ + VecU8 text = VecU8_fmt("/* Automatically generated file. Don't edit it.\n" + "* Don't include it in more than one place */\n\n%v", body); + VecU8 nt_path = VecU8_fmt("%s/eve/%s/%v.h%c", layer, bonus_ns, name, 0); + write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text)); + VecU8_drop(nt_path); + VecU8_drop(text); +} + +void generate_SOME_templ_inst_guarded_header(SpanU8 layer, SpanU8 bonus_ns, VecU8 all_dependencies, VecU8 body, VecU8 name){ + assert(layer.len > 1); + VecU8 path = VecU8_fmt("%s/%s%s%v.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), name); + GeneratedHeader head = begin_header(VecU8_to_span(&path)); + VecU8_drop(path); + VecU8_append_vec(&head.result, all_dependencies); + VecU8_append_span(&head.result, cstr("\n")); + VecU8_append_vec(&head.result, body); + finish_header(head); +} + +/* Assumed we are at some_layer/bonus_ns/header.h header */ +NODISCARD VecU8 codegen_include_relative_to_root(SpanU8 bonus_ns, SpanU8 abs_path){ + VecU8 res = vcstr("#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(&res, cstr("../")); + VecU8_append_span(&res, abs_path); + VecU8_append_span(&res, cstr("\"\n")); + return res; +} #endif diff --git a/src/l1/core/util.h b/src/l1/core/util.h index 5d65057..7c6291d 100644 --- a/src/l1/core/util.h +++ b/src/l1/core/util.h @@ -70,7 +70,7 @@ float pow2f(float x) { } bool U64_is_2pow(U64 n){ - return n > 0 && (n & (n - 1) == 0); + return n > 0 && ((n & (n - 1)) == 0); } U8 U64_2pow_log(U64 n){ diff --git a/src/l1_5/anne/l1_5_templ_very_base.h b/src/l1_5/anne/l1_5_templ_very_base.h index e028dce..c7c39ac 100644 --- a/src/l1_5/anne/l1_5_templ_very_base.h +++ b/src/l1_5/anne/l1_5_templ_very_base.h @@ -2,13 +2,20 @@ #define prototype1_src_l1_5_anne_l1_5_templ_very_base_h #include "../codegen/buff_rbtree_set_map_template_inst.h" +#include "../codegen/rbtree_set_map_template_inst.h" void generate_l1_5_template_instantiation_for_base_types(){ SpanU8 l = cstr("l1_5"), ns = cstr(""); - generate_buff_rbtree_Set_templ_inst_guarded_header(l, ns,cstr("#include \"../l1/VecAndSpan_U64.h\""), + generate_buf_rbtree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../l1/VecAndSpan_U64.h\""), (set_instantiation_op){.T = cstr("U64"), .t_integer = true}); - generate_buff_rbtree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../l1/VecAndSpan_S64.h\""), + generate_buf_rbtree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../l1/VecAndSpan_S64.h\""), (set_instantiation_op){.T = cstr("S64"), .t_integer = true}); + + // l1/core/int_primitives is included in l1_5/core/rb_tree_node.h, hence no additional dependencies needed + generate_rbtree_Set_templ_inst_guarded_header(l, ns, cstr(""), (set_instantiation_op){ + .T = cstr("U64"), .t_integer = true }, true); + generate_rbtree_Set_templ_inst_guarded_header(l, ns, cstr(""), (set_instantiation_op){ + .T = cstr("S64"), .t_integer = true }, true); } #endif diff --git a/src/l1_5/anne/margaret.h b/src/l1_5/anne/margaret.h index 40fc402..b8f0cc3 100644 --- a/src/l1_5/anne/margaret.h +++ b/src/l1_5/anne/margaret.h @@ -9,14 +9,14 @@ void generate_l1_5_template_instantiations_for_margaret(){ mkdir_nofail("l1_5/eve/margaret"); /* For MargaretMemAllocator */ - generate_buff_rbtree_Set_templ_inst_eve_header(l, ns, (set_instantiation_op){ + generate_buf_rbtree_Set_templ_inst_eve_header(l, ns, (set_instantiation_op){ .T = cstr("MargaretFreeMemSegment"), .t_primitive = true, .alternative_less = cstr("MargaretFreeMemSegment_less"), .alternative_equal = cstr("MargaretFreeMemSegment_equal"), .alternative_comp_set_name_embed = cstr("Len"), }); - generate_buff_rbtree_Set_templ_inst_eve_header(l, ns, (set_instantiation_op){ + generate_buf_rbtree_Set_templ_inst_eve_header(l, ns, (set_instantiation_op){ .T = cstr("MargaretFreeMemSegment"), .t_primitive = true, /* comparison takes additional U8 parameter */ @@ -25,12 +25,12 @@ void generate_l1_5_template_instantiations_for_margaret(){ .alternative_comp_set_name_embed = cstr("LenRespAlign"), .guest_data_T = cstr("U8"), }); - generate_buff_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ - .K = cstr("U64"), .k_integer = true, .V = cstr("MargaretMemoryOccupation"), /* MargaretMemoryOccupation is not primitive */ - }); - generate_buff_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ - .K = cstr("U64"), .k_integer = true, .V = cstr("MargaretBufferOccupationSubBuffer"), .v_primitive = true, - }); + // generate_buf_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ + // .K = cstr("U64"), .k_integer = true, .V = cstr("MargaretMemoryOccupation"), /* MargaretMemoryOccupation is not primitive */ + // }); + // generate_buf_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){ + // .K = cstr("U64"), .k_integer = true, .V = cstr("MargaretBufferOccupationSubBuffer"), .v_primitive = true, + // }); } #endif \ No newline at end of file diff --git a/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h b/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h index 2add1d1..65f2347 100644 --- a/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h +++ b/src/l1_5/codegen/buff_rbtree_set_map_template_inst.h @@ -174,7 +174,7 @@ void codegen_append_buff_rbtree_map__structure_and_simplest_methods( "}\n\n", set, set, TT)); VecU8_append_vec(res, VecU8_fmt( - "U64 %s_find(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */ + "U64 %s_find(const %s* self, %v key) {\n" /* set, set, taking_ref_k_argument */ SPACE "U64 cur = self->root;\n" SPACE "while (cur != 0 && %v) {\n" /* key reference not equal cur element */ SPACE SPACE "if (%v) {\n" /* key reference less than cur element */ @@ -202,11 +202,12 @@ void codegen_append_buff_rbtree_map__structure_and_simplest_methods( TT, op.guest_data_T.len > 0 ? cstr(", .guest = self->guest") : cstr(""))); } + // todo: move to common code VecU8_append_vec(res, VecU8_fmt( "U64 %s_find_next(const %s* self, U64 x){\n" SPACE "assert(x != 0 && x < self->tree.len);\n" SPACE "if (self->tree.buf[x].right != 0)\n" - SPACE SPACE "return RBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[x].right);\n" + SPACE SPACE "return BufRBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[x].right);\n" SPACE "while (true) {\n" SPACE SPACE "U64 p = self->tree.buf[x].parent;\n" SPACE SPACE "if (p == 0)\n" @@ -217,6 +218,7 @@ void codegen_append_buff_rbtree_map__structure_and_simplest_methods( SPACE "}\n" "}\n\n", set, set)); + // todo: move to comon code VecU8_append_vec(res, VecU8_fmt( "U64 %s_find_prev(const %s* self, U64 x){\n" SPACE "assert(x != 0 && x < self->tree.len);\n" @@ -338,9 +340,9 @@ void codegen_append_buff_rbtree_map__structure_and_simplest_methods( )); } -/* Generates methods _insert() _pop_substitute() _erase_substitute() for SetT - * Takes ownership of strings Tc, Fc */ -void codegen_append_buff_rbtree_map__insert_kind_method( + +// todo: no need for a separate method. Just write _try_insert() and derive all the shit from it +void codegen_append_buf_rbtree_map__insert_kind_method( VecU8* res, map_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); @@ -350,6 +352,8 @@ void codegen_append_buff_rbtree_map__insert_kind_method( VecU8_drop(Tc); VecU8_drop(Fc); + // todo: fix it. No buffered rbttrees here. Only my pure poijter basa[ks tree + VecU8 line_that_appends_new_el_to_el_vec = op.V.len > 0 ? VecU8_fmt("VecKVP%sTo%s_append(&self->el, (KVP%sTo%s){.key = key, .value = value});", op.K, op.V, op.K, op.V) : VecU8_fmt("Vec%s_append(&self->el, key);", op.K); @@ -412,6 +416,7 @@ void codegen_append_buff_rbtree_map__insert_kind_method( VecU8_drop(line_that_appends_new_el_to_el_vec); } +// todo: no need for a separate function. Do just like in normal RBTree void codegen_append_buff_rbtree_map__method_empty_index_erase(VecU8* res, SpanU8 set){ VecU8_append_vec(res, VecU8_fmt( "/* UNSAFE. Use when you dropped the symbol that is about to be deleted */\n" @@ -452,6 +457,7 @@ void codegen_append_buff_rbtree_map__method_empty_index_erase(VecU8* res, SpanU8 set, set)); } +// todo: no need for a separate method. void codegen_append_buff_rbtree_map__erase_kind_method( VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 method_name, VecU8 RT, VecU8 Fc, VecU8 Tc_cur_available, VecU8 Tc_returning @@ -538,7 +544,7 @@ void codegen_append_buff_rbtree_map__method_at(VecU8* res, map_instantiation_op )); } -NODISCARD VecU8 get_name_of_buff_rbtree_set_structure(set_instantiation_op op){ +NODISCARD VecU8 get_name_of_buf_rbtree_set_structure(set_instantiation_op op){ if (op.alternative_comp_set_name_embed.len) return VecU8_fmt("BuffRBTreeBy%s_Set%s", op.alternative_comp_set_name_embed, op.T); return VecU8_fmt("BuffRBTree_Set%s", op.T); @@ -547,10 +553,10 @@ NODISCARD VecU8 get_name_of_buff_rbtree_set_structure(set_instantiation_op op){ /* 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_buff_rbtree_Set_template_instantiation(set_instantiation_op op){ +NODISCARD VecU8 generate_buf_rbtree_Set_template_instantiation(set_instantiation_op op){ set_instantiation_op_fix(&op); VecU8 res = VecU8_new(); - VecU8 g_set = get_name_of_buff_rbtree_set_structure(op); + VecU8 g_set = get_name_of_buf_rbtree_set_structure(op); SpanU8 set = VecU8_to_span(&g_set); map_instantiation_op map_op = {.K = op.T, @@ -564,7 +570,7 @@ NODISCARD VecU8 generate_buff_rbtree_Set_template_instantiation(set_instantiatio /* 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_buff_rbtree_map__insert_kind_method(&res, map_op, set, cstr("insert"), vcstr("bool"), + codegen_append_buf_rbtree_map__insert_kind_method(&res, map_op, set, cstr("insert"), vcstr("bool"), vcstr("return true;\n"), op.t_primitive ? vcstr("return false;\n") : @@ -592,32 +598,18 @@ NODISCARD VecU8 generate_buff_rbtree_Set_template_instantiation(set_instantiatio } -void generate_buff_rbtree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, set_instantiation_op op) { - VecU8 text = vcstr(EVE_MESSAGE); - VecU8_append_vec(&text, generate_buff_rbtree_Set_template_instantiation(op)); - VecU8 nt_path = VecU8_fmt("%s/eve/%s/%v.h%c", layer, bonus_ns, get_name_of_buff_rbtree_set_structure(op), 0); - write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text)); - VecU8_drop(nt_path); - VecU8_drop(text); +void generate_buf_rbtree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, set_instantiation_op op) { + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_buf_rbtree_Set_template_instantiation(op), get_name_of_buf_rbtree_set_structure(op)); } -void generate_buff_rbtree_Set_templ_inst_guarded_header( +void generate_buf_rbtree_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%s%v.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), - get_name_of_buff_rbtree_set_structure(op)); - 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/buff_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_buff_rbtree_Set_template_instantiation(op)); - finish_header(head); + VecU8 all_dependencies = VecU8_fmt("%v%s", + codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/buff_rb_tree_node.h")), dependencies); + generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies, + generate_buf_rbtree_Set_template_instantiation(op), get_name_of_buf_rbtree_set_structure(op)); } /* ========= Now we add Map into the picture ======== */ @@ -637,31 +629,31 @@ void codegen_append_buff_rbtree_map__method_at_iter(VecU8* res, map_instantiatio op.k_integer ? cstr("") : cstr("&"), op.v_integer ? cstr("") : cstr("&"))); } -NODISCARD VecU8 get_name_of_buff_rbtree_map_structure(map_instantiation_op op){ +NODISCARD VecU8 get_name_of_buf_rbtree_map_structure(map_instantiation_op op){ if (op.alternative_comp_map_name_embed.len) return VecU8_fmt("BuffRBTreeBy%s_Map%sTo%s", op.alternative_comp_map_name_embed, op.K, op.V); return VecU8_fmt("BuffRBTree_Map%sTo%s", op.K, op.V); } -NODISCARD VecU8 generate_buff_rbtree_Map_template_instantiation(map_instantiation_op op){ +NODISCARD VecU8 generate_buf_rbtree_Map_template_instantiation(map_instantiation_op op){ assert(op.V.len > 0); map_instantiation_op_fix(&op); VecU8 res = VecU8_new(); - VecU8 map_g = get_name_of_buff_rbtree_map_structure(op); + VecU8 map_g = get_name_of_buf_rbtree_map_structure(op); SpanU8 map = VecU8_to_span(&map_g); VecU8 kvp_g = VecU8_fmt("KVP%sTo%s", op.K, op.V); codegen_append_buff_rbtree_map__structure_and_simplest_methods(&res, op, map, VecU8_to_span(&kvp_g)); VecU8_drop(kvp_g); - codegen_append_buff_rbtree_map__insert_kind_method(&res, op, map, cstr("insert"), vcstr("bool"), + codegen_append_buf_rbtree_map__insert_kind_method(&res, op, map, cstr("insert"), vcstr("bool"), vcstr("return true;\n"), VecU8_fmt("%v%v" "return false;\n", op.k_primitive ? vcstr("") : VecU8_fmt("%s_drop(key);\n", op.K), op.v_primitive ? vcstr("") : VecU8_fmt("%s_drop(value);\n", op.V))); - codegen_append_buff_rbtree_map__insert_kind_method(&res, op, map, cstr("erase_substitute"), vcstr("bool"), + codegen_append_buf_rbtree_map__insert_kind_method(&res, op, map, cstr("erase_substitute"), vcstr("bool"), vcstr("return true;\n"), VecU8_fmt("%v%v" "self->el.buf[cur - 1].key = key;\n" @@ -671,7 +663,7 @@ NODISCARD VecU8 generate_buff_rbtree_Map_template_instantiation(map_instantiatio op.k_primitive ? vcstr("") : VecU8_fmt("%s_drop(self->el.buf[cur - 1].value);\n", op.V) )); - codegen_append_buff_rbtree_map__insert_kind_method(&res, op, map, cstr("pop_substitute"), + codegen_append_buf_rbtree_map__insert_kind_method(&res, op, map, cstr("pop_substitute"), VecU8_fmt("Option%s", op.V), VecU8_fmt("return None_%s();\n", op.V), VecU8_fmt( @@ -711,32 +703,18 @@ NODISCARD VecU8 generate_buff_rbtree_Map_template_instantiation(map_instantiatio return res; } -void generate_buff_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op) { - VecU8 text = vcstr(EVE_MESSAGE); - VecU8_append_vec(&text, generate_buff_rbtree_Map_template_instantiation(op)); - VecU8 nt_path = VecU8_fmt("%s/eve/%s/%v.h%c", layer, bonus_ns, get_name_of_buff_rbtree_map_structure(op), 0); - write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text)); - VecU8_drop(nt_path); - VecU8_drop(text); +void generate_buf_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op) { + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_buf_rbtree_Map_template_instantiation(op), get_name_of_buf_rbtree_map_structure(op)); } -void generate_buff_rbtree_Map_templ_inst_guarded_header( +void generate_buf_rbtree_Map_templ_inst_guarded_header( SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, map_instantiation_op op ){ - assert(layer.len > 1); - VecU8 path = VecU8_fmt("%s/%s%s%v.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), - get_name_of_buff_rbtree_map_structure(op)); - 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/buff_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_buff_rbtree_Map_template_instantiation(op)); - finish_header(head); + VecU8 all_dependencies = VecU8_fmt("%v%s", + codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/buff_rb_tree_node.h")), dependencies); + generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies, + generate_buf_rbtree_Map_template_instantiation(op), get_name_of_buf_rbtree_map_structure(op)); } -#endif \ No newline at end of file +#endif diff --git a/src/l1_5/codegen/rbtree_set_map_template_inst.h b/src/l1_5/codegen/rbtree_set_map_template_inst.h index edad829..9dc861f 100644 --- a/src/l1_5/codegen/rbtree_set_map_template_inst.h +++ b/src/l1_5/codegen/rbtree_set_map_template_inst.h @@ -12,66 +12,432 @@ NODISCARD VecU8 codegen_rbtree__node_structure(map_instantiation_op op){ VecU8 node_g = codegen_rbtree__node_struct_name(op); SpanU8 node = VecU8_to_span(&node_g); VecU8 res = VecU8_fmt( - "typedef struct %s %s;\n\n" /* node, node */ - "struct {\n" - SPACE "%s* left;\n" /* node */ - SPACE "%s* right;\n" /* node */ - SPACE "%s* parent;\n" /* node */ - SPACE "int color;\n" - SPACE "%v;\n" /* Key key[] / KVP w[] */ - "} %s;\n\n", - node, node, node, node, node, - op.V.len > 0 ? VecU8_fmt("KVP%sTo%s w[]", op.K, op.V) : VecU8_fmt("%s key[]", op.K), + "typedef struct {\n" + SPACE "RBTreeNode base;\n" + SPACE "%s key;\n" /* op.K*/ + "" /* "" / op.V value; */ + "} %s;\n\n", /* node */ + op.K, op.V.len > 0 ? VecU8_fmt(SPACE "%s value;\n", op.V) : vcstr(""), node); - - VecU8_append_vec(&res, VecU8_fmt( - "%s* %s_minimum_in_subtree(const %s* x, const %s* NIL) {\n" - SPACE "assert(x != NIL);\n" - SPACE "" - "}\n")); VecU8_drop(node_g); return res; } +NODISCARD VecU8 codegen_rbtree_map__key_of_cur_el(map_instantiation_op op){ + return VecU8_fmt("((%v *)cur)->key", codegen_rbtree__node_struct_name(op)); +} + +/* Assuming A nd B are passed as intended */ +NODISCARD VecU8 codegen_rbtree_map__less(map_instantiation_op op, VecU8 A, VecU8 B){ + if (op.guest_data_T.len > 0) { + assert(op.alternative_equal.len > 0); + return VecU8_fmt("%s(%v, %v, self->guest)", op.alternative_less, A, B); + } + if (op.alternative_equal.len > 0) + return VecU8_fmt("%s(%v, %v)", op.alternative_less, A, B); + if (op.k_integer) + return VecU8_fmt("%v < %v", A, B); + return VecU8_fmt("%s_less_%s(%v %v)", op.K, op.K, A, B); +} + +NODISCARD VecU8 codegen_rbtree_map__exp_passing_key_ref(map_instantiation_op op){ + return op.k_integer ? vcstr("key") : vcstr("&key"); +} + +NODISCARD VecU8 codegen_rbtree_map__exp_passing_cur_key(map_instantiation_op op){ + return VecU8_fmt("%s" "((%v*)cur)->key", op.k_integer ? cstr("") : cstr("&"), codegen_rbtree__node_struct_name(op)); +} + + +NODISCARD VecU8 codegen_rbtree_map__taking_ref_k_argument(map_instantiation_op op){ + return op.k_integer ? VecU8_from_span(op.K) : VecU8_fmt("const %s*", op.K); +} + +NODISCARD VecU8 codegen_rbtree_map__taking_t_argument(map_instantiation_op op){ + return op.V.len > 0 ? VecU8_fmt("%s key, %s value", op.K, op.V) : VecU8_fmt("%s key", op.K); +} + void codegen_append_rbtree_map__structure_and_simplest_methods( VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 TT ){ VecU8_append_vec(res, VecU8_fmt( "typedef struct {\n" - SPACE "RBTreeNode_%s* root;\n" /* TT */ - SPACE "RBTreeNode_%s* NIL;\n" /* TT */ + SPACE "RBTreeNode* root;\n" + SPACE "RBTreeNode* NIL;\n" "%v" /* "" / guest field */ - "} %s;\n\n", TT, TT, + "} %s;\n\n", op.guest_data_T.len == 0 ? vcstr("") : VecU8_fmt("%s guest;\n", op.guest_data_T), set)); VecU8_append_vec(res, VecU8_fmt( "NODISCARD %s %s_new(" "%v" ") {\n" /* set, set, "" / GT guest */ - SPACE "RBTreeNode_%s* NIL = (RBTreeNode_%s*)safe_malloc(sizeof(RBTreeNode_%s));\n" /* TT, TT, TT*/ + /* Only color field initialization is important (should be 0) */ + SPACE "RBTreeNode* NIL = (RBTreeNode*)safe_calloc(1, sizeof(RBTreeNode));\n" SPACE "return (%s){.root = NIL, .NIL = NIL" "%s" "};\n" /* set, "" / , .guest = guest */ "}\n\n", set, set, op.guest_data_T.len == 0 ? vcstr("") : VecU8_fmt("%s guest", op.guest_data_T), - TT, TT, TT, set, op.guest_data_T.len == 0 ? cstr("") : cstr(", .guest = guest"))); + // todo: figure out mutability restrictions shit later VecU8_append_vec(res, VecU8_fmt( - "NODISCARD %s %s_drop(%s self) {\n")); + "RBTreeNode_%s* %s_find_min(const %s* self) {\n" /* TT, set, set */ + SPACE "if (self->root == self->NIL)\n" + SPACE SPACE "return NULL;\n" + SPACE "return (RBTreeNode_%s*)RBTreeNode_minimum_in_subtree(self->root, self->NIL);\n" /* TT */ + "}\n\n", TT, set, set, TT)); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_max(const %s* self) {\n" /* TT, set, set */ + SPACE "if (self->root == self->NIL)\n" + SPACE SPACE "return NULL;\n" + SPACE "return (RBTreeNode_%s*)RBTreeNode_maximum_in_subtree(self->root, self->NIL);\n" /* TT */ + "}\n\n", TT, set, set, TT)); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_next(const %s* self, RBTreeNode_%s* x){\n" /* TT, set, set, TT */ + SPACE "return (RBTreeNode_%s *)RBTreeNode_find_next((RBTreeNode*)x, self->NIL);\n" /* TT */ + "}\n\n", TT, set, set, TT, TT)); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_prev(const %s* self, RBTreeNode_%s* x){\n" /* TT, set, set, TT */ + SPACE "return (RBTreeNode_%s *)RBTreeNode_find_prev((RBTreeNode*)x, self->NIL);\n" /* TT */ + "}\n\n", TT, set, set, TT, TT)); + + /* Here we read and write something to ->left, ->right field of NIL sentinel node. + * These fields are correct pointers (NULL), so everything is ok */ + VecU8_append_vec(res, VecU8_fmt( + "void %s_drop(%s self){\n" /* set, set */ + SPACE "RBTreeNode* cur = self.root;\n" + SPACE "while (cur != self.NIL){\n" + SPACE SPACE "if (cur->left != self.NIL) {\n" + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (cur->right != self.NIL) {\n" + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + /* This is actually safe, although cur->parent may be self.NIL */ + SPACE SPACE SPACE "if (cur->parent->left == cur)\n" + SPACE SPACE SPACE SPACE "cur->parent->left = self.NIL;\n" + SPACE SPACE SPACE "else" + SPACE SPACE SPACE SPACE "cur->parent->right = self.NIL;\n" + SPACE SPACE SPACE "RBTreeNode* parent = cur->parent;\n" + "%v" /* "" / tabulation op.K_drop((RBTreeNode_TT*)cur->key */ + "%v" /* "" / tabulation op.V_drop((RBTreeNode_TT*)cur->value */ + SPACE SPACE SPACE "free((void*)cur);\n" + SPACE SPACE SPACE "cur = parent;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "free(self.NIL);\n" + "}\n\n", set, set, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE SPACE "%s_drop(((RBTreeNode_TT*)cur)->key);\n", op.K, TT), + op.v_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE SPACE "%s_drop(((RBTreeNode_TT*)cur)->value);\n", op.V, TT) + )); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_k_argument */ + SPACE "RBTreeNode* cur = self->root;\n" + SPACE "while (cur != self->NIL) {\n" + SPACE SPACE "if (%v) {\n" /* key < cur->key */ + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (%v) {\n" /* cur->key < key */ + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return NULL;\n" + "}\n\n", + TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_ref(op), codegen_rbtree_map__exp_passing_cur_key(op)), + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_ref(op)), + TT)); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_max_less(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */ + SPACE "RBTreeNode_%s* last_less = NULL;\n" /* TT */ + SPACE "RBTreeNode* cur = self->root;\n" + SPACE "while (cur != self->NIL) {\n" + SPACE SPACE "if (%v) {\n" /* key < cur->key */ + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (%v) {\n" /* cur->key < key */ + SPACE SPACE SPACE "last_less = (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE SPACE "if (cur == self->NIL)\n" + SPACE SPACE SPACE SPACE "return last_less;\n" + SPACE SPACE SPACE "while (cur->right != self->NIL)\n" + SPACE SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_less;\n" + "}\n\n", + TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT, + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_ref(op), codegen_rbtree_map__exp_passing_cur_key(op)), + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_ref(op)), + TT, TT)); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_max_less_or_eq(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */ + SPACE "RBTreeNode_%s* last_less = NULL;\n" /* TT */ + SPACE "RBTreeNode* cur = self->root;\n" + SPACE "while (cur != self->NIL) {\n" + SPACE SPACE "if (%v) {\n" /* key < cur->key */ + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (%v) {\n" /* cur->key < key */ + SPACE SPACE SPACE "last_less = (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_less;\n" + "}\n\n", + TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT, + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_ref(op), codegen_rbtree_map__exp_passing_cur_key(op)), + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_ref(op)), + TT, TT)); + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_min_grtr(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */ + SPACE "RBTreeNode_%s* last_grtr = NULL;\n" /* TT */ + SPACE "RBTreeNode* cur = self->root;\n" + SPACE "while (cur != self->NIL) {\n" + SPACE SPACE "if (%v) {\n" /* key < cur->key */ + SPACE SPACE SPACE "last_grtr = (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (%v) {\n" /* cur->key < key */ + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE SPACE "if (cur == self->NIL)\n" + SPACE SPACE SPACE SPACE "return last_grtr;\n" + SPACE SPACE SPACE "while (cur->left != self->NIL)\n" + SPACE SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_grtr;\n" + "}\n\n", + TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT, + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_ref(op), codegen_rbtree_map__exp_passing_cur_key(op)), + TT, + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_ref(op)), + TT)); + + + VecU8_append_vec(res, VecU8_fmt( + "RBTreeNode_%s* %s_find_min_grtr_or_eq(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */ + SPACE "RBTreeNode_%s* last_grtr = NULL;\n" /* TT */ + SPACE "RBTreeNode* cur = self->root;\n" + SPACE "while (cur != self->NIL) {\n" + SPACE SPACE "if (%v) {\n" /* key < cur->key */ + SPACE SPACE SPACE "last_grtr = (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (%v) {\n" /* cur->key < key */ + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */ + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_grtr;\n" + "}\n\n", + TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT, + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_ref(op), codegen_rbtree_map__exp_passing_cur_key(op)), + TT, + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_ref(op)), + TT)); + + VecU8_append_vec(res, VecU8_fmt( + /* This method is unsafe. Arguments key, value will be taken if 0 is returned, + * or left on their place if not-0 is returned */ + "/* UNSAFE */\n" + "NODISCARD RBTreeNode_%s* %s_try_insert(%s* self, %v) {\n" /* TT, set, set, taking_t_argument */ + SPACE "RBTreeNode** surprising = &self->root;\n" + SPACE "RBTreeNode* prev = self->NIL;\n" + SPACE "RBTreeNode* cur = self->root;\n" + SPACE "while (cur != self->NIL){\n" + SPACE SPACE "prev = cur;\n" + SPACE SPACE "if (%v) {\n" /* key < cur->key */ + SPACE SPACE SPACE "surprising = &cur->left;\n" + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE "} else if (%v) {\n" /* cur->key < key */ + SPACE SPACE SPACE "surprising = &cur->right;\n" + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "return (RBTreeNode_%s *)cur;\n" /* TT */ + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "RBTreeNode_%s* new_node = (RBTreeNode_%s *)safe_malloc(sizeof(RBTreeNode_%s));\n" /* TT, TT, TT */ + SPACE "*new_node = (RBTreeNode_%s){ .base.parent = prev,\n" /* TT */ + SPACE SPACE ".base.left = self->NIL, .base.right = self->NIL, .base.color = RBTREE_RED,\n" + SPACE SPACE ".key = key" "%s" "};\n" /* "" / ,.value = value */ + SPACE "*surprising = (RBTreeNode*)new_node;\n" + SPACE "RBTree_fix_after_insert(&self->root, self->NIL, (RBTreeNode*)new_node);\n" + SPACE "return NULL;\n" + "}\n\n", + TT, set, set, codegen_rbtree_map__taking_t_argument(op), + codegen_rbtree_map__less(op, vcstr("key"), codegen_rbtree_map__exp_passing_cur_key(op)), + codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), vcstr("key")), + TT, + TT, TT, TT, + TT, op.v_primitive ? cstr("") : cstr(", .value = value"))); + + VecU8_append_vec(res, VecU8_fmt( + "bool %s_insert(%s* self, %v){\n" /* set, set, taking_t_argument */ + SPACE "RBTreeNode_%s* col = %s_try_insert(self, key" "%s" ");\n" /* TT, set, "" /, value */ + SPACE "if (col == NULL)\n" + SPACE SPACE "return true;\n" + "%v" "%v" /* "" / dropping key, "" / dropping value */ + SPACE "return false;\n" + "}\n\n", + set, set, codegen_rbtree_map__taking_t_argument(op), + TT, set, op.V.len > 0 ? cstr(", value") : cstr(""), + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(key);\n", op.K), + op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(value);\n", op.V))); + + VecU8_append_vec(res, VecU8_fmt( + "bool %s_erase(%s* self, %v key) {\n" /* set, set, taking_ref_k_argument */ + SPACE "RBTreeNode_%s* v = %s_find(self, key);\n" /* TT, set */ + SPACE "if (v == NULL)\n" + SPACE SPACE "return false;\n" + "%v" /* "" / op.K_drop(v->key) */ + "%v" /* "" / op.V_drop(v->value) */ + SPACE "RBTree_erase_empty_by_iter(&self->root, self->NIL, (RBTreeNode*)v);\n" + SPACE "return true;\n" + "}\n\n", set, set, codegen_rbtree_map__taking_ref_k_argument(op), + TT, set, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(v->key);\n", op.K), + op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(v->value);\n", op.V))); } + +NODISCARD VecU8 get_name_of_rbtree_set_structure(set_instantiation_op op){ + if (op.alternative_comp_set_name_embed.len > 0) + return VecU8_fmt("RBTreeBy%s_Set%s", op.alternative_comp_set_name_embed, op.T); + return VecU8_fmt("RBTree_Set%s", op.T); +} + +NODISCARD VecU8 generate_rbtree_Set_template_instantiation(set_instantiation_op op, bool generate_node_struct){ + set_instantiation_op_fix(&op); + map_instantiation_op map_op = { + .K = op.T, .k_integer = op.t_integer, .k_primitive = op.t_primitive, .k_clonable = op.t_clonable, + .V = cstr(""), .v_primitive = true, .v_clonable = true, + .alternative_comp_map_name_embed = op.alternative_comp_set_name_embed, .alternative_less = op.alternative_less, + .guest_data_T = op.guest_data_T + }; + + VecU8 res = VecU8_new(); + VecU8 set_g = get_name_of_rbtree_set_structure(op); + if (generate_node_struct) + VecU8_append_vec(&res, codegen_rbtree__node_structure(map_op)); + codegen_append_rbtree_map__structure_and_simplest_methods(&res, map_op, VecU8_to_span(&set_g), op.T); + VecU8_drop(set_g); + return res; +} + +void generate_rbtree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, set_instantiation_op op, bool generate_node_struct) { + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_rbtree_Set_template_instantiation(op, generate_node_struct), get_name_of_rbtree_set_structure(op)); +} + +void generate_rbtree_Set_templ_inst_guarded_header( + SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, set_instantiation_op op, bool generate_node_struct + ){ + VecU8 all_dependencies = VecU8_fmt("%v%s", + codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/rb_tree_node.h")), dependencies); + generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies, + generate_rbtree_Set_template_instantiation(op, generate_node_struct), get_name_of_rbtree_set_structure(op)); +} + + +/* Don't forget to do the map stuff, Set is not enough */ + NODISCARD VecU8 get_name_of_rbtree_map_structure(map_instantiation_op op){ if (op.alternative_comp_map_name_embed.len > 0) return VecU8_fmt("RBTreeBy%s_Map%sTo%s", op.alternative_comp_map_name_embed, op.K, op.V); return VecU8_fmt("RBTree_Map%sTo%s", op.K, op.V); } -NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op op){ +NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op op, bool generate_node_struct){ map_instantiation_op_fix(&op); VecU8 res = VecU8_new(); VecU8 map_g = get_name_of_rbtree_map_structure(op); SpanU8 map = VecU8_to_span(&map_g); + VecU8 kvp_g = VecU8_fmt("KVP%sTo%s", op.K, op.V); + SpanU8 kvp = VecU8_to_span(&kvp_g); + + if (generate_node_struct) + VecU8_append_vec(&res, codegen_rbtree__node_structure(op)); + codegen_append_rbtree_map__structure_and_simplest_methods(&res, op, map, kvp); + + VecU8_append_vec(&res, VecU8_fmt( + "%s" "Option%s %s_pop_substitute(%s* self, %s key, %s value) {\n" /* "" / NODISCARD , op.V, map, map, op.K, op.V */ + /* Using unsafe method with conditional ownership transfer */ + SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */ + SPACE "if (col == NULL) {\n" + SPACE SPACE "return None_%s();\n" /* op.V */ + SPACE "} else {\n" + "%v" /* "" / dropping col->key */ + SPACE SPACE "%s saved = col->value;\n" /* op.V */ + SPACE SPACE "col->key = key;\n" + SPACE SPACE "col->value = value;\n" + SPACE SPACE "return Some_%s(saved);\n" /* op.V */ + SPACE "}\n" + "}\n\n", + op.v_primitive ? cstr("") : cstr("NODISCARD "), op.V, map, map, op.K, op.V, + kvp, map, op.V, + op.v_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE"%s_drop(col->key);\n", op.K), + op.V, op.V)); + + if (!op.v_primitive) { + VecU8_append_vec(&res, VecU8_fmt( + "bool %s_erase_substitute(%s* self, %s key, %s value) {\n" /* map, map, op.K, op.V */ + SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */ + SPACE "if (col == NULL)\n" + SPACE SPACE "return true;\n" + "%v" "%v" /* "" / op.K_drop(col->key), "" / op.V_drop(col->value) */ + SPACE "col->key = key;\n" + SPACE "col->value = value;\n" + SPACE "return false;\n" + "}\n\n", + map, map, op.K, op.V, kvp, map, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->key);\n", op.K), + op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->value);\n", op.V))); + } + + VecU8_append_vec(&res, VecU8_fmt( + "Option%s %s_pop(%s* self, %v key) {\n" /* op.V, map, map, taking_ref_k_argument */ + SPACE "RBTreeNode_%s* v = %s_find(self, key);\n" /* kvp, map */ + SPACE "if (v == NULL)\n" + SPACE SPACE "return None_%s();\n" /* op.V */ + "%v" /* "" / op.K_drop(v->key) */ + "%s saved = v->value;\n" /* op.V */ + SPACE "RBTree_erase_empty_by_iter(&self->root, self->NIL, v);\n" + SPACE "return Some_%s();\n" /* op.V */ + "}\n\n", + op.V, map, map, codegen_rbtree_map__taking_ref_k_argument(op), + kvp, map, op.V, + op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(v->key);\n", op.K), + op.V, op.V)); return res; } -#endif \ No newline at end of file +void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op, bool generate_node_struct) { + generate_SOME_templ_inst_eve_header(layer, bonus_ns, + generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op)); +} + +void generate_rbtree_Map_templ_inst_guarded_header( + SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, map_instantiation_op op, bool generate_node_struct + ){ + VecU8 all_dependencies = VecU8_fmt("%v%s", + codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/rb_tree_node.h")), dependencies); + generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies, + generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op)); +} + + +#endif diff --git a/src/l1_5/core/buff_rb_tree_node.h b/src/l1_5/core/buff_rb_tree_node.h index ae51bff..ba9a0db 100644 --- a/src/l1_5/core/buff_rb_tree_node.h +++ b/src/l1_5/core/buff_rb_tree_node.h @@ -3,6 +3,7 @@ #include "../../l1/core/util.h" +// todo: jam that one bit into parent field of BufRBTreeNode typedef enum { RBTree_black = 0, RBTree_red = 1, @@ -16,7 +17,7 @@ typedef struct { RBTreeColor color; } BufRBTreeNode; -#include "../../../gen/l1/eve/embassy_l1_5/VecBuffRBTreeNode.h" +#include "../../../gen/l1/eve/embassy_l1_5/VecBufRBTreeNode.h" void BufRBTree_left_rotate(BufRBTreeNode* tree, U64* root, U64 x){ assert(x != 0); @@ -219,4 +220,6 @@ void BufRBTree_fix_after_delete(BufRBTreeNode* tree, U64* root, U64 me){ tree[me].color = RBTree_black; } +// todo: move here erase_empty method (renmaed to _erase_empty_by_index) + #endif diff --git a/src/l1_5/core/rb_tree_node.h b/src/l1_5/core/rb_tree_node.h index 3d83e7a..a311e48 100644 --- a/src/l1_5/core/rb_tree_node.h +++ b/src/l1_5/core/rb_tree_node.h @@ -4,8 +4,8 @@ #include "../../l1/core/util.h" typedef enum { - RBTree_black = 0, - RBTree_red = 1, + RBTREE_BLACK = 0, + RBTREE_RED = 1, } RBTreeClr; typedef struct RBTreeNode RBTreeNode; @@ -16,29 +16,108 @@ struct RBTreeNode{ RBTreeClr color; }; -// todo: implement and then use -void BufRBTree_left_rotate(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* x){ - // assert(x != 0); - // U64 y = tree[x].right; - // assert(y != 0); - // tree[x].right = tree[y].left; - // if (tree[x].right != 0) - // tree[tree[x].right].parent = x; - // - // tree[y].parent = tree[x].parent; - // if (tree[y].parent == 0) { - // *root = y; - // } else if (x == tree[tree[x].parent].left) { - // tree[tree[x].parent].left = y; - // } else { - // tree[tree[x].parent].right = y; - // } - // tree[x].parent = y; - // tree[y].left = x; +void RBTree_left_rotate(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* x){ + assert(x != NIL); + RBTreeNode* y = x->right; + assert(y != NIL); + x->right = y->left; + if (y->left != NIL) + y->left->parent = x; + + y->parent = x->parent; + if (x->parent == NIL) + *root = y; + else if (x == x->parent->left) + x->parent->left = y; + else + x->parent->right = y; + + x->parent = y; + y->left = x; +} + +void RBTree_right_rotate(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* x){ + assert(x != NIL); + RBTreeNode* y = x->left; + assert(y != NIL); + x->left = y->right; + if (y->right != NIL) + y->right->parent = x; + + y->parent = x->parent; + if (x->parent == NIL) + *root = y; + else if (x->parent->right == x) + x->parent->right = y; + else + x->parent->left = y; + + x->parent = y; + y->right = x; +} + +void RBTree_fix_after_insert(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* me){ + assert(me != NIL); + while (true) { + RBTreeNode* mom = me->parent; + if (mom == NIL) + break; + if (mom->color == RBTREE_BLACK) + return; + RBTreeNode* grandma = mom->parent; + assert(grandma != NIL); + assert(grandma->color == RBTREE_BLACK); + RBTreeNode* aunt = grandma->left == mom ? grandma->right : grandma->left; + assert(aunt != mom); + if (aunt->color == RBTREE_RED) { + /* Easy case */ + mom->color = RBTREE_BLACK; + aunt->color = RBTREE_BLACK; + grandma->color = RBTREE_RED; + me = grandma; + } else if (grandma->left == mom) { + /* Hard case: firstborn orientation */ + if (mom->right == me) { + RBTree_left_rotate(root, NIL, mom); + me->color = RBTREE_BLACK; + } else { + mom->color = RBTREE_BLACK; + } + RBTree_right_rotate(root, NIL, grandma); + grandma->color = RBTREE_RED; + return; + } else { + /* Hard case: benjamin orientation */ + if (mom->left == me) { + RBTree_right_rotate(root, NIL, mom); + me->color = RBTREE_BLACK; + } else { + mom->color = RBTREE_BLACK; + } + RBTree_left_rotate(root, NIL, grandma); + grandma->color = RBTREE_RED; + return; + } + } + assert(*root == me); + me->color = RBTREE_BLACK; } -RBTreeNode* RBTree_minimum_in_subtree(RBTreeNode* x, RBTreeNode* NIL){ +void RBTree_steal_neighbours(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* fr, RBTreeNode* to){ + if (fr->parent == NIL) + *root = to; + else if (fr->parent->left == fr) + fr->parent->left = to; + else + fr->parent->right = to; + fr->left->parent = to; + fr->right->parent = to; + *to = *fr; +} + + +RBTreeNode* RBTreeNode_minimum_in_subtree(RBTreeNode* x, RBTreeNode* NIL){ assert(x != NIL); while (x->left != NIL) x = x->left; @@ -52,4 +131,149 @@ RBTreeNode* RBTreeNode_maximum_in_subtree(RBTreeNode* x, RBTreeNode* NIL){ return x; } +/* Returns NULL instead of NIL */ +RBTreeNode* RBTreeNode_find_next(RBTreeNode* x, RBTreeNode* NIL){ + assert(x != NIL); + if (x->right != NIL) + return RBTreeNode_minimum_in_subtree(x->right, NIL); + while (true) { + RBTreeNode* p = x->parent; + if (p == NIL) + return NULL; + if (p->left == x) + return p; + x = p; + } +} + +/* Returns NULL instead of NIL */ +RBTreeNode* RBTreeNode_find_prev(RBTreeNode* x, RBTreeNode* NIL){ + assert(x != NIL); + if (x->left != NIL) + return RBTreeNode_maximum_in_subtree(x->left, NIL); + while (true) { + RBTreeNode* p = x->parent; + if (p == NIL) + return NULL; + if (p->right == x) + return p; + x = p; + } +} + +/* me may be NIL at the beginning. ->parent field of NIL is meaningful */ +void RBTree_fix_after_delete(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* me){ + assert((*root)->parent == NIL); + while (me != *root && me->color == RBTREE_BLACK) { + RBTreeNode* mom = me->parent; + assert(mom != NIL); + if (me == mom->left) { /* We are on the left */ + RBTreeNode* sister = mom->right; + assert(sister != NIL); + if (sister->color == RBTREE_RED) { /* Case 1 */ + mom->color = RBTREE_RED; + sister->color = RBTREE_BLACK; + RBTree_left_rotate(root, NIL, mom); + /* Reassignation required */ + sister = mom->right; + assert(sister != NIL); + } + /* Cases 2,3,4 */ + RBTreeNode* nephew_firstborn = sister->left; + RBTreeNode* nephew_benjamin = sister->right; + if (nephew_firstborn->color == RBTREE_BLACK && nephew_benjamin->color == RBTREE_BLACK) { + /* Case 2 */ + sister->color = RBTREE_RED; + me = mom; + continue; + } + /* Cases 3,4 */ + if (nephew_benjamin->color == RBTREE_BLACK) { + /* Case 3 */ + nephew_firstborn->color = RBTREE_BLACK; + sister->color = RBTREE_RED; + RBTree_right_rotate(root, NIL, sister); + /* Reassignation required */ + nephew_benjamin = sister; + sister = nephew_firstborn; + assert(sister != NIL); + /*nephew_firstborn = sister->left;*/ + } + /* Case 4 */ + sister->color = mom->color; + mom->color = RBTREE_BLACK; + nephew_benjamin->color = RBTREE_BLACK; + RBTree_left_rotate(root, NIL, mom); + me = *root; + } else { /* We are on the right */ + assert(me == mom->right); + RBTreeNode* sister = mom->left; + assert(sister != NULL); + if (sister->color == RBTREE_RED) { /* Case 1 */ + mom->color = RBTREE_RED; + sister->color = RBTREE_BLACK; + RBTree_right_rotate(root, NIL, mom); + /* Reassignation required */ + sister = mom->left; + assert(sister != NIL); + } + /* Cases 2,3,4 (every instance of red-black tree has an itchy substring in source code containing 2,3,4) */ + RBTreeNode* nephew_firstborn = sister->left; + RBTreeNode* nephew_benjamin = sister->right; + if (nephew_firstborn->color == RBTREE_BLACK && nephew_benjamin->color == RBTREE_BLACK) { + /* Case 2 */ + sister->color = RBTREE_RED; + me = mom; + continue; + } + /* Cases 3,4 */ + if (nephew_firstborn->color == RBTREE_BLACK) { + /* Case 3 */ + nephew_benjamin->color = RBTREE_BLACK; + sister->color = RBTREE_RED; + RBTree_left_rotate(root, NIL, sister); + /* Reassignation required */ + nephew_firstborn = sister; + sister = nephew_benjamin; + assert(sister != NIL); + /*nephew_benjamin = sister->right;*/ + } + /* Case 4 */ + sister->color = mom->color; + mom->color = RBTREE_BLACK; + nephew_firstborn->color = RBTREE_BLACK; + RBTree_right_rotate(root, NIL, mom); + me = *root; + } + } + me->color = RBTREE_BLACK; +} + +/* Assumes that z->key and z->value were already dropped properly. Frees z node */ +void RBTree_erase_empty_by_iter(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* z) { + assert(z != NULL); + assert(z != NIL); + RBTreeNode* y = (z->left == NULL || z->right == 0) ? z : RBTreeNode_minimum_in_subtree(z, NIL); + RBTreeNode* x = y->left == NIL ? y->right : y->left; + assert(x != y && x != z); + RBTreeNode* x_adopter = y->parent; + x->parent = x_adopter; + if (x_adopter == NIL) + *root = x; + else if (x_adopter->left == y) + x_adopter->left = x; + else + x_adopter->right = x; + RBTreeClr y_org_clr = y->color; + if (z != y) { + RBTree_steal_neighbours(root, NIL, z, y); + if (x_adopter == z) + x_adopter = y; + } + x->parent = x_adopter; + if (y_org_clr == RBTREE_BLACK) + RBTree_fix_after_delete(root, NIL, x); + free((void*)z); +} + #endif \ No newline at end of file diff --git a/src/l2/tests/data_structures/t0.c b/src/l2/tests/data_structures/t0.c index 5631c4f..89dc5ee 100644 --- a/src/l2/tests/data_structures/t0.c +++ b/src/l2/tests/data_structures/t0.c @@ -5,17 +5,17 @@ #include "../../../l1/system/fsmanip.h" #include "../../../l1/system/creating_child_proc.h" -void check_structure_h_dfs(const VecRBTreeNode* tree, U64 x, VecU8* f){ +void check_structure_h_dfs(const VecBufRBTreeNode* tree, U64 x, VecU8* f){ if (x == 0) return; if (*VecU8_at(f, x - 1) != 0) check(false); *VecU8_mat(f, x - 1) = 1; - check_structure_h_dfs(tree, VecRBTreeNode_at(tree, x)->left, f); - check_structure_h_dfs(tree, VecRBTreeNode_at(tree, x)->right, f); + check_structure_h_dfs(tree, VecBufRBTreeNode_at(tree, x)->left, f); + check_structure_h_dfs(tree, VecBufRBTreeNode_at(tree, x)->right, f); } -U32 check_structure_h_dfs_2(RBTreeNode* tree, U64 x){ +U32 check_structure_h_dfs_2(BufRBTreeNode* tree, U64 x){ if (x == 0) { return 0; } @@ -420,10 +420,10 @@ void chaos(){ void triple_black(){ BuffRBTree_SetS64 set; { - VecRBTreeNode tree = VecRBTreeNode_new_zeroinit(4); - tree.buf[1] = (RBTreeNode){.parent = 3}; - tree.buf[2] = (RBTreeNode){.parent = 3}; - tree.buf[3] = (RBTreeNode){.left = 2, .right = 1}; + VecBufRBTreeNode tree = VecBufRBTreeNode_new_zeroinit(4); + tree.buf[1] = (BufRBTreeNode){.parent = 3}; + tree.buf[2] = (BufRBTreeNode){.parent = 3}; + tree.buf[3] = (BufRBTreeNode){.left = 2, .right = 1}; VecS64 el = VecS64_new_reserved(3); VecS64_append(&el, 300); VecS64_append(&el, 100); diff --git a/src/l2/tests/data_structures/t0_3.c b/src/l2/tests/data_structures/t0_3.c new file mode 100644 index 0000000..95e0f19 --- /dev/null +++ b/src/l2/tests/data_structures/t0_3.c @@ -0,0 +1,262 @@ +#include "../../../../gen/l1_5/RBTree_SetS64.h" +#include "../../../../gen/l1/VecAndSpan_U8.h" +#include "../../../../gen/l1/VecAndSpan_S64.h" + +#include "../../../l1/core/VecU8_as_str.h" +#include "../../../l1/system/fileio.h" +#include "../../../l1/system/fsmanip.h" +#include "../../../l1/system/creating_child_proc.h" + +typedef RBTreeNode_S64* RefRBTreeNode_S64; + +#include "../../../../gen/l1/eve/ds_test/VecRefRBTreeNode_S64.h" + +S64 min_key_in_subtree(RBTreeNode_S64* x, RBTreeNode* NIL){ + check(x != NULL && &x->base != NIL); + S64 ans = x->key; + if (x->base.left != NIL) + ans = MIN_S64(ans, min_key_in_subtree((RBTreeNode_S64*)x->base.left, NIL)); + if (x->base.right != NIL) + ans = MIN_S64(ans, min_key_in_subtree((RBTreeNode_S64*)x->base.right, NIL)); + return ans; +} + +S64 max_key_in_subtree(RBTreeNode_S64* x, RBTreeNode* NIL){ + check(x != NULL && &x->base != NIL); + S64 ans = x->key; + if (x->base.left != NIL) + ans = MAX_S64(ans, max_key_in_subtree((RBTreeNode_S64*)x->base.left, NIL)); + if (x->base.right != NIL) + ans = MAX_S64(ans, max_key_in_subtree((RBTreeNode_S64*)x->base.right, NIL)); + return ans; +} + +int check_structure_h_dfs(RBTree_SetS64* set, RBTreeNode_S64* x){ + check(x != NULL); + if (&x->base == set->NIL) + return 0; + int a = x->base.left == set->NIL ? 0 : check_structure_h_dfs(set, (RBTreeNode_S64*)x->base.left); + int b = x->base.right == set->NIL ? 0 : check_structure_h_dfs(set, (RBTreeNode_S64*)x->base.right); + check(a == b); + if (&x->base == set->root) { + check(x->base.parent == set->NIL); + } else { + check(x->base.parent != set->NIL); + } + if (x->base.left != set->NIL) + check(x->base.left->parent == &x->base); + if (x->base.right != set->NIL) + check(x->base.right->parent == &x->base); + + if (x->base.left != set->NIL) + check(max_key_in_subtree((RBTreeNode_S64*)x->base.left, set->NIL) < x->key); + if (x->base.right != set->NIL) + check(x->key < min_key_in_subtree((RBTreeNode_S64*)x->base.right, set->NIL)); + + if (x->base.color == RBTREE_RED) { + check(x->base.left->color == RBTREE_BLACK); + check(x->base.right->color == RBTREE_BLACK); + } + + return a + (x->base.color == RBTREE_BLACK ? 1 : 0); +} + +void check_correctness(RBTree_SetS64* set){ + check(set->root->color == RBTREE_BLACK); + check_structure_h_dfs(set, (RBTreeNode_S64*)set->root); +} + + +void save_tree_to_file(const RBTree_SetS64* set, SpanU8 name){ + // check_only_structure(set); + + VecU8 graph = vcstr( + "digraph rbtree {\n" + " fontsize = 20\n" + " rankdir = TB\n" + " bgcolor = \"lightgray\"\n" + " node [fontname = \"Arial\", style=\"rounded,filled\", shape=circle];\n\n"); + + VecRefRBTreeNode_S64 bfs_nxt = VecRefRBTreeNode_S64_new(); + VecRefRBTreeNode_S64 bfs = VecRefRBTreeNode_S64_new(); + if (set->root != set->NIL) + VecRefRBTreeNode_S64_append(&bfs_nxt, (RBTreeNode_S64*)set->root); + while (bfs_nxt.len > 0) { + VecRefRBTreeNode_S64 t = bfs_nxt; + bfs_nxt = bfs; + bfs = t; + for (size_t j = 0; j < bfs.len; j++) { + RBTreeNode_S64* cur = *VecRefRBTreeNode_S64_at(&bfs, j); + assert(cur != NULL); + if (cur->base.left != set->NIL) + VecRefRBTreeNode_S64_append(&bfs, (RBTreeNode_S64*)cur->base.left); + if (cur->base.right != set->NIL) + VecRefRBTreeNode_S64_append(&bfs, (RBTreeNode_S64*)cur->base.right); + + VecU8_append_vec(&graph, VecU8_fmt( + " v%i [label=%i, color=%s, fontcolor=%s]\n", + cur->key, cur->key, + cur->base.color == RBTREE_BLACK ? cstr("black") : cstr("red"), + cur->base.color == RBTREE_BLACK ? cstr("white") : cstr("black"))); + + if (cur->base.left != set->NIL) + VecU8_append_vec(&graph, VecU8_fmt(" v%i -> v%i [label=left]\n", + cur->key, ((RBTreeNode_S64*)cur->base.left)->key)); + if (cur->base.right != set->NIL) + VecU8_append_vec(&graph, VecU8_fmt(" v%i -> v%i [label=right]\n", + cur->key, ((RBTreeNode_S64*)cur->base.right)->key)); + } + bfs.len = 0; + } + VecU8_append_span(&graph, cstr("}\n")); + mkdir_nofail("GRAPHS"); + VecU8 dot_filename_nt = VecU8_fmt("GRAPHS/GRAPH_%s.gv%c", name, 0); + write_whole_file_or_abort((CSTR)dot_filename_nt.buf, VecU8_to_span(&graph)); + VecU8_drop(graph); + VecU8_drop(dot_filename_nt); + VecU8 command_nt = VecU8_fmt("dot -Tpng GRAPHS/GRAPH_%s.gv -o GRAPHS/GRAPH_%s.png%c", name, name, 0); + calling_system_func_nofail((CSTR)command_nt.buf); + VecU8_drop(command_nt); +} + + + +void insert_only(){ + { + RBTree_SetS64 set = RBTree_SetS64_new(); + check_correctness(&set); + RBTree_SetS64_drop(set); + } + { + RBTree_SetS64 set = RBTree_SetS64_new(); + for (S64 p = 0; p < 100; p++) { + bool ret = RBTree_SetS64_insert(&set, 2 * p); + check(ret); + check_correctness(&set); + // save_tree_to_file(&set, cstr("last_correct")); + for (S64 i = 0; i <= p; i++) { + RBTreeNode_S64* ret1 = RBTree_SetS64_find(&set, 2 * i); + check(ret1 != NULL); + RBTreeNode_S64* ret2 = RBTree_SetS64_find(&set, 2 * i + 1); + check(ret2 == NULL); + } + } + RBTree_SetS64_drop(set); + } + { + RBTree_SetS64 set = RBTree_SetS64_new(); + for (S64 p = -99; p <= 0; p++) { + bool ret = RBTree_SetS64_insert(&set, 2 * p); + check(ret); + check_correctness(&set); + // save_tree_to_file(&set, cstr("last_correct")); + for (S64 i = -99; i <= p; i++) { + RBTreeNode_S64* ret1 = RBTree_SetS64_find(&set, 2 * i); + check(ret1 != NULL); + RBTreeNode_S64* ret2 = RBTree_SetS64_find(&set, 2 * i + 1); + check(ret2 == NULL); + } + } + RBTree_SetS64_drop(set); + } + for (int s = 0; s < 1000; s++) { + srand(s); + VecS64 have = VecS64_new(); + RBTree_SetS64 set = RBTree_SetS64_new(); + for (int m = 0; m < 1000; m++) { + S64 x = (S64)rand(); + bool in = false; + for (size_t j = 0; j < have.len; j++) { + if (have.buf[j] == x) + in = true; + } + bool iret = RBTree_SetS64_insert(&set, x); + if (in) { + check(!iret); + } else { + check(iret); + VecS64_append(&have, x); + } + } + RBTree_SetS64_drop(set); + } +} + +void s_4_t_42(){ + RBTreeNode_S64* v0 = safe_malloc(sizeof(RBTreeNode_S64)); + RBTreeNode_S64* v10 = safe_malloc(sizeof(RBTreeNode_S64)); + RBTreeNode_S64* v20 = safe_malloc(sizeof(RBTreeNode_S64)); + RBTreeNode_S64* v30 = safe_malloc(sizeof(RBTreeNode_S64)); + RBTreeNode* NIL = safe_calloc(1, sizeof(RBTreeNode)); + *v0 = (RBTreeNode_S64){ .base.parent = &v20->base, .base.left = NIL, .base.right = &v10->base, + .base.color = RBTREE_BLACK, .key = 0}; + *v10 = (RBTreeNode_S64){ .base.parent = &v0->base, .base.left = NIL, .base.right = NIL, + .base.color = RBTREE_RED, .key = 10}; + *v20 = (RBTreeNode_S64){ .base.parent = NIL, .base.left = &v0->base, .base.right = &v30->base, + .base.color = RBTREE_BLACK, .key = 20}; + *v30 = (RBTreeNode_S64){ .base.parent = &v20->base, .base.left = NIL, .base.right = NIL, + .base.color = RBTREE_BLACK, .key = 30}; + RBTree_SetS64 set = {.root = &v20->base, .NIL = NIL}; + check_correctness(&set); + save_tree_to_file(&set, cstr("SOROK_ONE")); + check(RBTree_SetS64_erase(&set, 20)); + save_tree_to_file(&set, cstr("I_AM_LOOSING_MY_FUCKING_MIND")); + check_correctness(&set); +} + +void stress(){ + printf("Are you ready for real stress?\n"); + for (int s = 4; s < 1000; s++) { + srand(s); + RBTree_SetS64 set = RBTree_SetS64_new(); + VecS64 real_set = VecS64_new(); + U32 n = (U32)s; + VecS64 complementary_set = VecS64_new_reserved(n); + for (size_t i = 0; i < n; i++) { + VecS64_append(&complementary_set, (S64)i * 10); + } + for (int t = 0; t < 1000; t++) { + /* Do something */ + int do_insertion = rand() % 2; + if (real_set.len == 0) + do_insertion = 1; + if (complementary_set.len == 0) + do_insertion = 0; + if (do_insertion) { + assert(complementary_set.len > 0); + size_t j = rand() % complementary_set.len; + S64 v = VecS64_unordered_pop(&complementary_set, j); + VecS64_append(&real_set, v); + check(RBTree_SetS64_insert(&set, v)); + check_correctness(&set); + } else { + assert(real_set.len > 0); + size_t j = rand() % real_set.len; + S64 v = VecS64_unordered_pop(&real_set, j); + VecS64_append(&complementary_set, v); + check(RBTree_SetS64_erase(&set, v)); + check_correctness(&set); + } + // VecU8 name = VecU8_fmt("t_%u", (U64)t); + // save_tree_to_file(&set, VecU8_to_span(&name)); + /* We did something */ + for (size_t j = 0; j < real_set.len; j++) { + check(RBTree_SetS64_find(&set, real_set.buf[j]) != NULL); + } + for (size_t j = 0; j < complementary_set.len; j++) { + check(RBTree_SetS64_find(&set, complementary_set.buf[j]) == NULL); + } + } + VecS64_drop(real_set); + VecS64_drop(complementary_set); + RBTree_SetS64_drop(set); + printf("Seed s=%d passed test\n", s); + } +} + +int main(){ + // insert_only(); + // stress(); + s_4_t_42(); + return 0; +}