You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.7 KiB
177 lines
4.7 KiB
// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package cov
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
// Location describes a single line-column position in a source file.
|
|
type Location struct {
|
|
Line, Column int
|
|
}
|
|
|
|
func (l Location) String() string {
|
|
return fmt.Sprintf("%v:%v", l.Line, l.Column)
|
|
}
|
|
|
|
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
|
|
func (l Location) Compare(o Location) int {
|
|
switch {
|
|
case l.Line < o.Line:
|
|
return -1
|
|
case l.Line > o.Line:
|
|
return 1
|
|
case l.Column < o.Column:
|
|
return -1
|
|
case l.Column > o.Column:
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Before returns true if l comes before o.
|
|
func (l Location) Before(o Location) bool { return l.Compare(o) == -1 }
|
|
|
|
// After returns true if l comes after o.
|
|
func (l Location) After(o Location) bool { return l.Compare(o) == 1 }
|
|
|
|
// Span describes a start and end interval in a source file.
|
|
type Span struct {
|
|
Start, End Location
|
|
}
|
|
|
|
func (s Span) String() string {
|
|
return fmt.Sprintf("%v-%v", s.Start, s.End)
|
|
}
|
|
|
|
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
|
|
func (s Span) Compare(o Span) int {
|
|
switch {
|
|
case s.Start.Before(o.Start):
|
|
return -1
|
|
case o.Start.Before(s.Start):
|
|
return 1
|
|
case s.End.Before(o.End):
|
|
return -1
|
|
case o.End.Before(s.End):
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Before returns true if span s comes before o.
|
|
func (s Span) Before(o Span) bool { return s.Compare(o) == -1 }
|
|
|
|
// Inside returns true if span s fits entirely inside o.
|
|
func (s Span) Inside(o Span) bool { return s.Start.Compare(o.Start) >= 0 && s.End.Compare(o.End) <= 0 }
|
|
|
|
// SpanList is a sorted list of spans. Use SpanList.Add() to insert new spans.
|
|
type SpanList []Span
|
|
|
|
// Add adds the Span to the SpanList, merging and expanding overlapping spans.
|
|
func (l *SpanList) Add(s Span) {
|
|
// [===]
|
|
// [0] [1] | idxStart: 2 | idxEnd: 2
|
|
// [0] [1] | idxStart: 0 | idxEnd: 0
|
|
// [ 0 ] [ 1 ] [ 2 ] [ 3 ] | idxStart: 1 | idxEnd: 2
|
|
// [0] [1] [2] [3] [4] | idxStart: 2 | idxEnd: 2
|
|
idxStart := sort.Search(len(*l), func(i int) bool { return (*l)[i].End.Compare(s.Start) >= 0 })
|
|
|
|
if idxStart < len(*l) && s.Inside((*l)[idxStart]) {
|
|
return // No change.
|
|
}
|
|
|
|
idxEnd := sort.Search(len(*l), func(i int) bool { return (*l)[i].Start.Compare(s.End) > 0 })
|
|
|
|
if idxStart < idxEnd {
|
|
if first := (*l)[idxStart]; first.Start.Before(s.Start) {
|
|
s.Start = first.Start
|
|
}
|
|
if last := (*l)[idxEnd-1]; last.End.After(s.End) {
|
|
s.End = last.End
|
|
}
|
|
}
|
|
|
|
merged := append(SpanList{}, (*l)[:idxStart]...)
|
|
merged = append(merged, s)
|
|
merged = append(merged, (*l)[idxEnd:]...)
|
|
*l = merged
|
|
}
|
|
|
|
// Remove cuts out the Span from the SpanList, removing and trimming overlapping
|
|
// spans.
|
|
func (l *SpanList) Remove(s Span) {
|
|
if s.Start == s.End {
|
|
return // zero length == no split.
|
|
}
|
|
|
|
// [===]
|
|
// [0] [1] | idxStart: 2 | idxEnd: 2
|
|
// [0] [1] | idxStart: 0 | idxEnd: 0
|
|
// [ 0 ] [ 1 ] [ 2 ] [ 3 ] | idxStart: 1 | idxEnd: 2
|
|
// [0] [1] [2] [3] [4] | idxStart: 2 | idxEnd: 2
|
|
idxStart := sort.Search(len(*l), func(i int) bool { return (*l)[i].End.Compare(s.Start) > 0 })
|
|
idxEnd := sort.Search(len(*l), func(i int) bool { return (*l)[i].Start.Compare(s.End) >= 0 })
|
|
|
|
merged := append(SpanList{}, (*l)[:idxStart]...)
|
|
|
|
if idxStart < idxEnd {
|
|
first, last := (*l)[idxStart], (*l)[idxEnd-1]
|
|
if first.Start.Compare(s.Start) < 0 {
|
|
merged = append(merged, Span{first.Start, s.Start})
|
|
}
|
|
if last.End.Compare(s.End) > 0 {
|
|
merged = append(merged, Span{s.End, last.End})
|
|
}
|
|
}
|
|
|
|
merged = append(merged, (*l)[idxEnd:]...)
|
|
*l = merged
|
|
}
|
|
|
|
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
|
|
func (l SpanList) Compare(o SpanList) int {
|
|
switch {
|
|
case len(l) < len(o):
|
|
return -1
|
|
case len(l) > len(o):
|
|
return 1
|
|
}
|
|
for i, a := range l {
|
|
switch a.Compare(o[i]) {
|
|
case -1:
|
|
return -1
|
|
case 1:
|
|
return 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// NumLines returns the total number of lines covered by all spans in the list.
|
|
func (l SpanList) NumLines() int {
|
|
seen := map[int]struct{}{}
|
|
for _, span := range l {
|
|
for s := span.Start.Line; s <= span.End.Line; s++ {
|
|
if _, ok := seen[s]; !ok {
|
|
seen[s] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
return len(seen)
|
|
}
|