Browse Source

tree based memory management does not segfault anymore, but reusage does not seem to work, as well as free

release0.1.5
Georg Hopp 12 years ago
parent
commit
55675eb50a
  1. 159
      src/rbtree.c
  2. 745
      src/utils/memory.c

159
src/rbtree.c

@ -9,7 +9,8 @@ enum rbColor {rbBlack=1, rbRed=2};
struct element
{
int data;
size_t size;
void * ptr;
enum rbColor color;
@ -19,11 +20,13 @@ struct element
};
struct element *
newElement(int data)
newElement(size_t size)
{
struct element * element = malloc(sizeof(struct element));
struct element * element = malloc(size + sizeof(struct element));
element->size = size;
element->ptr = element + sizeof(struct element);
element->data = data;
element->color = rbRed;
element->parent = NULL;
element->left = NULL;
@ -36,21 +39,25 @@ newElement(int data)
* find element in tree
*/
struct element *
findElement(struct element * tree, int data)
findElement(struct element * tree, size_t size)
{
struct element * fitting = NULL;
while (NULL != tree) {
if (tree->data == data) {
if (tree->size == size) {
fitting = tree;
break;
}
if (data < tree->data) {
tree = tree->left;
} else {
if (size > tree->size) {
tree = tree->right;
} else {
fitting = tree;
tree = tree->left;
}
}
return tree;
return fitting;
}
/*
@ -190,8 +197,12 @@ insertElement(struct element ** tree, struct element * element)
*tree = node = new_node = element;
} else {
// normal binary tree add....
while (element->data != node->data) {
if (element->data < node->data) {
while (element->size != node->size || element->ptr != node->ptr) {
if (element->size < node->size && NULL != node->left) {
node = node->left;
} else if (element->size > node->size && NULL != node->right) {
node = node->right;
} else if (element->ptr < node->ptr) {
if (NULL == node->left) {
node->left = element;
node->left->parent = node;
@ -200,7 +211,7 @@ insertElement(struct element ** tree, struct element * element)
} else {
node = node->left;
}
} else if (element->data > node->data) {
} else if (element->ptr > node->ptr) {
if (NULL == node->right) {
node->right = element;
node->right->parent = node;
@ -286,6 +297,12 @@ insertElement(struct element ** tree, struct element * element)
* aka left in-order successor.
* We return the parent of the element in the out argument parent.
* This can be NULL wenn calling.
*
* 2: *successor = {size = 80, ptr = 0x603ae0, color = rbRed, parent = 0x603160,
* left = 0x0, right = 0x0}
* 1: *node = {size = 70, ptr = 0x603a60, color = rbBlack, parent = 0x603070,
* left = 0x6030e0, right = 0x6031e0}
*
*/
struct element *
findInOrderSuccessor(struct element * tree)
@ -310,8 +327,11 @@ deleteElement(struct element ** tree, struct element * element)
struct element * s;
// find the relevant node and it's parent
while (NULL != node && node->data != element->data) {
if (element->data < node->data) {
while (NULL != node
&& node->size != element->size
&& node->ptr != element->ptr) {
if (element->size < node->size || element->ptr < node->ptr) {
node = node->left;
} else {
node = node->right;
@ -332,8 +352,30 @@ deleteElement(struct element ** tree, struct element * element)
if (NULL != node->left && NULL != node->right) {
struct element * successor = findInOrderSuccessor(node);
node->data = successor->data;
del_node = node = successor;
enum rbColor tmpcolor = successor->color;
struct element * tmpparent = successor->parent;
struct element * tmpleft = successor->left;
struct element * tmpright = successor->right;
replaceNode(tree, node, successor);
successor->color = node->color;
successor->left = node->left;
successor->left->parent = successor;
// the right one might be successor...
if (node->right == successor) {
successor->right = node;
node->parent = successor;
} else {
successor->right = node->right;
node->right->parent = successor;
node->parent = tmpparent;
tmpparent->left = node;
}
node->color = tmpcolor;
node->left = tmpleft;
node->right = tmpright;
}
// Precondition: n has at most one non-null child.
@ -479,7 +521,7 @@ deleteElement(struct element ** tree, struct element * element)
void
traverse(struct element * tree, void (*cb)(int, int, enum rbColor))
traverse(struct element * tree, void (*cb)(size_t, void *, int, enum rbColor))
{
struct element * previous = tree;
struct element * node = tree;
@ -507,7 +549,7 @@ traverse(struct element * tree, void (*cb)(int, int, enum rbColor))
* If there are no more elements to the left or we
* came from the left, process data.
*/
cb(node->data, depth, node->color);
cb(node->size, node->ptr, depth, node->color);
previous = node;
if (NULL != node->right) {
@ -528,11 +570,11 @@ traverse(struct element * tree, void (*cb)(int, int, enum rbColor))
}
}
void printElement(int data, int depth, enum rbColor color)
void printElement(size_t size, void * ptr, int depth, enum rbColor color)
{
int i;
printf("%s %02d(%02d)", (color==rbRed)?"R":"B", data, depth);
printf("%s %010zu:0x%p(%02d)", (color==rbRed)?"R":"B", size, ptr, depth);
for (i=0; i<depth; i++) printf("-");
puts("");
}
@ -545,6 +587,7 @@ int
main(int argc, char * argv[])
{
struct element * root = NULL;
struct element * found = NULL;
int value;
int count;
@ -573,30 +616,76 @@ main(int argc, char * argv[])
// puts("traverse");
// traverse(root, printElement);
//
for (count=0; count<NVALUES;) {
value = (random() % 1000000) + 1;
// for (count=0; count<NVALUES;) {
// value = (random() % 1000000) + 1;
//
// if (NULL == findElement(root, value)) {
// insertElement(&root, newElement(value));
// count++;
// }
// }
//
// puts("traverse");
// traverse(root, printElement);
//
// for (count=0; count<NVALUES;) {
// value = (random() % 1000000) + 1;
// struct element * element = findElement(root, value);
//
// if (NULL != element) {
// free(deleteElement(&root, element));
// count++;
// }
// }
//
// puts("traverse");
// traverse(root, printElement);
if (NULL == findElement(root, value)) {
insertElement(&root, newElement(value));
count++;
}
}
insertElement(&root, newElement(40));
insertElement(&root, newElement(50));
insertElement(&root, newElement(60));
insertElement(&root, newElement(70));
insertElement(&root, newElement(80));
insertElement(&root, newElement(45));
insertElement(&root, newElement(75));
insertElement(&root, newElement(85));
puts("traverse");
traverse(root, printElement);
puts("");
insertElement(&root, newElement(70));
puts("traverse");
traverse(root, printElement);
puts("");
found = findElement(root, 10);
if (NULL == found) {
printf("can't find segmenet of minimum size: %d\n", 10);
} else {
printElement(found->size, found->ptr, 0, found->color);
}
puts("");
for (count=0; count<NVALUES;) {
value = (random() % 1000000) + 1;
struct element * element = findElement(root, value);
found = findElement(root, 64);
if (NULL == found) {
printf("can't find segmenet of minimum size: %d\n", 64);
} else {
printElement(found->size, found->ptr, 0, found->color);
}
puts("");
if (NULL != element) {
free(deleteElement(&root, element));
count++;
}
found = findElement(root, 90);
if (NULL == found) {
printf("can't find segmenet of minimum size: %d\n", 90);
} else {
printElement(found->size, found->ptr, 0, found->color);
}
puts("");
deleteElement(&root, findElement(root, 70));
puts("traverse");
traverse(root, printElement);
puts("");
return 0;
}

745
src/utils/memory.c

@ -22,6 +22,9 @@
* This is not implemented as a class because it will be used in the
* process of object creation.
*
* The data structure is a balanced tree with size as key.
* Under the size key is a list of elements of the same size.
*
* \author Georg Hopp
*
* \copyright
@ -43,87 +46,721 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <search.h>
#include "utils/memory.h"
enum rbColor {rbBlack=1, rbRed=2};
int malloccount = 0;
struct memSegment {
size_t size;
void * ptr;
// for address queue
struct memSegment * next;
struct memSegment * last;
// for rbtree
enum rbColor color;
struct memSegment * parent;
struct memSegment * left;
struct memSegment * right;
};
struct memSegment *
newElement(size_t size)
{
struct memSegment * element = malloc(size + sizeof(struct memSegment));
malloccount++;
printf("+");
element->size = size;
element->ptr = (void *)element + sizeof(struct memSegment);
element->next = NULL;
element->last = NULL;
void * segments = NULL;
element->color = rbRed;
element->parent = NULL;
element->left = NULL;
element->right = NULL;
return element;
}
/**
* this will interpret any memory segment that is not smaller
* than the expected size as fitting.
*
* @param void * size_ptr a pointer to a size_t value searched for
* @param void * subject a pointer to the currently analysed tree element
* find element in tree
*/
static
int
segmentFindCmp(const void * size_ptr, const void * subject)
struct memSegment *
findElement(struct memSegment * tree, size_t size)
{
if (*(size_t *)size_ptr > ((struct memSegment *)subject)->size)
return 1;
struct memSegment * fitting = NULL;
while (NULL != tree) {
if (tree->size == size) {
fitting = tree;
break;
}
return 0;
if (size > tree->size) {
tree = tree->right;
} else {
fitting = tree;
tree = tree->left;
}
}
return fitting;
}
/*
* function to get specific elements needed for
* rb handling, grandparent, uncle and sibbling
*/
struct memSegment *
grandparent(struct memSegment * node)
{
if (NULL != node && NULL != node->parent) {
return node->parent->parent;
}
return NULL;
}
struct memSegment *
uncle(struct memSegment * node)
{
struct memSegment * gp = grandparent(node);
if (NULL == gp) {
return NULL;
}
if (node->parent == gp->left) {
return gp->right;
}
return gp->left;
}
struct memSegment *
sibling(struct memSegment * node)
{
if (NULL == node) {
return NULL;
}
if (NULL == node->parent->left || node == node->parent->left) {
return node->parent->right;
} else {
return node->parent->left;
}
}
/*
* tree modifications...needed for rb handling.
*/
void
rotateLeft(struct memSegment ** tree, struct memSegment * node)
{
struct memSegment * rightChild = node->right;
struct memSegment * rcLeftSub = node->right->left;
rightChild->left = node;
rightChild->parent = node->parent;
node->right = rcLeftSub;
if (NULL != rcLeftSub) {
rcLeftSub->parent = node;
}
if (node->parent) {
if (node->parent->left == node) {
node->parent->left = rightChild;
} else {
node->parent->right = rightChild;
}
} else {
*tree = rightChild;
}
node->parent = rightChild;
}
void
rotateRight(struct memSegment ** tree, struct memSegment * node)
{
struct memSegment * leftChild = node->left;
struct memSegment * lcRightSub = node->left->right;
leftChild->right = node;
leftChild->parent = node->parent;
node->left = lcRightSub;
if (NULL != lcRightSub) {
lcRightSub->parent = node;
}
if (node->parent) {
if (node->parent->left == node) {
node->parent->left = leftChild;
} else {
node->parent->right = leftChild;
}
} else {
*tree = leftChild;
}
node->parent = leftChild;
}
void
replaceNode(
struct memSegment ** tree,
struct memSegment * node1,
struct memSegment * node2)
{
if (NULL != node1->parent) {
if (node1 == node1->parent->left) {
node1->parent->left = node2;
} else {
node1->parent->right = node2;
}
} else {
*tree = node2;
}
if (NULL != node2) {
node2->parent = node1->parent;
}
}
/**
* this returns exact fits....uhh.....I can't relate solely on
* the size argument as then same sized segments will never
* be stored.
* Maybe a tree is not the best data structure to use to store
* these.
* Anyway, right now take the ptr into account if size if equal.
* insert element in tree
*/
static
int
segmentSearchCmp(const void * search, const void * subject)
struct memSegment *
insertElement(struct memSegment ** tree, struct memSegment * element)
{
size_t idx =
((struct memSegment *)search)->size -
((struct memSegment *)subject)->size;
struct memSegment * node = *tree;
struct memSegment * new_node = NULL;
struct memSegment * u;
struct memSegment * g;
if (0 == idx) {
return
((struct memSegment *)search)->ptr -
((struct memSegment *)subject)->ptr;
}
element->color = rbRed;
element->parent = NULL;
element->left = NULL;
element->right = NULL;
element->next = NULL;
element->last = NULL;
// if tree is empty it's simple... :)
if (NULL == node) {
*tree = node = new_node = element;
} else {
// normal binary tree add....
while (element->size != node->size) {
if (element->size < node->size) {
if (NULL == node->left) {
node->left = element;
node->left->parent = node;
new_node = node = node->left;
break;
} else {
node = node->left;
}
} else if (element->size > node->size) {
if (NULL == node->right) {
node->right = element;
node->right->parent = node;
new_node = node = node->right;
break;
} else {
node = node->right;
}
} else {
if (NULL == node->next) {
node->next = node->last = element;
} else {
node->last->next = element;
node->last = element;
}
return element;
}
}
}
if (NULL != new_node) {
/*
* handle reballancing rb style
*/
while (1) {
// case 1
if (node->parent == NULL) {
node->color = rbBlack;
// we're done.... :)
break;
}
// case 2
if (node->parent->color == rbBlack) {
// Tree is still valid ... wow, again we're done... :)
break;
}
// case 3
u = uncle(node);
g = grandparent(node);
if (u != NULL && u->color == rbRed) {
node->parent->color = rbBlack;
u->color = rbBlack;
g->color = rbRed;
node = g;
continue;
}
// case 4
if (node == node->parent->right && node->parent == g->left) {
rotateLeft(tree, node->parent);
node = node->left;
} else if (node == node->parent->left && node->parent == g->right) {
rotateRight(tree, node->parent);
node = node->right;
}
// case 5
g = grandparent(node);
node->parent->color = rbBlack;
g->color = rbRed;
if (node == node->parent->left) {
rotateRight(tree, g);
} else {
rotateLeft(tree, g);
}
// we're done..
break;
}
}
return new_node;
}
/**
* delete element from tree
* here multiple functions are involved....
* =======================================================================
*/
/**
* find minimum of the right subtree aka leftmost leaf of right subtree
* aka left in-order successor.
* We return the parent of the element in the out argument parent.
* This can be NULL wenn calling.
*/
struct memSegment *
findInOrderSuccessor(struct memSegment * tree)
{
struct memSegment * node = tree->right;
while (NULL != node->left) {
node = node->left;
}
return idx;
return node;
}
struct memSegment * deleteOneChild(struct memSegment **, struct memSegment *);
struct memSegment *
deleteElement(struct memSegment ** tree, struct memSegment * element)
{
struct memSegment * node = *tree;
struct memSegment * del_node;
struct memSegment * child;
struct memSegment * s;
// find the relevant node and it's parent
while (NULL != node) {
if (element->size < node->size) {
node = node->left;
} else if (element->size > node->size) {
node = node->right;
} else {
// we know we found our tree element.
if (NULL != node->next) {
// last element.
if (NULL != node->parent) {
if (node->parent->left == node->parent) {
node->parent->left = node->next;
} else {
node->parent->right = node->next;
}
}
if (NULL != node->left) {
node->left->parent = node->next;
}
if (NULL != node->right) {
node->right->parent = node->next;
}
if (node->next == node->last) {
node->next->next = NULL;
node->next->last = NULL;
} else {
node->next->last = node->last;
}
node->next->parent = node->parent;
node->next->color = node->color;
node->next->left = node->left;
node->next->right = node->right;
return node;
}
break;
}
}
// element not found
if (NULL == node) {
return node;
}
del_node = node;
// now our cases follows...the first one is the same as with
// simple binary search trees. Two non null children.
// case 1: two children
if (NULL != node->left && NULL != node->right) {
struct memSegment * successor = findInOrderSuccessor(node);
// this is a replacement code for simply change value and remove
// successor...I can not do this here because the address of
// the object is part of the information that has to be
// preserved.
enum rbColor tmpcolor = successor->color;
struct memSegment * tmpparent = successor->parent;
struct memSegment * tmpleft = successor->left;
struct memSegment * tmpright = successor->right;
replaceNode(tree, node, successor);
successor->color = node->color;
successor->left = node->left;
successor->left->parent = successor;
// the right one might be successor...
if (node->right == successor) {
successor->right = node;
node->parent = successor;
} else {
successor->right = node->right;
node->right->parent = successor;
node->parent = tmpparent;
tmpparent->left = node;
}
node->color = tmpcolor;
node->left = tmpleft;
node->right = tmpright;
}
// Precondition: n has at most one non-null child.
child = (NULL == node->right) ? node->left : node->right;
replaceNode(tree, node, child);
// delete one child case
// TODO this is overly complex as simply derived from the function...
// maybe this can be simplified. Maybe not...check.
if (node->color == rbBlack) {
if (NULL != child && child->color == rbRed) {
child->color = rbBlack;
// done despite modifying tree itself if neccessary..
return del_node;
} else {
if (NULL != child) {
node = child;
} else {
node->color = rbBlack;
node->left = NULL;
node->right = NULL;
}
}
} else {
return del_node;
}
// delete and rb rebalance...
while(1) {
// case 1
if (NULL == node->parent) {
// done again
break;
}
// case 2
s = sibling(node);
if (NULL != s && s->color == rbRed) {
node->parent->color = rbRed;
s->color = rbBlack;
/*
* detect which child we are...assumption
* if we are not parent->right and parent->right is not
* null we must be left, even if its set to NULL previously
*/
if (NULL != node->parent->right && node != node->parent->right) {
rotateLeft(tree, node->parent);
} else {
rotateRight(tree, node->parent);
}
}
s = sibling(node);
// case 3 / 4
if (NULL == s || ((s->color == rbBlack) &&
(NULL == s->left || s->left->color == rbBlack) &&
(NULL == s->right || s->right->color == rbBlack))) {
if (NULL != s) {
s->color = rbRed;
}
if (node->parent->color == rbBlack) {
// case 3
node = node->parent;
continue;
} else {
// case 4
node->parent->color = rbBlack;
// and done again...
break;
}
}
// case 5
if (NULL != s && s->color == rbBlack) {
// this if statement is trivial,
// due to case 2 (even though case 2 changed the sibling to a
// sibling's child,
// the sibling's child can't be red, since no red parent can
// have a red child).
//
// the following statements just force the red to be on the
// left of the left of the parent,
// or right of the right, so case 6 will rotate correctly.
if ((node == node->parent->left) &&
(NULL == s->right || s->right->color == rbBlack) &&
(NULL != s->left && s->left->color == rbRed)) {
// this last test is trivial too due to cases 2-4.
s->color = rbRed;
s->left->color = rbBlack;
rotateRight(tree, s);
} else if ((node == node->parent->right) &&
(NULL == s->left || s->left->color == rbBlack) &&
(NULL != s->right && s->right->color == rbRed)) {
// this last test is trivial too due to cases 2-4.
s->color = rbRed;
s->right->color = rbBlack;
rotateLeft(tree, s);
}
}
s = sibling(node);
// case 6
if (NULL != s) {
s->color = node->parent->color;
}
if (NULL != node && NULL != node->parent) {
node->parent->color = rbBlack;
/*
* detect which child we are...assumption
* if we are not parent->right and parent->right is not
* null we must be left, even if its set to NULL previously
*/
if (NULL != node->parent->right && node != node->parent->right) {
if (NULL != s->right) {
s->right->color = rbBlack;
}
rotateLeft(tree, node->parent);
} else {
if (NULL != s->left) {
s->left->color = rbBlack;
}
rotateRight(tree, node->parent);
}
}
// done...
break;
}
//deleteOneChild(tree, node);
return del_node;
}
void
traverse(struct memSegment * tree, void (*cb)(struct memSegment *, int))
{
struct memSegment * previous = tree;
struct memSegment * node = tree;
int depth = 1;
/*
* I think this has something like O(n+log(n)) on a ballanced
* tree because I have to traverse back the rightmost leaf to
* the root to get a break condition.
*/
while (NULL != node) {
/*
* If we come from the right so nothing and go to our
* next parent.
*/
if (previous == node->right) {
previous = node;
node = node->parent;
depth--;
continue;
}
if ((NULL == node->left || previous == node->left)) {
/*
* If there are no more elements to the left or we
* came from the left, process data.
*/
cb(node, depth);
previous = node;
if (NULL != node->right) {
node = node->right;
depth++;
} else {
node = node->parent;
depth--;
}
} else {
/*
* if there are more elements to the left go there.
*/
previous = node;
node = node->left;
depth++;
}
}
}
void printElement(struct memSegment * node, int depth)
{
int i;
printf("%s %010zu:0x%p(%02d)",
(node->color==rbRed)?"R":"B",
node->size,
node->ptr,
depth);
for (i=0; i<depth; i++) printf("-");
puts("");
}
struct memSegment * segments = NULL;
// /**
// * this will interpret any memory segment that is not smaller
// * than the expected size as fitting.
// *
// * @param void * size_ptr a pointer to a size_t value searched for
// * @param void * subject a pointer to the currently analysed tree element
// */
// static
// int
// segmentFindCmp(const void * size_ptr, const void * subject)
// {
// if (*(size_t *)size_ptr > ((struct memSegment *)subject)->size)
// return 1;
//
// return 0;
// }
//
// /**
// * this returns exact fits....uhh.....I can't relate solely on
// * the size argument as then same sized segments will never
// * be stored.
// * Maybe a tree is not the best data structure to use to store
// * these.
// * Anyway, right now take the ptr into account if size if equal.
// */
// static
// int
// segmentSearchCmp(const void * search, const void * subject)
// {
// size_t idx =
// ((struct memSegment *)search)->size -
// ((struct memSegment *)subject)->size;
//
// if (0 == idx) {
// return
// ((struct memSegment *)search)->ptr -
// ((struct memSegment *)subject)->ptr;
// }
//
// return idx;
// }
static
void
segmentFree(void * segment)
segmentFree(struct memSegment * segment, int depth)
{
free(segment);
while (NULL != segment) {
struct memSegment * next = segment->next;
free(segment);
malloccount--;
printf("-");
segment = next;
}
}
void *
memMalloc(size_t size)
{
struct memSegment ** seg_ptr = tfind(&size, &segments, segmentFindCmp);
struct memSegment * seg;
struct memSegment * seg;
//printf("MALLOC of size: %zu\n", size);
//traverse(segments, printElement);
if (NULL == seg_ptr) {
seg = (struct memSegment *)malloc(sizeof(struct memSegment) + size);
seg = findElement(segments, size);
seg->size = size;
seg->ptr = (void *)seg + sizeof(struct memSegment);
if (NULL == seg) {
seg = newElement(size);
//printf(" CREATE Segment: 0x%p of size: %zu\n", seg, seg->size);
} else {
seg = *seg_ptr;
//printf(" FOUND Segment: 0x%p of size: %zu\n", seg, seg->size);
// remove the found one from the tree as we use it now.
tdelete((void *)seg, &segments, segmentSearchCmp);
deleteElement(&segments, seg);
}
return seg->ptr;
}
@ -150,15 +787,39 @@ void
memFree(void ** mem)
{
if (NULL != *mem) {
tsearch(*mem - sizeof(struct memSegment), &segments, segmentSearchCmp);
insertElement(&segments, (struct memSegment *)(*mem - sizeof(struct memSegment)));
//printf("FREE of Segment: 0x%p of size: %zu\n",
// *mem - sizeof(struct memSegment),
// ((struct memSegment *)(*mem - sizeof(struct memSegment)))->size);
//traverse(segments, printElement);
*mem = NULL;
}
}
void
pre_order(struct memSegment * tree, void (*cb)(struct memSegment *, int))
{
if (NULL != tree) {
if (NULL != tree->left) {
pre_order(tree->left, cb);
}
if (NULL != tree->right) {
pre_order(tree->right, cb);
}
cb(tree, 0);
}
}
void
memCleanup()
{
tdestroy(segments, segmentFree);
printf("\n");
pre_order(segments, segmentFree);
printf("\nmalloccount: %d\n", malloccount);
}
void

Loading…
Cancel
Save