1
2
3
4
5
6 package maps
7
8 import (
9 "internal/abi"
10 "internal/goarch"
11 "unsafe"
12 )
13
14
15
16
17
18
19
20 const maxTableCapacity = 1024
21
22
23
24 var _ = uint16(maxTableCapacity)
25
26
27
28
29
30
31
32
33
34 type table struct {
35
36 used uint16
37
38
39
40 capacity uint16
41
42
43
44
45
46
47 growthLeft uint16
48
49
50
51
52 localDepth uint8
53
54
55
56
57
58
59
60 index int
61
62
63
64
65
66
67
68
69
70
71 groups groupsReference
72 }
73
74 func newTable(typ *abi.SwissMapType, capacity uint64, index int, localDepth uint8) *table {
75 if capacity < abi.SwissMapGroupSlots {
76 capacity = abi.SwissMapGroupSlots
77 }
78
79 t := &table{
80 index: index,
81 localDepth: localDepth,
82 }
83
84 if capacity > maxTableCapacity {
85 panic("initial table capacity too large")
86 }
87
88
89
90 capacity, overflow := alignUpPow2(capacity)
91 if overflow {
92 panic("rounded-up capacity overflows uint64")
93 }
94
95 t.reset(typ, uint16(capacity))
96
97 return t
98 }
99
100
101
102 func (t *table) reset(typ *abi.SwissMapType, capacity uint16) {
103 groupCount := uint64(capacity) / abi.SwissMapGroupSlots
104 t.groups = newGroups(typ, groupCount)
105 t.capacity = capacity
106 t.resetGrowthLeft()
107
108 for i := uint64(0); i <= t.groups.lengthMask; i++ {
109 g := t.groups.group(typ, i)
110 g.ctrls().setEmpty()
111 }
112 }
113
114
115 func (t *table) resetGrowthLeft() {
116 var growthLeft uint16
117 if t.capacity == 0 {
118
119
120 panic("table must have positive capacity")
121 } else if t.capacity <= abi.SwissMapGroupSlots {
122
123
124
125
126
127
128 growthLeft = t.capacity - 1
129 } else {
130 if t.capacity*maxAvgGroupLoad < t.capacity {
131
132 panic("overflow")
133 }
134 growthLeft = (t.capacity * maxAvgGroupLoad) / abi.SwissMapGroupSlots
135 }
136 t.growthLeft = growthLeft
137 }
138
139 func (t *table) Used() uint64 {
140 return uint64(t.used)
141 }
142
143
144
145 func (t *table) Get(typ *abi.SwissMapType, m *Map, key unsafe.Pointer) (unsafe.Pointer, bool) {
146
147
148
149
150
151
152 hash := typ.Hasher(key, m.seed)
153 _, elem, ok := t.getWithKey(typ, hash, key)
154 return elem, ok
155 }
156
157
158
159
160
161
162
163
164
165
166 func (t *table) getWithKey(typ *abi.SwissMapType, hash uintptr, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer, bool) {
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
195 for ; ; seq = seq.next() {
196 g := t.groups.group(typ, seq.offset)
197
198 match := g.ctrls().matchH2(h2(hash))
199
200 for match != 0 {
201 i := match.first()
202
203 slotKey := g.key(typ, i)
204 if typ.IndirectKey() {
205 slotKey = *((*unsafe.Pointer)(slotKey))
206 }
207 if typ.Key.Equal(key, slotKey) {
208 slotElem := g.elem(typ, i)
209 if typ.IndirectElem() {
210 slotElem = *((*unsafe.Pointer)(slotElem))
211 }
212 return slotKey, slotElem, true
213 }
214 match = match.removeFirst()
215 }
216
217 match = g.ctrls().matchEmpty()
218 if match != 0 {
219
220
221 return nil, nil, false
222 }
223 }
224 }
225
226 func (t *table) getWithoutKey(typ *abi.SwissMapType, hash uintptr, key unsafe.Pointer) (unsafe.Pointer, bool) {
227 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
228 for ; ; seq = seq.next() {
229 g := t.groups.group(typ, seq.offset)
230
231 match := g.ctrls().matchH2(h2(hash))
232
233 for match != 0 {
234 i := match.first()
235
236 slotKey := g.key(typ, i)
237 if typ.IndirectKey() {
238 slotKey = *((*unsafe.Pointer)(slotKey))
239 }
240 if typ.Key.Equal(key, slotKey) {
241 slotElem := g.elem(typ, i)
242 if typ.IndirectElem() {
243 slotElem = *((*unsafe.Pointer)(slotElem))
244 }
245 return slotElem, true
246 }
247 match = match.removeFirst()
248 }
249
250 match = g.ctrls().matchEmpty()
251 if match != 0 {
252
253
254 return nil, false
255 }
256 }
257 }
258
259
260
261
262
263
264
265
266 func (t *table) PutSlot(typ *abi.SwissMapType, m *Map, hash uintptr, key unsafe.Pointer) (unsafe.Pointer, bool) {
267 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
268
269
270
271 var firstDeletedGroup groupReference
272 var firstDeletedSlot uintptr
273
274 for ; ; seq = seq.next() {
275 g := t.groups.group(typ, seq.offset)
276 match := g.ctrls().matchH2(h2(hash))
277
278
279 for match != 0 {
280 i := match.first()
281
282 slotKey := g.key(typ, i)
283 if typ.IndirectKey() {
284 slotKey = *((*unsafe.Pointer)(slotKey))
285 }
286 if typ.Key.Equal(key, slotKey) {
287 if typ.NeedKeyUpdate() {
288 typedmemmove(typ.Key, slotKey, key)
289 }
290
291 slotElem := g.elem(typ, i)
292 if typ.IndirectElem() {
293 slotElem = *((*unsafe.Pointer)(slotElem))
294 }
295
296 t.checkInvariants(typ, m)
297 return slotElem, true
298 }
299 match = match.removeFirst()
300 }
301
302
303
304 match = g.ctrls().matchEmptyOrDeleted()
305 if match == 0 {
306 continue
307 }
308 i := match.first()
309 if g.ctrls().get(i) == ctrlDeleted {
310
311
312 if firstDeletedGroup.data == nil {
313 firstDeletedGroup = g
314 firstDeletedSlot = i
315 }
316 continue
317 }
318
319
320
321
322
323 if firstDeletedGroup.data != nil {
324 g = firstDeletedGroup
325 i = firstDeletedSlot
326 t.growthLeft++
327 }
328
329
330 if t.growthLeft > 0 {
331 slotKey := g.key(typ, i)
332 if typ.IndirectKey() {
333 kmem := newobject(typ.Key)
334 *(*unsafe.Pointer)(slotKey) = kmem
335 slotKey = kmem
336 }
337 typedmemmove(typ.Key, slotKey, key)
338
339 slotElem := g.elem(typ, i)
340 if typ.IndirectElem() {
341 emem := newobject(typ.Elem)
342 *(*unsafe.Pointer)(slotElem) = emem
343 slotElem = emem
344 }
345
346 g.ctrls().set(i, ctrl(h2(hash)))
347 t.growthLeft--
348 t.used++
349 m.used++
350
351 t.checkInvariants(typ, m)
352 return slotElem, true
353 }
354
355 t.rehash(typ, m)
356 return nil, false
357 }
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376 func (t *table) uncheckedPutSlot(typ *abi.SwissMapType, hash uintptr, key, elem unsafe.Pointer) {
377 if t.growthLeft == 0 {
378 panic("invariant failed: growthLeft is unexpectedly 0")
379 }
380
381
382
383
384
385 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
386 for ; ; seq = seq.next() {
387 g := t.groups.group(typ, seq.offset)
388
389 match := g.ctrls().matchEmptyOrDeleted()
390 if match != 0 {
391 i := match.first()
392
393 slotKey := g.key(typ, i)
394 if typ.IndirectKey() {
395 *(*unsafe.Pointer)(slotKey) = key
396 } else {
397 typedmemmove(typ.Key, slotKey, key)
398 }
399
400 slotElem := g.elem(typ, i)
401 if typ.IndirectElem() {
402 *(*unsafe.Pointer)(slotElem) = elem
403 } else {
404 typedmemmove(typ.Elem, slotElem, elem)
405 }
406
407 t.growthLeft--
408 t.used++
409 g.ctrls().set(i, ctrl(h2(hash)))
410 return
411 }
412 }
413 }
414
415 func (t *table) Delete(typ *abi.SwissMapType, m *Map, hash uintptr, key unsafe.Pointer) {
416 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
417 for ; ; seq = seq.next() {
418 g := t.groups.group(typ, seq.offset)
419 match := g.ctrls().matchH2(h2(hash))
420
421 for match != 0 {
422 i := match.first()
423
424 slotKey := g.key(typ, i)
425 origSlotKey := slotKey
426 if typ.IndirectKey() {
427 slotKey = *((*unsafe.Pointer)(slotKey))
428 }
429
430 if typ.Key.Equal(key, slotKey) {
431 t.used--
432 m.used--
433
434 if typ.IndirectKey() {
435
436 *(*unsafe.Pointer)(origSlotKey) = nil
437 } else if typ.Key.Pointers() {
438
439
440 typedmemclr(typ.Key, slotKey)
441 }
442
443 slotElem := g.elem(typ, i)
444 if typ.IndirectElem() {
445
446 *(*unsafe.Pointer)(slotElem) = nil
447 } else {
448
449
450
451
452
453 typedmemclr(typ.Elem, slotElem)
454 }
455
456
457
458
459
460
461
462
463
464 if g.ctrls().matchEmpty() != 0 {
465 g.ctrls().set(i, ctrlEmpty)
466 t.growthLeft++
467 } else {
468 g.ctrls().set(i, ctrlDeleted)
469 }
470
471 t.checkInvariants(typ, m)
472 return
473 }
474 match = match.removeFirst()
475 }
476
477 match = g.ctrls().matchEmpty()
478 if match != 0 {
479
480
481 return
482 }
483 }
484 }
485
486
487
488
489 func (t *table) tombstones() uint16 {
490 return (t.capacity*maxAvgGroupLoad)/abi.SwissMapGroupSlots - t.used - t.growthLeft
491 }
492
493
494 func (t *table) Clear(typ *abi.SwissMapType) {
495 for i := uint64(0); i <= t.groups.lengthMask; i++ {
496 g := t.groups.group(typ, i)
497 typedmemclr(typ.Group, g.data)
498 g.ctrls().setEmpty()
499 }
500
501 t.used = 0
502 t.resetGrowthLeft()
503 }
504
505 type Iter struct {
506 key unsafe.Pointer
507 elem unsafe.Pointer
508 typ *abi.SwissMapType
509 m *Map
510
511
512
513
514 entryOffset uint64
515 dirOffset uint64
516
517
518
519 clearSeq uint64
520
521
522
523 globalDepth uint8
524
525
526
527 dirIdx int
528
529
530 tab *table
531
532
533 group groupReference
534
535
536
537
538 entryIdx uint64
539 }
540
541
542 func (it *Iter) Init(typ *abi.SwissMapType, m *Map) {
543 it.typ = typ
544
545 if m == nil || m.used == 0 {
546 return
547 }
548
549 dirIdx := 0
550 var groupSmall groupReference
551 if m.dirLen <= 0 {
552
553 dirIdx = -1
554 groupSmall.data = m.dirPtr
555 }
556
557 it.m = m
558 it.entryOffset = rand()
559 it.dirOffset = rand()
560 it.globalDepth = m.globalDepth
561 it.dirIdx = dirIdx
562 it.group = groupSmall
563 it.clearSeq = m.clearSeq
564 }
565
566 func (it *Iter) Initialized() bool {
567 return it.typ != nil
568 }
569
570
571 func (it *Iter) Map() *Map {
572 return it.m
573 }
574
575
576
577
578 func (it *Iter) Key() unsafe.Pointer {
579 return it.key
580 }
581
582
583
584
585
586 func (it *Iter) Elem() unsafe.Pointer {
587 return it.elem
588 }
589
590 func (it *Iter) nextDirIdx() {
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 entries := 1 << (it.m.globalDepth - it.tab.localDepth)
618 it.dirIdx += entries
619 it.tab = nil
620 it.group = groupReference{}
621 it.entryIdx = 0
622 }
623
624
625
626 func (it *Iter) grownKeyElem(key unsafe.Pointer, slotIdx uintptr) (unsafe.Pointer, unsafe.Pointer, bool) {
627 newKey, newElem, ok := it.m.getWithKey(it.typ, key)
628 if !ok {
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652 if it.clearSeq == it.m.clearSeq && !it.typ.Key.Equal(key, key) {
653 elem := it.group.elem(it.typ, slotIdx)
654 if it.typ.IndirectElem() {
655 elem = *((*unsafe.Pointer)(elem))
656 }
657 return key, elem, true
658 }
659
660
661 return nil, nil, false
662 }
663
664 return newKey, newElem, true
665 }
666
667
668
669
670
671
672
673
674 func (it *Iter) Next() {
675 if it.m == nil {
676
677 it.key = nil
678 it.elem = nil
679 return
680 }
681
682 if it.m.writing != 0 {
683 fatal("concurrent map iteration and map write")
684 return
685 }
686
687 if it.dirIdx < 0 {
688
689 for ; it.entryIdx < abi.SwissMapGroupSlots; it.entryIdx++ {
690 k := uintptr(it.entryIdx+it.entryOffset) % abi.SwissMapGroupSlots
691
692 if (it.group.ctrls().get(k) & ctrlEmpty) == ctrlEmpty {
693
694 continue
695 }
696
697 key := it.group.key(it.typ, k)
698 if it.typ.IndirectKey() {
699 key = *((*unsafe.Pointer)(key))
700 }
701
702
703
704
705
706 grown := it.m.dirLen > 0
707 var elem unsafe.Pointer
708 if grown {
709 var ok bool
710 newKey, newElem, ok := it.m.getWithKey(it.typ, key)
711 if !ok {
712
713 if it.clearSeq == it.m.clearSeq && !it.typ.Key.Equal(key, key) {
714 elem = it.group.elem(it.typ, k)
715 if it.typ.IndirectElem() {
716 elem = *((*unsafe.Pointer)(elem))
717 }
718 } else {
719 continue
720 }
721 } else {
722 key = newKey
723 elem = newElem
724 }
725 } else {
726 elem = it.group.elem(it.typ, k)
727 if it.typ.IndirectElem() {
728 elem = *((*unsafe.Pointer)(elem))
729 }
730 }
731
732 it.entryIdx++
733 it.key = key
734 it.elem = elem
735 return
736 }
737 it.key = nil
738 it.elem = nil
739 return
740 }
741
742 if it.globalDepth != it.m.globalDepth {
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772 orders := it.m.globalDepth - it.globalDepth
773 it.dirIdx <<= orders
774 it.dirOffset <<= orders
775
776
777 it.globalDepth = it.m.globalDepth
778 }
779
780
781 for ; it.dirIdx < it.m.dirLen; it.nextDirIdx() {
782
783 if it.tab == nil {
784 dirIdx := int((uint64(it.dirIdx) + it.dirOffset) & uint64(it.m.dirLen-1))
785 newTab := it.m.directoryAt(uintptr(dirIdx))
786 if newTab.index != dirIdx {
787
788
789
790
791
792
793
794
795
796
797
798 diff := dirIdx - newTab.index
799 it.dirOffset -= uint64(diff)
800 dirIdx = newTab.index
801 }
802 it.tab = newTab
803 }
804
805
806
807
808
809 entryMask := uint64(it.tab.capacity) - 1
810 if it.entryIdx > entryMask {
811
812 continue
813 }
814
815
816
817
818
819
820
821
822
823
824
825
826 entryIdx := (it.entryIdx + it.entryOffset) & entryMask
827 slotIdx := uintptr(entryIdx & (abi.SwissMapGroupSlots - 1))
828 if slotIdx == 0 || it.group.data == nil {
829
830
831
832
833 groupIdx := entryIdx >> abi.SwissMapGroupSlotsBits
834 it.group = it.tab.groups.group(it.typ, groupIdx)
835 }
836
837 if (it.group.ctrls().get(slotIdx) & ctrlEmpty) == 0 {
838
839
840 key := it.group.key(it.typ, slotIdx)
841 if it.typ.IndirectKey() {
842 key = *((*unsafe.Pointer)(key))
843 }
844
845 grown := it.tab.index == -1
846 var elem unsafe.Pointer
847 if grown {
848 newKey, newElem, ok := it.grownKeyElem(key, slotIdx)
849 if !ok {
850
851
852
853 goto next
854 } else {
855 key = newKey
856 elem = newElem
857 }
858 } else {
859 elem = it.group.elem(it.typ, slotIdx)
860 if it.typ.IndirectElem() {
861 elem = *((*unsafe.Pointer)(elem))
862 }
863 }
864
865 it.entryIdx++
866 it.key = key
867 it.elem = elem
868 return
869 }
870
871 next:
872 it.entryIdx++
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891 var groupMatch bitset
892 for it.entryIdx <= entryMask {
893 entryIdx := (it.entryIdx + it.entryOffset) & entryMask
894 slotIdx := uintptr(entryIdx & (abi.SwissMapGroupSlots - 1))
895
896 if slotIdx == 0 || it.group.data == nil {
897
898
899
900
901 groupIdx := entryIdx >> abi.SwissMapGroupSlotsBits
902 it.group = it.tab.groups.group(it.typ, groupIdx)
903 }
904
905 if groupMatch == 0 {
906 groupMatch = it.group.ctrls().matchFull()
907
908 if slotIdx != 0 {
909
910
911 groupMatch = groupMatch.removeBelow(slotIdx)
912 }
913
914
915
916 if groupMatch == 0 {
917
918
919 it.entryIdx += abi.SwissMapGroupSlots - uint64(slotIdx)
920 continue
921 }
922
923 i := groupMatch.first()
924 it.entryIdx += uint64(i - slotIdx)
925 if it.entryIdx > entryMask {
926
927 continue
928 }
929 entryIdx += uint64(i - slotIdx)
930 slotIdx = i
931 }
932
933 key := it.group.key(it.typ, slotIdx)
934 if it.typ.IndirectKey() {
935 key = *((*unsafe.Pointer)(key))
936 }
937
938
939
940
941
942
943
944
945
946
947
948
949 grown := it.tab.index == -1
950 var elem unsafe.Pointer
951 if grown {
952 newKey, newElem, ok := it.grownKeyElem(key, slotIdx)
953 if !ok {
954
955
956 groupMatch = groupMatch.removeFirst()
957 if groupMatch == 0 {
958
959
960
961 it.entryIdx += abi.SwissMapGroupSlots - uint64(slotIdx)
962 continue
963 }
964
965
966 i := groupMatch.first()
967 it.entryIdx += uint64(i - slotIdx)
968 continue
969 } else {
970 key = newKey
971 elem = newElem
972 }
973 } else {
974 elem = it.group.elem(it.typ, slotIdx)
975 if it.typ.IndirectElem() {
976 elem = *((*unsafe.Pointer)(elem))
977 }
978 }
979
980
981 groupMatch = groupMatch.removeFirst()
982 if groupMatch == 0 {
983
984
985
986 it.entryIdx += abi.SwissMapGroupSlots - uint64(slotIdx)
987 } else {
988
989 i := groupMatch.first()
990 it.entryIdx += uint64(i - slotIdx)
991 }
992
993 it.key = key
994 it.elem = elem
995 return
996 }
997
998
999 }
1000
1001 it.key = nil
1002 it.elem = nil
1003 return
1004 }
1005
1006
1007
1008
1009 func (t *table) rehash(typ *abi.SwissMapType, m *Map) {
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 newCapacity := 2 * t.capacity
1026 if newCapacity <= maxTableCapacity {
1027 t.grow(typ, m, newCapacity)
1028 return
1029 }
1030
1031 t.split(typ, m)
1032 }
1033
1034
1035 func localDepthMask(localDepth uint8) uintptr {
1036 if goarch.PtrSize == 4 {
1037 return uintptr(1) << (32 - localDepth)
1038 }
1039 return uintptr(1) << (64 - localDepth)
1040 }
1041
1042
1043 func (t *table) split(typ *abi.SwissMapType, m *Map) {
1044 localDepth := t.localDepth
1045 localDepth++
1046
1047
1048 left := newTable(typ, maxTableCapacity, -1, localDepth)
1049 right := newTable(typ, maxTableCapacity, -1, localDepth)
1050
1051
1052 mask := localDepthMask(localDepth)
1053
1054 for i := uint64(0); i <= t.groups.lengthMask; i++ {
1055 g := t.groups.group(typ, i)
1056 for j := uintptr(0); j < abi.SwissMapGroupSlots; j++ {
1057 if (g.ctrls().get(j) & ctrlEmpty) == ctrlEmpty {
1058
1059 continue
1060 }
1061
1062 key := g.key(typ, j)
1063 if typ.IndirectKey() {
1064 key = *((*unsafe.Pointer)(key))
1065 }
1066
1067 elem := g.elem(typ, j)
1068 if typ.IndirectElem() {
1069 elem = *((*unsafe.Pointer)(elem))
1070 }
1071
1072 hash := typ.Hasher(key, m.seed)
1073 var newTable *table
1074 if hash&mask == 0 {
1075 newTable = left
1076 } else {
1077 newTable = right
1078 }
1079 newTable.uncheckedPutSlot(typ, hash, key, elem)
1080 }
1081 }
1082
1083 m.installTableSplit(t, left, right)
1084 t.index = -1
1085 }
1086
1087
1088
1089
1090
1091 func (t *table) grow(typ *abi.SwissMapType, m *Map, newCapacity uint16) {
1092 newTable := newTable(typ, uint64(newCapacity), t.index, t.localDepth)
1093
1094 if t.capacity > 0 {
1095 for i := uint64(0); i <= t.groups.lengthMask; i++ {
1096 g := t.groups.group(typ, i)
1097 for j := uintptr(0); j < abi.SwissMapGroupSlots; j++ {
1098 if (g.ctrls().get(j) & ctrlEmpty) == ctrlEmpty {
1099
1100 continue
1101 }
1102
1103 key := g.key(typ, j)
1104 if typ.IndirectKey() {
1105 key = *((*unsafe.Pointer)(key))
1106 }
1107
1108 elem := g.elem(typ, j)
1109 if typ.IndirectElem() {
1110 elem = *((*unsafe.Pointer)(elem))
1111 }
1112
1113 hash := typ.Hasher(key, m.seed)
1114
1115 newTable.uncheckedPutSlot(typ, hash, key, elem)
1116 }
1117 }
1118 }
1119
1120 newTable.checkInvariants(typ, m)
1121 m.replaceTable(newTable)
1122 t.index = -1
1123 }
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136 type probeSeq struct {
1137 mask uint64
1138 offset uint64
1139 index uint64
1140 }
1141
1142 func makeProbeSeq(hash uintptr, mask uint64) probeSeq {
1143 return probeSeq{
1144 mask: mask,
1145 offset: uint64(hash) & mask,
1146 index: 0,
1147 }
1148 }
1149
1150 func (s probeSeq) next() probeSeq {
1151 s.index++
1152 s.offset = (s.offset + s.index) & s.mask
1153 return s
1154 }
1155
View as plain text