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  }