-
Notifications
You must be signed in to change notification settings - Fork 15
/
ops_tuple.go
78 lines (69 loc) · 2.18 KB
/
ops_tuple.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
package rel
import "github.com/arr-ai/frozen"
// CombineOp specifies which pairings to include in Combine().
type CombineOp int
// The following masks control which elements to include in Combine().
const (
OnlyOnLHS CombineOp = 1 << iota // Include elements only found on lhs.
InBoth // Include elements found on both sides.
OnlyOnRHS // Include elements only found on rhs.
AllPairs = OnlyOnLHS | InBoth | OnlyOnRHS
)
// Pair represents a pair of values.
type Pair struct {
a, b Value
}
// Combine returns a map of names to pairs of corresponding Values from a and b.
// Which names appear in the output is determined by the masks provided in op.
func Combine(a, b Tuple, op CombineOp) map[string]Pair {
names := make(map[string]Pair, a.Count()+b.Count())
for e := a.Enumerator(); e.MoveNext(); {
aName, aValue := e.Current()
bValue, found := b.Get(aName)
if !found && (op&OnlyOnLHS != 0) || found && (op&InBoth != 0) {
names[aName] = Pair{aValue, bValue}
}
}
for e := b.Enumerator(); e.MoveNext(); {
bName, bValue := e.Current()
_, found := a.Get(bName)
if !found && (op&OnlyOnRHS != 0) {
names[bName] = Pair{nil, bValue}
}
}
return names
}
// CombineNames returns names from a and b according to the given mask.
func CombineNames(a, b Tuple, op CombineOp) Names {
var sb frozen.SetBuilder
for name := range Combine(a, b, op) {
sb.Add(name)
}
return Names(sb.Finish())
}
// Merge returns the merger of a and b, if possible or nil otherwise.
// Success requires that common names map to equal values.
func Merge(a, b Tuple) Tuple {
attrs := []Attr{}
for name, pair := range Combine(a, b, AllPairs) {
if pair.a == nil {
attrs = append(attrs, NewAttr(name, pair.b))
} else if pair.b == nil || pair.a.Equal(pair.b) {
attrs = append(attrs, NewAttr(name, pair.a))
} else {
return nil
}
}
return NewTuple(attrs...)
}
// MergeLeftToRight returns the merger of a and b. Key from tuples to the right
// override tuples to the left.
func MergeLeftToRight(t Tuple, ts ...Tuple) Tuple {
for _, u := range ts {
for e := u.Enumerator(); e.MoveNext(); {
name, value := e.Current()
t = t.With(name, value)
}
}
return t
}