-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoperation.go
212 lines (174 loc) · 5.83 KB
/
operation.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
//
// @copyright: 2019 by Pauli Rikula <pauli.rikula@gmail.com>
// @license: MIT <http://www.opensource.org/licenses/mit-license.php>
//
package category
import (
"fmt"
"sort"
"strings"
)
// FreezedOperation is used to contain planned connection operation from source to sink
type FreezedOperation interface {
// GetSource returns the source of the planned connection operation
GetSource() Connectable
// GetSource returns the sink of the planned connection operation
GetSink() Connectable
// GetOperator returns the connection operation
GetOperator() Operator
// Evaluate executes the planned connection operation, which may fail
Evaluate() error
// Equals returns true if the sink, source and operation are equal
Equals(another FreezedOperation) bool
}
// OperationSet contains a set of operations and a set of set operations for the operations set
type OperationSet interface {
// Union is a set union. Returns a new set
Union(another OperationSet) OperationSet
// DiscardAll removes all instances of the another set from this one and returns it as a new
DiscardAll(another OperationSet) OperationSet
// Clone clones the set
Clone() OperationSet
// Add adds an item to this set
Add(f FreezedOperation)
// Remove removes and item from this set
Remove(f FreezedOperation)
// Equals is a set equality check
Equals(another OperationSet) bool
// AsArray returns the operations as an array
AsArray() []FreezedOperation
// AsSortedArray returns the operations as a sorted array
AsSortedArray() []FreezedOperation
// GetOperator returns the connection operation
GetOperator() Operator
}
// NewFreezedOperation creates a new FreezedOperation instance
func NewFreezedOperation(operator Operator, source Connectable, sink Connectable) FreezedOperation {
return &freezedOperation{Source: source, Sink: sink, Operator: operator}
}
// NewOperationSet creates a new OperationSet instance
func NewOperationSet(operator Operator) OperationSet {
return &operationSet{
Operator: operator,
FreezedOperations: make(map[freezedOperationKey]FreezedOperation),
}
}
// implementation details
type freezedOperationKey struct {
Source string
Sink string
Operator string
}
func getKey(op FreezedOperation) freezedOperationKey {
return freezedOperationKey{
Source: op.GetSource().GetId(),
Sink: op.GetSink().GetId(),
Operator: op.GetOperator().GetId()}
}
type freezedOperation struct {
Source Connectable
Sink Connectable
Operator Operator
}
func (f *freezedOperation) GetSink() Connectable { return f.Sink }
func (f *freezedOperation) GetSource() Connectable { return f.Source }
func (f *freezedOperation) Evaluate() error {
return f.Operator.Evaluate(f.Source, f.Sink)
}
func (f *freezedOperation) Equals(another FreezedOperation) bool {
return another != nil && f.Source == another.GetSource() && f.Sink == another.GetSink() && f.Operator.GetId() == another.GetOperator().GetId()
}
func (f *freezedOperation) GetOperator() Operator { return f.Operator }
type operationSet struct {
FreezedOperations map[freezedOperationKey]FreezedOperation
Operator Operator
}
func newOperationSetFromArray(operator Operator, operations []FreezedOperation) *operationSet {
aSet := &operationSet{
Operator: operator,
FreezedOperations: make(map[freezedOperationKey]FreezedOperation, len(operations)),
}
for _, v := range operations {
aSet.FreezedOperations[getKey(v)] = v
}
return aSet
}
func (fs *operationSet) Union(another OperationSet) OperationSet {
operations := another.AsArray()
for _, v := range fs.FreezedOperations {
operations = append(operations, v)
}
unionSet := newOperationSetFromArray(fs.Operator, operations)
return unionSet
}
func (fs *operationSet) DiscardAll(another OperationSet) OperationSet {
discardSet := fs.Clone()
for _, v := range another.AsArray() {
discardSet.Remove(v)
}
return discardSet
}
func (fs *operationSet) Clone() OperationSet {
freezeds := make(map[freezedOperationKey]FreezedOperation, len(fs.FreezedOperations))
for k, v := range fs.FreezedOperations {
freezeds[k] = v
}
return &operationSet{Operator: fs.Operator, FreezedOperations: freezeds}
}
func (fs *operationSet) Add(f FreezedOperation) {
fs.FreezedOperations[getKey(f)] = f
}
func (fs *operationSet) Remove(f FreezedOperation) {
fmt.Printf("%+v %+v\n", fs.FreezedOperations, f)
delete(fs.FreezedOperations, getKey(f))
}
func (fs *operationSet) Equals(another OperationSet) bool {
if !EqualOperators(fs.Operator, another.GetOperator()) {
return false
}
operations := another.AsArray()
if len(operations) != len(fs.FreezedOperations) {
return false
}
for _, f := range operations {
_, found := fs.FreezedOperations[getKey(f)]
if !found {
return false
}
}
return true
}
func (fs *operationSet) AsArray() []FreezedOperation {
values := make([]FreezedOperation, len(fs.FreezedOperations))
i := 0
for _, v := range fs.FreezedOperations {
values[i] = v
i++
}
return values
}
func (fs *operationSet) AsSortedArray() []FreezedOperation {
arr := fs.AsArray()
sort.Slice(arr, func(i, j int) bool {
cmpOp := strings.Compare(arr[i].GetOperator().GetId(), arr[j].GetOperator().GetId())
cmpSource := strings.Compare(arr[i].GetSource().GetId(), arr[j].GetSource().GetId())
cmpSink := strings.Compare(arr[i].GetSink().GetId(), arr[j].GetSink().GetId())
return (cmpOp < 0) || (cmpOp == 0 && cmpSource < 0) || (cmpOp == 0 && cmpSource == 0 && cmpSink < 0)
})
return arr
}
func (fs *operationSet) GetOperator() Operator {
return fs.Operator
}
func (fs *operationSet) CompatibleWithSet(another OperationSet) error {
return CompatibleOperators(fs.GetOperator(), another.GetOperator())
}
func (fs *operationSet) CompatibleWithList(another []FreezedOperation) error {
for f := range another {
err := CompatibleOperators(fs.GetOperator(), another[f].GetOperator())
if err != nil {
return err
}
}
return nil
}