Files
bl/common/utils/emap.go

208 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package utils
import (
"fmt"
"hash/maphash"
"sync"
)
// 泛型有序Map的实现结合了SliceMap的并发安全和orderedMap的有序性及高效查找
// MapEntry 表示Map中的一个键值对条目
type MapEntry[K comparable, V any] struct {
key K
value V
// 用于维护插入顺序的双向链表指针
prev, next *MapEntry[K, V]
// 用于哈希表碰撞处理的链表指针
hashNext *MapEntry[K, V]
// 标记是否被删除
deleted bool
}
// OrderedMap 是一个泛型的有序Map实现
type OrderedMap[K comparable, V any] struct {
mu sync.RWMutex // 并发安全锁
hash *maphash.Hash // 哈希计算器
hashTable map[uint64]*MapEntry[K, V] // 哈希表,用于快速查找
first *MapEntry[K, V] // 双向链表头,维护插入顺序
last *MapEntry[K, V] // 双向链表尾,维护插入顺序
size int // 当前元素数量(排除已删除的)
}
// NewOrderedMap 创建一个新的泛型有序Map
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
return &OrderedMap[K, V]{
hash: &maphash.Hash{},
hashTable: make(map[uint64]*MapEntry[K, V]),
}
}
// 计算键的哈希值
func (m *OrderedMap[K, V]) hashKey(key K) uint64 {
// 这里简化实现实际使用中可能需要根据K的类型做特殊处理
// 对于基本类型可以直接写入,复杂类型可能需要序列化
m.hash.Reset()
// 注意实际使用时需要根据K的具体类型实现正确的哈希计算
// 这里只是示例,可能需要调整
m.hash.WriteString(fmt.Sprintf("%v", key))
return m.hash.Sum64()
}
// 查找键对应的条目
func (m *OrderedMap[K, V]) lookup(key K) (hash uint64, entry, prevEntry *MapEntry[K, V]) {
hash = m.hashKey(key)
for entry = m.hashTable[hash]; entry != nil; prevEntry, entry = entry, entry.hashNext {
if !entry.deleted && entry.key == key {
break
}
}
return
}
// Store 存储键值对,如果键已存在则更新值
func (m *OrderedMap[K, V]) Store(key K, value V) {
m.mu.Lock()
defer m.mu.Unlock()
hash, entry, prevEntry := m.lookup(key)
if entry != nil {
// 键已存在,更新值并确保标记为未删除
entry.value = value
if entry.deleted {
entry.deleted = false
m.size++
}
return
}
// 创建新条目
entry = &MapEntry[K, V]{
key: key,
value: value,
}
// 添加到哈希表
if prevEntry == nil {
m.hashTable[hash] = entry
} else {
prevEntry.hashNext = entry
}
// 添加到双向链表末尾以保持插入顺序
if m.last != nil {
entry.prev = m.last
m.last.next = entry
} else {
// 第一个元素
m.first = entry
}
m.last = entry
m.size++
}
// Load 查找并返回键对应的值如果不存在则返回零值和false
func (m *OrderedMap[K, V]) Load(key K) (value V, exists bool) {
m.mu.RLock()
defer m.mu.RUnlock()
_, entry, _ := m.lookup(key)
if entry != nil && !entry.deleted {
return entry.value, true
}
return value, false
}
// LoadOrStore 查找并返回键对应的值,如果不存在则存储并返回给定值
func (m *OrderedMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
m.mu.Lock()
defer m.mu.Unlock()
_, entry, _ := m.lookup(key)
if entry != nil && !entry.deleted {
return entry.value, true
}
// 执行存储操作
hash := m.hashKey(key)
entry = &MapEntry[K, V]{
key: key,
value: value,
}
// 添加到哈希表
if m.hashTable[hash] == nil {
m.hashTable[hash] = entry
} else {
// 处理哈希冲突
last := m.hashTable[hash]
for last.hashNext != nil {
last = last.hashNext
}
last.hashNext = entry
}
// 添加到双向链表
if m.last != nil {
entry.prev = m.last
m.last.next = entry
} else {
m.first = entry
}
m.last = entry
m.size++
return value, false
}
// Delete 标记删除指定的键
func (m *OrderedMap[K, V]) Delete(key K) {
m.mu.Lock()
defer m.mu.Unlock()
_, entry, _ := m.lookup(key)
if entry != nil && !entry.deleted {
entry.deleted = true
m.size--
}
}
// Range 按插入顺序迭代Map中的所有键值对
// 如果f返回false则停止迭代
func (m *OrderedMap[K, V]) Range(f func(key K, value V) bool) {
m.mu.RLock()
defer m.mu.RUnlock()
current := m.first
for current != nil {
if !current.deleted {
if !f(current.key, current.value) {
return
}
}
current = current.next
}
}
// Len 返回当前Map中的元素数量排除已删除的
func (m *OrderedMap[K, V]) Len() int {
m.mu.RLock()
defer m.mu.RUnlock()
return m.size
}
// Clear 清空Map中的所有元素
func (m *OrderedMap[K, V]) Clear() {
m.mu.Lock()
defer m.mu.Unlock()
// 重置所有指针和计数器
m.first = nil
m.last = nil
m.hashTable = make(map[uint64]*MapEntry[K, V])
m.size = 0
}