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  }