//二进制键值类型hash map的简单应用

 

#include <hash_map>
#include <iostream>
#include <string>
#include <assert.h>

using namespace std;

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

//一,定义

//首先,定义键类,需要包含一个字节数组和长度字段(如果键值使用长度固定,这个字段可不用)

const int MAX_KEY_LEN = 17;//根据需要改变

typedef struct MyKey
{
public:
    MyKey()
    {
        len = 0;
        memset(keyVal, 0, MAX_KEY_LEN);
    }

public:
    uint8_t    keyVal[MAX_KEY_LEN];
    uint8_t    len;
}MyKey;


//然后,定义一个hash函数,这里用到著名的SuperFastHash(http://www.azillionmonkeys.com/qed/hash.html)
//safari和chrome的webkit引擎采用的就是这个hash函数,摘录改名如下:

#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )

 

uint32_t Myhash(const char * data, int len) {
   uint32_t hash = len, tmp;
   int rem;

if (len <= 0 || data == NULL) return 0;

rem = len & 3;
len >>= 2;

/* Main loop */
for (;len > 0; len--) {
hash += get16bits (data);
tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*sizeof (uint16_t);
hash += hash >> 11;
}

/* Handle end cases */
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= data[sizeof (uint16_t)] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}

/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;

return hash;
}

//最后,定义一个等于比较函数,这里先根据长度(如上所述若键的len字段不用,这里就不用这一步),
//再用memcmp直接比较就行

struct Myequal
{
    bool operator() (const MyKey &key1, const MyKey &key2) const
    {
        if (key1.len != key2.len)
            return false;
        return (0 == memcmp(key1.keyVal, key2.keyVal, key1.len));
    }
};


//二,使用

//定义好hash函数和等于比较函数以后就可以定义hash_map和相应的类型,如下:
typedef hash_map <MyKey, void *, Myhash, Myequal> MyHashmap;
typedef MyHashmap::iterator MyHashmap_iterator;
typedef pair <MyKey, void *> MyHashmap_Pair;
typedef pair <MyHashmap::iterator, bool > MyHashmap_PairInsert;

int main(int argc, char* argv[])
{
    MyHashmap fmap;
    MyKey key;
    
    //根据应用填充key
    uint8_t someval [] = {0x12,0x34,0x56,0xab,0xcd,0xef};
    key.len = sizeof(someval);
    memcpy(key.keyVal,someval,key.len);    
    
    //插入
    MyHashmap_Pair fpair(key, new string("hello,hash map!"));
    MyHashmap_PairInsert finst = fmap.insert(fpair);
    if( finst.second != true )//如果插入重复键
    {
        //...
        return -1;
    }

  //查找
    MyHashmap_iterator it = fmap.end();
    it = fmap.find(key);
    if (it == fmap.end())
    {
        cout<<"没找到,怎么可能!!"<<endl;    
    }else{
        cout<<*(string *)it->second<<endl;
    }
    
    key.keyVal[0] = 0x78;
    fmap.insert(make_pair(key,new string("第二个")));
    key.keyVal[5] = 0x90;
    fmap.insert(make_pair(key,new string("第三个")));
    //遍历和删除
    for (MyHashmap_iterator it = fmap.begin();it != fmap.end();)
    {
        std::string *v = (string*)it->second;
        assert(v);
        if (v->compare("第二个") == 0)
        {
            fmap.erase(it++);    
        }else{
            ++it;
        }
    }
    cout<<"hash map size:"<<(int)fmap.size()<<",buckets:"<<(int)fmap.bucket_count()<<endl;
    return 0;
}