mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 511040 - Make nanojit::HashMap usable for non-word keys, r=edwsmith.
--HG-- extra : rebase_source : 7d4dff334de629f60342736e50c518ec891df19f
This commit is contained in:
parent
0615e68e91
commit
571bd08a08
@ -159,16 +159,104 @@ namespace nanojit
|
||||
Seq<T>* last;
|
||||
};
|
||||
|
||||
#ifdef NANOJIT_64BIT
|
||||
static inline size_t murmurhash(const void *key, size_t len) {
|
||||
const uint64_t m = 0xc6a4a7935bd1e995;
|
||||
const int r = 47;
|
||||
|
||||
uint64_t h = seed ^ (len * m);
|
||||
|
||||
const uint64_t *data = (const uint64_t*)key;
|
||||
const uint64_t *end = data + (len/8);
|
||||
|
||||
while(data != end)
|
||||
{
|
||||
uint64_t k = *data++;
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h ^= k;
|
||||
h *= m;
|
||||
}
|
||||
|
||||
const unsigned char *data2 = (const unsigned char*)data;
|
||||
|
||||
switch(len & 7) {
|
||||
case 7: h ^= uint64_t(data2[6]) << 48;
|
||||
case 6: h ^= uint64_t(data2[5]) << 40;
|
||||
case 5: h ^= uint64_t(data2[4]) << 32;
|
||||
case 4: h ^= uint64_t(data2[3]) << 24;
|
||||
case 3: h ^= uint64_t(data2[2]) << 16;
|
||||
case 2: h ^= uint64_t(data2[1]) << 8;
|
||||
case 1: h ^= uint64_t(data2[0]);
|
||||
h *= m;
|
||||
};
|
||||
|
||||
h ^= h >> r;
|
||||
h *= m;
|
||||
h ^= h >> r;
|
||||
|
||||
return (size_t)h;
|
||||
}
|
||||
#else
|
||||
static inline size_t murmurhash(const void * key, size_t len) {
|
||||
const uint32_t m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
uint32_t h = 0;
|
||||
|
||||
const unsigned char * data = (const unsigned char *)key;
|
||||
while(len >= 4) {
|
||||
uint32_t k = *(size_t *)data;
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h *= m;
|
||||
h ^= k;
|
||||
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
switch(len) {
|
||||
case 3: h ^= data[2] << 16;
|
||||
case 2: h ^= data[1] << 8;
|
||||
case 1: h ^= data[0];
|
||||
h *= m;
|
||||
};
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return (size_t)h;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class K> struct DefaultHash {
|
||||
static size_t hash(const K &k) {
|
||||
return murmurhash(&k, sizeof(K));
|
||||
}
|
||||
};
|
||||
|
||||
template<class K> struct DefaultHash<K*> {
|
||||
static size_t hash(K* k) {
|
||||
uintptr_t h = (uintptr_t) k;
|
||||
// move the low 3 bits higher up since they're often 0
|
||||
h = (h>>3) ^ (h<<((sizeof(uintptr_t) * 8) - 3));
|
||||
return (size_t) h;
|
||||
}
|
||||
};
|
||||
|
||||
/** Bucket hashtable with a fixed # of buckets (never rehash)
|
||||
* Intended for use when a reasonable # of buckets can be estimated ahead of time.
|
||||
*
|
||||
* K is hashed by casting to intptr_t then to int. All users of this
|
||||
* class currently hash pointers and pointer-identity is okay. When this
|
||||
* changes we can parameterize the hash function and equality function,
|
||||
* or the caller can create a K type with custom cast(intptr_t) and == operators. */
|
||||
template<class K, class T> class HashMap {
|
||||
*/
|
||||
template<class K, class T, class H=DefaultHash<K> > class HashMap {
|
||||
Allocator& allocator;
|
||||
uint32_t nbuckets;
|
||||
size_t nbuckets;
|
||||
class Node {
|
||||
public:
|
||||
K key;
|
||||
@ -177,16 +265,9 @@ namespace nanojit
|
||||
};
|
||||
Seq<Node>** buckets;
|
||||
|
||||
/** optimized for the assumption that k is a 4-byte aligned pointer. */
|
||||
uint32_t hash(K k) {
|
||||
uintptr_t h = (uintptr_t) k;
|
||||
h = (h>>3) ^ (h<<29); // move the low 3 bits higher up since they're often 0
|
||||
return uint32_t(h) % nbuckets;
|
||||
}
|
||||
|
||||
/** return the node containing K, and the bucket index, or NULL if not found */
|
||||
Node* find(K k, uint32_t &i) {
|
||||
i = hash(k);
|
||||
Node* find(K k, size_t &i) {
|
||||
i = H::hash(k) % nbuckets;
|
||||
for (Seq<Node>* p = buckets[i]; p != NULL; p = p->tail) {
|
||||
if (p->head.key == k)
|
||||
return &p->head;
|
||||
@ -194,7 +275,7 @@ namespace nanojit
|
||||
return NULL;
|
||||
}
|
||||
public:
|
||||
HashMap(Allocator& a, uint32_t nbuckets = 16)
|
||||
HashMap(Allocator& a, size_t nbuckets = 16)
|
||||
: allocator(a)
|
||||
, nbuckets(nbuckets)
|
||||
, buckets(new (a) Seq<Node>*[nbuckets])
|
||||
@ -209,8 +290,8 @@ namespace nanojit
|
||||
}
|
||||
|
||||
/** add (k,v) to the map. If k is already in the map, replace the value */
|
||||
void put(K k, T v) {
|
||||
uint32_t i;
|
||||
void put(const K& k, const T& v) {
|
||||
size_t i;
|
||||
Node* n = find(k, i);
|
||||
if (n) {
|
||||
n->value = v;
|
||||
@ -220,22 +301,22 @@ namespace nanojit
|
||||
}
|
||||
|
||||
/** return v for element k, or T(0) if k is not present */
|
||||
T get(K k) {
|
||||
uint32_t i;
|
||||
T get(const K& k) {
|
||||
size_t i;
|
||||
Node* n = find(k, i);
|
||||
return n ? n->value : 0;
|
||||
}
|
||||
|
||||
/** returns true if k is in the map. */
|
||||
bool containsKey(K k) {
|
||||
uint32_t i;
|
||||
bool containsKey(const K& k) {
|
||||
size_t i;
|
||||
return find(k, i) != 0;
|
||||
}
|
||||
|
||||
/** remove k from the map, if it is present. if not, remove()
|
||||
* silently returns */
|
||||
void remove(K k) {
|
||||
uint32_t i = hash(k);
|
||||
void remove(const K& k) {
|
||||
size_t i = H::hash(k);
|
||||
Seq<Node>** prev = &buckets[i];
|
||||
for (Seq<Node>* p = buckets[i]; p != NULL; p = p->tail) {
|
||||
if (p->head.key == k) {
|
||||
@ -260,12 +341,12 @@ namespace nanojit
|
||||
*/
|
||||
class Iter {
|
||||
friend class HashMap;
|
||||
const HashMap<K,T> ↦
|
||||
const HashMap<K,T,H> ↦
|
||||
int bucket;
|
||||
const Seq<Node>* current;
|
||||
|
||||
public:
|
||||
Iter(HashMap<K,T>& map) : map(map), bucket(map.nbuckets-1), current(NULL)
|
||||
Iter(HashMap<K,T,H>& map) : map(map), bucket(map.nbuckets-1), current(NULL)
|
||||
{ }
|
||||
|
||||
/** return true if more (k,v) remain to be visited */
|
||||
@ -278,13 +359,13 @@ namespace nanojit
|
||||
}
|
||||
|
||||
/** return the current key */
|
||||
K key() const {
|
||||
const K& key() const {
|
||||
NanoAssert(current != NULL);
|
||||
return current->head.key;
|
||||
}
|
||||
|
||||
/** return the current value */
|
||||
T value() const {
|
||||
const T& value() const {
|
||||
NanoAssert(current != NULL);
|
||||
return current->head.value;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user