github.com/leslie-fei/fastcache@v0.0.0-20240520092641-b7a9eb05711f/hashmap_bucket.go (about)

     1  package fastcache
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  )
     7  
     8  type hashMapBucket struct {
     9  	len    uint32
    10  	offset uint64 // hashMapBucketElement linkedNode offset
    11  }
    12  
    13  func (l *hashMapBucket) Add(base uintptr, node *DataNode) {
    14  	// 更新list链表, 头插法
    15  	next := l.offset
    16  	// 把item的头指针指向当前的listElNode
    17  	l.offset = node.Offset(base)
    18  	// 更新next
    19  	node.Next = next
    20  	// hashed array len + 1
    21  	l.len++
    22  }
    23  
    24  func (l *hashMapBucket) Del(prevNode *DataNode, findNode *DataNode) error {
    25  	// not found
    26  	if findNode == nil {
    27  		return ErrNotFound
    28  	}
    29  
    30  	if prevNode == nil {
    31  		// 就说明这个是头节点, 需要更新list的头节点指向
    32  		l.offset = findNode.Next
    33  	} else {
    34  		prevNode.Next = findNode.Next
    35  	}
    36  
    37  	l.len--
    38  	// list中没有任何element, 就把head offset = 0
    39  	if l.len == 0 {
    40  		l.offset = 0
    41  	}
    42  
    43  	return nil
    44  }
    45  
    46  func (l *hashMapBucket) Reset() {
    47  	l.len = 0
    48  	l.offset = 0
    49  }
    50  
    51  func (l *hashMapBucket) FindNode(base uintptr, key string) (prevNode *DataNode, findNode *DataNode, findEl *hashMapBucketElement) {
    52  	if l.len == 0 {
    53  		return nil, nil, nil
    54  	}
    55  
    56  	offset := l.offset
    57  	for i := 0; i < int(l.len); i++ {
    58  		node := ToDataNode(base, offset)
    59  		el := NodeTo[hashMapBucketElement](node)
    60  		if el.Equals(key) {
    61  			findNode = node
    62  			findEl = el
    63  			return
    64  		}
    65  		prevNode = node
    66  		offset = node.Next
    67  	}
    68  
    69  	return
    70  }
    71  
    72  // hashMapBucketElement key DataNode string + val DataNode []byte
    73  type hashMapBucketElement struct {
    74  	lruNode listNode
    75  	keyLen  uint32 // key length
    76  	valLen  uint32 // val length
    77  }
    78  
    79  func (l *hashMapBucketElement) Equals(key string) bool {
    80  	if l.keyLen != uint32(len(key)) {
    81  		return false
    82  	}
    83  	keyPtr := uintptr(unsafe.Pointer(l)) + sizeOfHashmapBucketElement
    84  	kh := (*reflect.StringHeader)(unsafe.Pointer(&key))
    85  	return memequal(unsafe.Pointer(keyPtr), unsafe.Pointer(kh.Data), uintptr(len(key)))
    86  }
    87  
    88  func (l *hashMapBucketElement) UpdateValue(value []byte) {
    89  	valPtr := uintptr(unsafe.Pointer(l)) + sizeOfHashmapBucketElement + uintptr(l.keyLen)
    90  	bh := (*reflect.SliceHeader)(unsafe.Pointer(&value))
    91  	memmove(unsafe.Pointer(valPtr), unsafe.Pointer(bh.Data), uintptr(len(value)))
    92  	l.valLen = uint32(len(value))
    93  }
    94  
    95  func (l *hashMapBucketElement) Value() []byte {
    96  	valPtr := uintptr(unsafe.Pointer(l)) + sizeOfHashmapBucketElement + uintptr(l.keyLen)
    97  	var ss []byte
    98  	sh := (*reflect.SliceHeader)(unsafe.Pointer(&ss))
    99  	sh.Data = valPtr
   100  	sh.Len = int(l.valLen)
   101  	sh.Cap = sh.Len
   102  	return ss
   103  }
   104  
   105  func hashmapElementSize(key string, value []byte) uint64 {
   106  	return uint64(sizeOfHashmapBucketElement) + uint64(len(key)) + uint64(len(value))
   107  }