| | |
| | |
| | |
| |
|
| | package maps |
| |
|
| | import ( |
| | "internal/abi" |
| | "unsafe" |
| | ) |
| |
|
| | const debugLog = false |
| |
|
| | func (t *table) checkInvariants(typ *abi.MapType, m *Map) { |
| | if !debugLog { |
| | return |
| | } |
| |
|
| | |
| | |
| | var used uint16 |
| | var deleted uint16 |
| | var empty uint16 |
| | for i := uint64(0); i <= t.groups.lengthMask; i++ { |
| | g := t.groups.group(typ, i) |
| | for j := uintptr(0); j < abi.MapGroupSlots; j++ { |
| | c := g.ctrls().get(j) |
| | switch { |
| | case c == ctrlDeleted: |
| | deleted++ |
| | case c == ctrlEmpty: |
| | empty++ |
| | default: |
| | used++ |
| |
|
| | key := g.key(typ, j) |
| | if typ.IndirectKey() { |
| | key = *((*unsafe.Pointer)(key)) |
| | } |
| |
|
| | |
| | |
| | if !typ.Key.Equal(key, key) { |
| | continue |
| | } |
| |
|
| | if _, ok := t.Get(typ, m, key); !ok { |
| | hash := typ.Hasher(key, m.seed) |
| | print("invariant failed: slot(", i, "/", j, "): key ") |
| | dump(key, typ.Key.Size_) |
| | print(" not found [hash=", hash, ", h2=", h2(hash), " h1=", h1(hash), "]\n") |
| | t.Print(typ, m) |
| | panic("invariant failed: slot: key not found") |
| | } |
| | } |
| | } |
| | } |
| |
|
| | if used != t.used { |
| | print("invariant failed: found ", used, " used slots, but used count is ", t.used, "\n") |
| | t.Print(typ, m) |
| | panic("invariant failed: found mismatched used slot count") |
| | } |
| |
|
| | growthLeft := (t.capacity*maxAvgGroupLoad)/abi.MapGroupSlots - t.used - deleted |
| | if growthLeft != t.growthLeft { |
| | print("invariant failed: found ", t.growthLeft, " growthLeft, but expected ", growthLeft, "\n") |
| | t.Print(typ, m) |
| | panic("invariant failed: found mismatched growthLeft") |
| | } |
| | if deleted != t.tombstones() { |
| | print("invariant failed: found ", deleted, " tombstones, but expected ", t.tombstones(), "\n") |
| | t.Print(typ, m) |
| | panic("invariant failed: found mismatched tombstones") |
| | } |
| |
|
| | if empty == 0 { |
| | print("invariant failed: found no empty slots (violates probe invariant)\n") |
| | t.Print(typ, m) |
| | panic("invariant failed: found no empty slots (violates probe invariant)") |
| | } |
| | } |
| | func (t *table) Print(typ *abi.MapType, m *Map) { |
| | print(`table{ |
| | index: `, t.index, ` |
| | localDepth: `, t.localDepth, ` |
| | capacity: `, t.capacity, ` |
| | used: `, t.used, ` |
| | growthLeft: `, t.growthLeft, ` |
| | groups: |
| | `) |
| |
|
| | for i := uint64(0); i <= t.groups.lengthMask; i++ { |
| | print("\t\tgroup ", i, "\n") |
| |
|
| | g := t.groups.group(typ, i) |
| | ctrls := g.ctrls() |
| | for j := uintptr(0); j < abi.MapGroupSlots; j++ { |
| | print("\t\t\tslot ", j, "\n") |
| |
|
| | c := ctrls.get(j) |
| | print("\t\t\t\tctrl ", c) |
| | switch c { |
| | case ctrlEmpty: |
| | print(" (empty)\n") |
| | case ctrlDeleted: |
| | print(" (deleted)\n") |
| | default: |
| | print("\n") |
| | } |
| |
|
| | print("\t\t\t\tkey ") |
| | dump(g.key(typ, j), typ.Key.Size_) |
| | println("") |
| | print("\t\t\t\telem ") |
| | dump(g.elem(typ, j), typ.Elem.Size_) |
| | println("") |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | func dump(ptr unsafe.Pointer, size uintptr) { |
| | for size > 0 { |
| | print(*(*byte)(ptr), " ") |
| | ptr = unsafe.Pointer(uintptr(ptr) + 1) |
| | size-- |
| | } |
| | } |
| |
|