/******************************************************************************** * Hash table class template (char* based) * *********************************************************************************/ #ifndef GHash_HH #define GHash_HH #include "GBase.h" /** * This class maintains a fast-access hash table of entities * indexed by a character string (essentially, maps strings to pointers) */ //#define HASH_DBG_PRINT 1 #define GSTR_HASH(s) strhash(s) //#define GSTR_HASH(s) djb_hash(s) //#define GSTR_HASH(s) fnv1a_hash(s) //#define GSTR_HASH(s) murmur3(s) template class GHash { protected: struct GHashEntry { char* key; // Key string bool keyalloc; // shared key flag (to free/not the key) int hash; // Hash value of key pointer data; // Data }; GHashEntry* hash; // Hash int fCapacity; // table size int fCount; // number of valid entries int fCurrentEntry; char* lastkeyptr; //pointer to last key string added //---------- Raw data retrieval (including empty entries) // Return key at position pos. const char* Key(uint pos) const { return hash[pos].key; } // return data OBJ* at given position OBJ* Data(uint pos) const { return (OBJ*) hash[pos].data; } // Return position of first filled slot, or >= fCapacity int First() const; // Return position of last filled slot or -1 int Last() const; // Return position of next filled slot in hash table // or a value greater than or equal to fCapacity if no filled // slot was found int Next(int pos) const; //Return position of previous filled slot in hash table //or a -1 if no filled slot was found int Prev(int pos) const; private: GHash(const GHash&); GHash &operator=(const GHash&); GFreeProc* fFreeProc; //procedure to free item data protected: public: static void DefaultFreeProc(pointer item) { delete (OBJ*)item; } public: GHash(GFreeProc* freeProc); // constructs of an empty hash GHash(bool doFree=true); // constructs of an empty hash (free the item objects) void setFreeItem(GFreeProc *freeProc) { fFreeProc=freeProc; } void setFreeItem(bool doFree) { fFreeProc=(doFree)? &DefaultFreeProc : NULL; } int Capacity() const { return fCapacity; } // table's size, including the empty slots. void Resize(int m); // Resize the table to the given size. int Count() const { return fCount; }// the total number of entries in the table. // Insert a new entry into the table given key. // If there is already an entry with that key, leave it unchanged OBJ* Add(const char* ky, OBJ* ptr=NULL); //same with Add, but frees the old element if it's a replacement OBJ* fAdd(const char* ky, OBJ* ptr=NULL); //same as Add, but the key pointer is stored directly, no string copy needed //(shared-key-Add) OBJ* shkAdd(const char* ky, OBJ* ptr); // Replace data at key. If there was no existing entry, // a new entry is inserted. OBJ* Replace(const char* ky, OBJ* ptr); // Remove a given key and its data OBJ* Remove(const char* ky); // Find data OBJ* given key. OBJ* Find(const char* ky, char** keyptr=NULL); bool hasKey(const char* ky); char* getLastKey() { return lastkeyptr; } OBJ* operator[](const char* ky) { return Find(ky); } void startIterate(); //iterator-like initialization char* NextKey(); //returns next valid key in the table (NULL if no more) OBJ* NextData(); //returns next valid hash[].data OBJ* NextData(char*& nextkey); //returns next valid hash[].data //or NULL if no more //nextkey is SET to the corresponding key GHashEntry* NextEntry() { //returns a pointer to a GHashEntry int pos=fCurrentEntry; while (pos GHash::GHash(GFreeProc* freeProc) { GMALLOC(hash, sizeof(GHashEntry)*DEF_HASH_SIZE); fCurrentEntry=-1; fFreeProc=freeProc; lastkeyptr=NULL; for (uint i=0; i GHash::GHash(bool doFree) { GMALLOC(hash, sizeof(GHashEntry)*DEF_HASH_SIZE); fCurrentEntry=-1; lastkeyptr=NULL; fFreeProc = (doFree)?&DefaultFreeProc : NULL; for (uint i=0; i void GHash::Resize(int m) { int i,n,p,x,h; GHashEntry *k; GASSERT(fCount<=fCapacity); if(m>2)>m) n>>=1; // Shrink until n/4 <= m while((n>>1)>1)); GASSERT(DEF_HASH_SIZE<=n); if(n!=fCapacity){ GASSERT(m<=n); GMALLOC(k, sizeof(GHashEntry)*n); for(i=0; i=0){ p=HASH1(h,n); GASSERT(0<=p && p OBJ* GHash::Add(const char* ky, OBJ* pdata) { int p,i,x,h,n; if(!ky) GError("GHash::insert: NULL key argument.\n"); GASSERT(fCount=(MAX_LOAD*fCapacity)) Resize(fCount); GASSERT(fCount OBJ* GHash::fAdd(const char* ky, OBJ* pdata) { int p,i,x,h,n; if(!ky) GError("GHash::insert: NULL key argument.\n"); GASSERT(fCount=(MAX_LOAD*fCapacity)) Resize(fCount); GASSERT(fCount OBJ* GHash::shkAdd(const char* ky, OBJ* pdata) { int p,i,x,h,n; if(!ky) GError("GHash::insert: NULL key argument.\n"); GASSERT(fCount=(MAX_LOAD*fCapacity)) Resize(fCount); GASSERT(fCount OBJ* GHash::Replace(const char* ky, OBJ* pdata){ int p,i,x,h,n; if(!ky){ GError("GHash::replace: NULL key argument.\n"); } GASSERT(fCount=(MAX_LOAD*fCapacity)) Resize(fCount); GASSERT(fCount OBJ* GHash::Remove(const char* ky){ int p,x,h,n; if(!ky){ GError("GHash::remove: NULL key argument.\n"); } OBJ* removed=NULL; if(0 bool GHash::hasKey(const char* ky) { int p,x,h,n; if(!ky){ GError("GHash::find: NULL key argument.\n"); } if(0 OBJ* GHash::Find(const char* ky, char** keyptr){ int p,x,h,n; if(!ky){ GError("GHash::find: NULL key argument.\n"); } if (fCount==0) return NULL; h=GSTR_HASH(ky); GASSERT(0<=h); p=HASH1(h,fCapacity); GASSERT(0<=p && p void GHash::startIterate() {// initialize a key iterator; call fCurrentEntry=0; } template char* GHash::NextKey() { int pos=fCurrentEntry; while (pos OBJ* GHash::NextData() { int pos=fCurrentEntry; while (pos OBJ* GHash::NextData(char* &nextkey) { int pos=fCurrentEntry; while (pos int GHash::First() const { int pos=0; while(pos int GHash::Last() const { int pos=fCapacity-1; while(0<=pos){ if(0<=hash[pos].hash) break; pos--; } GASSERT(pos<0 || 0<=hash[pos].hash); return pos; } // Find next valid entry template int GHash::Next(int pos) const { GASSERT(0<=pos && pos int GHash::Prev(int pos) const { GASSERT(0<=pos && pos= 0){ if(0<=hash[pos].hash) break; } GASSERT(pos<0 || 0<=hash[pos].hash); return pos; } // Remove all template void GHash::Clear(){ int i; for(i=0; i=0){ if (hash[i].keyalloc) GFREE((hash[i].key)); if (FREEDATA) (*fFreeProc)(hash[i].data); } } GFREE(hash); GMALLOC(hash, sizeof(GHashEntry)*DEF_HASH_SIZE); //reinitialize it for (i=0; i GHash::~GHash(){ for(int i=0; i=0){ if (hash[i].keyalloc) GFREE((hash[i].key)); if (FREEDATA) (*fFreeProc)(hash[i].data); } } GFREE(hash); } class GStrSet:public GHash { protected: bool free_keys; public: GStrSet(bool shared_keys=false):GHash(false), free_keys(!shared_keys) { } void Add(const char* str) { if (free_keys) { //allocates a copy of str GHash::Add(str, NULL); } else this->shkAdd(str, NULL); } void add(const char* str) { this->Add(str); } void push(const char* str) { this->Add(str); } bool has(const char* str) { return hasKey(str); } }; #endif