-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathordered_map.go
More file actions
151 lines (132 loc) · 3.32 KB
/
Copy pathordered_map.go
File metadata and controls
151 lines (132 loc) · 3.32 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
package structx
import (
"github.com/lif0/pkg/structx/internal"
)
type kv[K any, V any] struct {
K K
V V
}
// OrderedMap is a map[Type]Type1-like collection that preserves the order
// in which keys were inserted. It behaves like a regular map but
// allows deterministic iteration over its elements.
//
// OrderedMap is useful when both quick key-based access and
// predictable iteration order are desired.
type OrderedMap[K comparable, V any] struct {
dict map[K]*internal.ChainLink[kv[K, V]]
list internal.Chain[kv[K, V]]
objPool *ObjectPool[internal.ChainLink[kv[K, V]]]
}
// NewOrderedMap returns a new empty OrderedMap.
func NewOrderedMap[K comparable, V any](size ...uint32) *OrderedMap[K, V] {
var capacity uint32
if len(size) > 0 && size[0] > 0 {
capacity = size[0]
}
return &OrderedMap[K, V]{
dict: make(map[K]*internal.ChainLink[kv[K, V]], capacity),
list: internal.Chain[kv[K, V]]{},
objPool: NewObjectPool[internal.ChainLink[kv[K, V]]](capacity),
}
}
// Get retrieves the value stored under the given key.
// The second return value reports whether the key was present.
//
// Complexity:
// - time: O(1)
// - mem: O(1)
func (m *OrderedMap[K, V]) Get(key K) (V, bool) {
if node, ok := m.dict[key]; ok {
return node.Val.V, true
}
var zeroVal V
return zeroVal, false
}
// Put sets the value for the given key.
// If the key already exists, its value is updated.
// Otherwise, a new entry is added to the end of the order.
//
// Complexity:
// - time: O(1)
// - mem: O(1)
func (m *OrderedMap[K, V]) Put(key K, value V) {
if node, ok := m.dict[key]; ok {
node.Val.V = value
} else {
node = m.objPool.Get() // &internal.Node[kv[K,V]]{Val: value}
node.Val.K = key
node.Val.V = value
node.Prev = nil // overcautiousness
node.Next = nil // overcautiousness
m.list.Append(node)
m.dict[key] = node
}
}
// Delete removes the element with the specified key.
// If the key does not exist, Delete does nothing.
//
// Complexity:
// - time: O(1)
// - mem: O(1)
func (m *OrderedMap[K, V]) Delete(key K) {
Delete(m, key)
}
// GetValues returns all values in insertion order.
// The returned slice has the same length as the number of elements.
//
// Complexity:
// - time: O(N)
// - mem: O(N)
func (m *OrderedMap[K, V]) GetValues() []V {
result := make([]V, m.list.Len())
if cap(result) == 0 {
return result
}
if cap(result) == 1 {
result[0] = m.list.GetHead().Val.V
}
for i, v := range m.list.Iter() {
result[i] = v.V
}
return result
}
// Iter iteration on map in insertion order
//
// Example:
//
// m := NewOrderedMap[int, string]()
//
// for k, v := range m.Iter() {
// fmt.Println(k,v)
// }
func (m *OrderedMap[K, V]) Iter() func(func(K, V) bool) {
return func(yield func(K, V) bool) {
h := m.list.GetHead()
for n := h; n != nil; n = n.Next {
if !yield(n.Val.K, n.Val.V) {
return
}
}
}
}
// Delete built-in function deletes the element with the specified key
// (m[key]) from the OrderedMap. If m is nil or there is no such element, delete
// is a no-op.
//
// Example:
//
// var om = NewOrderedMap[string, int]()
// om.Put("x", 1)
// structx.Delete(om, "x")
func Delete[Type comparable, Type1 any](m *OrderedMap[Type, Type1], key Type) {
if m == nil {
return
}
if m.list.Len() == 0 {
return
}
if node, ok := m.dict[key]; ok {
m.list.Remove(node)
delete(m.dict, key)
}
}