-
Notifications
You must be signed in to change notification settings - Fork 42
/
orderedmap.go
167 lines (149 loc) · 4.96 KB
/
orderedmap.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package hjson
import (
"bytes"
"encoding/json"
)
// OrderedMap wraps a map and a slice containing all of the keys from the map,
// so that the order of the keys can be specified. The Keys slice can be sorted
// or rearranged like any other slice, but do not add or remove keys manually
// on it. Use OrderedMap.Insert(), OrderedMap.Set(), OrderedMap.DeleteIndex() or
// OrderedMap.DeleteKey() instead.
//
// Example of how to iterate through the elements of an OrderedMap in order:
//
// for _, key := range om.Keys {
// fmt.Printf("%v\n", om.Map[key])
// }
//
// Always use the functions Insert() or Set() instead of setting values
// directly on OrderedMap.Map, because any new keys must also be added to
// OrderedMap.Keys. Otherwise those keys will be ignored when iterating through
// the elements of the OrderedMap in order, as for example happens in the
// function hjson.Marshal().
type OrderedMap struct {
Keys []string
Map map[string]interface{}
}
// KeyValue is only used as input to NewOrderedMapFromSlice().
type KeyValue struct {
Key string
Value interface{}
}
// NewOrderedMap returns a pointer to a new OrderedMap. An OrderedMap should
// always be passed by reference, never by value. If an OrderedMap is passed
// by value then appending new keys won't affect all of the copies of the
// OrderedMap.
func NewOrderedMap() *OrderedMap {
return &OrderedMap{
Keys: nil,
Map: map[string]interface{}{},
}
}
// NewOrderedMapFromSlice is like NewOrderedMap but with initial values.
// Example:
//
// om := NewOrderedMapFromSlice([]KeyValue{
// {"B", "first"},
// {"A", "second"},
// })
func NewOrderedMapFromSlice(args []KeyValue) *OrderedMap {
c := NewOrderedMap()
for _, elem := range args {
c.Set(elem.Key, elem.Value)
}
return c
}
// Len returns the number of values contained in the OrderedMap.
func (c *OrderedMap) Len() int {
return len(c.Keys)
}
// AtIndex returns the value found at the specified index. Panics if
// index < 0 or index >= c.Len().
func (c *OrderedMap) AtIndex(index int) interface{} {
return c.Map[c.Keys[index]]
}
// AtKey returns the value found for the specified key, and true if the value
// was found. Returns nil and false if the value was not found.
func (c *OrderedMap) AtKey(key string) (interface{}, bool) {
ret, ok := c.Map[key]
return ret, ok
}
// Insert inserts a new key/value pair at the specified index. Panics if
// index < 0 or index > c.Len(). If the key already exists in the OrderedMap,
// the new value is set but the position of the key is not changed. Returns
// the old value and true if the key already exists in the OrderedMap, nil and
// false otherwise.
func (c *OrderedMap) Insert(index int, key string, value interface{}) (interface{}, bool) {
oldValue, exists := c.Map[key]
c.Map[key] = value
if exists {
return oldValue, true
}
if index == len(c.Keys) {
c.Keys = append(c.Keys, key)
} else {
c.Keys = append(c.Keys[:index+1], c.Keys[index:]...)
c.Keys[index] = key
}
return nil, false
}
// Set sets the specified value for the specified key. If the key does not
// already exist in the OrderedMap it is appended to the end of the OrderedMap.
// If the key already exists in the OrderedMap, the new value is set but the
// position of the key is not changed. Returns the old value and true if the
// key already exists in the OrderedMap, nil and false otherwise.
func (c *OrderedMap) Set(key string, value interface{}) (interface{}, bool) {
return c.Insert(len(c.Keys), key, value)
}
// DeleteIndex deletes the key/value pair found at the specified index.
// Returns the deleted key and value. Panics if index < 0 or index >= c.Len().
func (c *OrderedMap) DeleteIndex(index int) (string, interface{}) {
key := c.Keys[index]
value := c.Map[key]
delete(c.Map, key)
c.Keys = append(c.Keys[:index], c.Keys[index+1:]...)
return key, value
}
// DeleteKey deletes the key/value pair with the specified key, if found.
// Returns the deleted value and true if the key was found, nil and false
// otherwise.
func (c *OrderedMap) DeleteKey(key string) (interface{}, bool) {
for index, ck := range c.Keys {
if ck == key {
_, value := c.DeleteIndex(index)
return value, true
}
}
return nil, false
}
// MarshalJSON is an implementation of the json.Marshaler interface, enabling
// hjson.OrderedMap to be used as input for json.Marshal().
func (c *OrderedMap) MarshalJSON() ([]byte, error) {
var b bytes.Buffer
b.WriteString("{")
for index, key := range c.Keys {
if index > 0 {
b.WriteString(",")
}
jbuf, err := json.Marshal(key)
if err != nil {
return nil, err
}
b.Write(jbuf)
b.WriteString(":")
jbuf, err = json.Marshal(c.Map[key])
if err != nil {
return nil, err
}
b.Write(jbuf)
}
b.WriteString("}")
return b.Bytes(), nil
}
// UnmarshalJSON is an implementation of the json.Unmarshaler interface,
// enabling hjson.OrderedMap to be used as destination for json.Unmarshal().
func (c *OrderedMap) UnmarshalJSON(b []byte) error {
c.Keys = nil
c.Map = map[string]interface{}{}
return Unmarshal(b, c)
}