mirror of https://github.com/k3s-io/k3s
254 lines
6.6 KiB
Go
254 lines
6.6 KiB
Go
![]() |
package mesos
|
||
|
|
||
|
import (
|
||
|
"sort"
|
||
|
)
|
||
|
|
||
|
// Ranges represents a list of Ranges.
|
||
|
type Ranges []Value_Range
|
||
|
|
||
|
// NewRanges returns squashed Ranges from the given numbers.
|
||
|
func NewRanges(ns ...uint64) Ranges {
|
||
|
xs := append(uint64s{}, ns...)
|
||
|
sort.Sort(xs)
|
||
|
rs := make(Ranges, len(xs))
|
||
|
for i := range xs {
|
||
|
rs[i].Begin, rs[i].End = xs[i], xs[i]
|
||
|
}
|
||
|
return rs.Squash()
|
||
|
}
|
||
|
|
||
|
// NewPortRanges returns Ranges from the "ports" resource in the
|
||
|
// given *Offer. If that resource isn't provided, nil will be returned.
|
||
|
//
|
||
|
// The returned Ranges are sorted and have all overlapping ranges merged from
|
||
|
// left to right. e.g. [[0, 5], [4, 3], [10, 7]] -> [[0, 5], [7, 10]]
|
||
|
func NewPortRanges(o *Offer) Ranges {
|
||
|
if o == nil {
|
||
|
return Ranges{}
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
r Resource
|
||
|
found bool
|
||
|
)
|
||
|
for i := range o.Resources {
|
||
|
if o.Resources[i].GetName() == "ports" {
|
||
|
r = o.Resources[i]
|
||
|
found = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !found {
|
||
|
return Ranges{}
|
||
|
}
|
||
|
|
||
|
offered := r.GetRanges().GetRange()
|
||
|
rs := make(Ranges, len(offered))
|
||
|
for i, r := range offered {
|
||
|
if lo, hi := r.GetBegin(), r.GetEnd(); lo <= hi {
|
||
|
rs[i].Begin, rs[i].End = lo, hi
|
||
|
} else {
|
||
|
rs[i].Begin, rs[i].End = hi, lo
|
||
|
}
|
||
|
}
|
||
|
return rs.Sort().Squash()
|
||
|
}
|
||
|
|
||
|
// These three methods implement sort.Interface
|
||
|
func (rs Ranges) Len() int { return len(rs) }
|
||
|
func (rs Ranges) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
|
||
|
func (rs Ranges) Less(i, j int) bool {
|
||
|
return rs[i].Begin < rs[j].Begin || (rs[i].Begin == rs[j].Begin && rs[i].End < rs[j].End)
|
||
|
}
|
||
|
|
||
|
// Size returns the sum of the Size of all Ranges.
|
||
|
func (rs Ranges) Size() uint64 {
|
||
|
var sz uint64
|
||
|
for i := range rs {
|
||
|
sz += 1 + (rs[i].End - rs[i].Begin)
|
||
|
}
|
||
|
return sz
|
||
|
}
|
||
|
|
||
|
// Sort sorts the receiving Ranges and returns the result; convenience
|
||
|
func (rs Ranges) Sort() Ranges {
|
||
|
sort.Sort(rs)
|
||
|
return rs
|
||
|
}
|
||
|
|
||
|
// Squash merges overlapping and continuous Ranges. It assumes they're pre-sorted.
|
||
|
func (rs Ranges) Squash() Ranges {
|
||
|
if len(rs) < 2 {
|
||
|
return rs
|
||
|
}
|
||
|
squashed := Ranges{rs[0]}
|
||
|
for i := 1; i < len(rs); i++ {
|
||
|
switch max := squashed[len(squashed)-1].End; {
|
||
|
case 1+max < rs[i].Begin: // no overlap nor continuity: push
|
||
|
squashed = append(squashed, rs[i])
|
||
|
case max <= rs[i].End: // overlap or continuity: squash
|
||
|
squashed[len(squashed)-1].End = rs[i].End
|
||
|
}
|
||
|
}
|
||
|
return squashed
|
||
|
}
|
||
|
|
||
|
// Search performs a binary search for n returning the index of the Range it was
|
||
|
// found at or -1 if not found.
|
||
|
func (rs Ranges) Search(n uint64) int {
|
||
|
for lo, hi := 0, len(rs)-1; lo <= hi; {
|
||
|
switch m := lo + (hi-lo)/2; {
|
||
|
case n < rs[m].Begin:
|
||
|
hi = m - 1
|
||
|
case n > rs[m].End:
|
||
|
lo = m + 1
|
||
|
default:
|
||
|
return m
|
||
|
}
|
||
|
}
|
||
|
return -1
|
||
|
}
|
||
|
|
||
|
// Partition partitions Ranges around n. It returns the partitioned Ranges
|
||
|
// and a boolean indicating if n was found.
|
||
|
func (rs Ranges) Partition(n uint64) (Ranges, bool) {
|
||
|
i := rs.Search(n)
|
||
|
if i < 0 {
|
||
|
return rs, false
|
||
|
}
|
||
|
|
||
|
pn := make(Ranges, 0, len(rs)+1)
|
||
|
switch pn = append(pn, rs[:i]...); {
|
||
|
case rs[i].Begin == rs[i].End: // delete
|
||
|
case rs[i].Begin == n: // increment lower bound
|
||
|
pn = append(pn, Value_Range{rs[i].Begin + 1, rs[i].End})
|
||
|
case rs[i].End == n: // decrement upper bound
|
||
|
pn = append(pn, Value_Range{rs[i].Begin, rs[i].End - 1})
|
||
|
default: // split
|
||
|
pn = append(pn, Value_Range{rs[i].Begin, n - 1}, Value_Range{n + 1, rs[i].End})
|
||
|
}
|
||
|
return append(pn, rs[i+1:]...), true
|
||
|
}
|
||
|
|
||
|
// Remove removes a range from already coalesced ranges.
|
||
|
// The algorithms constructs a new vector of ranges which is then
|
||
|
// Squash'ed into a Ranges instance.
|
||
|
func (rs Ranges) Remove(removal Value_Range) Ranges {
|
||
|
ranges := make([]Value_Range, 0, len(rs))
|
||
|
for _, r := range rs {
|
||
|
// skip if the entire range is subsumed by removal
|
||
|
if r.Begin >= removal.Begin && r.End <= removal.End {
|
||
|
continue
|
||
|
}
|
||
|
// divide if the range subsumes the removal
|
||
|
if r.Begin < removal.Begin && r.End > removal.End {
|
||
|
ranges = append(ranges,
|
||
|
Value_Range{r.Begin, removal.Begin - 1},
|
||
|
Value_Range{removal.End + 1, r.End},
|
||
|
)
|
||
|
continue
|
||
|
}
|
||
|
// add the full range if there's no intersection
|
||
|
if r.End < removal.Begin || r.Begin > removal.End {
|
||
|
ranges = append(ranges, r)
|
||
|
continue
|
||
|
}
|
||
|
// trim if the range does intersect
|
||
|
if r.End > removal.End {
|
||
|
ranges = append(ranges, Value_Range{removal.End + 1, r.End})
|
||
|
} else {
|
||
|
if r.Begin >= removal.Begin {
|
||
|
// should never happen
|
||
|
panic("r.Begin >= removal.Begin")
|
||
|
}
|
||
|
ranges = append(ranges, Value_Range{r.Begin, removal.Begin - 1})
|
||
|
}
|
||
|
}
|
||
|
return Ranges(ranges).Squash()
|
||
|
}
|
||
|
|
||
|
// Compare assumes that both Ranges are already in sort-order.
|
||
|
// Returns 0 if rs and right are equivalent, -1 if rs is a subset of right, or else 1
|
||
|
func (rs Ranges) Compare(right Ranges) int {
|
||
|
x, y, result := rs.equiv(right)
|
||
|
if result {
|
||
|
return 0
|
||
|
}
|
||
|
for _, a := range x {
|
||
|
// make sure that this range is a subset of a range in y
|
||
|
matched := false
|
||
|
for _, b := range y {
|
||
|
if a.Begin >= b.Begin && a.End <= b.End {
|
||
|
matched = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if !matched {
|
||
|
return 1
|
||
|
}
|
||
|
}
|
||
|
return -1
|
||
|
}
|
||
|
|
||
|
// Equivalent assumes that both Ranges are already in sort-order.
|
||
|
func (rs Ranges) Equivalent(right Ranges) (result bool) {
|
||
|
_, _, result = rs.equiv(right)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Equivalent assumes that both Ranges are already in sort-order.
|
||
|
func (rs Ranges) equiv(right Ranges) (_, _ Ranges, _ bool) {
|
||
|
// we need to squash rs and right but don't want to change the originals
|
||
|
switch len(rs) {
|
||
|
case 0:
|
||
|
case 1:
|
||
|
rs = Ranges{rs[0]}
|
||
|
default:
|
||
|
rs = Ranges(append([]Value_Range{rs[0], rs[1]}, rs[2:]...)).Sort().Squash()
|
||
|
}
|
||
|
switch len(right) {
|
||
|
case 0:
|
||
|
case 1:
|
||
|
right = Ranges{right[0]}
|
||
|
default:
|
||
|
right = Ranges(append([]Value_Range{right[0], right[1]}, right[2:]...)).Sort().Squash()
|
||
|
}
|
||
|
return rs, right, (&Value_Ranges{Range: rs}).Equal(&Value_Ranges{Range: right})
|
||
|
}
|
||
|
|
||
|
func (rs Ranges) Clone() Ranges {
|
||
|
if len(rs) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
x := make(Ranges, len(rs))
|
||
|
copy(x, rs)
|
||
|
return x
|
||
|
}
|
||
|
|
||
|
// Min returns the minimum number in Ranges. It will panic on empty Ranges.
|
||
|
func (rs Ranges) Min() uint64 { return rs[0].Begin }
|
||
|
|
||
|
// Max returns the maximum number in Ranges. It will panic on empty Ranges.
|
||
|
func (rs Ranges) Max() uint64 { return rs[len(rs)-1].End }
|
||
|
|
||
|
// resource returns a *Resource with the given name and Ranges.
|
||
|
func (rs Ranges) resource(name string) Resource {
|
||
|
vr := make([]Value_Range, len(rs))
|
||
|
copy(vr, rs)
|
||
|
return Resource{
|
||
|
Name: name,
|
||
|
Type: RANGES.Enum(),
|
||
|
Ranges: &Value_Ranges{Range: vr},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// uint64s is an utility used to sort a slice of uint64s
|
||
|
type uint64s []uint64
|
||
|
|
||
|
// These three methods implement sort.Interface
|
||
|
func (ns uint64s) Len() int { return len(ns) }
|
||
|
func (ns uint64s) Less(i, j int) bool { return ns[i] < ns[j] }
|
||
|
func (ns uint64s) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
|