Fix memory management of trees
This commit is contained in:
parent
05250e6af9
commit
6e53fe29e2
@ -23,10 +23,11 @@ struct RJP_tree_node{
|
||||
};
|
||||
|
||||
RJP_tree_node* irjp_new_node(RJP_object_member value);
|
||||
RJP_tree_node* irjp_insert_value(RJP_tree_node* root, RJP_object_member value, int* status);
|
||||
RJP_tree_node* irjp_remove_value(RJP_tree_node* root, RJP_object_member value, int* status);
|
||||
RJP_tree_node* irjp_search_value(RJP_tree_node* root, RJP_object_member value);
|
||||
RJP_tree_node* irjp_tree_insert_value(RJP_tree_node* root, RJP_object_member value, int* status);
|
||||
RJP_tree_node* irjp_tree_remove_value(RJP_tree_node* root, RJP_object_member value, int* status);
|
||||
RJP_tree_node* irjp_tree_search_value(RJP_tree_node* root, RJP_object_member value);
|
||||
RJP_tree_node* irjp_copy_tree(RJP_tree_node* root);
|
||||
void irjp_free_tree(RJP_tree_node* root);
|
||||
|
||||
int irjp_init_object_iterator(RJP_object_iterator* it, RJP_tree_node* root);
|
||||
void irjp_delete_object_iterator(RJP_object_iterator* it);
|
||||
|
||||
184
src/tree.c
184
src/tree.c
@ -4,6 +4,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "strings.h"
|
||||
|
||||
#define BLACK 0
|
||||
#define RED 1
|
||||
|
||||
@ -12,9 +14,11 @@
|
||||
#define rjp_malloc malloc
|
||||
#define rjp_free free
|
||||
#define rjp_free_value(x)
|
||||
|
||||
#define irjp_strcpy(dest, src) do{(dest)->value = rjp_malloc((src)->length + 1);strcpy((dest)->value, (src)->value);(dest)->value[(src)->length] = 0;(dest)->length = (src)->length;}while(0);
|
||||
#define rjp_copy_value(dest, src) ((dest)->integer = (src)->integer)
|
||||
#define RJP_TREE_ITERATOR_STACK_START_SIZE 32
|
||||
|
||||
//Internal use only structs
|
||||
typedef struct RJP_tree_stack{
|
||||
RJP_tree_node** data;
|
||||
int size;
|
||||
@ -25,14 +29,22 @@ typedef struct RJP_object_iterator{
|
||||
RJP_tree_node* current;
|
||||
}RJP_object_iterator;
|
||||
|
||||
|
||||
static RJP_tree_node* irjp_insert_node(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode);
|
||||
static RJP_tree_node* irjp_insert_impl(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode);
|
||||
static RJP_tree_node* irjp_repair_tree(RJP_tree_node* node);
|
||||
static void irjp_copy_node_data(RJP_tree_node *restrict dest, RJP_tree_node *restrict src);
|
||||
//Forward declare static functions
|
||||
static inline RJP_tree_node* irjp_grandparent(RJP_tree_node* n);
|
||||
static inline RJP_tree_node* irjp_sibling(RJP_tree_node* n);
|
||||
static inline RJP_tree_node* irjp_uncle(RJP_tree_node* n);
|
||||
static inline RJP_tree_node* irjp_rotate_left(RJP_tree_node* pivot);
|
||||
static inline RJP_tree_node* irjp_rotate_right(RJP_tree_node* pivot);
|
||||
static inline int irjp_is_inside_left(RJP_tree_node* n);
|
||||
static inline int irjp_is_inside_right(RJP_tree_node* n);
|
||||
static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restrict child);
|
||||
|
||||
static void irjp_copy_node_data(RJP_tree_node *restrict dest, RJP_tree_node *restrict src);
|
||||
static RJP_tree_node* irjp_clone_node(RJP_tree_node* src, RJP_tree_node* parent);
|
||||
static RJP_tree_node* irjp_copy_node(RJP_tree_node* root, RJP_tree_node* parent);
|
||||
static void irjp_free_node(RJP_tree_node* node);
|
||||
static RJP_tree_node* irjp_remove_node(RJP_tree_node* target);
|
||||
static void irjp_delete_node(RJP_tree_node* node);
|
||||
|
||||
static int irjp_init_tree_stack(RJP_tree_stack* stack);
|
||||
static void irjp_delete_tree_stack(RJP_tree_stack* stack);
|
||||
static void irjp_resize_tree_stack(RJP_tree_stack* stack);
|
||||
@ -40,6 +52,13 @@ static void irjp_push_tree_stack(RJP_tree_stack* stack, RJP_tree_node* value);
|
||||
static RJP_tree_node* irjp_pop_tree_stack(RJP_tree_stack* stack);
|
||||
static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack);
|
||||
|
||||
static RJP_tree_node* irjp_tree_insert_node(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode);
|
||||
static RJP_tree_node* irjp_tree_insert_impl(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode);
|
||||
static RJP_tree_node* irjp_tree_repair(RJP_tree_node* node);
|
||||
static RJP_tree_node* irjp_tree_remove_node(RJP_tree_node* target);
|
||||
|
||||
|
||||
//Tree helpers
|
||||
static inline RJP_tree_node* irjp_grandparent(RJP_tree_node* n){
|
||||
if(!n->parent)
|
||||
return NULL;
|
||||
@ -100,9 +119,6 @@ static inline int irjp_is_inside_right(RJP_tree_node* n){
|
||||
RJP_tree_node* g = irjp_grandparent(n);
|
||||
return n == p->left && p == g->right;
|
||||
}
|
||||
static void irjp_copy_node_data(RJP_tree_node *restrict dest, RJP_tree_node *restrict src){
|
||||
dest->data = src->data;
|
||||
}
|
||||
static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restrict child){
|
||||
if(child)
|
||||
child->parent = node->parent;
|
||||
@ -113,12 +129,8 @@ static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restr
|
||||
else
|
||||
node->parent->right = child;
|
||||
}
|
||||
static void irjp_free_node(RJP_tree_node* node){
|
||||
rjp_free(node->data.name.value);
|
||||
rjp_free_value(&node->data.value);
|
||||
rjp_free(node);
|
||||
}
|
||||
|
||||
//Node construction / destruction
|
||||
RJP_tree_node* irjp_new_node(RJP_object_member value){
|
||||
RJP_tree_node* node = rjp_malloc(sizeof(RJP_tree_node));
|
||||
node->data.name = value.name;
|
||||
@ -126,8 +138,37 @@ RJP_tree_node* irjp_new_node(RJP_object_member value){
|
||||
node->parent = node->left = node->right = NULL;
|
||||
return node;
|
||||
}
|
||||
static void irjp_copy_node_data(RJP_tree_node *restrict dest, RJP_tree_node *restrict src){
|
||||
dest->data = src->data;
|
||||
}
|
||||
static RJP_tree_node* irjp_clone_node(RJP_tree_node* src, RJP_tree_node* parent){
|
||||
RJP_tree_node* dest = rjp_malloc(sizeof(RJP_tree_node));
|
||||
rjp_copy_value(&dest->data.value, &src->data.value);
|
||||
irjp_strcpy(&dest->data.name, &src->data.name);
|
||||
dest->parent = parent;
|
||||
return dest;
|
||||
}
|
||||
static RJP_tree_node* irjp_copy_node(RJP_tree_node* root, RJP_tree_node* parent){
|
||||
if(!root){
|
||||
return NULL;
|
||||
}
|
||||
RJP_tree_node* newnode = irjp_clone_node(root, parent);
|
||||
newnode->left = irjp_copy_node(root->left, newnode);
|
||||
newnode->right = irjp_copy_node(root->right, newnode);
|
||||
return newnode;
|
||||
}
|
||||
static void irjp_free_node(RJP_tree_node* node){
|
||||
irjp_delete_node(node);
|
||||
rjp_free(node);
|
||||
}
|
||||
static void irjp_delete_node(RJP_tree_node* node){
|
||||
rjp_free(node->data.name.value);
|
||||
rjp_free_value(&node->data.value);
|
||||
}
|
||||
|
||||
|
||||
/* TREE STACK */
|
||||
//Stack construction / destruction
|
||||
static int irjp_init_tree_stack(RJP_tree_stack* stack){
|
||||
stack->data = rjp_malloc(sizeof(RJP_tree_node*)*RJP_TREE_ITERATOR_STACK_START_SIZE);
|
||||
stack->size = RJP_TREE_ITERATOR_STACK_START_SIZE;
|
||||
@ -147,6 +188,7 @@ static void irjp_resize_tree_stack(RJP_tree_stack* stack){
|
||||
stack->data = newdata;
|
||||
stack->size = newsize;
|
||||
}
|
||||
//Stack operations
|
||||
static void irjp_push_tree_stack(RJP_tree_stack* stack, RJP_tree_node* value){
|
||||
stack->data[stack->pos++] = value;
|
||||
if(stack->pos == stack->size)
|
||||
@ -160,6 +202,7 @@ static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack){
|
||||
}
|
||||
|
||||
/* TREE ITERATOR */
|
||||
//Iterator construction / destruction
|
||||
int irjp_init_object_iterator(RJP_object_iterator* it, RJP_tree_node* root){
|
||||
irjp_init_tree_stack(&it->stack);
|
||||
it->current = root;
|
||||
@ -173,6 +216,7 @@ int irjp_init_object_iterator(RJP_object_iterator* it, RJP_tree_node* root){
|
||||
void irjp_delete_object_iterator(RJP_object_iterator* it){
|
||||
irjp_delete_tree_stack(&it->stack);
|
||||
}
|
||||
//Iterator operations
|
||||
RJP_tree_node* irjp_object_iterator_next(RJP_object_iterator* it){
|
||||
RJP_tree_node* last = irjp_pop_tree_stack(&it->stack);
|
||||
if(last->right){
|
||||
@ -185,30 +229,34 @@ RJP_tree_node* irjp_object_iterator_current(RJP_object_iterator* it){
|
||||
}
|
||||
|
||||
/* TREE */
|
||||
//Tree construction / destruction
|
||||
RJP_tree_node* irjp_copy_tree(RJP_tree_node* root){
|
||||
if(!root)
|
||||
return NULL;
|
||||
RJP_tree_node* newnode = irjp_new_node(root->data);
|
||||
newnode->left = irjp_copy_tree(root->left);
|
||||
newnode->right = irjp_copy_tree(root->right);
|
||||
return newnode;
|
||||
return irjp_copy_node(root, NULL);
|
||||
}
|
||||
RJP_tree_node* irjp_insert_value(RJP_tree_node* root, RJP_object_member value, int* status){
|
||||
void irjp_free_tree(RJP_tree_node* root){
|
||||
if(!root)
|
||||
return;
|
||||
irjp_free_tree(root->left);
|
||||
irjp_free_tree(root->right);
|
||||
irjp_free_node(root);
|
||||
}
|
||||
//Tree operations
|
||||
RJP_tree_node* irjp_tree_insert_value(RJP_tree_node* root, RJP_object_member value, int* status){
|
||||
*status = RJP_TREE_SUCCESS;
|
||||
if(!root){
|
||||
root = irjp_new_node(value);
|
||||
return root;
|
||||
}
|
||||
return irjp_insert_node(root, irjp_new_node(value));
|
||||
return irjp_tree_insert_node(root, irjp_new_node(value));
|
||||
}
|
||||
static RJP_tree_node* irjp_insert_node(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode){
|
||||
irjp_insert_impl(root, newnode);
|
||||
irjp_repair_tree(newnode);
|
||||
static RJP_tree_node* irjp_tree_insert_node(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode){
|
||||
irjp_tree_insert_impl(root, newnode);
|
||||
irjp_tree_repair(newnode);
|
||||
while(root->parent)
|
||||
root = root->parent;
|
||||
return root;
|
||||
}
|
||||
static RJP_tree_node* irjp_insert_impl(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode){
|
||||
static RJP_tree_node* irjp_tree_insert_impl(RJP_tree_node *restrict root, RJP_tree_node *restrict newnode){
|
||||
if(!root){
|
||||
return newnode;
|
||||
}
|
||||
@ -236,7 +284,7 @@ static RJP_tree_node* irjp_insert_impl(RJP_tree_node *restrict root, RJP_tree_no
|
||||
}
|
||||
return newnode;
|
||||
}
|
||||
static RJP_tree_node* irjp_repair_tree(RJP_tree_node* node){
|
||||
static RJP_tree_node* irjp_tree_repair(RJP_tree_node* node){
|
||||
node->color = RED;
|
||||
while(1){
|
||||
if(!node->parent){
|
||||
@ -270,7 +318,7 @@ static RJP_tree_node* irjp_repair_tree(RJP_tree_node* node){
|
||||
}
|
||||
}
|
||||
|
||||
RJP_tree_node* irjp_search_value(RJP_tree_node* root, RJP_object_member value){
|
||||
RJP_tree_node* irjp_tree_search_value(RJP_tree_node* root, RJP_object_member value){
|
||||
while(root != NULL){
|
||||
int cmpval = strcmp(value.name.value, root->data.name.value);
|
||||
if(cmpval < 0){
|
||||
@ -283,6 +331,7 @@ RJP_tree_node* irjp_search_value(RJP_tree_node* root, RJP_object_member value){
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
//Debug printouts
|
||||
void irjp_dbg_print_tree(RJP_tree_node* root){
|
||||
if(!root){
|
||||
return;
|
||||
@ -346,21 +395,25 @@ void irjp_dbg_print_tree_bfs(RJP_tree_node* root){
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#undef pop
|
||||
#undef push
|
||||
|
||||
RJP_tree_node* irjp_remove_value(RJP_tree_node* root, RJP_object_member value, int* status){
|
||||
RJP_tree_node* irjp_tree_remove_value(RJP_tree_node* root, RJP_object_member value, int* status){
|
||||
if(!root){
|
||||
*status = RJP_TREE_ERR_NULL_ROOT;
|
||||
return root;
|
||||
}
|
||||
RJP_tree_node* n = irjp_search_value(root, value);
|
||||
RJP_tree_node* n = irjp_tree_search_value(root, value);
|
||||
if(!n){
|
||||
*status = RJP_TREE_ERR_NOT_FOUND;
|
||||
return root;
|
||||
}
|
||||
*status = RJP_TREE_SUCCESS;
|
||||
return irjp_remove_node(n);
|
||||
return irjp_tree_remove_node(n);
|
||||
}
|
||||
static RJP_tree_node* irjp_remove_node(RJP_tree_node* target){
|
||||
static RJP_tree_node* irjp_tree_remove_node(RJP_tree_node* target){
|
||||
irjp_delete_node(target);
|
||||
|
||||
while(target->right && target->left){
|
||||
irjp_copy_node_data(target, target->right);
|
||||
target = target->right;
|
||||
@ -454,9 +507,7 @@ static RJP_tree_node* irjp_remove_node(RJP_tree_node* target){
|
||||
}while(1);
|
||||
|
||||
irjp_replace_node(to_delete, NULL);
|
||||
to_delete->data.name.value = NULL;
|
||||
to_delete->data.value.type = rjp_json_null;
|
||||
irjp_free_node(to_delete);
|
||||
rjp_free(to_delete);
|
||||
|
||||
//return new root
|
||||
if(!retval)
|
||||
@ -465,65 +516,4 @@ static RJP_tree_node* irjp_remove_node(RJP_tree_node* target){
|
||||
retval = retval->parent;
|
||||
return retval;
|
||||
}
|
||||
/*void irjp_handle_del_with_red_sibling(RJP_tree_node* n){
|
||||
RJP_tree_node* sibling = irjp_sibling(n);
|
||||
if(s->color == RED){
|
||||
sibling->color = BLACK;
|
||||
n->parent->color = RED;
|
||||
if(target == parent->left)
|
||||
irjp_rotate_left(parent);
|
||||
else
|
||||
irjp_rotate_right(parent);
|
||||
}else{
|
||||
irjp_handle_del_with_black_parent_sibling_niblings(n);
|
||||
}
|
||||
void irjp_handle_del_with_black_parent_sibling_niblings(RJP_tree_node* n){
|
||||
RJP_tree_node* sibling = irjp_sibling(n);
|
||||
if(n->parent->color == BLACK && sibling->color == BLACK &&
|
||||
((!sibling->left) || sibling->left->color == BLACK) &&
|
||||
((!sibling->right) || sibling->right->color == BLACK)
|
||||
{
|
||||
sibling->color = RED;
|
||||
irjp_handle_del_root(n->parent);
|
||||
}else{
|
||||
irjp_handle_del_with_black_sibling_niblings_red_parent(n);
|
||||
}
|
||||
}
|
||||
void irjp_handle_del_with_black_sibling_niblings_red_parent(RJP_tree_node* n){
|
||||
RJP_tree_node* sibling = irjp_sibling(n);
|
||||
if(n->parent->color == RED && sibling->color == BLACK &&
|
||||
((!sibling->left) || sibling->left->color == BLACK) &&
|
||||
((!sibling->right) || sibling->right->color == BLACK)
|
||||
{
|
||||
sibling->color = RED;
|
||||
n->parent->color = BLACK;
|
||||
}else{
|
||||
irjp_handle_del_with_black_sibling_rnibling_black_lnibling(n);
|
||||
}
|
||||
}
|
||||
void irjp_handle_del_with_black_sibling_rnibling_black_lnibling(RJP_tree_node* n){
|
||||
RJP_tree_node* sibling = irjp_sibling(n);
|
||||
if((n == n->parent->left) && (sibling->right->color == BLACK) && (sibling->left->color == RED)){
|
||||
sibling->color = RED;
|
||||
s->left->color = BLACK;
|
||||
irjp_rotate_right(sibling);
|
||||
}else if((n == n->parent->right) && (sibling->right->color == RED) && (sibling->left->color == BLACK)){
|
||||
sibling->color = RED;
|
||||
s->right->color = BLACK;
|
||||
irjp_rotate_left(sibling);
|
||||
}
|
||||
irjp_handle_del_with_black_sibling_lnibling_black_rnibling_red(n);
|
||||
}
|
||||
void irjp_handle_del_with_black_sibling_lnibling_black_rnibling_red(RJP_tree_node* n){
|
||||
RJP_tree_node* sibling = irjp_sibling(n);
|
||||
sibling->color = n->parent->color;
|
||||
n->parent->color = BLACK;
|
||||
if(n == n->parent->left){
|
||||
sibling->right->color = BLACK;
|
||||
irjp_rotate_left(n->parent);
|
||||
}else{
|
||||
sibling->left->color = BLACK;
|
||||
irjp_rotate_right(n->parent);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user