-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.go
106 lines (89 loc) · 2.63 KB
/
cache.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
package acal
import "strconv"
type extractable interface {
// ExtractValues extracts this Value and all Value that were used to calculate it.
ExtractValues(cache IValueCache) IValueCache
}
// IValueCache keeps extracted values during marshalling so that we can
// build a complete JSON structure containing all calculated variables
// from a small set of input variables.
//
//go:generate mockery --name=IValueCache --case underscore --inpackage
type IValueCache interface {
// Take accepts a Value to put into ValueCache. It will automatically de-duplicate
// variables under the same name by giving duplicates an alias if it doesn't have
// one already. The return value indicates whether the given value was accepted
// into the cache.
//
// Format for alias of de-duplicated variables: <name_of_variable><count>.
// - count starts from 2
// - example: duplicate2, duplicate3
Take(v Value) bool
// Flatten returns a map of calculated variables that is ready for marshalling into
// JSON. Variables with colliding alias will be de-duplicated by appending a count
// suffix to the alias of all duplicates.
//
// Format for alias of de-duplicated variables: <name_of_variable>_<count>.
// - count starts from 2
// - example: duplicate_2, duplicate3_2
Flatten() map[string]Value
}
type valueCache struct {
values map[string][]Value
}
// NewValueCache ...
func NewValueCache() IValueCache {
return valueCache{
values: make(map[string][]Value),
}
}
// Take ...
func (c valueCache) Take(v Value) bool {
existings, ok := c.values[v.GetName()]
if !ok {
c.values[v.GetName()] = []Value{
v,
}
return true
}
for _, existing := range existings {
// Already took this v before
if existing == v {
return false
}
}
if v.GetAlias() == "" {
alias := v.GetName() + strconv.Itoa(len(existings)+1)
v.SetAlias(alias)
}
c.values[v.GetName()] = append(existings, v)
return true
}
// Flatten ...
func (c valueCache) Flatten() map[string]Value {
flattens := make(map[string]Value)
for _, values := range c.values {
for _, value := range values {
identity := Identify(value)
if flattens[identity] == nil {
flattens[identity] = value
continue
}
// When name and alias of 2 different values are the same,
// it means the alias of these values was set manually by
// clients to mark that they are the same thing.
if flattens[identity].GetName() == value.GetName() {
continue
}
count := 2
key := identity + "_" + strconv.Itoa(count)
for flattens[key] != nil {
count++
key = identity + "_" + strconv.Itoa(count)
}
value.SetAlias(key)
flattens[key] = value
}
}
return flattens
}