diff --git a/CMakeLists.txt b/CMakeLists.txt index 70daa25..27fea5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/src/l1/anne/util_temp_very_base.h b/src/l1/anne/util_temp_very_base.h index 22ad5bc..095ddb2 100644 --- a/src/l1/anne/util_temp_very_base.h +++ b/src/l1/anne/util_temp_very_base.h @@ -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, diff --git a/src/l1/codegen/codegen.h b/src/l1/codegen/codegen.h index 61741f0..75850a1 100644 --- a/src/l1/codegen/codegen.h +++ b/src/l1/codegen/codegen.h @@ -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 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 127e91f..798b527 100644 --- a/src/l1_5/anne/l1_5_templ_very_base.h +++ b/src/l1_5/anne/l1_5_templ_very_base.h @@ -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 \ No newline at end of file +#endif diff --git a/src/l1_5/codegen/rb_tree_set_map_template_inst.h b/src/l1_5/codegen/rb_tree_set_map_template_inst.h index e903ee9..7974e5b 100644 --- a/src/l1_5/codegen/rb_tree_set_map_template_inst.h +++ b/src/l1_5/codegen/rb_tree_set_map_template_inst.h @@ -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 \ No newline at end of file diff --git a/src/l2/tests/data_structures/t0.c b/src/l2/tests/data_structures/t0.c new file mode 100644 index 0000000..6c2af0c --- /dev/null +++ b/src/l2/tests/data_structures/t0.c @@ -0,0 +1,5 @@ +#include "../../../../gen/l1_5/BuffRBTree_SetS64.h" + +int main() { + return 0; +} diff --git a/src/l2/tests/t0.c b/src/l2/tests/t0.c deleted file mode 100644 index a74e630..0000000 --- a/src/l2/tests/t0.c +++ /dev/null @@ -1,3 +0,0 @@ -int main(){ - -} \ No newline at end of file