github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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 NOSPLIT 16 void 17 HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value) 18 { 19 uintptr bucket, i; 20 Bucket *b; 21 KEYTYPE *k; 22 byte *v; 23 uint8 top; 24 int8 keymaybe; 25 26 if(debug) { 27 runtime·prints("runtime.mapaccess1_fastXXX: map="); 28 runtime·printpointer(h); 29 runtime·prints("; key="); 30 t->key->alg->print(t->key->size, &key); 31 runtime·prints("\n"); 32 } 33 if(h == nil || h->count == 0) { 34 value = empty_value; 35 FLUSH(&value); 36 return; 37 } 38 if(raceenabled) 39 runtime·racereadpc(h, runtime·getcallerpc(&t), HASH_LOOKUP1); 40 if(docheck) 41 check(t, h); 42 43 if(h->B == 0) { 44 // One-bucket table. Don't hash, just check each bucket entry. 45 b = (Bucket*)h->buckets; 46 if(FASTKEY(key)) { 47 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 48 if(b->tophash[i] == 0) 49 continue; 50 if(QUICK_NE(key, *k)) 51 continue; 52 if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) { 53 value = v; 54 FLUSH(&value); 55 return; 56 } 57 } 58 } else { 59 keymaybe = -1; 60 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 61 if(b->tophash[i] == 0) 62 continue; 63 if(QUICK_NE(key, *k)) 64 continue; 65 if(QUICK_EQ(key, *k)) { 66 value = v; 67 FLUSH(&value); 68 return; 69 } 70 if(MAYBE_EQ(key, *k)) { 71 if(keymaybe >= 0) { 72 // Two same-length strings in this bucket. 73 // use slow path. 74 // TODO: keep track of more than just 1. We could 75 // afford about 3 equals calls before it would be more 76 // expensive than 1 hash + 1 equals. 77 goto dohash; 78 } 79 keymaybe = i; 80 } 81 } 82 if(keymaybe >= 0) { 83 k = (KEYTYPE*)b->data + keymaybe; 84 if(SLOW_EQ(key, *k)) { 85 value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize; 86 FLUSH(&value); 87 return; 88 } 89 } 90 } 91 } else { 92 dohash: 93 bucket = h->hash0; 94 HASHFUNC(&bucket, sizeof(KEYTYPE), &key); 95 top = bucket >> (sizeof(uintptr)*8 - 8); 96 if(top == 0) 97 top = 1; 98 bucket &= (((uintptr)1 << h->B) - 1); 99 if(h->oldbuckets != nil) { 100 i = bucket & (((uintptr)1 << (h->B - 1)) - 1); 101 b = (Bucket*)(h->oldbuckets + i * h->bucketsize); 102 if(evacuated(b)) { 103 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 104 } 105 } else { 106 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 107 } 108 do { 109 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 110 if(b->tophash[i] != top) 111 continue; 112 if(QUICK_NE(key, *k)) 113 continue; 114 if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) { 115 value = v; 116 FLUSH(&value); 117 return; 118 } 119 } 120 b = b->overflow; 121 } while(b != nil); 122 } 123 value = empty_value; 124 FLUSH(&value); 125 } 126 127 #pragma textflag NOSPLIT 128 void 129 HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res) 130 { 131 uintptr bucket, i; 132 Bucket *b; 133 KEYTYPE *k; 134 byte *v; 135 uint8 top; 136 int8 keymaybe; 137 138 if(debug) { 139 runtime·prints("runtime.mapaccess2_fastXXX: map="); 140 runtime·printpointer(h); 141 runtime·prints("; key="); 142 t->key->alg->print(t->key->size, &key); 143 runtime·prints("\n"); 144 } 145 if(h == nil || h->count == 0) { 146 value = empty_value; 147 res = false; 148 FLUSH(&value); 149 FLUSH(&res); 150 return; 151 } 152 if(raceenabled) 153 runtime·racereadpc(h, runtime·getcallerpc(&t), HASH_LOOKUP2); 154 if(docheck) 155 check(t, h); 156 157 if(h->B == 0) { 158 // One-bucket table. Don't hash, just check each bucket entry. 159 b = (Bucket*)h->buckets; 160 if(FASTKEY(key)) { 161 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 162 if(b->tophash[i] == 0) 163 continue; 164 if(QUICK_NE(key, *k)) 165 continue; 166 if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) { 167 value = v; 168 res = true; 169 FLUSH(&value); 170 FLUSH(&res); 171 return; 172 } 173 } 174 } else { 175 keymaybe = -1; 176 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 177 if(b->tophash[i] == 0) 178 continue; 179 if(QUICK_NE(key, *k)) 180 continue; 181 if(QUICK_EQ(key, *k)) { 182 value = v; 183 res = true; 184 FLUSH(&value); 185 FLUSH(&res); 186 return; 187 } 188 if(MAYBE_EQ(key, *k)) { 189 if(keymaybe >= 0) { 190 // Two same-length strings in this bucket. 191 // use slow path. 192 // TODO: keep track of more than just 1. We could 193 // afford about 3 equals calls before it would be more 194 // expensive than 1 hash + 1 equals. 195 goto dohash; 196 } 197 keymaybe = i; 198 } 199 } 200 if(keymaybe >= 0) { 201 k = (KEYTYPE*)b->data + keymaybe; 202 if(SLOW_EQ(key, *k)) { 203 value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize; 204 res = true; 205 FLUSH(&value); 206 FLUSH(&res); 207 return; 208 } 209 } 210 } 211 } else { 212 dohash: 213 bucket = h->hash0; 214 HASHFUNC(&bucket, sizeof(KEYTYPE), &key); 215 top = bucket >> (sizeof(uintptr)*8 - 8); 216 if(top == 0) 217 top = 1; 218 bucket &= (((uintptr)1 << h->B) - 1); 219 if(h->oldbuckets != nil) { 220 i = bucket & (((uintptr)1 << (h->B - 1)) - 1); 221 b = (Bucket*)(h->oldbuckets + i * h->bucketsize); 222 if(evacuated(b)) { 223 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 224 } 225 } else { 226 b = (Bucket*)(h->buckets + bucket * h->bucketsize); 227 } 228 do { 229 for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) { 230 if(b->tophash[i] != top) 231 continue; 232 if(QUICK_NE(key, *k)) 233 continue; 234 if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) { 235 value = v; 236 res = true; 237 FLUSH(&value); 238 FLUSH(&res); 239 return; 240 } 241 } 242 b = b->overflow; 243 } while(b != nil); 244 } 245 value = empty_value; 246 res = false; 247 FLUSH(&value); 248 FLUSH(&res); 249 }