forked from cloudfoundry/cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
map.go
154 lines (130 loc) · 3 KB
/
map.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
package generic
import "fmt"
// interface declaration
type Map interface {
IsEmpty() bool
Count() int
Keys() []interface{}
Has(key interface{}) bool
Except(keys []interface{}) Map
IsNil(key interface{}) bool
NotNil(key interface{}) bool
Get(key interface{}) interface{}
Set(key interface{}, value interface{})
Delete(key interface{})
String() string
}
// concrete map type
type ConcreteMap map[interface{}]interface{}
// constructors
func newEmptyMap() Map {
return &ConcreteMap{}
}
func NewMap(data ...interface{}) Map {
if len(data) == 0 {
return newEmptyMap()
} else if len(data) > 1 {
panic("NewMap called with more than one argument")
}
switch data := data[0].(type) {
case Map:
return data
case map[string]string:
stringMap := newEmptyMap()
for key, val := range data {
stringMap.Set(key, val)
}
return stringMap
case map[string]interface{}:
stringToInterfaceMap := newEmptyMap()
for key, val := range data {
stringToInterfaceMap.Set(key, val)
}
return stringToInterfaceMap
case map[interface{}]interface{}:
mapp := ConcreteMap(data)
return &mapp
}
fmt.Printf("\n\n map: %T", data)
panic("NewMap called with unexpected argument")
}
// implementing interface methods
func (data *ConcreteMap) IsEmpty() bool {
return data.Count() == 0
}
func (data *ConcreteMap) Count() int {
return len(*data)
}
func (data *ConcreteMap) Has(key interface{}) bool {
_, ok := (*data)[key]
return ok
}
func (data *ConcreteMap) Except(keys []interface{}) Map {
otherMap := NewMap()
Each(data, func(key, value interface{}) {
if !Contains(keys, key) {
otherMap.Set(key, value)
}
})
return otherMap
}
func (data *ConcreteMap) IsNil(key interface{}) bool {
maybe, ok := (*data)[key]
return ok && maybe == nil
}
func (data *ConcreteMap) NotNil(key interface{}) bool {
maybe, ok := (*data)[key]
return ok && maybe != nil
}
func (data *ConcreteMap) Keys() (keys []interface{}) {
keys = make([]interface{}, 0, data.Count())
for key := range *data {
keys = append(keys, key)
}
return
}
func (data *ConcreteMap) Get(key interface{}) interface{} {
return (*data)[key]
}
func (data *ConcreteMap) Set(key, value interface{}) {
(*data)[key] = value
}
func (data *ConcreteMap) Delete(key interface{}) {
delete(*data, key)
}
func (data *ConcreteMap) String() string {
return fmt.Sprintf("% v", *data)
}
// helper functions
func IsMappable(value interface{}) bool {
switch value.(type) {
case Map:
return true
case map[string]interface{}:
return true
case map[interface{}]interface{}:
return true
default:
return false
}
}
type Iterator func(key, val interface{})
func Each(collection Map, cb Iterator) {
for _, key := range collection.Keys() {
cb(key, collection.Get(key))
}
}
func Contains(collection, item interface{}) bool {
switch collection := collection.(type) {
case Map:
return collection.Has(item)
case []interface{}:
for _, val := range collection {
if val == item {
return true
}
}
return false
}
panic("unexpected type passed to Contains")
}