-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmap.go
More file actions
176 lines (151 loc) · 4.13 KB
/
map.go
File metadata and controls
176 lines (151 loc) · 4.13 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Package genericmap provides a thread-safe, generic bidirectional map implementation.
// It supports efficient forward lookups (key->value) and reverse lookups (value->keys).
package genericmap
import (
"fmt"
"sync"
)
// Map is a thread-safe, generic map with bidirectional lookup capabilities.
// It supports both key-to-value and value-to-keys operations efficiently.
type Map[K comparable, V comparable] struct {
data map[K]V
reverseMap map[V]map[K]struct{}
mu sync.RWMutex
}
// New creates a new generic map with optional initial data.
//
// Examples:
//
// // Create empty map
// m := New[string, int]()
//
// // Create with initial data
// initial := map[string]int{"a": 1, "b": 2}
// m := New[string, int](initial)
func New[K comparable, V comparable](initialData ...map[K]V) *Map[K, V] {
m := &Map[K, V]{
data: make(map[K]V),
reverseMap: make(map[V]map[K]struct{}),
}
// Populate with initial data if provided
if len(initialData) > 0 {
for _, dataMap := range initialData {
for k, v := range dataMap {
m.data[k] = v
if m.reverseMap[v] == nil {
m.reverseMap[v] = make(map[K]struct{})
}
m.reverseMap[v][k] = struct{}{}
}
}
}
return m
}
// NewWithCapacity creates a new generic map with specified initial capacity.
// This can improve performance when the expected size is known in advance.
func NewWithCapacity[K comparable, V comparable](capacity int) *Map[K, V] {
return &Map[K, V]{
data: make(map[K]V, capacity),
reverseMap: make(map[V]map[K]struct{}, capacity),
}
}
// Set adds or updates a key-value pair in the map.
func (m *Map[K, V]) Set(key K, value V) {
m.mu.Lock()
defer m.mu.Unlock()
// Single lookup to check existing value
oldValue, exists := m.data[key]
if exists && oldValue == value {
return // No-op if key already has this value
}
// Remove key from old value's reverse map if key exists
if exists {
m.removeFromReverseMap(key, oldValue)
}
// Add to data and reverse maps
m.data[key] = value
if m.reverseMap[value] == nil {
m.reverseMap[value] = make(map[K]struct{})
}
m.reverseMap[value][key] = struct{}{}
}
// Get retrieves the value associated with the key.
// Returns the value and a boolean indicating if the key exists.
func (m *Map[K, V]) Get(key K) (V, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
val, ok := m.data[key]
return val, ok
}
// GetKeys retrieves all keys associated with a given value.
// Returns a slice of keys that map to the specified value.
func (m *Map[K, V]) GetKeys(value V) []K {
m.mu.RLock()
defer m.mu.RUnlock()
if keyMap, ok := m.reverseMap[value]; ok {
result := make([]K, 0, len(keyMap))
for key := range keyMap {
result = append(result, key)
}
return result
}
return []K{}
}
// List returns all keys in the map.
func (m *Map[K, V]) List() []K {
m.mu.RLock()
defer m.mu.RUnlock()
keys := make([]K, len(m.data))
i := 0
for k := range m.data {
keys[i] = k
i++
}
return keys
}
// Values returns all values in the map.
func (m *Map[K, V]) Values() []V {
m.mu.RLock()
defer m.mu.RUnlock()
values := make([]V, len(m.data))
i := 0
for _, v := range m.data {
values[i] = v
i++
}
return values
}
// Remove removes a key-value pair from the map.
// Returns true if the key existed and was removed, false otherwise.
func (m *Map[K, V]) Remove(key K) bool {
m.mu.Lock()
defer m.mu.Unlock()
if value, exists := m.data[key]; exists {
delete(m.data, key)
m.removeFromReverseMap(key, value)
return true
}
return false
}
// Len returns the number of key-value pairs in the map.
func (m *Map[K, V]) Len() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.data)
}
// String returns a string representation of the map.
func (m *Map[K, V]) String() string {
m.mu.RLock()
defer m.mu.RUnlock()
return fmt.Sprintf("Map[%d]{%v}", len(m.data), m.data)
}
// removeFromReverseMap removes a key from the reverse map for a given value.
// This is an internal method and assumes the caller holds the appropriate lock.
func (m *Map[K, V]) removeFromReverseMap(key K, value V) {
if keyMap, exists := m.reverseMap[value]; exists {
delete(keyMap, key)
if len(keyMap) == 0 {
delete(m.reverseMap, value)
}
}
}