-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuilder.go
114 lines (93 loc) · 2.28 KB
/
builder.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
package qualify
// Builder instances are used to map sets of rules to
// outcomes.
type Builder struct {
outcomes map[int]int
fields fieldSet // fields with rules
explicit fieldMap // explicitly targeted fields
oneOf fieldValueMap // one-of targeting
oneOfX fieldMultiMap // one-of extra conditions
noneOf fieldValueMap // none-of targeting
readOnly bool
}
// NewBuilder inits a new builder
func NewBuilder() *Builder {
return &Builder{
outcomes: make(map[int]int),
fields: make(fieldSet),
explicit: make(fieldMap),
oneOf: make(fieldValueMap),
oneOfX: make(fieldMultiMap),
noneOf: make(fieldValueMap),
}
}
// Require adds a requirement condition for a particular outcome. Returns true if
// the requirement was acknowledged.
func (b *Builder) Require(outcome int, field Field, cond Condition) bool {
if b.readOnly {
return false
}
switch c := cond.(type) {
case oneOf:
b.requireOneOf(outcome, field, c)
case noneOf:
b.requireNoneOf(outcome, field, c)
}
return true
}
// Compile compiles a qualifier. The builder will become read-only as soon as this method is called.
func (b *Builder) Compile() *Qualifier {
b.readOnly = true
size := len(b.outcomes)
// set outcomes
outcomes := make([]int, size)
for outcome, pos := range b.outcomes {
outcomes[pos] = outcome
}
// set fields
fields := make([]Field, 0, len(b.fields))
for field := range b.fields {
fields = append(fields, field)
}
// prune
b.oneOfX.Prune()
return &Qualifier{
outcomes: outcomes,
fields: fields,
implicit: b.explicit.InvertTo(size),
oneOf: b.oneOf,
oneOfX: b.oneOfX,
noneOf: b.noneOf,
}
}
func (b *Builder) requireOneOf(outcome int, field Field, c oneOf) {
if len(c) == 0 {
return
}
pos := b.findPos(outcome)
b.fields.Add(field)
b.explicit.Fetch(field).Insert(pos)
for _, val := range c {
b.oneOf.Fetch(field, val).Insert(pos)
}
b.oneOfX.Fetch(outcome, field).OneOf(c...)
}
func (b *Builder) requireNoneOf(outcome int, field Field, c noneOf) {
if len(c) == 0 {
return
}
pos := b.findPos(outcome)
b.fields.Add(field)
b.explicit.Fetch(field)
for _, val := range c {
b.noneOf.Fetch(field, val).Insert(pos)
}
}
func (b *Builder) findPos(outcome int) int {
n, ok := b.outcomes[outcome]
if !ok {
n = len(b.outcomes)
b.outcomes[outcome] = n
}
return n
}