github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/reflectmap/reflect_interface.go (about)

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