From a83208d0552c8ae571a8f77bf9fc5f462b907ce5 Mon Sep 17 00:00:00 2001 From: saad0105050 Date: Sun, 21 Sep 2014 05:50:22 -0400 Subject: [PATCH] Updated HopScotchHashTable with bitmap lookup. (I am surprised it worked the first time: all previous tests passed. Of course, I tested the newly added functions before running everything together.) Signed-off-by: saad0105050 --- YASI_12/ds.HopScotchHashTable.h | 236 ++++++++++++++++++++++---------- 1 file changed, 166 insertions(+), 70 deletions(-) diff --git a/YASI_12/ds.HopScotchHashTable.h b/YASI_12/ds.HopScotchHashTable.h index aeae980..dfdec01 100644 --- a/YASI_12/ds.HopScotchHashTable.h +++ b/YASI_12/ds.HopScotchHashTable.h @@ -1,6 +1,7 @@ #pragma once #include "common.h" #include "ds.IntLinearProbingHashTable.h" +#include namespace yasi{ namespace ds{ @@ -11,11 +12,11 @@ struct HopScotchEntry{ typedef HopScotchEntry self; size_t key; Value value; - int bitField; // map of bucket elements + unsigned int bitField; // map of bucket elements HopScotchEntry() : key(0), bitField(0){} HopScotchEntry(const size_t& k) : key(k){} HopScotchEntry(const size_t& k, const Value& v) : key(k), value(v){} - HopScotchEntry(const size_t& k, const Value& v, const int& bf) : + HopScotchEntry(const size_t& k, const Value& v, const unsigned int& bf) : key(k), value(v), bitField(bf){} HopScotchEntry(const self& other):key(other.key), value(other.value),bitField(other.bitField){ } self& operator=(const self& other){ @@ -72,6 +73,8 @@ class HopScotchHashTable size_t H; // the neighborhood size size_t logH; // log of H size_t _zeroKeyBucket; // the bucket containing (hashed) zero key + const int SCAN_BUCKET_PREV = -1; + const int SCAN_BUCKET_NEXT = 1; #if _DEBUG int _numHops; #endif // _DEBUG @@ -126,74 +129,75 @@ class HopScotchHashTable // swap two bucket entries void swap(const int bucketOne, const int bucketTwo) const{ + + + // do not swap bitmaps EntryType temp = table[bucketOne]; - table[bucketOne] = table[bucketTwo]; - table[bucketTwo] = temp; - } - // push this entry to the right - // returns false if it is not possible to push - // returns true on success - bool pushToRight(const int bucket, int startOfBumping = -1){ - if (startOfBumping > 0 ){ - // .... bucket startOfBumping .... - if (circularDiff(bucket, startOfBumping) == 1) { - // we traversed the entire array - // this operation is impossible - return false; - } - else{ - // continue working below - } - } - else{ - // initialize search - startOfBumping = bucket; - } + table[bucketOne].key = table[bucketTwo].key; + table[bucketOne].value = table[bucketTwo].value; + + table[bucketTwo].key = temp.key; + table[bucketTwo].value = temp.value; - bool found = false; - int cur = bucket; + } - // try at most H-1 places to the right - int firstBucket = index(table[bucket].key); - // this is the invariant of hopscotch hashing - if (circularDiff(firstBucket, bucket) >= H){ - // the table is broken - cerr << "HopScotch invariant broken: item at bucket [" << bucket << "] is originally hashed at bucket [" << firstBucket << "], which is >= H, which is " << H << endl; - return false; + inline void setBitmap(const int bucket, const unsigned int position, const unsigned int bit) const{ + if (bucket >= 0 && bucket < _size && + position >= 0 && position < H && + bit <= 1){ + table[bucket].bitField &= (0x80000000 >> position); } + } - int last = modSize(firstBucket + H-1); - if (bucket == last){ - // this bucket is not allowed to leave the neighborhood - return false; + // returns the next/prev item in bucket + // if no more items, returns -1 + // in error, returns -1 + inline int jumpInBucket( + const unsigned int bitmap, + const unsigned int curPosInBucket, + const int direction) const{ + if (direction != SCAN_BUCKET_NEXT && direction != SCAN_BUCKET_PREV){ + cerr << "HopScotchHashTable::nextInBucket(): wrong direction: " << direction << endl; + return -1; } - int next; - for (; cur != last; cur = next){ - next = circularNext(cur); - if (next == startOfBumping) { - // tried all slots - // no way we can bump any more - return false; - } - - if ( isNull(next) ){ - // insert into blank slot - table[next] = table[bucket]; - return true; - } + if (direction == SCAN_BUCKET_NEXT && (curPosInBucket < 0 ||curPosInBucket >= H - 1)){ + cerr << "HopScotchHashTable::nextInBucket(): current pos" << curPosInBucket << " is >= (H-1), which is " << (H - 1) << endl; + return -1; } - // could not place the entry within neighborhood H - // bump the last guy in the neighborhood - // make room - if (pushToRight(last, startOfBumping)){ - table[last] = table[bucket]; - return true; + if (direction == SCAN_BUCKET_PREV && (curPosInBucket <= 0 || curPosInBucket >= H)){ + cerr << "HopScotchHashTable::nextInBucket(): current pos" << curPosInBucket << " is <= 0" << endl; + return -1; } - else{ - // the hopping failed - return false; + int nextPos = curPosInBucket + direction; + unsigned int mask = 0x80000000 >> nextPos; + for (; mask != 0; nextPos += direction){ + int nextBit = (bitmap & mask); + if (nextBit) return nextPos; + if (direction == SCAN_BUCKET_NEXT){ + mask >>= 1; + } + else{ + // scan prev + mask <<= 1; + } } + // no more items + return -1; + } + + // returns the prev item in bucket + // if no more items, returns -1 + // in error, returns -1 + inline int prevPosInBucket(const unsigned int bitmap, const unsigned int curPosInBucket) const{ + return jumpInBucket(bitmap, curPosInBucket, SCAN_BUCKET_PREV); + } + + // returns the next item in bucket + // if no more items, returns -1 + // in error, returns -1 + inline int nextPosInBucket(const unsigned int bitmap, const unsigned int curPosInBucket) const{ + return jumpInBucket(bitmap, curPosInBucket, SCAN_BUCKET_NEXT); } bool canSwapCurWithEmpty(const int firstBucket, const int cur, const int hashCur, const int emptySlot){ @@ -272,7 +276,7 @@ class HopScotchHashTable //when to stop int remainingSlots = circularDiff(firstBucket, emptySlot); if (remainingSlots < H){ - // the empty slot is wihing the neighborhood of firstBucket + // the empty slot is within the neighborhood of firstBucket return &table[emptySlot]; } // H @@ -297,6 +301,15 @@ class HopScotchHashTable { // candidate for swap swap(cur, emptySlot); + + // calculate bitmap bit positions set/reset + int diff1 = circularDiff(hashCur, cur); // before + int diff1final = circularDiff(hashCur, emptySlot); // after + + // update bitmaps + setBitmap(hashCur, diff1, 0); + setBitmap(hashCur, diff1final, 1); + // repeat return pullFromLeft(firstBucket, cur); } @@ -315,6 +328,7 @@ class HopScotchHashTable grow(); int firstBucket = index(k); + // try to find an empty slot int cur = firstBucket; while (!isNull(cur) ){ cur = circularNext(cur); @@ -326,10 +340,13 @@ class HopScotchHashTable } // found an empty slot - if (circularDiff(firstBucket, cur) < H){ - // empth slot within the neighborhood of firstBucket + int positionInBucket = circularDiff(firstBucket, cur); + if ( positionInBucket < H){ + // empty slot within the neighborhood of firstBucket table[cur].key = k; _population++; + // set this bit in bitmap of firstBucket + setBitmap(firstBucket, positionInBucket, 1); return &table[cur]; } else{ @@ -338,9 +355,16 @@ class HopScotchHashTable // pull it within the immediate neighborhood BucketType* pBucket = pullFromLeft(firstBucket, cur); if (pBucket){ + // now cur contains the final position of emptySlot // moved the empty slot to the immediate neighborhood table[cur].key = k; _population++; + + // set this bit in bitmap of firstBucket + int emptyPosFinal = (pBucket - table); + positionInBucket = circularDiff(firstBucket, emptyPosFinal); + setBitmap(firstBucket, positionInBucket, 1); + return &table[cur]; } else{ @@ -360,13 +384,14 @@ class HopScotchHashTable } int firstBucket = index(k); + const unsigned int bitmap = table[firstBucket].bitField; #if _DEBUG // keep track of how many hops till found _numHops = 0; #endif // keep probing to the right // the item, if exists, must be in the neighborhood H - for (int i = 0; i < H; i = circularNext(i) ){ + for (int i = 0; i < H; i = nextPosInBucket(bitmap, i)){ if (table[firstBucket + i].key == k) return &table[firstBucket + i]; #if _DEBUG @@ -385,8 +410,13 @@ class HopScotchHashTable BucketType* pBucket = lookupKey(k); if (pBucket){ pBucket->key = 0; - pBucket->bitField = 0; _population--; + + // update bitmap + int firstBucket = index(k); + int cur = (pBucket - table); + int positionInBucket = circularDiff(firstBucket, cur); + setBitmap(firstBucket, positionInBucket, 0); } } @@ -945,18 +975,84 @@ class HopScotchHashTableTest : public yasi::Test ASSERT_EQ(32, h2.size()); ASSERT_EQ(h2.H+1, h2.population()); } + void nextPosInBucket(){ + IntHashTable h(4, 4); + int cur, bitmap, next; + + bitmap = 0xC0000000; cur = -1; next = -1; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = h.H; next = -1; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = h.H - 1; next = -1; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = 1; next = -1; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = 0; next = 1; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC8800000; cur = 4; next = -1; // cur >= H + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC8000000; cur = 1; next = 4; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000001; cur = 1; next = 31; + ASSERT_EQ(next, h.nextPosInBucket(bitmap, cur)) + << "next(" << cur << ") not " << next << " in bitmap " << std::bitset<32>(bitmap); + } + + void prevPosInBucket(){ + IntHashTable h(4, 4); + int cur, bitmap, prev; + + bitmap = 0xC0000000; cur = -1; prev = -1; + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = 0; prev = -1; + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = h.H; prev = -1; + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC0000000; cur = 1; prev = 0; + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xA0000000; cur = 2; prev = 0; + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xC8000000; cur = 4; prev = -1; // cur >= H + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + + bitmap = 0xD8000000; cur = 3; prev = 1; + ASSERT_EQ(prev, h.prevPosInBucket(bitmap, cur)) + << "prev(" << cur << ") not " << prev << " in bitmap " << std::bitset<32>(bitmap); + } }; ADD_TEST_F(HopScotchHashTableTest, circularDiff); +ADD_TEST_F(HopScotchHashTableTest, nextPosInBucket); +ADD_TEST_F(HopScotchHashTableTest, prevPosInBucket); ADD_TEST_F(HopScotchHashTableTest, canSwapCurWithEmpty); ADD_TEST_F(HopScotchHashTableTest, pullFromLeft); ADD_TEST_F(HopScotchHashTableTest, insertRemoveLookup); -//ADD_TEST_F(HopScotchHashTableTest, copyTable); -//ADD_TEST_F(HopScotchHashTableTest, growCondition); -//ADD_TEST_F(HopScotchHashTableTest, shrinkCondition); -//ADD_TEST_F(HopScotchHashTableTest, isKeyZero); -//ADD_TEST_F(HopScotchHashTableTest, remove); } } \ No newline at end of file