Skip to content

Commit b3c040e

Browse files
dgryskiaykevl
authored andcommitted
runtime: make map iteration less defined
Fixes #3726
1 parent 52788e5 commit b3c040e

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

src/runtime/hashmap.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ type hashmapIterator struct {
4545
buckets unsafe.Pointer // pointer to array of hashapBuckets
4646
numBuckets uintptr // length of buckets array
4747
bucketNumber uintptr // current index into buckets array
48+
startBucket uintptr // starting location for iterator
4849
bucket *hashmapBucket // current bucket in chain
4950
bucketIndex uint8 // current index into bucket
51+
startIndex uint8 // starting bucket index for iterator
52+
wrapped bool // true if the iterator has wrapped
5053
}
5154

5255
func hashmapNewIterator() unsafe.Pointer {
@@ -390,28 +393,44 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
390393
// initialize iterator
391394
it.buckets = m.buckets
392395
it.numBuckets = uintptr(1) << m.bucketBits
396+
it.startBucket = uintptr(fastrand()) & (it.numBuckets - 1)
397+
it.startIndex = uint8(fastrand() & 7)
398+
399+
it.bucketNumber = it.startBucket
400+
it.bucket = hashmapBucketAddr(m, it.buckets, it.bucketNumber)
401+
it.bucketIndex = it.startIndex
393402
}
394403

395404
for {
405+
// If we've wrapped and we're back at our starting location, terminate the iteration.
406+
if it.wrapped && it.bucketNumber == it.startBucket && it.bucketIndex == it.startIndex {
407+
return false
408+
}
409+
396410
if it.bucketIndex >= 8 {
397411
// end of bucket, move to the next in the chain
398412
it.bucketIndex = 0
399413
it.bucket = it.bucket.next
400414
}
415+
401416
if it.bucket == nil {
417+
it.bucketNumber++ // next bucket
402418
if it.bucketNumber >= it.numBuckets {
403-
// went through all buckets
404-
return false
419+
// went through all buckets -- wrap around
420+
it.bucketNumber = 0
421+
it.wrapped = true
405422
}
406423
it.bucket = hashmapBucketAddr(m, it.buckets, it.bucketNumber)
407-
it.bucketNumber++ // next bucket
424+
continue
408425
}
426+
409427
if it.bucket.tophash[it.bucketIndex] == 0 {
410428
// slot is empty - move on
411429
it.bucketIndex++
412430
continue
413431
}
414432

433+
// Found a key.
415434
slotKey := hashmapSlotKey(m, it.bucket, it.bucketIndex)
416435
memcpy(key, slotKey, m.keySize)
417436

0 commit comments

Comments
 (0)