1
2
3
4
5 package maps_test
6
7 import (
8 "fmt"
9 "internal/abi"
10 "internal/runtime/maps"
11 "math"
12 "testing"
13 "unsafe"
14 )
15
16 func TestCtrlSize(t *testing.T) {
17 cs := unsafe.Sizeof(maps.CtrlGroup(0))
18 if cs != abi.SwissMapGroupSlots {
19 t.Errorf("ctrlGroup size got %d want abi.SwissMapGroupSlots %d", cs, abi.SwissMapGroupSlots)
20 }
21 }
22
23 func TestMapPut(t *testing.T) {
24 m, typ := maps.NewTestMap[uint32, uint64](8)
25
26 key := uint32(0)
27 elem := uint64(256 + 0)
28
29 for i := 0; i < 31; i++ {
30 key += 1
31 elem += 1
32 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
33
34 if maps.DebugLog {
35 fmt.Printf("After put %d: %v\n", key, m)
36 }
37 }
38
39 if m.Used() != 31 {
40 t.Errorf("Used() used got %d want 31", m.Used())
41 }
42
43 key = uint32(0)
44 elem = uint64(256 + 0)
45
46 for i := 0; i < 31; i++ {
47 key += 1
48 elem += 1
49 got, ok := m.Get(typ, unsafe.Pointer(&key))
50 if !ok {
51 t.Errorf("Get(%d) got ok false want true", key)
52 }
53 gotElem := *(*uint64)(got)
54 if gotElem != elem {
55 t.Errorf("Get(%d) got elem %d want %d", key, gotElem, elem)
56 }
57 }
58 }
59
60
61 func TestMapSplit(t *testing.T) {
62 m, typ := maps.NewTestMap[uint32, uint64](0)
63
64 key := uint32(0)
65 elem := uint64(256 + 0)
66
67 for i := 0; i < 2*maps.MaxTableCapacity; i++ {
68 key += 1
69 elem += 1
70 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
71
72 if maps.DebugLog {
73 fmt.Printf("After put %d: %v\n", key, m)
74 }
75 }
76
77 if m.Used() != 2*maps.MaxTableCapacity {
78 t.Errorf("Used() used got %d want 31", m.Used())
79 }
80
81 key = uint32(0)
82 elem = uint64(256 + 0)
83
84 for i := 0; i < 2*maps.MaxTableCapacity; i++ {
85 key += 1
86 elem += 1
87 got, ok := m.Get(typ, unsafe.Pointer(&key))
88 if !ok {
89 t.Errorf("Get(%d) got ok false want true", key)
90 }
91 gotElem := *(*uint64)(got)
92 if gotElem != elem {
93 t.Errorf("Get(%d) got elem %d want %d", key, gotElem, elem)
94 }
95 }
96 }
97
98 func TestMapDelete(t *testing.T) {
99 m, typ := maps.NewTestMap[uint32, uint64](32)
100
101 key := uint32(0)
102 elem := uint64(256 + 0)
103
104 for i := 0; i < 31; i++ {
105 key += 1
106 elem += 1
107 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
108
109 if maps.DebugLog {
110 fmt.Printf("After put %d: %v\n", key, m)
111 }
112 }
113
114 key = uint32(0)
115 elem = uint64(256 + 0)
116
117 for i := 0; i < 31; i++ {
118 key += 1
119 m.Delete(typ, unsafe.Pointer(&key))
120 }
121
122 if m.Used() != 0 {
123 t.Errorf("Used() used got %d want 0", m.Used())
124 }
125
126 key = uint32(0)
127 elem = uint64(256 + 0)
128
129 for i := 0; i < 31; i++ {
130 key += 1
131 elem += 1
132 _, ok := m.Get(typ, unsafe.Pointer(&key))
133 if ok {
134 t.Errorf("Get(%d) got ok true want false", key)
135 }
136 }
137 }
138
139 func TestTableClear(t *testing.T) {
140 m, typ := maps.NewTestMap[uint32, uint64](32)
141
142 key := uint32(0)
143 elem := uint64(256 + 0)
144
145 for i := 0; i < 31; i++ {
146 key += 1
147 elem += 1
148 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
149
150 if maps.DebugLog {
151 fmt.Printf("After put %d: %v\n", key, m)
152 }
153 }
154
155 m.Clear(typ)
156
157 if m.Used() != 0 {
158 t.Errorf("Clear() used got %d want 0", m.Used())
159 }
160
161 key = uint32(0)
162 elem = uint64(256 + 0)
163
164 for i := 0; i < 31; i++ {
165 key += 1
166 elem += 1
167 _, ok := m.Get(typ, unsafe.Pointer(&key))
168 if ok {
169 t.Errorf("Get(%d) got ok true want false", key)
170 }
171 }
172 }
173
174
175
176 func TestTableKeyUpdate(t *testing.T) {
177 m, typ := maps.NewTestMap[float64, uint64](8)
178
179 zero := float64(0.0)
180 negZero := math.Copysign(zero, -1.0)
181 elem := uint64(0)
182
183 m.Put(typ, unsafe.Pointer(&zero), unsafe.Pointer(&elem))
184 if maps.DebugLog {
185 fmt.Printf("After put %f: %v\n", zero, m)
186 }
187
188 elem = 1
189 m.Put(typ, unsafe.Pointer(&negZero), unsafe.Pointer(&elem))
190 if maps.DebugLog {
191 fmt.Printf("After put %f: %v\n", negZero, m)
192 }
193
194 if m.Used() != 1 {
195 t.Errorf("Used() used got %d want 1", m.Used())
196 }
197
198 it := new(maps.Iter)
199 it.Init(typ, m)
200 it.Next()
201 keyPtr, elemPtr := it.Key(), it.Elem()
202 if keyPtr == nil {
203 t.Fatal("it.Key() got nil want key")
204 }
205
206 key := *(*float64)(keyPtr)
207 elem = *(*uint64)(elemPtr)
208 if math.Copysign(1.0, key) > 0 {
209 t.Errorf("map key %f has positive sign", key)
210 }
211 if elem != 1 {
212 t.Errorf("map elem got %d want 1", elem)
213 }
214 }
215
216
217 func TestTablePutDelete(t *testing.T) {
218
219
220
221
222
223
224
225
226
227 m, typ := maps.NewTestMap[uint32, uint32](16)
228
229 key := uint32(0)
230 elem := uint32(256 + 0)
231
232 for {
233 key += 1
234 elem += 1
235
236 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
237
238
239
240
241
242
243
244
245 fullKeyPtr := m.KeyFromFullGroup(typ)
246 if fullKeyPtr != nil {
247
248 key = *(*uint32)(fullKeyPtr)
249 elem = 256 + key
250 break
251 }
252 }
253
254
255
256 m.Delete(typ, unsafe.Pointer(&key))
257
258
259
260 tabWant := m.TableFor(typ, unsafe.Pointer(&key))
261 growthLeftWant := tabWant.GrowthLeft()
262
263 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
264
265 tabGot := m.TableFor(typ, unsafe.Pointer(&key))
266 growthLeftGot := tabGot.GrowthLeft()
267
268 if tabGot != tabWant {
269
270
271 t.Errorf("Put(%d) grew table got %v want %v map %v", key, tabGot, tabWant, m)
272 }
273
274 if growthLeftGot != growthLeftWant {
275 t.Errorf("GrowthLeft got %d want %d: map %v tab %v", growthLeftGot, growthLeftWant, m, tabGot)
276 }
277 }
278
279 func TestTableIteration(t *testing.T) {
280 m, typ := maps.NewTestMap[uint32, uint64](8)
281
282 key := uint32(0)
283 elem := uint64(256 + 0)
284
285 for i := 0; i < 31; i++ {
286 key += 1
287 elem += 1
288 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
289
290 if maps.DebugLog {
291 fmt.Printf("After put %d: %v\n", key, m)
292 }
293 }
294
295 got := make(map[uint32]uint64)
296
297 it := new(maps.Iter)
298 it.Init(typ, m)
299 for {
300 it.Next()
301 keyPtr, elemPtr := it.Key(), it.Elem()
302 if keyPtr == nil {
303 break
304 }
305
306 key := *(*uint32)(keyPtr)
307 elem := *(*uint64)(elemPtr)
308 got[key] = elem
309 }
310
311 if len(got) != 31 {
312 t.Errorf("Iteration got %d entries, want 31: %+v", len(got), got)
313 }
314
315 key = uint32(0)
316 elem = uint64(256 + 0)
317
318 for i := 0; i < 31; i++ {
319 key += 1
320 elem += 1
321 gotElem, ok := got[key]
322 if !ok {
323 t.Errorf("Iteration missing key %d", key)
324 continue
325 }
326 if gotElem != elem {
327 t.Errorf("Iteration key %d got elem %d want %d", key, gotElem, elem)
328 }
329 }
330 }
331
332
333 func TestTableIterationDelete(t *testing.T) {
334 m, typ := maps.NewTestMap[uint32, uint64](8)
335
336 key := uint32(0)
337 elem := uint64(256 + 0)
338
339 for i := 0; i < 31; i++ {
340 key += 1
341 elem += 1
342 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
343
344 if maps.DebugLog {
345 fmt.Printf("After put %d: %v\n", key, m)
346 }
347 }
348
349 got := make(map[uint32]uint64)
350 first := true
351 deletedKey := uint32(1)
352 it := new(maps.Iter)
353 it.Init(typ, m)
354 for {
355 it.Next()
356 keyPtr, elemPtr := it.Key(), it.Elem()
357 if keyPtr == nil {
358 break
359 }
360
361 key := *(*uint32)(keyPtr)
362 elem := *(*uint64)(elemPtr)
363 got[key] = elem
364
365 if first {
366 first = false
367
368
369
370 if key == deletedKey {
371 deletedKey++
372 }
373 m.Delete(typ, unsafe.Pointer(&deletedKey))
374 }
375 }
376
377 if len(got) != 30 {
378 t.Errorf("Iteration got %d entries, want 30: %+v", len(got), got)
379 }
380
381 key = uint32(0)
382 elem = uint64(256 + 0)
383
384 for i := 0; i < 31; i++ {
385 key += 1
386 elem += 1
387
388 wantOK := true
389 if key == deletedKey {
390 wantOK = false
391 }
392
393 gotElem, gotOK := got[key]
394 if gotOK != wantOK {
395 t.Errorf("Iteration key %d got ok %v want ok %v", key, gotOK, wantOK)
396 continue
397 }
398 if wantOK && gotElem != elem {
399 t.Errorf("Iteration key %d got elem %d want %d", key, gotElem, elem)
400 }
401 }
402 }
403
404
405 func TestTableIterationGrowDelete(t *testing.T) {
406 m, typ := maps.NewTestMap[uint32, uint64](8)
407
408 key := uint32(0)
409 elem := uint64(256 + 0)
410
411 for i := 0; i < 31; i++ {
412 key += 1
413 elem += 1
414 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
415
416 if maps.DebugLog {
417 fmt.Printf("After put %d: %v\n", key, m)
418 }
419 }
420
421 got := make(map[uint32]uint64)
422 first := true
423 deletedKey := uint32(1)
424 it := new(maps.Iter)
425 it.Init(typ, m)
426 for {
427 it.Next()
428 keyPtr, elemPtr := it.Key(), it.Elem()
429 if keyPtr == nil {
430 break
431 }
432
433 key := *(*uint32)(keyPtr)
434 elem := *(*uint64)(elemPtr)
435 got[key] = elem
436
437 if first {
438 first = false
439
440
441
442 if key == deletedKey {
443 deletedKey++
444 }
445
446
447 key := uint32(32)
448 elem := uint64(256 + 32)
449
450 for i := 0; i < 31; i++ {
451 key += 1
452 elem += 1
453 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
454
455 if maps.DebugLog {
456 fmt.Printf("After put %d: %v\n", key, m)
457 }
458 }
459
460
461 m.Delete(typ, unsafe.Pointer(&deletedKey))
462 }
463 }
464
465
466
467
468
469 key = uint32(0)
470 elem = uint64(256 + 0)
471
472 for i := 0; i < 31; i++ {
473 key += 1
474 elem += 1
475
476 wantOK := true
477 if key == deletedKey {
478 wantOK = false
479 }
480
481 gotElem, gotOK := got[key]
482 if gotOK != wantOK {
483 t.Errorf("Iteration key %d got ok %v want ok %v", key, gotOK, wantOK)
484 continue
485 }
486 if wantOK && gotElem != elem {
487 t.Errorf("Iteration key %d got elem %d want %d", key, gotElem, elem)
488 }
489 }
490 }
491
492 func testTableIterationGrowDuplicate(t *testing.T, grow int) {
493 m, typ := maps.NewTestMap[uint32, uint64](8)
494
495 key := uint32(0)
496 elem := uint64(256 + 0)
497
498 for i := 0; i < 31; i++ {
499 key += 1
500 elem += 1
501 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
502
503 if maps.DebugLog {
504 fmt.Printf("After put %d: %v\n", key, m)
505 }
506 }
507
508 got := make(map[uint32]uint64)
509 it := new(maps.Iter)
510 it.Init(typ, m)
511 for i := 0; ; i++ {
512 it.Next()
513 keyPtr, elemPtr := it.Key(), it.Elem()
514 if keyPtr == nil {
515 break
516 }
517
518 key := *(*uint32)(keyPtr)
519 elem := *(*uint64)(elemPtr)
520 if elem != 256+uint64(key) {
521 t.Errorf("iteration got key %d elem %d want elem %d", key, elem, 256+uint64(key))
522 }
523 if _, ok := got[key]; ok {
524 t.Errorf("iteration got key %d more than once", key)
525 }
526 got[key] = elem
527
528
529 if i == 16 {
530 key := uint32(32)
531 elem := uint64(256 + 32)
532
533 for i := 0; i < grow; i++ {
534 key += 1
535 elem += 1
536 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
537
538 if maps.DebugLog {
539 fmt.Printf("After put %d: %v\n", key, m)
540 }
541 }
542 }
543 }
544
545
546
547 }
548
549
550 func TestTableIterationGrowDuplicate(t *testing.T) {
551
552 t.Run("grow", func(t *testing.T) { testTableIterationGrowDuplicate(t, 32) })
553
554
555 t.Run("split", func(t *testing.T) { testTableIterationGrowDuplicate(t, 2*maps.MaxTableCapacity) })
556 }
557
558 func TestAlignUpPow2(t *testing.T) {
559 tests := []struct {
560 in uint64
561 want uint64
562 overflow bool
563 }{
564 {
565 in: 0,
566 want: 0,
567 },
568 {
569 in: 3,
570 want: 4,
571 },
572 {
573 in: 4,
574 want: 4,
575 },
576 {
577 in: 1 << 63,
578 want: 1 << 63,
579 },
580 {
581 in: (1 << 63) - 1,
582 want: 1 << 63,
583 },
584 {
585 in: (1 << 63) + 1,
586 overflow: true,
587 },
588 }
589
590 for _, tc := range tests {
591 got, overflow := maps.AlignUpPow2(tc.in)
592 if got != tc.want {
593 t.Errorf("alignUpPow2(%d) got %d, want %d", tc.in, got, tc.want)
594 }
595 if overflow != tc.overflow {
596 t.Errorf("alignUpPow2(%d) got overflow %v, want %v", tc.in, overflow, tc.overflow)
597 }
598 }
599 }
600
601
602 func TestMapZeroSizeSlot(t *testing.T) {
603 m, typ := maps.NewTestMap[struct{}, struct{}](16)
604
605 key := struct{}{}
606 elem := struct{}{}
607
608 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
609
610 if maps.DebugLog {
611 fmt.Printf("After put %d: %v\n", key, m)
612 }
613
614 got, ok := m.Get(typ, unsafe.Pointer(&key))
615 if !ok {
616 t.Errorf("Get(%d) got ok false want true", key)
617 }
618 gotElem := *(*struct{})(got)
619 if gotElem != elem {
620 t.Errorf("Get(%d) got elem %d want %d", key, gotElem, elem)
621 }
622
623 tab := m.TableFor(typ, unsafe.Pointer(&key))
624 start := tab.GroupsStart()
625 length := tab.GroupsLength()
626 end := unsafe.Pointer(uintptr(start) + length*typ.GroupSize - 1)
627 if uintptr(got) < uintptr(start) || uintptr(got) > uintptr(end) {
628 t.Errorf("elem address outside groups allocation; got %p want [%p, %p]", got, start, end)
629 }
630 }
631
632 func TestMapIndirect(t *testing.T) {
633 type big [abi.SwissMapMaxKeyBytes + abi.SwissMapMaxElemBytes]byte
634
635 m, typ := maps.NewTestMap[big, big](8)
636
637 key := big{}
638 elem := big{}
639 elem[0] = 128
640
641 for i := 0; i < 31; i++ {
642 key[0] += 1
643 elem[0] += 1
644 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
645
646 if maps.DebugLog {
647 fmt.Printf("After put %v: %v\n", key, m)
648 }
649 }
650
651 if m.Used() != 31 {
652 t.Errorf("Used() used got %d want 31", m.Used())
653 }
654
655 key = big{}
656 elem = big{}
657 elem[0] = 128
658
659 for i := 0; i < 31; i++ {
660 key[0] += 1
661 elem[0] += 1
662 got, ok := m.Get(typ, unsafe.Pointer(&key))
663 if !ok {
664 t.Errorf("Get(%v) got ok false want true", key)
665 }
666 gotElem := *(*big)(got)
667 if gotElem != elem {
668 t.Errorf("Get(%v) got elem %v want %v", key, gotElem, elem)
669 }
670 }
671 }
672
673
674 func TestMapDeleteClear(t *testing.T) {
675 m, typ := maps.NewTestMap[int64, int64](8)
676
677 key := int64(0)
678 elem := int64(128)
679
680 m.Put(typ, unsafe.Pointer(&key), unsafe.Pointer(&elem))
681
682 if maps.DebugLog {
683 fmt.Printf("After put %d: %v\n", key, m)
684 }
685
686 got, ok := m.Get(typ, unsafe.Pointer(&key))
687 if !ok {
688 t.Errorf("Get(%d) got ok false want true", key)
689 }
690 gotElem := *(*int64)(got)
691 if gotElem != elem {
692 t.Errorf("Get(%d) got elem %d want %d", key, gotElem, elem)
693 }
694
695 m.Delete(typ, unsafe.Pointer(&key))
696
697 gotElem = *(*int64)(got)
698 if gotElem != 0 {
699 t.Errorf("Delete(%d) failed to clear element. got %d want 0", key, gotElem)
700 }
701 }
702
View as plain text