Skip to content

Commit 70a2195

Browse files
committed
wip
1 parent 6ebf45e commit 70a2195

File tree

4 files changed

+186
-84
lines changed

4 files changed

+186
-84
lines changed

and.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "slices"
44

55
const (
66
ErrNotEnoughEndless stringError = "not enough endless"
7-
ErrUnpextedAnd stringError = "unexpected and"
7+
ErrUnexpectedAndLogic stringError = "unexpected and logic"
88
ErrImpossibleInterval stringError = "impossible interval"
99
)
1010

@@ -36,7 +36,7 @@ func And(es ...Endless) (CeilingFloorConstrainter, error) {
3636
if !floorOk && !ceilingOk {
3737
var c CeilingFloorConstrainter
3838
// logic error! This should never happen.
39-
return c, ErrUnpextedAnd
39+
return c, ErrUnexpectedAndLogic
4040
}
4141

4242
if floorOk && !ceilingOk {

constraint.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,65 @@
11
package comver
22

3+
import "slices"
4+
35
type Constrainter interface {
46
Check(v Version) bool
7+
String() string
58
}
69

710
type CeilingFloorConstrainter interface {
11+
Constrainter
812
ceilinger
913
floorer
10-
Constrainter
1114
}
1215

13-
func overlap(a, b CeilingFloorConstrainter) bool {
16+
func wildcard(c CeilingFloorConstrainter) bool {
17+
return c.Floor().wildcard() && c.Ceiling().wildcard()
18+
}
19+
20+
// TODO: test me.
21+
func minCeilinglessFloor(cs ...CeilingFloorConstrainter) (CeilingFloorConstrainter, bool) {
22+
cs = slices.Clone(cs)
23+
24+
cs = slices.DeleteFunc(cs, func(c CeilingFloorConstrainter) bool {
25+
return !c.Ceiling().wildcard()
26+
})
27+
28+
if len(cs) == 0 {
29+
var c CeilingFloorConstrainter
30+
return c, false
31+
}
32+
33+
return slices.MinFunc(cs, func(a, b CeilingFloorConstrainter) int {
34+
return a.Floor().compare(b.Floor())
35+
}), true
36+
}
37+
38+
// TODO: test me.
39+
func maxFloorlessCeiling(cs ...CeilingFloorConstrainter) (CeilingFloorConstrainter, bool) {
40+
cs = slices.Clone(cs)
41+
42+
cs = slices.DeleteFunc(cs, func(c CeilingFloorConstrainter) bool {
43+
return !c.Floor().wildcard()
44+
})
45+
46+
if len(cs) == 0 {
47+
var c CeilingFloorConstrainter
48+
return c, false
49+
}
50+
51+
return slices.MaxFunc(cs, func(a, b CeilingFloorConstrainter) int {
52+
return a.Ceiling().compare(b.Ceiling())
53+
}), true
54+
}
55+
56+
func overlap(a, b CeilingFloorConstrainter) bool { // TODO: Test me.
1457
// TODO: Assume version != nil?
1558
return a.Check(*b.Floor().version) ||
1659
b.Check(*a.Floor().version)
1760
}
1861

19-
func seamless(a, b CeilingFloorConstrainter) bool {
62+
func seamless(a, b CeilingFloorConstrainter) bool { // TODO: Test me.
2063
// TODO: Assume version != nil?
2164

2265
fn := func(a, b CeilingFloorConstrainter) bool {

interval.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,5 @@ func (i interval) Floor() Endless {
2121
}
2222

2323
func (i interval) String() string {
24-
if i.ceiling.wildcard() {
25-
return i.floor.String()
26-
}
27-
28-
if i.floor.wildcard() {
29-
return i.ceiling.String()
30-
}
31-
3224
return i.Floor().String() + " " + i.Ceiling().String()
3325
}

or.go

Lines changed: 138 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,111 @@
11
package comver
22

3-
type Or []CeilingFloorConstrainter
3+
import (
4+
"slices"
5+
)
6+
7+
// Or represents a logical OR operation between multiple [CeilingFloorConstrainter] instances.
8+
// The zero value of Or is a constraint could never be satisfied.
9+
type Or []CeilingFloorConstrainter //nolint:godox // TODO: Use Constrainter so that we can nest Or.
410

511
func (o Or) Check(v Version) bool {
6-
return true // TODO: Implement!
12+
for i := range o {
13+
if o[i].Check(v) {
14+
return true
15+
}
16+
}
17+
return false
718
}
819

9-
//func CompactOr(cs Or) Constrainter {
10-
// if len(cs) == 0 {
11-
// return NewWildcard()
12-
// }
13-
// if len(cs) == 1 {
14-
// return cs[0]
15-
// }
16-
//
17-
// cs = slices.Clone(cs)
18-
//
19-
// // if there cs a wildcard, return only the wildcard
20-
// w := slices.ContainsFunc(cs, func(c CeilingFloorConstrainter) bool {
21-
// return c.Floor().version == nil && c.Ceiling().version == nil
22-
// })
23-
// if w {
24-
// return NewWildcard()
25-
// }
26-
//
27-
// head, headOk := minBoundedFloor(cs...)
28-
// cs = slices.DeleteFunc(cs, func(c CeilingFloorConstrainter) bool {
29-
// return c.Floor().version == nil
30-
// })
31-
// if headOk {
32-
// cs = append(cs, head)
33-
// }
34-
//
35-
// tail, tailOk := maxBoundedCelling(cs)
36-
// cs = slices.DeleteFunc(cs, func(c CeilingFloorConstrainter) bool {
37-
// return c.Ceiling().version == nil
38-
// })
39-
// if tailOk {
40-
// cs = append(cs, tail)
41-
// }
42-
//
43-
// // TODO: Check whether interval{head, tail} are wildcard.
44-
// // If yes, early return wildcard
45-
//
46-
// // important!
47-
// slices.SortFunc(cs, compareSimpleConstrainters)
48-
//
49-
// // remove duplicates
50-
// cs = slices.CompactFunc(cs, func(a, b CeilingFloorConstrainter) bool {
51-
// return compareSimpleConstrainters(a, b) == 0
52-
// })
53-
//
54-
// vals := make(Or, 0, len(cs))
55-
// pendingI := cs[0]
56-
// for index := range cs {
57-
// i, ok := compactTwoSCs(pendingI, cs[index])
58-
// if ok {
59-
// pendingI = i
60-
// } else {
61-
// vals = append(vals, pendingI)
62-
// pendingI = cs[index]
63-
// }
64-
//
65-
// if index == len(cs)-1 {
66-
// vals = append(vals, pendingI)
67-
// }
68-
// }
69-
//
70-
// return slices.Clip(vals)
71-
//}
72-
73-
func compactTwoSCs(a, b CeilingFloorConstrainter) (CeilingFloorConstrainter, bool) {
74-
cmp := compareSimpleConstrainters(a, b)
75-
if cmp > 0 {
76-
a, b = b, a
20+
func (o Or) String() string { // TODO: Test me.
21+
s := ""
22+
for i := range o {
23+
if i > 0 {
24+
s += " || "
25+
}
26+
s += o[i].String()
7727
}
28+
return s
29+
}
7830

31+
// Compact returns a new [Constrainter] that is logically equivalent to the input o.
32+
// The returned [Constrainter] may or may be not be an [Or] instance.
33+
// When it is, Compact tries to return the shortest [Or] possible.
34+
func Compact(o Or) Constrainter { // TODO: Test me.
35+
if len(o) == 0 {
36+
return o
37+
}
38+
if len(o) == 1 {
39+
return o[0]
40+
}
41+
42+
o = slices.Clone(o)
43+
44+
// wildcard trumps everything else.
45+
if slices.ContainsFunc(o, wildcard) {
46+
return NewWildcard()
47+
}
48+
49+
ceiling, ceilingOk := maxFloorlessCeiling(o...)
50+
floor, floorOk := minCeilinglessFloor(o...)
51+
52+
if ceilingOk && floorOk {
53+
if formWildcard(ceiling.Ceiling(), floor.Floor()) {
54+
return NewWildcard()
55+
}
56+
}
57+
58+
o = slices.DeleteFunc(o, func(c CeilingFloorConstrainter) bool {
59+
return c.Ceiling().wildcard() || c.Floor().wildcard()
60+
})
61+
62+
// important to sort before compacting
63+
slices.SortFunc(o, compareCeilingFloorConstrainters)
64+
// remove duplicates
65+
o = slices.CompactFunc(o, func(a, b CeilingFloorConstrainter) bool {
66+
return compareCeilingFloorConstrainters(a, b) == 0
67+
})
68+
69+
vals := make(Or, 0, len(o)+2)
70+
pendingI := o[0]
71+
for index := range o {
72+
i, ok := compactTwo(pendingI, o[index])
73+
if ok {
74+
pendingI = i
75+
} else {
76+
vals = append(vals, pendingI)
77+
pendingI = o[index]
78+
}
79+
80+
if index == len(o)-1 {
81+
vals = append(vals, pendingI)
82+
}
83+
}
84+
85+
var head Or
86+
if floorOk {
87+
head = append(head, floor)
88+
}
89+
var tail Or
90+
if ceilingOk {
91+
tail = append(tail, ceiling)
92+
}
93+
94+
r := slices.Concat(head, vals, tail)
95+
return slices.Clip(r)
96+
}
97+
98+
// TODO: Test me.
99+
func compactTwo(a, b CeilingFloorConstrainter) (CeilingFloorConstrainter, bool) {
100+
cmp := compareCeilingFloorConstrainters(a, b)
79101
if cmp == 0 {
80102
return a, true
81103
}
82104

105+
if cmp > 0 {
106+
a, b = b, a
107+
}
108+
83109
if !overlap(a, b) && !seamless(a, b) {
84110
return a, false
85111
}
@@ -91,10 +117,51 @@ func compactTwoSCs(a, b CeilingFloorConstrainter) (CeilingFloorConstrainter, boo
91117
return interval{a.Floor(), b.Ceiling()}, true
92118
}
93119

94-
func compareSimpleConstrainters(a, b CeilingFloorConstrainter) int {
120+
// TODO: Test me.
121+
func compareCeilingFloorConstrainters(a, b CeilingFloorConstrainter) int {
95122
cmp := a.Floor().compare(b.Floor())
96123
if cmp != 0 {
97124
return cmp
98125
}
99126
return a.Ceiling().compare(b.Ceiling())
100127
}
128+
129+
// TODO: Test me.
130+
func formWildcard(e, f Endless) bool {
131+
if e.wildcard() {
132+
return true
133+
}
134+
135+
if f.wildcard() {
136+
return true
137+
}
138+
139+
if e.op.ceilingBounded() && f.op.ceilingBounded() {
140+
return false
141+
}
142+
143+
if e.op.floorBounded() && f.op.floorBounded() {
144+
return false
145+
}
146+
147+
cmp := e.compare(f)
148+
149+
if cmp == 0 {
150+
return false
151+
}
152+
153+
if cmp > 0 {
154+
e, f = f, e
155+
}
156+
157+
vCmp := e.version.Compare(*f.version)
158+
if vCmp == 0 {
159+
return e.inclusive() || f.inclusive()
160+
}
161+
162+
if e.op.ceilingBounded() || f.op.floorBounded() {
163+
return false
164+
}
165+
166+
return false
167+
}

0 commit comments

Comments
 (0)