/*************************************************************************** hashvector.h - class implementing hash/vector ------------------- begin : Sun Dec 22 2002 copyright : (C) 2002 by Meilof email : meilof@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __POSADIS_HASHVECTOR_H #define __POSADIS_HASHVECTOR_H #include #include #include "vector.h" #include "pbl.h" inline char *mystrlwr(char *str) { char *ptr = str; while (*ptr) { *ptr = tolower(*ptr); ptr++; } return str; } template class vitem { public: vitem(const char *_name, TYPE _data) { name = strdup(_name); data = _data; } ~vitem() { free(name); if (data) delete data; } char *name; TYPE data; }; typedef bool(*iteratorfn)(void *userdata, char *name, void *item); #define HV_TRESHOLD 32 template class hashvector { public: union { pvector *> *vec; pblHashTable_t *table; } data; int nitems; hashvector() { nitems = 0; data.vec = NULL; } void clean(bool dodelete = true) { if (nitems < HV_TRESHOLD) { if (data.vec) { data.vec->destroy(dodelete); delete data.vec; data.vec = NULL; } } else { TYPE dat; for(dat = (TYPE)pblHtFirst(data.table); dat; dat = (TYPE)pblHtNext(data.table)) { if (dodelete) delete dat; pblHtRemove(data.table, 0, 0); } pblHtDelete(data.table); data.table = NULL; } nitems = 0; } ~hashvector() { clean(true); } /* name should be static, not dynamic */ void add_item(const char *_name, TYPE dat) { char *name = strdup(_name); mystrlwr(name); if (nitems < HV_TRESHOLD - 1) { if (nitems == 0) data.vec = new pvector *>(); data.vec->add(new vitem(name, dat)); nitems++; } else if (nitems == HV_TRESHOLD - 1) { pblHashTable_t *table = pblHtCreate(); vitem *v; for (int x = 0; x < data.vec->count; x++) { v = (*data.vec)[x]; pblHtInsert(table, (void *)strdup(v->name), strlen(v->name)+1, v->data); v->data = NULL; delete v; (*data.vec)[x] = NULL; } pblHtInsert(table, (void *)strdup(name), strlen(name)+1, dat); delete data.vec; data.table = table; nitems++; } else { pblHtInsert(data.table, (void *)name, strlen(name)+1, dat); nitems++; } free(name); } void convertback() { pvector *> *vec = new pvector *>(); TYPE dat; for(dat = (TYPE)pblHtFirst(data.table); dat; dat = (TYPE)pblHtNext(data.table)) { vec->add(new vitem((char *)pblHtCurrentKey(data.table), dat)); pblHtRemove(data.table, 0, 0); } pblHtDelete(data.table); data.vec = vec; } void remove_item(const char *_name) { if (nitems == 0) return; if (nitems < HV_TRESHOLD + 1) { if (nitems == HV_TRESHOLD) convertback(); for (int x = data.vec->count - 1; x >= 0; x--) { if (strcmpi((*data.vec)[x]->name, _name) == 0) { nitems--; data.vec->removeindex(x); return; } } } else { char *name = strdup(_name); mystrlwr(name); TYPE dat = (TYPE)pblHtLookup(data.table, (void *)name, strlen(name)+1); free(name); if (dat) { delete dat; if (pblHtRemove(data.table, 0, 0) == -1) { printf("*** Critical: pblHtRemove failed!\n"); exit(255); } nitems--; } } } TYPE get_item(const char *_name) { if (nitems == 0) return NULL; if (nitems < HV_TRESHOLD) { for (int x = data.vec->count - 1; x >= 0; x--) if (strcmpi((*data.vec)[x]->name, _name) == 0) return (*data.vec)[x]->data; return NULL; } else { char *name = strdup(_name); mystrlwr(name); TYPE ret = (TYPE)pblHtLookup(data.table, (void *)name, strlen(name)+1); free(name); return ret; } } void iterate(iteratorfn fn, void *arg = NULL) { if (nitems == 0) return; if (nitems < HV_TRESHOLD) { for (int x = 0; x < data.vec->count; x++) fn(arg, (*data.vec)[x]->name, (*data.vec)[x]->data); } else { TYPE dat; for(dat = (TYPE)pblHtFirst(data.table); dat; dat = (TYPE)pblHtNext(data.table)) { fn(arg, (char *)pblHtCurrentKey(data.table), dat); } } } bool isempty() { return (nitems == 0); } }; #endif /* __POSADIS_HASHVECTOR_H */