122 #include "qinternal.h"
123 #include "utilities/qstring.h"
124 #include "containers/qtreetbl.h"
126 #ifndef _DOXYGEN_SKIP
129 static bool is_red(qtreetbl_obj_t *obj);
130 static qtreetbl_obj_t *flip_color(qtreetbl_obj_t *obj);
131 static qtreetbl_obj_t *rotate_left(qtreetbl_obj_t *obj);
132 static qtreetbl_obj_t *rotate_right(qtreetbl_obj_t *obj);
133 static qtreetbl_obj_t *move_red_left(qtreetbl_obj_t *obj);
134 static qtreetbl_obj_t *move_red_right(qtreetbl_obj_t *obj);
135 static qtreetbl_obj_t *fix(qtreetbl_obj_t *obj);
136 static qtreetbl_obj_t *find_min(qtreetbl_obj_t *obj);
137 static qtreetbl_obj_t *find_max(qtreetbl_obj_t *obj);
138 static qtreetbl_obj_t *find_obj(qtreetbl_t *tbl,
const void *name,
140 static qtreetbl_obj_t *remove_min(qtreetbl_obj_t *obj);
141 static qtreetbl_obj_t *new_obj(
bool red,
const void *name,
size_t namesize,
142 const void *data,
size_t datasize);
143 static qtreetbl_obj_t *put_obj(qtreetbl_t *tbl, qtreetbl_obj_t *obj,
144 const void *name,
size_t namesize,
145 const void *data,
size_t datasize);
146 static qtreetbl_obj_t *remove_obj(qtreetbl_t *tbl, qtreetbl_obj_t *obj,
147 const void *name,
size_t namesize);
148 static void free_objs(qtreetbl_obj_t *obj);
149 static void free_obj(qtreetbl_obj_t *obj);
150 static uint8_t reset_iterator(qtreetbl_t *tbl);
172 qtreetbl_t *tbl = (qtreetbl_t *) calloc(1,
sizeof(qtreetbl_t));
177 if (options & QTREETBL_THREADSAFE) {
178 Q_MUTEX_NEW(tbl->qmutex,
true);
179 if (tbl->qmutex == NULL)
223 assert(tbl->qmutex == NULL);
242 int (*cmp)(
const void *name1,
size_t namesize1,
const void *name2,
263 (name != NULL) ? (strlen(name) + 1) : 0, data,
281 (name != NULL) ? (strlen(name) + 1) : 0, str,
282 (str != NULL) ? (strlen(str) + 1) : 0);
300 DYNAMIC_VSPRINTF(str, format);
329 const void *data,
size_t datasize) {
330 if (name == NULL || namesize == 0 || data == NULL || datasize == 0) {
337 qtreetbl_obj_t *root = put_obj(tbl, tbl->root, name, namesize, data,
339 if (root == NULL || errno == ENOMEM) {
384 void *
qtreetbl_get(qtreetbl_t *tbl,
const char *name,
size_t *datasize,
387 (name != NULL) ? (strlen(name) + 1) : 0,
412 (name != NULL) ? (strlen(name) + 1) : 0, NULL,
438 size_t *datasize,
bool newmem) {
439 if (name == NULL || namesize == 0) {
445 qtreetbl_obj_t *obj = find_obj(tbl, name, namesize);
448 data = (newmem) ?
qmemdup(obj->data, obj->datasize) : obj->data;
449 if (data != NULL && datasize != NULL) {
450 *datasize = obj->datasize;
470 (name != NULL) ? strlen(name) + 1 : 0);
493 tbl->root = remove_obj(tbl, tbl->root, name, namesize);
495 tbl->root->red =
false;
496 bool removed = (errno != ENOENT) ?
true :
false;
584 uint8_t tid = obj->tid;
585 if (obj->next == NULL) {
586 if (tbl->root == NULL) {
590 tid = reset_iterator(tbl);;
593 qtreetbl_obj_t *cursor = ((obj->next != NULL) ? obj->next : tbl->root);
594 while (cursor != NULL) {
595 if (cursor->left && cursor->left->tid != tid) {
596 cursor->left->next = cursor;
597 cursor = cursor->left;
599 }
else if (cursor->tid != tid) {
603 obj->name =
qmemdup(cursor->name, cursor->namesize);
604 obj->data =
qmemdup(cursor->data, cursor->datasize);
608 }
else if (cursor->right && cursor->right->tid != tid) {
609 cursor->right->next = cursor;
610 cursor = cursor->right;
613 cursor = cursor->next;
634 qtreetbl_obj_t *obj = find_min(tbl->root);
641 if (namesize != NULL) {
642 *namesize = obj->namesize;
644 void *name =
qmemdup(obj->name, obj->namesize);
662 qtreetbl_obj_t *obj = find_max(tbl->root);
669 if (namesize != NULL) {
670 *namesize = obj->namesize;
672 void *name =
qmemdup(obj->name, obj->namesize);
713 size_t namesize,
bool newmem) {
714 qtreetbl_obj_t retobj;
715 memset((
void*) &retobj, 0,
sizeof(retobj));
717 if (name == NULL || namesize == 0) {
723 qtreetbl_obj_t *obj, *lastobj;
724 for (obj = lastobj = tbl->root; obj != NULL;) {
725 int cmp = tbl->compare(name, namesize, obj->name, obj->namesize);
732 obj->left->next = obj;
736 obj->right->next = obj;
744 && (tbl->compare(name, namesize, obj->name,
745 obj->namesize) < 0); obj = obj->next)
755 retobj.name =
qmemdup(obj->name, obj->namesize);
756 retobj.data =
qmemdup(obj->data, obj->datasize);
759 retobj.tid = tbl->tid;
788 free_objs(tbl->root);
808 Q_MUTEX_ENTER(tbl->qmutex);
821 Q_MUTEX_LEAVE(tbl->qmutex);
831 Q_MUTEX_DESTROY(tbl->qmutex);
835 int qtreetbl_byte_cmp(
const void *name1,
size_t namesize1,
const void *name2,
837 size_t minsize = (namesize1 < namesize2) ? namesize1 : namesize2;
838 int cmp = memcmp(name1, name2, minsize);
839 if (cmp != 0 || namesize1 == namesize2)
841 return (namesize1 < namesize2) ? -1 : +1;
880 for (
int i = 0; i < depth; i++) {
885 printf(
"R=%c W= ", (obj->red) ?
'Y' :
'N');
888 for (
int i = 0; i < obj->namesize; i++) {
889 printf(
"%c", ((
char *) obj->name)[i]);
927 if (obj == NULL)
return 0;
930 if (is_red(obj->right) || is_red(obj->left)) {
931 printf(
"ERROR: Rule 4 violated.\n");
932 printf(
"Red node with key '");
934 for (
int i = 0; i < obj->namesize; i++) {
935 printf(
"%c", ((
char *) obj->name)[i]);
937 printf(
"' has at least one red child.\n");
975 if (right_path_len != left_path_len) {
976 printf(
"ERROR: Rule 5 violated.");
980 *path_len = right_path_len;
982 if (!is_red(obj)) (*path_len)++;
996 printf(
"Checking tree... \n");
997 if (tbl == NULL)
return 0;
1012 #ifndef _DOXYGEN_SKIP
1014 static bool is_red(qtreetbl_obj_t *obj) {
1015 return (obj != NULL) ? obj->red :
false;
1018 static qtreetbl_obj_t *flip_color(qtreetbl_obj_t *obj) {
1019 obj->red = !(obj->red);
1020 obj->left->red = !(obj->left->red);
1021 obj->right->red = !(obj->right->red);
1025 static qtreetbl_obj_t *rotate_left(qtreetbl_obj_t *obj) {
1026 qtreetbl_obj_t *x = obj->right;
1027 obj->right = x->left;
1029 x->red = x->left->red;
1030 x->left->red =
true;
1034 static qtreetbl_obj_t *rotate_right(qtreetbl_obj_t *obj) {
1035 qtreetbl_obj_t *x = obj->left;
1036 obj->left = x->right;
1038 x->red = x->right->red;
1039 x->right->red =
true;
1043 static qtreetbl_obj_t *move_red_left(qtreetbl_obj_t *obj) {
1045 if (obj->right && is_red(obj->right->left)) {
1046 obj->right = rotate_right(obj->right);
1047 obj = rotate_left(obj);
1053 static qtreetbl_obj_t *move_red_right(qtreetbl_obj_t *obj) {
1055 if (obj->left && is_red(obj->left->left)) {
1056 obj = rotate_right(obj);
1062 static qtreetbl_obj_t *fix(qtreetbl_obj_t *obj) {
1064 if (is_red(obj->right)) {
1065 obj = rotate_left(obj);
1068 if (obj->left && is_red(obj->left) && is_red(obj->left->left)) {
1069 obj = rotate_right(obj);
1072 if (is_red(obj->left) && is_red(obj->right)) {
1078 static qtreetbl_obj_t *find_min(qtreetbl_obj_t *obj) {
1085 for (o = obj; o->left != NULL; o = o->left)
1090 static qtreetbl_obj_t *find_max(qtreetbl_obj_t *obj) {
1097 for (o = obj; o->right != NULL; o = o->right)
1102 static qtreetbl_obj_t *find_obj(qtreetbl_t *tbl,
const void *name,
1104 if (name == NULL || namesize == 0) {
1110 qtreetbl_obj_t *obj;
1111 for (obj = tbl->root; obj != NULL;) {
1112 int cmp = tbl->compare(name, namesize, obj->name, obj->namesize);
1117 obj = (cmp < 0) ? obj->left : obj->right;
1125 static qtreetbl_obj_t *remove_min(qtreetbl_obj_t *obj) {
1126 if (obj->left == NULL) {
1132 if (!is_red(obj->left) && !is_red(obj->left->left)) {
1133 obj = move_red_left(obj);
1135 obj->left = remove_min(obj->left);
1139 static qtreetbl_obj_t *new_obj(
bool red,
const void *name,
size_t namesize,
1140 const void *data,
size_t datasize) {
1141 qtreetbl_obj_t *obj = (qtreetbl_obj_t *) calloc(1,
sizeof(qtreetbl_obj_t));
1142 void *copyname =
qmemdup(name, namesize);
1143 void *copydata =
qmemdup(data, datasize);
1145 if (obj == NULL || copyname == NULL || copydata == NULL) {
1154 obj->name = copyname;
1155 obj->namesize = namesize;
1156 obj->data = copydata;
1157 obj->datasize = datasize;
1162 static qtreetbl_obj_t *put_obj(qtreetbl_t *tbl, qtreetbl_obj_t *obj,
1163 const void *name,
size_t namesize,
1164 const void *data,
size_t datasize) {
1167 return new_obj(
true, name, namesize, data, datasize);
1171 if (is_red(obj->left) && is_red(obj->right)) {
1175 int cmp = tbl->compare(obj->name, obj->namesize, name, namesize);
1177 void *copydata =
qmemdup(data, datasize);
1178 if (copydata != NULL) {
1180 obj->data = copydata;
1181 obj->datasize = datasize;
1183 }
else if (cmp < 0) {
1184 obj->right = put_obj(tbl, obj->right, name, namesize, data, datasize);
1186 obj->left = put_obj(tbl, obj->left, name, namesize, data, datasize);
1190 if (is_red(obj->right)) {
1191 obj = rotate_left(obj);
1195 if (is_red(obj->left) && is_red(obj->left->left)) {
1196 obj = rotate_right(obj);
1202 static qtreetbl_obj_t *remove_obj(qtreetbl_t *tbl, qtreetbl_obj_t *obj,
1203 const void *name,
size_t namesize) {
1209 if (tbl->compare(name, namesize, obj->name, obj->namesize) < 0) {
1211 if (obj->left && (!is_red(obj->left) && !is_red(obj->left->left))) {
1212 obj = move_red_left(obj);
1215 obj->left = remove_obj(tbl, obj->left, name, namesize);
1217 if (is_red(obj->left) && !is_red(obj->right)) {
1218 obj = rotate_right(obj);
1221 if (tbl->compare(name, namesize, obj->name, obj->namesize)
1222 == 0&& obj->right == NULL) {
1227 assert(tbl->num >= 0);
1231 if (obj->right != NULL
1232 && (!is_red(obj->right) && !is_red(obj->right->left))) {
1233 obj = move_red_right(obj);
1236 if (tbl->compare(name, namesize, obj->name, obj->namesize) == 0) {
1238 qtreetbl_obj_t *minobj = find_min(obj->right);
1239 assert(minobj != NULL);
1242 obj->name =
qmemdup(minobj->name, minobj->namesize);
1243 obj->namesize = minobj->namesize;
1244 obj->data =
qmemdup(minobj->data, minobj->datasize);
1245 obj->datasize = minobj->datasize;
1246 obj->right = remove_min(obj->right);
1250 obj->right = remove_obj(tbl, obj->right, name, namesize);
1257 static void free_objs(qtreetbl_obj_t *obj) {
1262 free_objs(obj->left);
1265 free_objs(obj->right);
1270 static void free_obj(qtreetbl_obj_t *obj) {
1279 static uint8_t reset_iterator(qtreetbl_t *tbl) {
1280 return (++tbl->tid);
qtreetbl_t * qtreetbl(int options)
Initialize a tree table.
void print_node(qtreetbl_obj_t *obj, int depth)
Display the tree structure from the node pointed by obj and down.
void qtreetbl_print(qtreetbl_t *tbl)
Display the tree structure.
char * qtreetbl_getstr(qtreetbl_t *tbl, const char *name, const bool newmem)
qtreetbl->getstr(): Finds an object and returns as string type.
bool qtreetbl_remove_by_obj(qtreetbl_t *tbl, const void *name, size_t namesize)
qtreetbl->remove(): Remove an object from this table with an object name.
bool qtreetbl_debug(qtreetbl_t *tbl, FILE *out)
qtreetbl->debug(): Print hash table for debugging purpose
int qtreetbl_check(qtreetbl_t *tbl)
Verifies that the (some) invariants of the red-black tree are satisfied.
size_t qtreetbl_size(qtreetbl_t *tbl)
qtreetbl->size(): Returns the number of keys in the table.
bool qtreetbl_putstr(qtreetbl_t *tbl, const char *name, const char *str)
qtreetbl->putstr(): Put a string into this table.
void qtreetbl_free(qtreetbl_t *tbl)
qtreetbl->free(): De-allocate the table
void * qtreetbl_find_min(qtreetbl_t *tbl, size_t *namesize)
qtreetbl->find_min(): Find the name of very left object.
void * qtreetbl_get_by_obj(qtreetbl_t *tbl, const char *name, size_t namesize, size_t *datasize, bool newmem)
qtreetbl->get_by_obj(): Get an object from this table with an object name.
bool qtreetbl_getnext(qtreetbl_t *tbl, qtreetbl_obj_t *obj, const bool newmem)
qhashtbl->getnext(): Get next element.
void * qtreetbl_find_max(qtreetbl_t *tbl, size_t *namesize)
qtreetbl->find_max(): Find the name of very right object.
void qtreetbl_unlock(qtreetbl_t *tbl)
qtreetbl->unlock(): Leave critical section.
bool qtreetbl_put_by_obj(qtreetbl_t *tbl, const void *name, size_t namesize, const void *data, size_t datasize)
qtreetbl->put_by_obj(): Put an object data into this table with an object name.
void qtreetbl_clear(qtreetbl_t *tbl)
qtreetbl->clear(): Clears the table so that it contains no keys.
qtreetbl_obj_t qtreetbl_find_nearest(qtreetbl_t *tbl, const void *name, size_t namesize, bool newmem)
qtreetbl->find_nearest(): Find equal or nearest object.
bool qtreetbl_remove(qtreetbl_t *tbl, const char *name)
qtreetbl->remove(): Remove an object from this table.
void * qmemdup(const void *data, size_t size)
Duplicate a copy of memory data.
int node_check_rule5(qtreetbl_t *tbl, qtreetbl_obj_t *obj, int *path_len)
Verifies that RULE 5 of the red-black tree is verified for the node pointed by obj and all its childr...
bool qtreetbl_put(qtreetbl_t *tbl, const char *name, const void *data, size_t datasize)
qtreetbl->put(): Put an object into this table with string type key.
void qtreetbl_set_compare(qtreetbl_t *tbl, int(*cmp)(const void *name1, size_t namesize1, const void *name2, size_t namesize2))
qtreetbl->set_compare(): Set user comparator.
void * qtreetbl_get(qtreetbl_t *tbl, const char *name, size_t *datasize, bool newmem)
qtreetbl->get(): Get an object from this table.
void qtreetbl_lock(qtreetbl_t *tbl)
qtreetbl->lock(): Enter critical section.
bool qtreetbl_putstrf(qtreetbl_t *tbl, const char *name, const char *format,...)
qtreetbl->putstrf(): Put a formatted string into this table.
int node_check_rule4(qtreetbl_t *tbl, qtreetbl_obj_t *obj)
Verifies that RULE 4 of the red-black tree is verified for the node pointed by obj and all its childr...