1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| #include <glib.h> #include <stdio.h> #include <stdint.h> #include <unistd.h> #include <malloc.h>
/* copy from qemu code */ #define PRIME32_1 2654435761U #define PRIME32_2 2246822519U #define PRIME32_3 3266489917U #define PRIME32_4 668265263U #define PRIME32_5 374761393U #define QEMU_XXHASH_SEED 1
static inline uint32_t rol32(uint32_t word, unsigned int shift) { return (word << shift) | (word >> ((32 - shift) & 31)); }
static inline uint32_t qemu_xxhash7(uint64_t ab, uint64_t cd, uint32_t e, uint32_t f, uint32_t g) { uint32_t v1 = QEMU_XXHASH_SEED + PRIME32_1 + PRIME32_2; uint32_t v2 = QEMU_XXHASH_SEED + PRIME32_2; uint32_t v3 = QEMU_XXHASH_SEED + 0; uint32_t v4 = QEMU_XXHASH_SEED - PRIME32_1; uint32_t a = ab; uint32_t b = ab >> 32; uint32_t c = cd; uint32_t d = cd >> 32; uint32_t h32;
v1 += a * PRIME32_2; v1 = rol32(v1, 13); v1 *= PRIME32_1;
v2 += b * PRIME32_2; v2 = rol32(v2, 13); v2 *= PRIME32_1;
v3 += c * PRIME32_2; v3 = rol32(v3, 13); v3 *= PRIME32_1;
v4 += d * PRIME32_2; v4 = rol32(v4, 13); v4 *= PRIME32_1;
h32 = rol32(v1, 1) + rol32(v2, 7) + rol32(v3, 12) + rol32(v4, 18); h32 += 28;
h32 += e * PRIME32_3; h32 = rol32(h32, 17) * PRIME32_4;
h32 += f * PRIME32_3; h32 = rol32(h32, 17) * PRIME32_4;
h32 += g * PRIME32_3; h32 = rol32(h32, 17) * PRIME32_4;
h32 ^= h32 >> 15; h32 *= PRIME32_2; h32 ^= h32 >> 13; h32 *= PRIME32_3; h32 ^= h32 >> 16;
return h32; }
typedef struct key { int bus; int devfn; } key;
typedef struct value { int base; int bar; } value;
static guint key_hash(gconstpointer v) { key *k = (key *)v;
return qemu_xxhash7((uint64_t)k->bus, k->devfn, 0, 0, 0); }
static gboolean key_equal(gconstpointer v1, gconstpointer v2) { key *k1 = (key *)v1; key *k2 = (key *)v2;
return (k1->bus == k2->bus) && (k1->devfn == k2->devfn); }
int main() { /* 表示一个哈希表的具柄 */ GHashTable *hash_table; /* 哈希表的key是可以自定义的, 可以把用到的参数封装到一个struct里,把这个struct作为key */ value v, *p_v; key k, *p_k;
/* * 初始化哈希表具柄, 函数的定义在gnome的官网都可以查询: * https://developer.gnome.org/glib/stable/glib-Hash-Tables.html * * ghash是要建立一个key struct到一个value struct的映射,所以下面的key_hash, * key_equal这两个函数就比较容易理解。 * * key_hash的输入是用户自定义的key struct,输出是一个hash值,ghash真正用 * 计算得到的这个hash值作为key。可以看到这个计算是一个数学问题,QEMU里直接 * 把Jenkins hash, xxhash的代码放到了QEMU的代码里,我们这里也照搬过来, * 上面直接copy的是xxhash的部分代码,他完成的功能比较直白,就是输入一组 * 数,然后按照一定的算法输出一个哈希值。这里的key_hash就是直接调用xxhash * 的函数。 * * key_equal是判断两个key相等的函数,一般就是key里面的每一个元素都相等就 * 认为两个key相等。 * * 后面的两个函数是key和value的销毁函数,一般是g_free。注意,如果不是动态 * 创建的结构就不需要配置这里的销毁函数。 */ hash_table = g_hash_table_new_full(key_hash, key_equal, g_free, g_free);
p_v = malloc(sizeof(v)); p_v->base = 1; p_v->bar = 3; p_k = malloc(sizeof(k)); p_k->bus = 0x10; p_k->devfn = 0x75;
/* 把一个key-value的map插入到哈希表里,如上,key, value这里是需要动态分配的结构 */ g_hash_table_insert(hash_table, p_k, p_v);
k.bus = 0x10; k.devfn = 0x75; /* 找一个key对应的value, 这时key可以是静态的结构 */ p_v = g_hash_table_lookup(hash_table, &k); if (p_v) printf("found!\n"); else printf("not found!\n");
/* 销毁哈希表 */ g_hash_table_remove_all(hash_table); return 0; }
|