Skip to content

Commit a1d35eb

Browse files
committed
update map
1 parent d23e9ef commit a1d35eb

File tree

1 file changed

+30
-24
lines changed

1 file changed

+30
-24
lines changed

map.md

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,27 @@ v, ok := m[k]
210210

211211
## 赋值
212212

213+
### 编译器如何选择 assign 函数
214+
215+
mapassign 有几个变种,是由编译器决定具体用哪一个函数的。选择依据:
216+
217+
1. key 的类型是否是 string
218+
2. 如果不是 string,那么根据 key 的类型大小做选择
219+
220+
流程图:
221+
222+
```mermaid
223+
graph TD
224+
A[key is string] --> |yes|B[mapassign_faststr]
225+
A --> |no|C[key size is 32]
226+
C --> |yes|D[mapassign_fast32]
227+
C --> |no|E[key size is 64]
228+
E --> |yes|F[mapassign_fast64]
229+
E --> |no|G[mapassign]
230+
```
231+
232+
几个函数长得都差不多,我们看一下 mapassign 的逻辑就行了:
233+
213234
```go
214235
// 和 mapaccess 函数差不多,但在没有找到 key 时,会为 key 分配一个新的槽位
215236
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
@@ -564,7 +585,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
564585
// TODO: reuse overflow buckets instead of using new ones, if there
565586
// is no iterator using the old buckets. (If !oldIterator.)
566587

567-
// xy 包含的是移动的目标,x 表示前(low)半部分,y 表示后(high)半部分
588+
// xy 包含的是移动的目标
589+
// x 表示新 bucket 数组的前(low)半部分
590+
// y 表示新 bucket 数组的后(high)半部分
568591
var xy [2]evacDst
569592
x := &xy[0]
570593
x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
@@ -598,8 +621,8 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
598621
}
599622
var useY uint8
600623
if !h.sameSizeGrow() {
601-
// Compute hash to make our evacuation decision (whether we need
602-
// to send this key/value to bucket x or bucket y).
624+
// 计算哈希,以判断我们的数据要转移到哪一部分的 bucket
625+
// 可能是 x 部分,也可能是 y 部分
603626
hash := t.key.alg.hash(k2, uintptr(h.hash0))
604627
if h.flags&iterator != 0 && !t.reflexivekey && !t.key.alg.equal(k2, k2) {
605628
// If key != key (NaNs), then the hash could be (and probably
@@ -627,7 +650,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
627650
}
628651

629652
b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY
630-
dst := &xy[useY] // evacuation destination
653+
dst := &xy[useY] // 移动目标
631654

632655
if dst.i == bucketCnt {
633656
dst.b = h.newoverflow(t, dst.b)
@@ -637,9 +660,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
637660
}
638661
dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check
639662
if t.indirectkey {
640-
*(*unsafe.Pointer)(dst.k) = k2 // copy pointer
663+
*(*unsafe.Pointer)(dst.k) = k2 // 拷贝指针
641664
} else {
642-
typedmemmove(t.key, dst.k, k) // copy value
665+
typedmemmove(t.key, dst.k, k) // 拷贝值
643666
}
644667
if t.indirectvalue {
645668
*(*unsafe.Pointer)(dst.v) = *(*unsafe.Pointer)(v)
@@ -698,24 +721,7 @@ func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) {
698721
}
699722
```
700723

701-
## 编译期判断
702-
703-
### 编译器如何选择 assign 函数
704-
705-
就两个依据:
706-
707-
1. key 的类型是否是 string
708-
2. 如果不是 string,那么根据 key 的类型大小做选择
709-
710-
```mermaid
711-
```
712-
713-
mapassign
714-
mapassign_fast32
715-
mapassign_fasat64
716-
mapassign_faststr
717-
718-
### indirectkey 和 indirectvalue
724+
## indirectkey 和 indirectvalue
719725

720726
key > 128 字节时,indirectkey = true
721727

0 commit comments

Comments
 (0)