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 7974e5b..496e4b9 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 @@ -6,8 +6,8 @@ /* When key is given by value into some method of Buff_RBTreeSet */ NODISCARD VecU8 codegen_rb_tree_set_key_value_NOT_EQUAL_element(set_instantiation_op op){ if (op.t_integer) - return VecU8_fmt("self->el.buf[cur - 1] != key"); - return VecU8_fmt("!%s_equal_%s(&self->el.buf[cur - 1], &key)", op.T, op.T); + return VecU8_fmt("key != self->el.buf[cur - 1]"); + return VecU8_fmt("!%s_equal_%s(&key, &self->el.buf[cur - 1])", op.T, op.T); } /* When key is given by value into some method of Buff_RBTreeSet */ @@ -17,17 +17,25 @@ NODISCARD VecU8 codegen_rb_tree_set_key_value_LESS_element(set_instantiation_op return VecU8_fmt("%s_less_%s(&key, &self->el.buf[cur - 1])", op.T, op.T); } +/* When key is given by ref into some method of Buff_RBTreeSet + * Ofk when op.T is integer, argument is still taken by a value */ +NODISCARD VecU8 codegen_rb_tree_set_key_ref_NOT_EQUAL_element(set_instantiation_op op){ + if (op.t_integer) + return VecU8_fmt("key != self->el.buf[cur - 1]"); + return VecU8_fmt("!%s_equal_%s(key, &self->el.buf[cur - 1])", op.T, op.T); +} + /* When key is given by a pointer into some method of Buff_RBTreeSet */ NODISCARD VecU8 codegen_rb_tree_set_key_ref_EQUAL_element(set_instantiation_op op){ if (op.t_integer) - return VecU8_fmt("self->el.buf[cur - 1] == key"); - return VecU8_fmt("%s_equal_%s(&self->el.buf[cur - 1], key)", op.T, op.T); + return VecU8_fmt("key == self->el.buf[cur - 1]"); + return VecU8_fmt("%s_equal_%s(ref, &self->el.buf[cur - 1])", op.T, op.T); } /* When key is given by a pointer into some method of Buff_RBTreeSet */ NODISCARD VecU8 codegen_rb_tree_set_key_ref_LESS_element(set_instantiation_op op){ if (op.t_integer) - return VecU8_fmt("self->el.buf[cur - 1] < key"); + return VecU8_fmt("key < self->el.buf[cur - 1]"); return VecU8_fmt("%s_less_%s(key, &self->el.buf[cur - 1])", op.T, op.T); } @@ -162,6 +170,11 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op SPACE "Vec%s el;\n" "} %s;\n\n", op.T, set)); + VecU8_append_vec(&res, VecU8_fmt( + "NODISCARD %s %s_new() {\n" + SPACE "return (%s){.tree = VecRBTreeNode_new_zeroinit(1), .root = 0, .el = Vec%s_new()};\n" + "}\n\n", set, set, set, op.T)); + VecU8_append_vec(&res, VecU8_fmt( "void %s_drop(%s self) {\n" SPACE "VecRBTreeNode_drop(self.tree);\n" @@ -179,19 +192,21 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op "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) { + /* Method _erase_substitute() is a more 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" + )); + + /* Method _pop_substitute() is just like _erase_substitute(), but it returns a previous key + * that was overthrown after collision. Wrapped in option, ofcourse */ 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)), @@ -224,7 +239,7 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op SPACE SPACE "self->root = x;\n" SPACE "else if (self->tree.buf[py].left == y)\n" SPACE SPACE "self->tree.buf[py].left = x;\n" - SPACE "else" + SPACE "else\n" 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" @@ -234,7 +249,7 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op SPACE "self->tree.len--;\n" SPACE "self->el.buf[z-1] = self->el.buf[L-1];\n" SPACE "self->el.len--;\n" - SPACE "if (y_org_clr)" + SPACE "if (y_org_clr)\n" SPACE SPACE "RBTree_fix_after_delete(self->tree.buf, &self->root, x);\n" SPACE "return true;\n" "}\n\n", @@ -243,11 +258,50 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op codegen_rb_tree_set_key_ref_LESS_element(op) )); + VecU8_append_vec(&res, VecU8_fmt( + "U64 %s_find(const %s* self, %v key) {\n" /* set, set taking_ref_t_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 cue element */ + SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return cur;\n" + "}\n\n", + set, set, codegen_rb_tree_set_taking_ref_t_argument(op), + codegen_rb_tree_set_key_ref_NOT_EQUAL_element(op), + codegen_rb_tree_set_key_ref_LESS_element(op) + )); + + if (!op.t_integer) { + VecU8_append_vec(&res, VecU8_fmt( + "%v %s_at(const %s* self, %v key) {\n" /* option_returned_ref_t, set, set, taking_ref_t_argument */ + SPACE "U64 cur = self->root;\n" + SPACE "while (cur != 0) {\n" + SPACE SPACE "if (%v) {\n" /* key_ref_EQUAL_element */ + SPACE SPACE SPACE "return %v;\n" /* some_ref_t */ + SPACE SPACE "} else if (%v) {\n" /* key_ref_LESS_element */ + SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return %v;\n" /* none_ref_t */ + "}\n\n", + codegen_rb_tree_set_option_returned_ref_t(op), set, set, codegen_rb_tree_set_taking_ref_t_argument(op), + codegen_rb_tree_set_key_ref_EQUAL_element(op), + codegen_rb_tree_set_some_ref_t(op, cstr("cur")), + codegen_rb_tree_set_key_ref_LESS_element(op), + codegen_rb_tree_set_none_ref_t(op) + )); + } + // todo: continue from here. Implement method _pop_and_substitute() - // todo: implement contains method + // todo: All the other methods are secondary in importance - // todo: implment _find and _at methods. All the other methods are secondary in importance VecU8_drop(g_set); return res; } diff --git a/src/l1_5/core/rb_tree_node.h b/src/l1_5/core/rb_tree_node.h index d7c0450..d39aa16 100644 --- a/src/l1_5/core/rb_tree_node.h +++ b/src/l1_5/core/rb_tree_node.h @@ -27,7 +27,7 @@ void RBTree_left_rotate(RBTreeNode* tree, U64* root, U64 x){ tree[tree[x].right].parent = x; tree[y].parent = tree[x].parent; - if (tree[y].parent != 0) { + if (tree[y].parent == 0) { *root = y; } else if (x == tree[tree[x].parent].left) { tree[tree[x].parent].left = y; @@ -47,7 +47,7 @@ void RBTree_right_rotate(RBTreeNode* tree, U64* root, U64 x){ tree[tree[x].left].parent = x; tree[y].parent = tree[x].parent; - if (tree[y].parent != 0) { + if (tree[y].parent == 0) { *root = y; } else if (x == tree[tree[x].parent].right) { tree[tree[x].parent].right = y; @@ -66,7 +66,7 @@ void RBTree_fix_after_insert(RBTreeNode* tree, U64* root, U64 me){ if (mom == 0) break; if (tree[mom].color == RBTree_black) - break; + return; U64 grandma = tree[mom].parent; U64 aunt = tree[grandma].left == mom ? tree[grandma].right : tree[grandma].left; assert(aunt != mom); diff --git a/src/l2/tests/data_structures/t0.c b/src/l2/tests/data_structures/t0.c index 6c2af0c..d5b8535 100644 --- a/src/l2/tests/data_structures/t0.c +++ b/src/l2/tests/data_structures/t0.c @@ -1,5 +1,177 @@ #include "../../../../gen/l1_5/BuffRBTree_SetS64.h" +void assert_structure_h_dfs(const VecRBTreeNode* tree, U64 x, VecU8* f){ + if (x == 0) + return; + if (*VecU8_at(f, x - 1) != 0) + assert(false); + *VecU8_mat(f, x - 1) = 1; + assert_structure_h_dfs(tree, VecRBTreeNode_at(tree, x)->left, f); + assert_structure_h_dfs(tree, VecRBTreeNode_at(tree, x)->right, f); +} + +U32 assert_structure_h_dfs_2(RBTreeNode* tree, U64 x){ + if (x == 0) { + return 0; + } + U32 a = assert_structure_h_dfs_2(tree, tree[x].left); + U32 b = assert_structure_h_dfs_2(tree, tree[x].right); + assert(a == b); + return a + (tree[x].color == RBTree_black ? 1 : 0); +} + +void assert_structure(const BuffRBTree_SetS64* self){ + assert(self->tree.len == self->el.len + 1); + assert(self->root < self->tree.len); + if (self->tree.len > 1) { + assert(self->root != 0); + } + VecU8 f = VecU8_new_zeroinit(self->tree.len - 1); + assert_structure_h_dfs(&self->tree, self->root, &f); + for (size_t i = 0; i < self->tree.len - 1; i++) { + assert(*VecU8_at(&f, i)); + } + VecU8_drop(f); /* f invalidated */ + for (size_t v = 1; v < self->tree.len; v++) { + if (v == self->root) { + assert(self->tree.buf[v].parent == 0); + } else { + assert(self->tree.buf[v].parent != 0); + } + assert(self->tree.buf[v].parent < self->tree.len); + assert(self->tree.buf[v].left < self->tree.len); + assert(self->tree.buf[v].right < self->tree.len); + if (self->tree.buf[v].left != 0) { + assert(self->tree.buf[self->tree.buf[v].left].parent == v); + assert(self->el.buf[self->tree.buf[v].left - 1] < self->el.buf[v - 1]); + } + if (self->tree.buf[v].right != 0) { + assert(self->tree.buf[self->tree.buf[v].right].parent == v); + assert(self->el.buf[v - 1] < self->el.buf[self->tree.buf[v].right - 1]); + } + } + + /* Checking coloring */ + assert(self->tree.buf[0].color == RBTree_black); + if (self->root != 0) + assert(self->tree.buf[self->root].color == RBTree_black); + for (size_t v = 1; v < self->tree.len; v++) { + if (self->tree.buf[v].color == RBTree_red) { + assert(self->tree.buf[self->tree.buf[v].left].color == RBTree_black); + assert(self->tree.buf[self->tree.buf[v].right].color == RBTree_black); + } + } + assert_structure_h_dfs_2(self->tree.buf, self->root); +} + +void insert_only(){ + { + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + assert_structure(&set); + BuffRBTree_SetS64_drop(set); + } + { + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + bool ret = BuffRBTree_SetS64_insert(&set, 42); + assert(ret); + assert_structure(&set); + assert(set.el.len == 1); + assert(set.root == 1); + BuffRBTree_SetS64_drop(set); + } + { + bool ret; + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + ret = BuffRBTree_SetS64_insert(&set, 42); + assert(ret); + assert_structure(&set); + ret = BuffRBTree_SetS64_insert(&set, 69); + assert(ret); + assert_structure(&set); + assert(set.el.len == 2); + BuffRBTree_SetS64_drop(set); + } + { + bool ret; + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + ret = BuffRBTree_SetS64_insert(&set, 70); + assert(ret); + assert_structure(&set); + ret = BuffRBTree_SetS64_insert(&set, 50); + assert(ret); + assert_structure(&set); + assert(set.el.len == 2); + BuffRBTree_SetS64_drop(set); + } + { + bool ret; + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + ret = BuffRBTree_SetS64_insert(&set, 1); + assert(ret); + assert_structure(&set); + ret = BuffRBTree_SetS64_insert(&set, 2); + assert(ret); + assert_structure(&set); + ret = BuffRBTree_SetS64_insert(&set, 3); + assert(ret); + assert_structure(&set); + BuffRBTree_SetS64_drop(set); + } + { + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + for (S64 i = 10; i < 100; i++) { + bool ret = BuffRBTree_SetS64_insert(&set, i); + assert(ret); + assert_structure(&set); + } + BuffRBTree_SetS64_drop(set); + } + { + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + for (S64 i = 99; i >= 10; i--) { + bool ret = BuffRBTree_SetS64_insert(&set, i); + assert(ret); + assert_structure(&set); + } + BuffRBTree_SetS64_drop(set); + } + { + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + for (S64 i = 10; i < 100; i++) { + bool ret = BuffRBTree_SetS64_insert(&set, i); + assert(ret); + assert_structure(&set); + bool ret2 = BuffRBTree_SetS64_insert(&set, 1000 - i); + assert(ret2); + assert_structure(&set); + } + BuffRBTree_SetS64_drop(set); + } + { + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + // BuffRBTree_SetS64_erase_substitute() + BuffRBTree_SetS64_drop(set); + } +} + +void insert_and_then_find(){ + BuffRBTree_SetS64 set = BuffRBTree_SetS64_new(); + for (S64 p = 0; p < 100; p++) { + bool ret = BuffRBTree_SetS64_insert(&set, 2 * p); + assert(ret); + assert_structure(&set); + for (S64 i = 0; i <= p; i++) { + U64 ret1 = BuffRBTree_SetS64_find(&set, 2 * i); + assert(ret1); + U64 ret2 = BuffRBTree_SetS64_find(&set, 2 * i + 1); + assert(ret2 == 0); + } + } + BuffRBTree_SetS64_drop(set); +} + int main() { + insert_only(); + insert_and_then_find(); return 0; }