Tests for insertion passed + written _find(), _at() methods

This commit is contained in:
Андреев Григорий 2025-09-21 16:02:16 +03:00
parent bcc20b2f6e
commit 36ef29cff1
3 changed files with 250 additions and 24 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}