github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/dump/test/map_test.go (about) 1 package test 2 3 import ( 4 "testing" 5 "github.com/v2pro/plz/test" 6 "github.com/v2pro/plz/countlog" 7 "github.com/v2pro/plz/test/must" 8 "github.com/v2pro/plz/dump" 9 "reflect" 10 "fmt" 11 "unsafe" 12 ) 13 14 type nameOff int32 // offset to a name 15 type typeOff int32 // offset to an *rtype 16 type textOff int32 // offset from top of text section 17 18 // a copy of runtime.typeAlg 19 type typeAlg struct { 20 // function for hashing objects of this type 21 // (ptr to object, seed) -> hash 22 hash func(unsafe.Pointer, uintptr) uintptr 23 // function for comparing objects of this type 24 // (ptr to object A, ptr to object B) -> ==? 25 equal func(unsafe.Pointer, unsafe.Pointer) bool 26 } 27 28 // tflag is used by an rtype to signal what extra type information is 29 // available in the memory directly following the rtype value. 30 // 31 // tflag values must be kept in sync with copies in: 32 // cmd/compile/internal/gc/reflect.go 33 // cmd/link/internal/ld/decodesym.go 34 // runtime/type.go 35 type tflag uint8 36 37 // rtype is the common implementation of most values. 38 // It is embedded in other, public struct types, but always 39 // with a unique tag like `reflect:"array"` or `reflect:"ptr"` 40 // so that code cannot convert from, say, *arrayType to *ptrType. 41 // 42 // rtype must be kept in sync with ../runtime/type.go:/^type._type. 43 type rtype struct { 44 size uintptr 45 ptrdata uintptr // number of bytes in the type that can contain pointers 46 hash uint32 // hash of type; avoids computation in hash tables 47 tflag tflag // extra type information flags 48 align uint8 // alignment of variable with this type 49 fieldAlign uint8 // alignment of struct field with this type 50 kind uint8 // enumeration for C 51 alg *typeAlg // algorithm table 52 gcdata *byte // garbage collection data 53 str nameOff // string form 54 ptrToThis typeOff // type for pointer to this type, may be zero 55 } 56 57 type iface struct { 58 itab unsafe.Pointer 59 data unsafe.Pointer 60 } 61 62 // mapType represents a map type. 63 type mapType struct { 64 rtype `reflect:"map"` 65 key *rtype // map key type 66 elem *rtype // map element (value) type 67 bucket *rtype // internal bucket structure 68 hmap *rtype // internal map header 69 keysize uint8 // size of key slot 70 indirectkey uint8 // store ptr to key instead of key itself 71 valuesize uint8 // size of value slot 72 indirectvalue uint8 // store ptr to value instead of value itself 73 bucketsize uint16 // size of bucket 74 reflexivekey bool // true if k==k for all keys 75 needkeyupdate bool // true if we need to update key on an overwrite 76 } 77 78 func Test_map(t *testing.T) { 79 t.Run("map int to int", test.Case(func(ctx *countlog.Context) { 80 must.JsonEqual(`{ 81 "__root__": { 82 "type": "map[int]int", 83 "data": { 84 "__ptr__": "{ptr1}" 85 } 86 }, 87 "{ptr1}": { 88 "count": 2, 89 "flags": 0, 90 "B": 0, 91 "noverflow": 0, 92 "hash0": "{ANYTHING}", 93 "buckets": {"__ptr__":"{ptr2}"}, 94 "oldbuckets": {"__ptr__":"0"}, 95 "nevacuate": 0, 96 "extra": {"__ptr__":"0"} 97 }, 98 "{ptr2}": [{ 99 "tophash": "{ANYTHING}", 100 "keys": [9,8,0,0,0,0,0,0], 101 "elems": [7,6,0,0,0,0,0,0] 102 }]}`, dump.Var{map[int]int{ 103 9: 7, 104 8: 6, 105 }}.String()) 106 })) 107 t.Run("map string to string", test.Case(func(ctx *countlog.Context) { 108 must.JsonEqual(`{ 109 "__root__": { 110 "type": "map[string]string", 111 "data": { 112 "__ptr__": "{ptr1}" 113 } 114 }, 115 "{ptr1}": { 116 "count": 2, 117 "flags": 0, 118 "B": 0, 119 "noverflow": 0, 120 "hash0": "{ANYTHING}", 121 "buckets": {"__ptr__":"{ptr2}"}, 122 "oldbuckets": {"__ptr__":"0"}, 123 "nevacuate": 0, 124 "extra": {"__ptr__":"0"} 125 }, 126 "{ptr2}": [{ 127 "tophash": "{ANYTHING}", 128 "keys": [ 129 {"data":{"__ptr__":"{key1}"},"len":1}, 130 {"data":{"__ptr__":"{key2}"},"len":1}, 131 {"data":{"__ptr__":"0"},"len":0}, 132 {"data":{"__ptr__":"0"},"len":0}, 133 {"data":{"__ptr__":"0"},"len":0}, 134 {"data":{"__ptr__":"0"},"len":0}, 135 {"data":{"__ptr__":"0"},"len":0}, 136 {"data":{"__ptr__":"0"},"len":0} 137 ], 138 "elems": [ 139 {"data":{"__ptr__":"{elem1}"},"len":1}, 140 {"data":{"__ptr__":"{elem2}"},"len":1}, 141 {"data":{"__ptr__":"0"},"len":0}, 142 {"data":{"__ptr__":"0"},"len":0}, 143 {"data":{"__ptr__":"0"},"len":0}, 144 {"data":{"__ptr__":"0"},"len":0}, 145 {"data":{"__ptr__":"0"},"len":0}, 146 {"data":{"__ptr__":"0"},"len":0} 147 ] 148 }], 149 "{key1}":"a", 150 "{key2}":"c", 151 "{elem1}":"b", 152 "{elem2}":"d" 153 }`, dump.Var{map[string]string{ 154 "a": "b", 155 "c": "d", 156 }}.String()) 157 })) 158 t.Run("map type", test.Case(func(ctx *countlog.Context) { 159 m := map[int]*int{} 160 mType := reflect.TypeOf(m) 161 mIFace := (*iface)(unsafe.Pointer(&mType)) 162 mapType := (*mapType)(mIFace.data) 163 fmt.Println(mapType.bucket.ptrdata) 164 })) 165 }