github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/hashmap_fast.c (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Fast hashmap lookup specialized to a specific key type. 6 // Included by hashmap.c once for each specialized type. 7 8 // Note that this code differs from hash_lookup in that 9 // it returns a pointer to the result, not the result itself. 10 // The returned pointer is only valid until the next GC 11 // point, so the caller must dereference it before then. 12 13 // +build ignore 14 15 #pragma textflag 7 16 void 17 HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value) 18 { 19 uintptr hash; 20 uintptr bucket, oldbucket; 21 Bucket *b; 22 uintptr i; 23 KEYTYPE *k; 24 byte *v; 25 uint8 top; 26 int8 keymaybe; 27 bool quickkey; 28 29 if(debug) { 30 runtime·prints("runtime.mapaccess1_fastXXX: map="); 31 runtime·printpointer(h); 32 runtime·prints("; key="); 33 t->key->alg->print(t->key->size, &key); 34 runtime·prints("\n"); 35 } 36 if(h == nil || h->count == 0) { 37 value = empty_value; 38 FLUSH(&value); 39 return; 40 } 41 if(raceenabled) 42 runtime·racereadpc(h, runtime·getcallerpc(&t), HASH_LOOKUP1); 43 if(docheck) 44 check(t, h); 45 46 if(h->B == 0) { 47 // One-bucket table. Don't hash, just check each bucket entry. 48 if(HASMAYBE) { 49 keymaybe = -1; 50 } 51 quickkey = QUICKEQ(key); 52 b = (Bucket*)h->buckets; 53 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 54 if(b->tophash[i] != 0) { 55 if(quickkey && EQFUNC(key, *k)) { 56 value = v; 57 FLUSH(&value); 58 return; 59 } 60 if(HASMAYBE && EQMAYBE(key, *k)) { 61 // TODO: check if key.str matches. Add EQFUNCFAST? 62 if(keymaybe >= 0) { 63 // Two same-length strings in this bucket. 64 // use slow path. 65 // TODO: keep track of more than just 1. Especially 66 // if doing the TODO above. 67 goto dohash; 68 } 69 keymaybe = i; 70 } 71 } 72 } 73 if(HASMAYBE && keymaybe >= 0) { 74 k = (KEYTYPE*)b->data + keymaybe; 75 if(EQFUNC(key, *k)) { 76 value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize; 77 FLUSH(&value); 78 return; 79 } 80 } 81 } else { 82 dohash: 83 hash = h->hash0; 84 HASHFUNC(&hash, sizeof(KEYTYPE), &key); 85 bucket = hash & (((uintptr)1 << h->B) - 1); 86 if(h->oldbuckets != nil) { 87 oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1); 88 b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize); 89 if(evacuated(b)) { 90 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 91 } 92 } else { 93 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 94 } 95 top = hash >> (sizeof(uintptr)*8 - 8); 96 if(top == 0) 97 top = 1; 98 do { 99 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 100 if(b->tophash[i] == top && EQFUNC(key, *k)) { 101 value = v; 102 FLUSH(&value); 103 return; 104 } 105 } 106 b = b->overflow; 107 } while(b != nil); 108 } 109 value = empty_value; 110 FLUSH(&value); 111 } 112 113 #pragma textflag 7 114 void 115 HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res) 116 { 117 uintptr hash; 118 uintptr bucket, oldbucket; 119 Bucket *b; 120 uintptr i; 121 KEYTYPE *k; 122 byte *v; 123 uint8 top; 124 int8 keymaybe; 125 bool quickkey; 126 127 if(debug) { 128 runtime·prints("runtime.mapaccess2_fastXXX: map="); 129 runtime·printpointer(h); 130 runtime·prints("; key="); 131 t->key->alg->print(t->key->size, &key); 132 runtime·prints("\n"); 133 } 134 if(h == nil || h->count == 0) { 135 value = empty_value; 136 res = false; 137 FLUSH(&value); 138 FLUSH(&res); 139 return; 140 } 141 if(raceenabled) 142 runtime·racereadpc(h, runtime·getcallerpc(&t), HASH_LOOKUP2); 143 if(docheck) 144 check(t, h); 145 146 if(h->B == 0) { 147 // One-bucket table. Don't hash, just check each bucket entry. 148 if(HASMAYBE) { 149 keymaybe = -1; 150 } 151 quickkey = QUICKEQ(key); 152 b = (Bucket*)h->buckets; 153 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 154 if(b->tophash[i] != 0) { 155 if(quickkey && EQFUNC(key, *k)) { 156 value = v; 157 res = true; 158 FLUSH(&value); 159 FLUSH(&res); 160 return; 161 } 162 if(HASMAYBE && EQMAYBE(key, *k)) { 163 // TODO: check if key.str matches. Add EQFUNCFAST? 164 if(keymaybe >= 0) { 165 // Two same-length strings in this bucket. 166 // use slow path. 167 // TODO: keep track of more than just 1. Especially 168 // if doing the TODO above. 169 goto dohash; 170 } 171 keymaybe = i; 172 } 173 } 174 } 175 if(HASMAYBE && keymaybe >= 0) { 176 k = (KEYTYPE*)b->data + keymaybe; 177 if(EQFUNC(key, *k)) { 178 value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize; 179 res = true; 180 FLUSH(&value); 181 FLUSH(&res); 182 return; 183 } 184 } 185 } else { 186 dohash: 187 hash = h->hash0; 188 HASHFUNC(&hash, sizeof(KEYTYPE), &key); 189 bucket = hash & (((uintptr)1 << h->B) - 1); 190 if(h->oldbuckets != nil) { 191 oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1); 192 b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize); 193 if(evacuated(b)) { 194 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 195 } 196 } else { 197 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 198 } 199 top = hash >> (sizeof(uintptr)*8 - 8); 200 if(top == 0) 201 top = 1; 202 do { 203 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 204 if(b->tophash[i] == top && EQFUNC(key, *k)) { 205 value = v; 206 res = true; 207 FLUSH(&value); 208 FLUSH(&res); 209 return; 210 } 211 } 212 b = b->overflow; 213 } while(b != nil); 214 } 215 value = empty_value; 216 res = false; 217 FLUSH(&value); 218 FLUSH(&res); 219 }