-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
saad0105050
committed
Sep 12, 2014
1 parent
cc44183
commit b8fbafd
Showing
6 changed files
with
251 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
#pragma once | ||
#include "common.h" | ||
#include "ds.kvpair.h" | ||
#include "ds.doublylinkedlist.h" | ||
using namespace std; | ||
|
||
namespace yasi{ | ||
namespace ds{ | ||
|
||
template<class Key, class Value = Key> | ||
class IKeyValueStore{ | ||
public: | ||
virtual ~IKeyValueStore(){} | ||
virtual Value* get(const Key&) const = 0; | ||
virtual void put(const Key&, const Value&) = 0; | ||
virtual bool contains(const Key&) const = 0; | ||
virtual void remove(const Key&) = 0; | ||
}; | ||
|
||
template<class Key> | ||
class IHashFunction{ | ||
public: | ||
virtual int operator()(Key n) const = 0; | ||
}; | ||
|
||
template<class Key> | ||
class IntHashFunction : public IHashFunction<Key>{ | ||
public: | ||
virtual int operator()(Key n) const override{ | ||
return n ^ (~n << 11) ^ (n << 3) ^ (~n << 27); | ||
} | ||
}; | ||
|
||
//template<class Bucket, class Key> | ||
//class ICollisionStrategy{ | ||
// | ||
//public: | ||
// virtual ~ICollisionResolutionStrategy(){} | ||
// // either returns a ptr to the bucket-index, or NULL if no bucket found | ||
// virtual int* findBucket(const Key& k, (void*)pHashTable) = 0; | ||
//}; | ||
|
||
|
||
template< class Key, | ||
class Value, | ||
class BucketType, | ||
class HashFunction | ||
> | ||
class HashTableBase : public IKeyValueStore < Key, Value >{ | ||
protected: | ||
// size of the table | ||
// must be a power of two | ||
unsigned int _size; | ||
unsigned int _logSize; | ||
// actual number of keys stored in the table | ||
unsigned int _population; | ||
// the buckets array | ||
BucketType* table; | ||
// the hash function | ||
HashFunction hash; | ||
inline int index(const Key& k) const{ | ||
return hash(k) & ((1 << _logSize) - 1); // hash(k) % _size | ||
} | ||
BucketType& bucket(const Key& k) const{ | ||
return table[index(k)]; | ||
} | ||
public: | ||
// the type of the entries in the hash table | ||
HashTableBase():HashTableBase(6){} | ||
HashTableBase(unsigned int logSize) : _logSize(logSize), _size(1 << logSize), _population(0){ | ||
table = new BucketType[_size]; | ||
// initialize to zero | ||
memset(table, 0, _size * sizeof(BucketType)); | ||
} | ||
virtual ~HashTableBase(){ DELETE_ARR_SAFE(table); _size = _population = 0; } | ||
}; | ||
|
||
|
||
// Separate chaining collision resolution strategy | ||
// each bucket holds a list of values mapped into that bucket | ||
template< | ||
class Key, | ||
class Value = Key, | ||
class HashFunction = IntHashFunction<int>, | ||
class Pred = KVPairEqualityPredicate<Key> | ||
> | ||
class SeparateChainingHashTable : public HashTableBase< | ||
Key, | ||
Value, | ||
DoublyLinkedList< KVPair<Key,Value> >*, | ||
HashFunction> | ||
{ | ||
///////////////// enable testing /////////////////// | ||
friend class SeparateChainingHashTableTest; | ||
|
||
protected: | ||
typedef KVPair<Key, Value> Pair; | ||
typedef DoublyLinkedList < Pair > List; | ||
typedef typename List::NodeType Node; | ||
public: | ||
typedef List* BucketType; | ||
protected: | ||
// returns the pointer to the value if exists, otherwise returns NULL | ||
Node* bucketNode(BucketType pList, const Key& k) const{ | ||
Pred keyEquals; | ||
for (List::iterator n = pList->begin(); n != pList->end(); n++){ | ||
if (keyEquals((*n).key,k)){ | ||
// found node; | ||
return n.pNode; | ||
} | ||
} | ||
return NULL; | ||
} | ||
Pair* bucketEntry(BucketType pList, const Key& k) const{ | ||
Pred keyEquals; | ||
for (List::iterator n = pList->begin(); n != pList->end(); n++){ | ||
if (keyEquals((*n).key, k)){ | ||
// found node; | ||
return & (n.pNode->element); | ||
} | ||
} | ||
return NULL; | ||
} | ||
bool bucketContains(BucketType pList, const Key& k) const{ | ||
Pred keyEquals; | ||
for (List::iterator n = pList->begin(); n != pList->end(); n++){ | ||
if (keyEquals((*n).key, k)){ | ||
// found node; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
public: | ||
typedef Key KeyType; | ||
typedef Value ValueType; | ||
|
||
virtual ~SeparateChainingHashTable(){ | ||
if (table){ | ||
for (int i = 0; i < _size; i++){ | ||
// each entry is either NULL or a List* | ||
if (table[i]){ | ||
table[i]->clear(); | ||
DELETE_SAFE(table[i]); | ||
} | ||
} | ||
} | ||
} | ||
SeparateChainingHashTable() :SeparateChainingHashTable(6){} | ||
SeparateChainingHashTable(unsigned int logSize) : HashTableBase(logSize){ | ||
|
||
//collisionHandler(this); | ||
} | ||
// returns true on success, false on failure | ||
virtual void put(const Key& k, const Value& v) override{ | ||
int i = index(k); | ||
BucketType pList = table[i]; | ||
if (pList == NULL){ | ||
// empty slot; create a new list | ||
pList = new List(); | ||
// pushFront for better temporal locality | ||
pList->pushFront(Pair(k, v)); | ||
_population++; | ||
} | ||
else{ | ||
// existing bucket | ||
Pair* pEntry = bucketEntry(pList, k); | ||
if (pEntry){ | ||
// key already exists; update value | ||
pEntry->value = v; | ||
} | ||
else{ | ||
pList->pushFront(Pair(k, v)); | ||
_population++; | ||
} | ||
} | ||
} | ||
virtual Value* get(const Key& k) const override{ | ||
int i = index(k); | ||
BucketType pList = table[i]; | ||
if (pList != NULL){ | ||
// existing bucket | ||
Pair* pEntry = bucketEntry(pList, k); | ||
if (pEntry) | ||
return &pEntry->value; | ||
} | ||
return NULL; | ||
} | ||
virtual void remove(const Key& k) override{ | ||
int i = index(k); | ||
BucketType pList = table[i]; | ||
if (pList == NULL){ | ||
// the key is absent | ||
// nothing to do | ||
} | ||
else{ | ||
// existing bucket | ||
Node* pNode = bucketNode(pList, k); | ||
if (pNode){ | ||
pList->remove(pNode); | ||
_population--; | ||
} | ||
} | ||
} | ||
virtual bool contains(const Key& k) const override{ | ||
int i = index(k); | ||
BucketType pList = table[i]; | ||
if (pList != NULL){ | ||
// existing bucket | ||
return bucketContains(pList,k); | ||
} | ||
return false; | ||
} | ||
|
||
int size(){ return _size; } | ||
int population(){ return _population; } | ||
|
||
}; | ||
|
||
class SeparateChainingHashTableTest : public yasi::Test{ | ||
protected: | ||
typedef SeparateChainingHashTable<int, int> IntHashTable; | ||
typedef KVPair<int, int> Pair; | ||
typedef IntHashTable::BucketType BucketType; | ||
|
||
IntHashTable h; | ||
public: | ||
|
||
void hashCode(){ | ||
// hashcode must be within range | ||
ASSERT_LT(h.index(10), h.size()) << "index(10) out of range"; | ||
} | ||
}; | ||
|
||
ADD_TEST_F(SeparateChainingHashTableTest, hashCode); | ||
|
||
} // namespace ds | ||
} // namespace yasi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters