@@ -1549,36 +1549,63 @@ func (v Value) MapKeys() []Value {
1549
1549
if m != nil {
1550
1550
mlen = maplen (m )
1551
1551
}
1552
- it := mapiterinit (v .typ , m )
1552
+ var it hiter
1553
+ mapiterinit (v .typ , m , & it )
1553
1554
a := make ([]Value , mlen )
1554
1555
var i int
1555
1556
for i = 0 ; i < len (a ); i ++ {
1556
- key := mapiterkey (it )
1557
+ key := mapiterkey (& it )
1557
1558
if key == nil {
1558
1559
// Someone deleted an entry from the map since we
1559
1560
// called maplen above. It's a data race, but nothing
1560
1561
// we can do about it.
1561
1562
break
1562
1563
}
1563
1564
a [i ] = copyVal (keyType , fl , key )
1564
- mapiternext (it )
1565
+ mapiternext (& it )
1565
1566
}
1566
1567
return a [:i ]
1567
1568
}
1568
1569
1570
+ // hiter's structure matches runtime.hiter's structure.
1571
+ // Having a clone here allows us to embed a map iterator
1572
+ // inside type MapIter so that MapIters can be re-used
1573
+ // without doing any allocations.
1574
+ type hiter struct {
1575
+ key unsafe.Pointer
1576
+ elem unsafe.Pointer
1577
+ t unsafe.Pointer
1578
+ h unsafe.Pointer
1579
+ buckets unsafe.Pointer
1580
+ bptr unsafe.Pointer
1581
+ overflow * []unsafe.Pointer
1582
+ oldoverflow * []unsafe.Pointer
1583
+ startBucket uintptr
1584
+ offset uint8
1585
+ wrapped bool
1586
+ B uint8
1587
+ i uint8
1588
+ bucket uintptr
1589
+ checkBucket uintptr
1590
+ }
1591
+
1592
+ func (h hiter ) initialized () bool {
1593
+ return h .t != nil
1594
+ }
1595
+
1569
1596
// A MapIter is an iterator for ranging over a map.
1570
1597
// See Value.MapRange.
1571
1598
type MapIter struct {
1572
- m Value
1573
- it unsafe. Pointer
1599
+ m Value
1600
+ hiter hiter
1574
1601
}
1575
1602
1576
1603
// Key returns the key of the iterator's current map entry.
1577
1604
func (it * MapIter ) Key () Value {
1578
- if it .it == nil {
1605
+ if ! it .hiter . initialized () {
1579
1606
panic ("MapIter.Key called before Next" )
1580
1607
}
1581
- iterkey := mapiterkey (it .it )
1608
+ iterkey := mapiterkey (& it .hiter )
1582
1609
if iterkey == nil {
1583
1610
panic ("MapIter.Key called on exhausted iterator" )
1584
1611
}
@@ -1592,10 +1619,10 @@ func (it *MapIter) Key() Value {
1592
1619
// It is equivalent to dst.Set(it.Key()), but it avoids allocating a new Value.
1593
1620
// As in Go, the key must be assignable to dst's type.
1594
1621
func (it * MapIter ) SetKey (dst Value ) {
1595
- if it .it == nil {
1622
+ if ! it .hiter . initialized () {
1596
1623
panic ("MapIter.SetKey called before Next" )
1597
1624
}
1598
- iterkey := mapiterkey (it .it )
1625
+ iterkey := mapiterkey (& it .hiter )
1599
1626
if iterkey == nil {
1600
1627
panic ("MapIter.SetKey called on exhausted iterator" )
1601
1628
}
@@ -1616,10 +1643,10 @@ func (it *MapIter) SetKey(dst Value) {
1616
1643
1617
1644
// Value returns the value of the iterator's current map entry.
1618
1645
func (it * MapIter ) Value () Value {
1619
- if it .it == nil {
1646
+ if ! it .hiter . initialized () {
1620
1647
panic ("MapIter.Value called before Next" )
1621
1648
}
1622
- iterelem := mapiterelem (it .it )
1649
+ iterelem := mapiterelem (& it .hiter )
1623
1650
if iterelem == nil {
1624
1651
panic ("MapIter.Value called on exhausted iterator" )
1625
1652
}
@@ -1633,10 +1660,10 @@ func (it *MapIter) Value() Value {
1633
1660
// It is equivalent to dst.Set(it.Value()), but it avoids allocating a new Value.
1634
1661
// As in Go, the value must be assignable to dst's type.
1635
1662
func (it * MapIter ) SetValue (dst Value ) {
1636
- if it .it == nil {
1663
+ if ! it .hiter . initialized () {
1637
1664
panic ("MapIter.SetValue called before Next" )
1638
1665
}
1639
- iterelem := mapiterelem (it .it )
1666
+ iterelem := mapiterelem (& it .hiter )
1640
1667
if iterelem == nil {
1641
1668
panic ("MapIter.SetValue called on exhausted iterator" )
1642
1669
}
@@ -1659,15 +1686,15 @@ func (it *MapIter) SetValue(dst Value) {
1659
1686
// entry. It returns false when the iterator is exhausted; subsequent
1660
1687
// calls to Key, Value, or Next will panic.
1661
1688
func (it * MapIter ) Next () bool {
1662
- if it .it == nil {
1663
- it . it = mapiterinit (it .m .typ , it .m .pointer ())
1689
+ if ! it .hiter . initialized () {
1690
+ mapiterinit (it .m .typ , it .m .pointer (), & it . hiter )
1664
1691
} else {
1665
- if mapiterkey (it .it ) == nil {
1692
+ if mapiterkey (& it .hiter ) == nil {
1666
1693
panic ("MapIter.Next called on exhausted iterator" )
1667
1694
}
1668
- mapiternext (it .it )
1695
+ mapiternext (& it .hiter )
1669
1696
}
1670
- return mapiterkey (it .it ) != nil
1697
+ return mapiterkey (& it .hiter ) != nil
1671
1698
}
1672
1699
1673
1700
// MapRange returns a range iterator for a map.
@@ -3216,19 +3243,17 @@ func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
3216
3243
//go:noescape
3217
3244
func mapdelete (t * rtype , m unsafe.Pointer , key unsafe.Pointer )
3218
3245
3219
- // m escapes into the return value, but the caller of mapiterinit
3220
- // doesn't let the return value escape.
3221
3246
//go:noescape
3222
- func mapiterinit (t * rtype , m unsafe.Pointer ) unsafe. Pointer
3247
+ func mapiterinit (t * rtype , m unsafe.Pointer , it * hiter )
3223
3248
3224
3249
//go:noescape
3225
- func mapiterkey (it unsafe. Pointer ) (key unsafe.Pointer )
3250
+ func mapiterkey (it * hiter ) (key unsafe.Pointer )
3226
3251
3227
3252
//go:noescape
3228
- func mapiterelem (it unsafe. Pointer ) (elem unsafe.Pointer )
3253
+ func mapiterelem (it * hiter ) (elem unsafe.Pointer )
3229
3254
3230
3255
//go:noescape
3231
- func mapiternext (it unsafe. Pointer )
3256
+ func mapiternext (it * hiter )
3232
3257
3233
3258
//go:noescape
3234
3259
func maplen (m unsafe.Pointer ) int
0 commit comments