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;
867 #ifndef _DOXYGEN_SKIP
869 static bool is_red(qtreetbl_obj_t *obj) {
870 return (obj != NULL) ? obj->red :
false;
873 static qtreetbl_obj_t *flip_color(qtreetbl_obj_t *obj) {
874 obj->red = !(obj->red);
875 obj->left->red = !(obj->left->red);
876 obj->right->red = !(obj->right->red);
880 static qtreetbl_obj_t *rotate_left(qtreetbl_obj_t *obj) {
881 qtreetbl_obj_t *x = obj->right;
882 obj->right = x->left;
884 x->red = x->left->red;
889 static qtreetbl_obj_t *rotate_right(qtreetbl_obj_t *obj) {
890 qtreetbl_obj_t *x = obj->left;
891 obj->left = x->right;
893 x->red = x->right->red;
894 x->right->red =
true;
898 static qtreetbl_obj_t *move_red_left(qtreetbl_obj_t *obj) {
900 if (obj->right && is_red(obj->right->left)) {
901 obj->right = rotate_right(obj->right);
902 obj = rotate_left(obj);
908 static qtreetbl_obj_t *move_red_right(qtreetbl_obj_t *obj) {
910 if (obj->left && is_red(obj->left->left)) {
911 obj = rotate_right(obj);
917 static qtreetbl_obj_t *fix(qtreetbl_obj_t *obj) {
919 if (is_red(obj->right)) {
920 obj = rotate_left(obj);
923 if (obj->left && is_red(obj->left) && is_red(obj->left->left)) {
924 obj = rotate_right(obj);
927 if (is_red(obj->left) && is_red(obj->right)) {
933 static qtreetbl_obj_t *find_min(qtreetbl_obj_t *obj) {
940 for (o = obj; o->left != NULL; o = o->left)
945 static qtreetbl_obj_t *find_max(qtreetbl_obj_t *obj) {
952 for (o = obj; o->right != NULL; o = o->right)
957 static qtreetbl_obj_t *find_obj(qtreetbl_t *tbl,
const void *name,
959 if (name == NULL || namesize == 0) {
966 for (obj = tbl->root; obj != NULL;) {
967 int cmp = tbl->compare(name, namesize, obj->name, obj->namesize);
972 obj = (cmp < 0) ? obj->left : obj->right;
980 static qtreetbl_obj_t *remove_min(qtreetbl_obj_t *obj) {
981 if (obj->left == NULL) {
987 if (!is_red(obj->left) && !is_red(obj->left->left)) {
988 obj = move_red_left(obj);
990 obj->left = remove_min(obj->left);
994 static qtreetbl_obj_t *new_obj(
bool red,
const void *name,
size_t namesize,
995 const void *data,
size_t datasize) {
996 qtreetbl_obj_t *obj = (qtreetbl_obj_t *) calloc(1,
sizeof(qtreetbl_obj_t));
997 void *copyname =
qmemdup(name, namesize);
998 void *copydata =
qmemdup(data, datasize);
1000 if (obj == NULL || copyname == NULL || copydata == NULL) {
1009 obj->name = copyname;
1010 obj->namesize = namesize;
1011 obj->data = copydata;
1012 obj->datasize = datasize;
1017 static qtreetbl_obj_t *put_obj(qtreetbl_t *tbl, qtreetbl_obj_t *obj,
1018 const void *name,
size_t namesize,
1019 const void *data,
size_t datasize) {
1022 return new_obj(
true, name, namesize, data, datasize);
1026 if (is_red(obj->left) && is_red(obj->right)) {
1030 int cmp = tbl->compare(obj->name, obj->namesize, name, namesize);
1032 void *copydata =
qmemdup(data, datasize);
1033 if (copydata != NULL) {
1035 obj->data = copydata;
1036 obj->datasize = datasize;
1038 }
else if (cmp < 0) {
1039 obj->right = put_obj(tbl, obj->right, name, namesize, data, datasize);
1041 obj->left = put_obj(tbl, obj->left, name, namesize, data, datasize);
1045 if (is_red(obj->right)) {
1046 obj = rotate_left(obj);
1050 if (is_red(obj->left) && is_red(obj->left->left)) {
1051 obj = rotate_right(obj);
1057 static qtreetbl_obj_t *remove_obj(qtreetbl_t *tbl, qtreetbl_obj_t *obj,
1058 const void *name,
size_t namesize) {
1064 if (tbl->compare(name, namesize, obj->name, obj->namesize) < 0) {
1066 if (obj->left && (!is_red(obj->left) && !is_red(obj->left->left))) {
1067 obj = move_red_left(obj);
1070 obj->left = remove_obj(tbl, obj->left, name, namesize);
1072 if (is_red(obj->left)) {
1073 obj = rotate_right(obj);
1076 if (tbl->compare(name, namesize, obj->name, obj->namesize)
1077 == 0&& obj->right == NULL) {
1082 assert(tbl->num >= 0);
1086 if (obj->right != NULL
1087 && (!is_red(obj->right) && !is_red(obj->right->left))) {
1088 obj = move_red_right(obj);
1091 if (tbl->compare(name, namesize, obj->name, obj->namesize) == 0) {
1093 qtreetbl_obj_t *minobj = find_min(obj->right);
1094 assert(minobj != NULL);
1097 obj->name =
qmemdup(minobj->name, minobj->namesize);
1098 obj->namesize = minobj->namesize;
1099 obj->data =
qmemdup(minobj->data, minobj->datasize);
1100 obj->datasize = minobj->datasize;
1101 obj->right = remove_min(obj->right);
1105 obj->right = remove_obj(tbl, obj->right, name, namesize);
1112 static void free_objs(qtreetbl_obj_t *obj) {
1117 free_objs(obj->left);
1120 free_objs(obj->right);
1125 static void free_obj(qtreetbl_obj_t *obj) {
1134 static uint8_t reset_iterator(qtreetbl_t *tbl) {
1135 return (++tbl->tid);
qtreetbl_t * qtreetbl(int options)
Initialize a tree table.
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
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.
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.