/* * dictionary.h * * Created on: Aug 5, 2014 * Author: nnosov */ #ifndef DICTIONARY_H_ #define DICTIONARY_H_ //system #include #include //framework #include "data_entry.h" #include "linkedlist.h" #define HASH_MIN_SHIFT (8) #define HASH_MAX_SHIFT (15) typedef uint32_t (* SC_HashFn)(const void *key, uint32_t key_size); inline uint32_t hash_bernstein(const void* key, uint32_t key_size) { uint32_t hash = 0; register unsigned char* p = (unsigned char*)key; for (unsigned int i = 0; i < key_size; i++) { hash = 33 * hash + p[i]; } return hash; } inline uint32_t hash_sdbm(const void *key, uint32_t key_size) { uint32_t hash = 0; register unsigned char* p = (unsigned char*)key; for (uint32_t i = 0; i < key_size; i++) { hash = p[i] + (hash << 6) + (hash << 16) - hash; } return hash; } inline uint32_t hash_fnv(const void *key, uint32_t key_size ) { register unsigned char *p = (unsigned char*)key; uint32_t hash = 2166136261U; for (uint32_t i = 0; i < key_size; i++ ) { hash = ( hash * 16777619 ) ^ p[i]; } return hash; } typedef struct __SC_DictItem : public SC_ListNode { __SC_DictItem() { data = 0; hash = 0; } ~__SC_DictItem() { if(key.data) { delete[] key.data; } key.data = 0; key.size = 0; } void* data; SC_Data key; uint32_t hash; } SC_DictItem; class SC_Dict { private: SC_Dict(SC_Dict& other) : pHashFn(0), mCurIdx(0), pCurItem(0), mCount(0), mShift(0), mMask(0), mBuckets(0), mSize(0){(void) other;} public: SC_Dict(uint16_t shift = 8, SC_HashFn fn = hash_bernstein) : pHashFn(fn), mCurIdx(0), pCurItem(0), mCount(0) { if(shift <= HASH_MIN_SHIFT) { mShift = HASH_MIN_SHIFT; } else if(shift >= HASH_MAX_SHIFT) { mShift = HASH_MAX_SHIFT; } else { mShift = shift; } mSize = 1UL << shift; mMask = mSize -1; mBuckets = new SC_ListHead[mSize]; } virtual ~SC_Dict() { Clean(); delete[] mBuckets; } void Clean() { First(); while(mCount) Remove(); mCurIdx = 0; pCurItem = 0; } inline void Insert(const void* key, uint32_t size, void* data) { SC_DictItem* item = new SC_DictItem; item->hash = pHashFn(key, size); item->data = data; // save key item->key.data = new char[size]; memcpy(item->key.data, key, size); item->key.size = size; mCurIdx = item->hash & mMask; for(pCurItem = (SC_DictItem*)mBuckets[mCurIdx].First(); pCurItem ; pCurItem = (SC_DictItem*)mBuckets[mCurIdx].Next(pCurItem)) { if(pCurItem->key.size == item->key.size) { if(!memcmp(pCurItem->key.data, item->key.data, size)) { pCurItem->data = data; delete item; return; } } } mBuckets[mCurIdx].InsertLast(item); pCurItem = item; mCount++; } void Remove() { SC_DictItem* item = pCurItem; if(item) { MoveNext(); mBuckets[item->hash & mMask].Remove(item); if(pCurItem == item) pCurItem = 0; delete item; mCount--; } } //returns first data in dictionary inline void* First() { if(!mCount) { return 0; } mCurIdx = 0; pCurItem = 0; MoveNext(); return pCurItem ? pCurItem->data : 0; } //returns next data in dictionary inline void* Next() { MoveNext(); return pCurItem ? pCurItem->data : 0; } //looking up for the next data inline void* LookupNext(const void* key, uint32_t size) { uint32_t hash = pHashFn(key, size); for(SC_DictItem* curr = (SC_DictItem*)mBuckets[mCurIdx].Next(pCurItem); curr; curr = (SC_DictItem*)mBuckets[mCurIdx].Next(curr)) { if(curr->hash == hash && curr->key.size == size) { if(!memcmp(key, curr->key.data, size)) { pCurItem = curr; return curr->data; } } } return 0; } //looking up for the first data corresponds to the key value inline void* Lookup(const void* key, uint32_t size) { uint32_t hash = pHashFn(key, size); uint32_t idx = hash & mMask; for(SC_DictItem* curr = (SC_DictItem*)mBuckets[idx].First(); curr; curr = (SC_DictItem*)mBuckets[idx].Next(curr)) { if(curr->hash == hash && curr->key.size == size) { if(!memcmp(key, curr->key.data, size)) { mCurIdx = idx; pCurItem = curr; return curr->data; } } } return 0; } uint32_t Size() { return mCount; } protected: inline SC_DictItem* MoveNext() { if(mCurIdx >= mSize) { return 0; } if(pCurItem) { pCurItem = (SC_DictItem*)mBuckets[mCurIdx].Next(pCurItem); if(!pCurItem) mCurIdx++; } while(!pCurItem && mCurIdx < mSize) { pCurItem = (SC_DictItem*)mBuckets[mCurIdx].First(); if(pCurItem) break; mCurIdx++; } return pCurItem; } public: virtual bool UnitTest(); protected: SC_HashFn pHashFn; //hash function uint32_t mCurIdx; //index of current bucket SC_DictItem* pCurItem; //current item uint32_t mCount; //number of elements in dictionary uint32_t mShift; //shift of the hash uint32_t mMask; //mask to be applied to the hash SC_ListHead* mBuckets; //Buckets of hash table uint32_t mSize; //size of array in buckets }; #endif /* DICTIONARY_H_ */