146#include "qinternal.h"
147#include "utilities/qhash.h"
148#include "containers/qhasharr.h"
150#define COLLISION_MARK (-1)
151#define EXTBLOCK_MARK (-2)
155static qhasharr_slot_t* get_slots(qhasharr_t *tbl);
156static int find_avail(qhasharr_t *tbl,
int startidx);
157static int get_idx(qhasharr_t *tbl,
const void *name,
size_t namesize,
159static void *get_data(qhasharr_t *tbl,
int idx,
size_t *size);
160static bool put_data(qhasharr_t *tbl,
int idx, uint32_t hash,
const void *name,
161 size_t namesize,
const void *data,
size_t datasize,
163static bool copy_slot(qhasharr_t *tbl,
int idx1,
int idx2);
164static bool remove_slot(qhasharr_t *tbl,
int idx);
165static bool remove_data(qhasharr_t *tbl,
int idx);
180 size_t memsize =
sizeof(qhasharr_data_t)
181 + (
sizeof(qhasharr_slot_t) * (max));
208qhasharr_t *
qhasharr(
void *memory,
size_t memsize) {
210 qhasharr_data_t *tbldata = (qhasharr_data_t *) memory;
215 int maxslots = (memsize -
sizeof(qhasharr_data_t))
216 /
sizeof(qhasharr_slot_t);
217 if (maxslots < 1 || memsize <=
sizeof(qhasharr_t)) {
223 memset((
void *) tbldata, 0, memsize);
224 tbldata->maxslots = maxslots;
225 tbldata->usedslots = 0;
230 qhasharr_t *tbl = (qhasharr_t *) malloc(
sizeof(qhasharr_t));
235 memset((
void *) tbl, 0,
sizeof(qhasharr_t));
299 data, (data) ? strlen(data) + 1 : 0);
318 DYNAMIC_VSPRINTF(str, format);
345 const void *data,
size_t datasize) {
346 if (tbl == NULL || name == NULL || namesize == 0 || data == NULL
352 qhasharr_data_t *tbldata = tbl->data;
353 qhasharr_slot_t *tblslots = get_slots(tbl);
356 if (tbldata->usedslots >= tbldata->maxslots) {
365 if (tblslots[hash].count == 0) {
367 if (put_data(tbl, hash, hash, name, namesize, data, datasize,
371 }
else if (tblslots[hash].count > 0) {
373 int idx = get_idx(tbl, name, namesize, hash);
380 int idx = find_avail(tbl, hash);
387 if (put_data(tbl, idx, hash, name, namesize, data, datasize,
388 COLLISION_MARK) ==
false) {
393 tblslots[hash].count++;
399 int idx = find_avail(tbl, hash + 1);
406 copy_slot(tbl, idx, hash);
407 remove_slot(tbl, hash);
410 if (tblslots[idx].link != -1) {
411 tblslots[tblslots[idx].link].hash = idx;
413 if (tblslots[idx].count == EXTBLOCK_MARK) {
414 tblslots[tblslots[idx].hash].link = idx;
418 if (put_data(tbl, hash, hash, name, namesize, data, datasize,
444void *
qhasharr_get(qhasharr_t *tbl,
const char *name,
size_t *datasize) {
488 if (tbl == NULL || name == NULL || namesize == 0) {
493 qhasharr_data_t *tbldata = tbl->data;
497 int idx = get_idx(tbl, name, namesize, hash);
503 return get_data(tbl, idx, datasize);
536 if (tbl == NULL || name == NULL || namesize == 0) {
541 qhasharr_data_t *tbldata = tbl->data;
545 int idx = get_idx(tbl, name, namesize, hash);
597 qhasharr_data_t *tbldata = tbl->data;
598 qhasharr_slot_t *tblslots = get_slots(tbl);
600 if (tblslots[idx].count == 1) {
602 remove_data(tbl, idx);
603 }
else if (tblslots[idx].count > 1) {
606 for (idx2 = idx + 1;; idx2++) {
607 if (idx2 >= tbldata->maxslots)
613 if (tblslots[idx2].count == COLLISION_MARK
614 && tblslots[idx2].hash == tblslots[idx].hash) {
620 int backupcount = tblslots[idx].count;
621 remove_data(tbl, idx);
622 copy_slot(tbl, idx, idx2);
623 remove_slot(tbl, idx2);
625 tblslots[idx].count = backupcount - 1;
626 if (tblslots[idx].link != -1) {
627 tblslots[tblslots[idx].link].hash = idx;
630 }
else if (tblslots[idx].count == COLLISION_MARK) {
632 if (tblslots[tblslots[idx].hash].count <= 1) {
636 tblslots[tblslots[idx].hash].count--;
639 remove_data(tbl, idx);
677 if (tbl == NULL || obj == NULL || idx == NULL) {
682 qhasharr_data_t *tbldata = tbl->data;
683 qhasharr_slot_t *tblslots = get_slots(tbl);
685 for (; *idx < tbldata->maxslots; (*idx)++) {
686 if (tblslots[*idx].count == 0 || tblslots[*idx].count == EXTBLOCK_MARK) {
690 size_t namesize = tblslots[*idx].data.pair.namesize;
691 if (namesize > Q_HASHARR_NAMESIZE)
692 namesize = Q_HASHARR_NAMESIZE;
694 obj->name = malloc(namesize + 1);
695 if (obj->name == NULL) {
699 memcpy(obj->name, tblslots[*idx].data.pair.name, namesize);
700 memcpy(obj->name + namesize,
"", 1);
701 obj->namesize = namesize;
703 obj->data = get_data(tbl, *idx, &obj->datasize);
704 if (obj->data == NULL) {
733 qhasharr_data_t *tbldata = tbl->data;
735 if (maxslots != NULL)
736 *maxslots = tbldata->maxslots;
737 if (usedslots != NULL)
738 *usedslots = tbldata->usedslots;
756 qhasharr_data_t *tbldata = tbl->data;
757 qhasharr_slot_t *tblslots = get_slots(tbl);
759 if (tbldata->usedslots == 0)
762 tbldata->usedslots = 0;
766 memset((
void *) tblslots,
'\0',
767 (tbldata->maxslots *
sizeof(qhasharr_slot_t)));
791 qhasharr_slot_t *tblslots = get_slots(tbl);
795 while (tbl->getnext(tbl, &obj, &idx) ==
true) {
796 uint16_t namesize = tblslots[idx - 1].data.pair.namesize;
797 _q_textout(out, obj.name, obj.namesize, MAX_HUMANOUT);
798 fprintf(out,
"%s(%d)=", (namesize > Q_HASHARR_NAMESIZE) ?
"..." :
"",
800 _q_textout(out, obj.data, obj.datasize, MAX_HUMANOUT);
801 fprintf(out,
" (%zu)\n", obj.datasize);
808 qhasharr_data_t *tbldata = tbl->data;
809 fprintf(out,
"%d elements (slot %d used/%d total)\n",
810 tbldata->num, tbldata->usedslots, tbldata->maxslots);
811 for (idx = 0; idx < tbldata->maxslots; idx++) {
812 if (tblslots[idx].count == 0)
continue;
814 fprintf(out,
"slot=%d,type=", idx);
815 if (tblslots[idx].count == EXTBLOCK_MARK) {
816 fprintf(out,
"EXTEND");
817 fprintf(out,
",prev=%d", tblslots[idx].hash);
818 fprintf(out,
",next=%d", tblslots[idx].link);
819 fprintf(out,
",datasize=%d", tblslots[idx].datasize);
820 fprintf(out,
",data=");
822 tblslots[idx].data.ext.data,
823 tblslots[idx].datasize,
826 fprintf(out,
"%s", (tblslots[idx].count == COLLISION_MARK)?
"COLISN":
"NORMAL");
827 fprintf(out,
",next=%d", tblslots[idx].link);
828 fprintf(out,
",count=%d", tblslots[idx].count);
829 fprintf(out,
",hash=%u", tblslots[idx].hash);
830 fprintf(out,
",namesize=%d", tblslots[idx].data.pair.namesize);
831 fprintf(out,
",datasize=%d", tblslots[idx].datasize);
832 fprintf(out,
",name=");
834 tblslots[idx].data.pair.name,
835 (tblslots[idx].data.pair.namesize>Q_HASHARR_NAMESIZE)
837 : tblslots[idx].data.pair.namesize,
839 fprintf(out,
",data=");
841 tblslots[idx].data.pair.data,
842 tblslots[idx].datasize,
868static qhasharr_slot_t* get_slots(qhasharr_t *tbl) {
869 return (qhasharr_slot_t*) ((
char*) (tbl->data) +
sizeof(qhasharr_data_t));
873static int find_avail(qhasharr_t *tbl,
int startidx) {
874 qhasharr_data_t *tbldata = tbl->data;
875 qhasharr_slot_t *tblslots = get_slots(tbl);
877 if (startidx >= tbldata->maxslots)
882 if (tblslots[idx].count == 0)
886 if (idx >= tbldata->maxslots)
895static int get_idx(qhasharr_t *tbl,
const void *name,
size_t namesize,
897 qhasharr_data_t *tbldata = tbl->data;
898 qhasharr_slot_t *tblslots = get_slots(tbl);
900 if (tblslots[hash].count > 0) {
902 for (count = 0, idx = hash; count < tblslots[hash].count;) {
903 if (tblslots[idx].hash == hash
904 && (tblslots[idx].count > 0 || tblslots[idx].count == COLLISION_MARK)) {
910 if (namesize == tblslots[idx].data.pair.namesize) {
911 if (namesize <= Q_HASHARR_NAMESIZE) {
913 if (!memcmp(name, tblslots[idx].data.pair.name,
919 unsigned char namemd5[16];
921 if (!memcmp(name, tblslots[idx].data.pair.name,
924 tblslots[idx].data.pair.namemd5,
934 if (idx >= tbldata->maxslots)
948static void *get_data(qhasharr_t *tbl,
int idx,
size_t *size) {
954 qhasharr_slot_t *tblslots = get_slots(tbl);
958 for (newidx = idx, datasize = 0;; newidx = tblslots[newidx].link) {
959 datasize += tblslots[newidx].datasize;
960 if (tblslots[newidx].link == -1)
965 if ((data = malloc(datasize)) == NULL) {
970 for (newidx = idx, dp = data;; newidx = tblslots[newidx].link) {
971 if (tblslots[newidx].count == EXTBLOCK_MARK) {
973 memcpy(dp, (
void *) tblslots[newidx].data.ext.data,
974 tblslots[newidx].datasize);
977 memcpy(dp, (
void *) tblslots[newidx].data.pair.data,
978 tblslots[newidx].datasize);
981 dp += tblslots[newidx].datasize;
982 if (tblslots[newidx].link == -1)
991static bool put_data(qhasharr_t *tbl,
int idx, uint32_t hash,
const void *name,
992 size_t namesize,
const void *data,
size_t datasize,
994 qhasharr_data_t *tbldata = tbl->data;
995 qhasharr_slot_t *tblslots = get_slots(tbl);
997 assert(tblslots[idx].count == 0);
999 unsigned char namemd5[16];
1003 tblslots[idx].count = count;
1004 tblslots[idx].hash = hash;
1005 memcpy(tblslots[idx].data.pair.name, name,
1006 (namesize < Q_HASHARR_NAMESIZE) ? namesize : Q_HASHARR_NAMESIZE);
1007 memcpy((
char *) tblslots[idx].data.pair.namemd5, (
char *) namemd5, 16);
1008 tblslots[idx].data.pair.namesize = namesize;
1009 tblslots[idx].link = -1;
1014 for (newidx = idx, savesize = 0; savesize < datasize;) {
1016 int tmpidx = find_avail(tbl, newidx + 1);
1018 remove_data(tbl, idx);
1024 memset((
void *) (&tblslots[tmpidx]),
'\0',
sizeof(qhasharr_slot_t));
1026 tblslots[tmpidx].count = EXTBLOCK_MARK;
1027 tblslots[tmpidx].hash = newidx;
1028 tblslots[tmpidx].link = -1;
1029 tblslots[tmpidx].datasize = 0;
1030 tblslots[newidx].link = tmpidx;
1036 size_t copysize = datasize - savesize;
1037 if (tblslots[newidx].count == EXTBLOCK_MARK) {
1039 if (copysize >
sizeof(
struct Q_HASHARR_SLOT_EXT)) {
1040 copysize =
sizeof(
struct Q_HASHARR_SLOT_EXT);
1042 memcpy(tblslots[newidx].data.ext.data, data + savesize, copysize);
1045 if (copysize > Q_HASHARR_DATASIZE) {
1046 copysize = Q_HASHARR_DATASIZE;
1048 memcpy(tblslots[newidx].data.pair.data, data + savesize, copysize);
1053 tblslots[newidx].datasize = copysize;
1054 savesize += copysize;
1057 tbldata->usedslots++;
1063static bool copy_slot(qhasharr_t *tbl,
int idx1,
int idx2) {
1064 qhasharr_slot_t *tblslots = get_slots(tbl);
1066 if (tblslots[idx1].count != 0 || tblslots[idx2].count == 0) {
1071 memcpy((
void *) (&tblslots[idx1]), (
void *) (&tblslots[idx2]),
1072 sizeof(qhasharr_slot_t));
1077static bool remove_slot(qhasharr_t *tbl,
int idx) {
1078 qhasharr_slot_t *tblslots = get_slots(tbl);
1079 assert(tblslots[idx].count != 0);
1081 tblslots[idx].count = 0;
1085static bool remove_data(qhasharr_t *tbl,
int idx) {
1086 qhasharr_data_t *tbldata = tbl->data;
1087 qhasharr_slot_t *tblslots = get_slots(tbl);
1088 assert(tblslots[idx].count != 0);
1091 int link = tblslots[idx].link;
1092 remove_slot(tbl, idx);
1093 tbldata->usedslots--;
bool qhashmd5(const void *data, size_t nbytes, void *retbuf)
Calculate 128-bit(16-bytes) MD5 hash.
uint32_t qhashmurmur3_32(const void *data, size_t nbytes)
Get 32-bit Murmur3 hash.
void qhasharr_clear(qhasharr_t *tbl)
qhasharr->clear(): Clears this table so that it contains no keys.
int qhasharr_size(qhasharr_t *tbl, int *maxslots, int *usedslots)
qhasharr->size(): Returns the number of objects in this table.
bool qhasharr_put_by_obj(qhasharr_t *tbl, const void *name, size_t namesize, const void *data, size_t datasize)
qhasharr->put_by_obj(): ut an object into this table by key object.
bool qhasharr_remove_by_idx(qhasharr_t *tbl, int idx)
qhasharr->remove_by_idx(): Remove an object from this table by index number.
void * qhasharr_get(qhasharr_t *tbl, const char *name, size_t *datasize)
qhasharr->get(): Get an object from this table
bool qhasharr_debug(qhasharr_t *tbl, FILE *out)
qhasharr->debug(): Print hash table for debugging purpose
bool qhasharr_put(qhasharr_t *tbl, const char *name, const void *data, size_t datasize)
qhasharr->put(): Put an object into this table.
qhasharr_t * qhasharr(void *memory, size_t memsize)
Initialize static hash table.
size_t qhasharr_calculate_memsize(int max)
Get how much memory is needed for N slots.
char * qhasharr_getstr(qhasharr_t *tbl, const char *name)
qhasharr->getstr(): Finds an object with given name and returns as string type.
bool qhasharr_getnext(qhasharr_t *tbl, qhasharr_obj_t *obj, int *idx)
qhasharr->getnext(): Get next element.
void * qhasharr_get_by_obj(qhasharr_t *tbl, const void *name, size_t namesize, size_t *datasize)
qhasharr->get_by_object(): Get an object from this table by key object
bool qhasharr_putstrf(qhasharr_t *tbl, const char *name, const char *format,...)
qhasharr->putstrf(): Put a formatted string into this table.
void qhasharr_free(qhasharr_t *tbl)
qhasharr->free(): De-allocate table reference object.
bool qhasharr_remove(qhasharr_t *tbl, const char *name)
qhasharr->remove(): Remove an object from this table.
bool qhasharr_putstr(qhasharr_t *tbl, const char *name, const char *data)
qhasharr->putstr(): Put a string into this table
bool qhasharr_remove_by_obj(qhasharr_t *tbl, const char *name, size_t namesize)
qhasharr->remove_by_obj(): Remove an object from this table by key object