-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlinkedhashmap.go
147 lines (126 loc) · 3.1 KB
/
linkedhashmap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Package tomtp provides a concurrent-safe linked hash map implementation.
// All exported methods are thread-safe.
package tomtp
import (
"sync"
)
// linkedHashMap is a concurrent-safe map that preserves insertion order.
type linkedHashMap[K comparable, V any] struct {
items map[K]*lhmPair[K, V]
head *lhmPair[K, V]
tail *lhmPair[K, V]
mu sync.RWMutex
}
// lhmPair represents a key-value pair in the linkedHashMap's doubly-linked list.
type lhmPair[K comparable, V any] struct {
key K
value V
prev *lhmPair[K, V]
nxt *lhmPair[K, V]
m *linkedHashMap[K, V]
}
// newLinkedHashMap creates a new empty linkedHashMap.
func newLinkedHashMap[K comparable, V any]() *linkedHashMap[K, V] {
return &linkedHashMap[K, V]{
items: make(map[K]*lhmPair[K, V]),
}
}
// Size returns the number of elements in the map.
func (m *linkedHashMap[K, V]) Size() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.items)
}
// Put adds or updates a key-value pair in the map.
// Returns true if the operation was successful, false if the value is nil.
func (m *linkedHashMap[K, V]) Put(key K, value V) *lhmPair[K, V] {
if isNil(value) {
return nil
}
m.mu.Lock()
defer m.mu.Unlock()
// Update existing value if key exists
if existing, ok := m.items[key]; ok {
existing.value = value
return existing
}
// Create and insert new pair
newPair := &lhmPair[K, V]{
key: key,
value: value,
m: m,
}
m.items[key] = newPair
// Update linked list
if m.head == nil {
m.head = newPair
m.tail = newPair
} else {
newPair.prev = m.tail
m.tail.nxt = newPair
m.tail = newPair
}
return newPair
}
// Get retrieves a value from the map.
// Returns the pair if found, nil otherwise.
func (m *linkedHashMap[K, V]) Get(key K) *lhmPair[K, V] {
m.mu.RLock()
defer m.mu.RUnlock()
return m.items[key]
}
// Remove removes a key-value pair from the map.
// Returns the removed pair if found, nil otherwise.
func (m *linkedHashMap[K, V]) Remove(key K) *lhmPair[K, V] {
m.mu.Lock()
defer m.mu.Unlock()
pair, ok := m.items[key]
if !ok {
return nil
}
// Update linked list
if pair.prev != nil {
pair.prev.nxt = pair.nxt
} else {
m.head = pair.nxt
}
if pair.nxt != nil {
pair.nxt.prev = pair.prev
} else {
m.tail = pair.prev
}
delete(m.items, key)
return pair
}
// Oldest returns the Oldest (first inserted) pair in the map.
// Returns nil if the map is empty.
func (m *linkedHashMap[K, V]) Oldest() *lhmPair[K, V] {
m.mu.RLock()
defer m.mu.RUnlock()
return m.head
}
// Next returns the Next pair in the linked list.
// Returns nil if there is no Next pair or if the pair or map is nil.
func (p *lhmPair[K, V]) Next() *lhmPair[K, V] {
if p == nil || p.m == nil {
return nil
}
p.m.mu.RLock()
defer p.m.mu.RUnlock()
return p.nxt
}
// Replace updates the key and value of an existing pair in the map.
// Does not change the prev/Next ordering.
// No effect if the pair or map is nil.
func (p *lhmPair[K, V]) Replace(key K, value V) {
if p == nil || p.m == nil {
return
}
p.m.mu.Lock()
defer p.m.mu.Unlock()
oldKey := p.key
p.key = key
p.value = value
p.m.items[key] = p
delete(p.m.items, oldKey)
}