1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2020 The SwiftShader Authors. All Rights Reserved. 2*03ce13f7SAndroid Build Coastguard Worker// 3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*03ce13f7SAndroid Build Coastguard Worker// 7*03ce13f7SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*03ce13f7SAndroid Build Coastguard Worker// 9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License. 14*03ce13f7SAndroid Build Coastguard Worker 15*03ce13f7SAndroid Build Coastguard Workerpackage cov 16*03ce13f7SAndroid Build Coastguard Worker 17*03ce13f7SAndroid Build Coastguard Workerimport ( 18*03ce13f7SAndroid Build Coastguard Worker "fmt" 19*03ce13f7SAndroid Build Coastguard Worker "sort" 20*03ce13f7SAndroid Build Coastguard Worker) 21*03ce13f7SAndroid Build Coastguard Worker 22*03ce13f7SAndroid Build Coastguard Worker// Location describes a single line-column position in a source file. 23*03ce13f7SAndroid Build Coastguard Workertype Location struct { 24*03ce13f7SAndroid Build Coastguard Worker Line, Column int 25*03ce13f7SAndroid Build Coastguard Worker} 26*03ce13f7SAndroid Build Coastguard Worker 27*03ce13f7SAndroid Build Coastguard Workerfunc (l Location) String() string { 28*03ce13f7SAndroid Build Coastguard Worker return fmt.Sprintf("%v:%v", l.Line, l.Column) 29*03ce13f7SAndroid Build Coastguard Worker} 30*03ce13f7SAndroid Build Coastguard Worker 31*03ce13f7SAndroid Build Coastguard Worker// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0. 32*03ce13f7SAndroid Build Coastguard Workerfunc (l Location) Compare(o Location) int { 33*03ce13f7SAndroid Build Coastguard Worker switch { 34*03ce13f7SAndroid Build Coastguard Worker case l.Line < o.Line: 35*03ce13f7SAndroid Build Coastguard Worker return -1 36*03ce13f7SAndroid Build Coastguard Worker case l.Line > o.Line: 37*03ce13f7SAndroid Build Coastguard Worker return 1 38*03ce13f7SAndroid Build Coastguard Worker case l.Column < o.Column: 39*03ce13f7SAndroid Build Coastguard Worker return -1 40*03ce13f7SAndroid Build Coastguard Worker case l.Column > o.Column: 41*03ce13f7SAndroid Build Coastguard Worker return 1 42*03ce13f7SAndroid Build Coastguard Worker } 43*03ce13f7SAndroid Build Coastguard Worker return 0 44*03ce13f7SAndroid Build Coastguard Worker} 45*03ce13f7SAndroid Build Coastguard Worker 46*03ce13f7SAndroid Build Coastguard Worker// Before returns true if l comes before o. 47*03ce13f7SAndroid Build Coastguard Workerfunc (l Location) Before(o Location) bool { return l.Compare(o) == -1 } 48*03ce13f7SAndroid Build Coastguard Worker 49*03ce13f7SAndroid Build Coastguard Worker// After returns true if l comes after o. 50*03ce13f7SAndroid Build Coastguard Workerfunc (l Location) After(o Location) bool { return l.Compare(o) == 1 } 51*03ce13f7SAndroid Build Coastguard Worker 52*03ce13f7SAndroid Build Coastguard Worker// Span describes a start and end interval in a source file. 53*03ce13f7SAndroid Build Coastguard Workertype Span struct { 54*03ce13f7SAndroid Build Coastguard Worker Start, End Location 55*03ce13f7SAndroid Build Coastguard Worker} 56*03ce13f7SAndroid Build Coastguard Worker 57*03ce13f7SAndroid Build Coastguard Workerfunc (s Span) String() string { 58*03ce13f7SAndroid Build Coastguard Worker return fmt.Sprintf("%v-%v", s.Start, s.End) 59*03ce13f7SAndroid Build Coastguard Worker} 60*03ce13f7SAndroid Build Coastguard Worker 61*03ce13f7SAndroid Build Coastguard Worker// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0. 62*03ce13f7SAndroid Build Coastguard Workerfunc (s Span) Compare(o Span) int { 63*03ce13f7SAndroid Build Coastguard Worker switch { 64*03ce13f7SAndroid Build Coastguard Worker case s.Start.Before(o.Start): 65*03ce13f7SAndroid Build Coastguard Worker return -1 66*03ce13f7SAndroid Build Coastguard Worker case o.Start.Before(s.Start): 67*03ce13f7SAndroid Build Coastguard Worker return 1 68*03ce13f7SAndroid Build Coastguard Worker case s.End.Before(o.End): 69*03ce13f7SAndroid Build Coastguard Worker return -1 70*03ce13f7SAndroid Build Coastguard Worker case o.End.Before(s.End): 71*03ce13f7SAndroid Build Coastguard Worker return 1 72*03ce13f7SAndroid Build Coastguard Worker } 73*03ce13f7SAndroid Build Coastguard Worker return 0 74*03ce13f7SAndroid Build Coastguard Worker} 75*03ce13f7SAndroid Build Coastguard Worker 76*03ce13f7SAndroid Build Coastguard Worker// Before returns true if span s comes before o. 77*03ce13f7SAndroid Build Coastguard Workerfunc (s Span) Before(o Span) bool { return s.Compare(o) == -1 } 78*03ce13f7SAndroid Build Coastguard Worker 79*03ce13f7SAndroid Build Coastguard Worker// Inside returns true if span s fits entirely inside o. 80*03ce13f7SAndroid Build Coastguard Workerfunc (s Span) Inside(o Span) bool { return s.Start.Compare(o.Start) >= 0 && s.End.Compare(o.End) <= 0 } 81*03ce13f7SAndroid Build Coastguard Worker 82*03ce13f7SAndroid Build Coastguard Worker// SpanList is a sorted list of spans. Use SpanList.Add() to insert new spans. 83*03ce13f7SAndroid Build Coastguard Workertype SpanList []Span 84*03ce13f7SAndroid Build Coastguard Worker 85*03ce13f7SAndroid Build Coastguard Worker// Add adds the Span to the SpanList, merging and expanding overlapping spans. 86*03ce13f7SAndroid Build Coastguard Workerfunc (l *SpanList) Add(s Span) { 87*03ce13f7SAndroid Build Coastguard Worker // [===] 88*03ce13f7SAndroid Build Coastguard Worker // [0] [1] | idxStart: 2 | idxEnd: 2 89*03ce13f7SAndroid Build Coastguard Worker // [0] [1] | idxStart: 0 | idxEnd: 0 90*03ce13f7SAndroid Build Coastguard Worker // [ 0 ] [ 1 ] [ 2 ] [ 3 ] | idxStart: 1 | idxEnd: 2 91*03ce13f7SAndroid Build Coastguard Worker // [0] [1] [2] [3] [4] | idxStart: 2 | idxEnd: 2 92*03ce13f7SAndroid Build Coastguard Worker idxStart := sort.Search(len(*l), func(i int) bool { return (*l)[i].End.Compare(s.Start) >= 0 }) 93*03ce13f7SAndroid Build Coastguard Worker 94*03ce13f7SAndroid Build Coastguard Worker if idxStart < len(*l) && s.Inside((*l)[idxStart]) { 95*03ce13f7SAndroid Build Coastguard Worker return // No change. 96*03ce13f7SAndroid Build Coastguard Worker } 97*03ce13f7SAndroid Build Coastguard Worker 98*03ce13f7SAndroid Build Coastguard Worker idxEnd := sort.Search(len(*l), func(i int) bool { return (*l)[i].Start.Compare(s.End) > 0 }) 99*03ce13f7SAndroid Build Coastguard Worker 100*03ce13f7SAndroid Build Coastguard Worker if idxStart < idxEnd { 101*03ce13f7SAndroid Build Coastguard Worker if first := (*l)[idxStart]; first.Start.Before(s.Start) { 102*03ce13f7SAndroid Build Coastguard Worker s.Start = first.Start 103*03ce13f7SAndroid Build Coastguard Worker } 104*03ce13f7SAndroid Build Coastguard Worker if last := (*l)[idxEnd-1]; last.End.After(s.End) { 105*03ce13f7SAndroid Build Coastguard Worker s.End = last.End 106*03ce13f7SAndroid Build Coastguard Worker } 107*03ce13f7SAndroid Build Coastguard Worker } 108*03ce13f7SAndroid Build Coastguard Worker 109*03ce13f7SAndroid Build Coastguard Worker merged := append(SpanList{}, (*l)[:idxStart]...) 110*03ce13f7SAndroid Build Coastguard Worker merged = append(merged, s) 111*03ce13f7SAndroid Build Coastguard Worker merged = append(merged, (*l)[idxEnd:]...) 112*03ce13f7SAndroid Build Coastguard Worker *l = merged 113*03ce13f7SAndroid Build Coastguard Worker} 114*03ce13f7SAndroid Build Coastguard Worker 115*03ce13f7SAndroid Build Coastguard Worker// Remove cuts out the Span from the SpanList, removing and trimming overlapping 116*03ce13f7SAndroid Build Coastguard Worker// spans. 117*03ce13f7SAndroid Build Coastguard Workerfunc (l *SpanList) Remove(s Span) { 118*03ce13f7SAndroid Build Coastguard Worker if s.Start == s.End { 119*03ce13f7SAndroid Build Coastguard Worker return // zero length == no split. 120*03ce13f7SAndroid Build Coastguard Worker } 121*03ce13f7SAndroid Build Coastguard Worker 122*03ce13f7SAndroid Build Coastguard Worker // [===] 123*03ce13f7SAndroid Build Coastguard Worker // [0] [1] | idxStart: 2 | idxEnd: 2 124*03ce13f7SAndroid Build Coastguard Worker // [0] [1] | idxStart: 0 | idxEnd: 0 125*03ce13f7SAndroid Build Coastguard Worker // [ 0 ] [ 1 ] [ 2 ] [ 3 ] | idxStart: 1 | idxEnd: 2 126*03ce13f7SAndroid Build Coastguard Worker // [0] [1] [2] [3] [4] | idxStart: 2 | idxEnd: 2 127*03ce13f7SAndroid Build Coastguard Worker idxStart := sort.Search(len(*l), func(i int) bool { return (*l)[i].End.Compare(s.Start) > 0 }) 128*03ce13f7SAndroid Build Coastguard Worker idxEnd := sort.Search(len(*l), func(i int) bool { return (*l)[i].Start.Compare(s.End) >= 0 }) 129*03ce13f7SAndroid Build Coastguard Worker 130*03ce13f7SAndroid Build Coastguard Worker merged := append(SpanList{}, (*l)[:idxStart]...) 131*03ce13f7SAndroid Build Coastguard Worker 132*03ce13f7SAndroid Build Coastguard Worker if idxStart < idxEnd { 133*03ce13f7SAndroid Build Coastguard Worker first, last := (*l)[idxStart], (*l)[idxEnd-1] 134*03ce13f7SAndroid Build Coastguard Worker if first.Start.Compare(s.Start) < 0 { 135*03ce13f7SAndroid Build Coastguard Worker merged = append(merged, Span{first.Start, s.Start}) 136*03ce13f7SAndroid Build Coastguard Worker } 137*03ce13f7SAndroid Build Coastguard Worker if last.End.Compare(s.End) > 0 { 138*03ce13f7SAndroid Build Coastguard Worker merged = append(merged, Span{s.End, last.End}) 139*03ce13f7SAndroid Build Coastguard Worker } 140*03ce13f7SAndroid Build Coastguard Worker } 141*03ce13f7SAndroid Build Coastguard Worker 142*03ce13f7SAndroid Build Coastguard Worker merged = append(merged, (*l)[idxEnd:]...) 143*03ce13f7SAndroid Build Coastguard Worker *l = merged 144*03ce13f7SAndroid Build Coastguard Worker} 145*03ce13f7SAndroid Build Coastguard Worker 146*03ce13f7SAndroid Build Coastguard Worker// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0. 147*03ce13f7SAndroid Build Coastguard Workerfunc (l SpanList) Compare(o SpanList) int { 148*03ce13f7SAndroid Build Coastguard Worker switch { 149*03ce13f7SAndroid Build Coastguard Worker case len(l) < len(o): 150*03ce13f7SAndroid Build Coastguard Worker return -1 151*03ce13f7SAndroid Build Coastguard Worker case len(l) > len(o): 152*03ce13f7SAndroid Build Coastguard Worker return 1 153*03ce13f7SAndroid Build Coastguard Worker } 154*03ce13f7SAndroid Build Coastguard Worker for i, a := range l { 155*03ce13f7SAndroid Build Coastguard Worker switch a.Compare(o[i]) { 156*03ce13f7SAndroid Build Coastguard Worker case -1: 157*03ce13f7SAndroid Build Coastguard Worker return -1 158*03ce13f7SAndroid Build Coastguard Worker case 1: 159*03ce13f7SAndroid Build Coastguard Worker return 1 160*03ce13f7SAndroid Build Coastguard Worker } 161*03ce13f7SAndroid Build Coastguard Worker } 162*03ce13f7SAndroid Build Coastguard Worker return 0 163*03ce13f7SAndroid Build Coastguard Worker} 164*03ce13f7SAndroid Build Coastguard Worker 165*03ce13f7SAndroid Build Coastguard Worker// NumLines returns the total number of lines covered by all spans in the list. 166*03ce13f7SAndroid Build Coastguard Workerfunc (l SpanList) NumLines() int { 167*03ce13f7SAndroid Build Coastguard Worker seen := map[int]struct{}{} 168*03ce13f7SAndroid Build Coastguard Worker for _, span := range l { 169*03ce13f7SAndroid Build Coastguard Worker for s := span.Start.Line; s <= span.End.Line; s++ { 170*03ce13f7SAndroid Build Coastguard Worker if _, ok := seen[s]; !ok { 171*03ce13f7SAndroid Build Coastguard Worker seen[s] = struct{}{} 172*03ce13f7SAndroid Build Coastguard Worker } 173*03ce13f7SAndroid Build Coastguard Worker } 174*03ce13f7SAndroid Build Coastguard Worker } 175*03ce13f7SAndroid Build Coastguard Worker return len(seen) 176*03ce13f7SAndroid Build Coastguard Worker} 177