github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/reflectmap/reflect_pointer.go (about) 1 package reflectmap 2 3 import ( 4 "reflect" 5 "unsafe" 6 ) 7 8 // only supports int for key 9 type PointerMap struct { 10 keyType reflect.Type 11 valueType reflect.Type 12 bucketType reflect.Type 13 14 tempKey reflect.Value 15 tempValue reflect.Value 16 17 bucketCount int 18 buckets reflect.Value 19 } 20 21 func NewPointerMap(key, value interface{}) *PointerMap { 22 keyType := reflect.TypeOf(key) 23 valueType := reflect.TypeOf(value) 24 bucketCount := 128 25 26 bucketType := reflect.StructOf([]reflect.StructField{ 27 reflect.StructField{ 28 Name: "Hash", 29 Type: reflect.TypeOf(hashBucket{}), 30 }, 31 reflect.StructField{ 32 Name: "Key", 33 Type: reflect.ArrayOf(bucketSize, keyType), 34 }, 35 reflect.StructField{ 36 Name: "Value", 37 Type: reflect.ArrayOf(bucketSize, valueType), 38 }, 39 }) 40 41 buckets := reflect.New(reflect.ArrayOf(bucketCount, bucketType)) 42 return &PointerMap{ 43 keyType: keyType, 44 valueType: valueType, 45 bucketType: bucketType, 46 47 tempKey: reflect.NewAt(keyType, nil), 48 tempValue: reflect.NewAt(valueType, nil), 49 50 bucketCount: bucketCount, 51 buckets: buckets, 52 } 53 } 54 55 func (m *PointerMap) Add(key, value unsafe.Pointer) { 56 // hack to avoid figuring out a hash function 57 keyi := *(*int)(key) 58 59 bucketi := keyi % m.bucketCount 60 tophash := byte(keyi) 61 if tophash == 0 { 62 tophash = 1 63 } 64 65 bucket := m.buckets.Elem().Index(bucketi) 66 hashesField := bucket.Field(0) 67 keys := bucket.Field(1) 68 values := bucket.Field(2) 69 70 hashes := hashesField.Addr().Interface().(*hashBucket) 71 for i, v := range *hashes { 72 if v == 0 { 73 (*hashes)[i] = tophash 74 (*reflectvalue)(unsafe.Pointer(&m.tempKey)).ptr = key 75 keys.Index(i).Set(m.tempKey.Elem()) 76 (*reflectvalue)(unsafe.Pointer(&m.tempValue)).ptr = value 77 values.Index(i).Set(m.tempValue.Elem()) 78 return 79 } 80 } 81 82 i := 0 83 (*hashes)[i] = tophash 84 (*reflectvalue)(unsafe.Pointer(&m.tempKey)).ptr = key 85 keys.Index(i).Set(m.tempKey.Elem()) 86 (*reflectvalue)(unsafe.Pointer(&m.tempValue)).ptr = value 87 values.Index(i).Set(m.tempValue.Elem()) 88 }