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  }