// h *Hmap
// buckets *Bucket
// bptr *Bucket
- // other [5]uintptr
+ // other [4]uintptr
// }
// must match ../../pkg/runtime/hashmap.c:hash_iter.
field[0] = typ(TFIELD);
field[6] = typ(TFIELD);
field[6]->type = typ(TARRAY);
field[6]->type->type = types[TUINTPTR];
- field[6]->type->bound = 5;
- field[6]->type->width = 5 * widthptr;
+ field[6]->type->bound = 4;
+ field[6]->type->width = 4 * widthptr;
field[6]->sym = mal(sizeof(Sym));
field[6]->sym->name = "other";
}
field[6]->down = T;
off += field[6]->type->width;
- if(off != 11 * widthptr)
- yyerror("hash_iter size not correct %d %d", off, 11 * widthptr);
+ if(off != 10 * widthptr)
+ yyerror("hash_iter size not correct %d %d", off, 10 * widthptr);
t->hiter = i;
i->map = t;
return i;
byte *buckets; // bucket ptr at hash_iter initialization time
struct Bucket *bptr; // current bucket
- // end point for iteration
- uintptr endbucket;
- bool wrapped;
+ uint32 offset; // intra-bucket offset to start from during iteration
+ bool done;
// state of table at time iterator is initialized
uint8 B;
{
uint32 old;
- if(sizeof(struct hash_iter) / sizeof(uintptr) != 11) {
- runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/range.c
+ if(sizeof(struct hash_iter) / sizeof(uintptr) != 10) {
+ runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/reflect.c
}
it->t = t;
it->h = h;
it->buckets = h->buckets;
// iterator state
- it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1);
- it->wrapped = false;
+ it->bucket = 0;
+ it->offset = runtime·fastrand1() & (BUCKETSIZE - 1);
+ it->done = false;
it->bptr = nil;
// Remember we have an iterator.
if(h->buckets == nil) {
// Empty map. Force next hash_next to exit without
- // evalulating h->bucket.
- it->wrapped = true;
+ // evaluating h->bucket.
+ it->done = true;
}
}
uintptr bucket, oldbucket;
uintptr hash;
Bucket *b;
- uintptr i;
+ uintptr i, offi;
intptr check_bucket;
bool eq;
byte *k, *v;
next:
if(b == nil) {
- if(bucket == it->endbucket && it->wrapped) {
+ if(it->done) {
// end of iteration
it->key = nil;
it->value = nil;
bucket++;
if(bucket == ((uintptr)1 << it->B)) {
bucket = 0;
- it->wrapped = true;
+ it->done = true;
}
i = 0;
}
- k = b->data + h->keysize * i;
- v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
- for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] != Empty && b->tophash[i] != EvacuatedEmpty) {
+ for(; i < BUCKETSIZE; i++) {
+ offi = (i + it->offset) & (BUCKETSIZE - 1);
+ k = b->data + h->keysize * offi;
+ v = b->data + h->keysize * BUCKETSIZE + h->valuesize * offi;
+ if(b->tophash[offi] != Empty && b->tophash[offi] != EvacuatedEmpty) {
if(check_bucket >= 0) {
// Special case: iterator was started during a grow and the
// grow is not done yet. We're working on a bucket whose
// NOTE: this case is why we need two evacuate tophash
// values, evacuatedX and evacuatedY, that differ in
// their low bit.
- if(check_bucket >> (it->B - 1) != (b->tophash[i] & 1)) {
+ if(check_bucket >> (it->B - 1) != (b->tophash[offi] & 1)) {
continue;
}
}
}
- if(b->tophash[i] != EvacuatedX && b->tophash[i] != EvacuatedY) {
+ if(b->tophash[offi] != EvacuatedX && b->tophash[offi] != EvacuatedY) {
// this is the golden data, we can return it.
it->key = IK(h, k);
it->value = IV(h, v);
}
func TestMapIterOrder(t *testing.T) {
- // TODO: For issue 6719, add 3 and 7 to this list.
- for _, n := range [...]int{9, 15} {
+ for _, n := range [...]int{3, 7, 9, 15} {
// Make m be {0: true, 1: true, ..., n-1: true}.
m := make(map[int]bool)
for i := 0; i < n; i++ {