-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathassoc.go
164 lines (143 loc) · 4.61 KB
/
assoc.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
// This file defines an AWK-like associative array, ValueArray.
package awk
import (
"strings"
)
// A ValueArray maps Values to Values.
type ValueArray struct {
script *Script // Pointer to the script that produced this value
data map[string]*Value // The associative array proper
}
// NewValueArray creates and returns an associative array of Values.
func (s *Script) NewValueArray() *ValueArray {
return &ValueArray{
script: s,
data: make(map[string]*Value),
}
}
// Set (index, value) assigns a Value to an index of a ValueArray. Multiple
// indexes can be specified to simulate multidimensional arrays. (In fact, the
// indexes are concatenated into a single string with intervening Script.SubSep
// characters.) The final argument is always the value to assign. Arguments
// can be provided either as Values or as any types that can be converted to
// Values.
func (va *ValueArray) Set(args ...interface{}) {
// Ensure we were given at least one index and a value.
if len(args) < 2 {
panic("ValueArray.Set requires at least one index and one value")
}
// Convert each argument to a Value.
argVals := make([]*Value, len(args))
for i, arg := range args {
v, ok := arg.(*Value)
if !ok {
v = va.script.NewValue(arg)
}
argVals[i] = v
}
// Handle the most common case: one index and one value.
if len(args) == 2 {
va.data[argVals[0].String()] = argVals[1]
return
}
// Merge the indexes into a single string.
idxStrs := make([]string, len(argVals)-1)
for i, v := range argVals[:len(argVals)-1] {
idxStrs[i] = v.String()
}
idx := strings.Join(idxStrs, va.script.SubSep)
// Associate the final argument with the index string.
va.data[idx] = argVals[len(argVals)-1]
}
// Get returns the Value associated with a given index into a ValueArray.
// Multiple indexes can be specified to simulate multidimensional arrays. (In
// fact, the indexes are concatenated into a single string with intervening
// Script.SubSep characters.) The arguments can be provided either as Values
// or as any types that can be converted to Values. If the index doesn't
// appear in the array, a zero value is returned.
func (va *ValueArray) Get(args ...interface{}) *Value {
// Ensure we were given at least one index.
if len(args) < 1 {
panic("ValueArray.Get requires at least one index")
}
// Convert each argument to a Value.
argVals := make([]*Value, len(args))
for i, arg := range args {
v, ok := arg.(*Value)
if !ok {
v = va.script.NewValue(arg)
}
argVals[i] = v
}
// Handle the most common case: a single index.
if len(args) == 1 {
vv, found := va.data[argVals[0].String()]
if !found {
return va.script.NewValue("")
}
return vv
}
// Merge the indexes into a single string.
idxStrs := make([]string, len(argVals))
for i, v := range argVals {
idxStrs[i] = v.String()
}
idx := strings.Join(idxStrs, va.script.SubSep)
// Look up the index in the associative array.
vv, found := va.data[idx]
if !found {
return va.script.NewValue("")
}
return vv
}
// Delete deletes a key and associated value from a ValueArray. Multiple
// indexes can be specified to simulate multidimensional arrays. (In fact, the
// indexes are concatenated into a single string with intervening Script.SubSep
// characters.) The arguments can be provided either as Values or as any types
// that can be converted to Values. If no argument is provided, the entire
// ValueArray is emptied.
func (va *ValueArray) Delete(args ...interface{}) {
// If we were given no arguments, delete the entire array.
if args == nil {
va.data = make(map[string]*Value)
return
}
// Convert each argument to a Value.
argVals := make([]*Value, len(args))
for i, arg := range args {
v, ok := arg.(*Value)
if !ok {
v = va.script.NewValue(arg)
}
argVals[i] = v
}
// Handle the most common case: a single index.
if len(args) == 1 {
delete(va.data, argVals[0].String())
return
}
// Merge the indexes into a single string.
idxStrs := make([]string, len(argVals))
for i, v := range argVals {
idxStrs[i] = v.String()
}
idx := strings.Join(idxStrs, va.script.SubSep)
// Delete the index from the associative array.
delete(va.data, idx)
}
// Keys returns all keys in the associative array in undefined order.
func (va *ValueArray) Keys() []*Value {
keys := make([]*Value, 0, len(va.data))
for kstr := range va.data {
keys = append(keys, va.script.NewValue(kstr))
}
return keys
}
// Values returns all values in the associative array in undefined order.
func (va *ValueArray) Values() []*Value {
vals := make([]*Value, 0, len(va.data))
for _, v := range va.data {
vals = append(vals, va.script.NewValue(v))
}
return vals
}