1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2020 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage depset 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "fmt" 19*1fa6dee9SAndroid Build Coastguard Worker "iter" 20*1fa6dee9SAndroid Build Coastguard Worker "slices" 21*1fa6dee9SAndroid Build Coastguard Worker 22*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/gobtools" 23*1fa6dee9SAndroid Build Coastguard Worker) 24*1fa6dee9SAndroid Build Coastguard Worker 25*1fa6dee9SAndroid Build Coastguard Worker// DepSet is designed to be conceptually compatible with Bazel's depsets: 26*1fa6dee9SAndroid Build Coastguard Worker// https://docs.bazel.build/versions/master/skylark/depsets.html 27*1fa6dee9SAndroid Build Coastguard Worker 28*1fa6dee9SAndroid Build Coastguard Workertype Order int 29*1fa6dee9SAndroid Build Coastguard Worker 30*1fa6dee9SAndroid Build Coastguard Workerconst ( 31*1fa6dee9SAndroid Build Coastguard Worker PREORDER Order = iota 32*1fa6dee9SAndroid Build Coastguard Worker POSTORDER 33*1fa6dee9SAndroid Build Coastguard Worker TOPOLOGICAL 34*1fa6dee9SAndroid Build Coastguard Worker) 35*1fa6dee9SAndroid Build Coastguard Worker 36*1fa6dee9SAndroid Build Coastguard Workerfunc (o Order) String() string { 37*1fa6dee9SAndroid Build Coastguard Worker switch o { 38*1fa6dee9SAndroid Build Coastguard Worker case PREORDER: 39*1fa6dee9SAndroid Build Coastguard Worker return "PREORDER" 40*1fa6dee9SAndroid Build Coastguard Worker case POSTORDER: 41*1fa6dee9SAndroid Build Coastguard Worker return "POSTORDER" 42*1fa6dee9SAndroid Build Coastguard Worker case TOPOLOGICAL: 43*1fa6dee9SAndroid Build Coastguard Worker return "TOPOLOGICAL" 44*1fa6dee9SAndroid Build Coastguard Worker default: 45*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("Invalid Order %d", o)) 46*1fa6dee9SAndroid Build Coastguard Worker } 47*1fa6dee9SAndroid Build Coastguard Worker} 48*1fa6dee9SAndroid Build Coastguard Worker 49*1fa6dee9SAndroid Build Coastguard Workertype depSettableType comparable 50*1fa6dee9SAndroid Build Coastguard Worker 51*1fa6dee9SAndroid Build Coastguard Worker// A DepSet efficiently stores a slice of an arbitrary type from transitive dependencies without 52*1fa6dee9SAndroid Build Coastguard Worker// copying. It is stored as a DAG of DepSet nodes, each of which has some direct contents and a list 53*1fa6dee9SAndroid Build Coastguard Worker// of dependency DepSet nodes. 54*1fa6dee9SAndroid Build Coastguard Worker// 55*1fa6dee9SAndroid Build Coastguard Worker// A DepSet has an order that will be used to walk the DAG when ToList() is called. The order 56*1fa6dee9SAndroid Build Coastguard Worker// can be POSTORDER, PREORDER, or TOPOLOGICAL. POSTORDER and PREORDER orders return a postordered 57*1fa6dee9SAndroid Build Coastguard Worker// or preordered left to right flattened list. TOPOLOGICAL returns a list that guarantees that 58*1fa6dee9SAndroid Build Coastguard Worker// elements of children are listed after all of their parents (unless there are duplicate direct 59*1fa6dee9SAndroid Build Coastguard Worker// elements in the DepSet or any of its transitive dependencies, in which case the ordering of the 60*1fa6dee9SAndroid Build Coastguard Worker// duplicated element is not guaranteed). 61*1fa6dee9SAndroid Build Coastguard Worker// 62*1fa6dee9SAndroid Build Coastguard Worker// A DepSet is created by New or NewBuilder.Build from the slice for direct contents 63*1fa6dee9SAndroid Build Coastguard Worker// and the *DepSets of dependencies. A DepSet is immutable once created. 64*1fa6dee9SAndroid Build Coastguard Workertype DepSet[T depSettableType] struct { 65*1fa6dee9SAndroid Build Coastguard Worker handle *depSet[T] 66*1fa6dee9SAndroid Build Coastguard Worker} 67*1fa6dee9SAndroid Build Coastguard Worker 68*1fa6dee9SAndroid Build Coastguard Workertype depSet[T depSettableType] struct { 69*1fa6dee9SAndroid Build Coastguard Worker preorder bool 70*1fa6dee9SAndroid Build Coastguard Worker reverse bool 71*1fa6dee9SAndroid Build Coastguard Worker order Order 72*1fa6dee9SAndroid Build Coastguard Worker direct []T 73*1fa6dee9SAndroid Build Coastguard Worker transitive []DepSet[T] 74*1fa6dee9SAndroid Build Coastguard Worker} 75*1fa6dee9SAndroid Build Coastguard Worker 76*1fa6dee9SAndroid Build Coastguard Workerfunc (d DepSet[T]) impl() *depSet[T] { 77*1fa6dee9SAndroid Build Coastguard Worker return d.handle 78*1fa6dee9SAndroid Build Coastguard Worker} 79*1fa6dee9SAndroid Build Coastguard Worker 80*1fa6dee9SAndroid Build Coastguard Workerfunc (d DepSet[T]) order() Order { 81*1fa6dee9SAndroid Build Coastguard Worker impl := d.impl() 82*1fa6dee9SAndroid Build Coastguard Worker return impl.order 83*1fa6dee9SAndroid Build Coastguard Worker} 84*1fa6dee9SAndroid Build Coastguard Worker 85*1fa6dee9SAndroid Build Coastguard Workertype depSetGob[T depSettableType] struct { 86*1fa6dee9SAndroid Build Coastguard Worker Preorder bool 87*1fa6dee9SAndroid Build Coastguard Worker Reverse bool 88*1fa6dee9SAndroid Build Coastguard Worker Order Order 89*1fa6dee9SAndroid Build Coastguard Worker Direct []T 90*1fa6dee9SAndroid Build Coastguard Worker Transitive []DepSet[T] 91*1fa6dee9SAndroid Build Coastguard Worker} 92*1fa6dee9SAndroid Build Coastguard Worker 93*1fa6dee9SAndroid Build Coastguard Workerfunc (d *DepSet[T]) ToGob() *depSetGob[T] { 94*1fa6dee9SAndroid Build Coastguard Worker impl := d.impl() 95*1fa6dee9SAndroid Build Coastguard Worker return &depSetGob[T]{ 96*1fa6dee9SAndroid Build Coastguard Worker Preorder: impl.preorder, 97*1fa6dee9SAndroid Build Coastguard Worker Reverse: impl.reverse, 98*1fa6dee9SAndroid Build Coastguard Worker Order: impl.order, 99*1fa6dee9SAndroid Build Coastguard Worker Direct: impl.direct, 100*1fa6dee9SAndroid Build Coastguard Worker Transitive: impl.transitive, 101*1fa6dee9SAndroid Build Coastguard Worker } 102*1fa6dee9SAndroid Build Coastguard Worker} 103*1fa6dee9SAndroid Build Coastguard Worker 104*1fa6dee9SAndroid Build Coastguard Workerfunc (d *DepSet[T]) FromGob(data *depSetGob[T]) { 105*1fa6dee9SAndroid Build Coastguard Worker d.handle = &depSet[T]{ 106*1fa6dee9SAndroid Build Coastguard Worker preorder: data.Preorder, 107*1fa6dee9SAndroid Build Coastguard Worker reverse: data.Reverse, 108*1fa6dee9SAndroid Build Coastguard Worker order: data.Order, 109*1fa6dee9SAndroid Build Coastguard Worker direct: data.Direct, 110*1fa6dee9SAndroid Build Coastguard Worker transitive: data.Transitive, 111*1fa6dee9SAndroid Build Coastguard Worker } 112*1fa6dee9SAndroid Build Coastguard Worker} 113*1fa6dee9SAndroid Build Coastguard Worker 114*1fa6dee9SAndroid Build Coastguard Workerfunc (d DepSet[T]) GobEncode() ([]byte, error) { 115*1fa6dee9SAndroid Build Coastguard Worker return gobtools.CustomGobEncode[depSetGob[T]](&d) 116*1fa6dee9SAndroid Build Coastguard Worker} 117*1fa6dee9SAndroid Build Coastguard Worker 118*1fa6dee9SAndroid Build Coastguard Workerfunc (d *DepSet[T]) GobDecode(data []byte) error { 119*1fa6dee9SAndroid Build Coastguard Worker return gobtools.CustomGobDecode[depSetGob[T]](data, d) 120*1fa6dee9SAndroid Build Coastguard Worker} 121*1fa6dee9SAndroid Build Coastguard Worker 122*1fa6dee9SAndroid Build Coastguard Worker// New returns an immutable DepSet with the given order, direct and transitive contents. 123*1fa6dee9SAndroid Build Coastguard Workerfunc New[T depSettableType](order Order, direct []T, transitive []DepSet[T]) DepSet[T] { 124*1fa6dee9SAndroid Build Coastguard Worker var directCopy []T 125*1fa6dee9SAndroid Build Coastguard Worker var transitiveCopy []DepSet[T] 126*1fa6dee9SAndroid Build Coastguard Worker nonEmptyTransitiveCount := 0 127*1fa6dee9SAndroid Build Coastguard Worker for _, t := range transitive { 128*1fa6dee9SAndroid Build Coastguard Worker if t.handle != nil { 129*1fa6dee9SAndroid Build Coastguard Worker if t.order() != order { 130*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s", 131*1fa6dee9SAndroid Build Coastguard Worker order, t.order())) 132*1fa6dee9SAndroid Build Coastguard Worker } 133*1fa6dee9SAndroid Build Coastguard Worker nonEmptyTransitiveCount++ 134*1fa6dee9SAndroid Build Coastguard Worker } 135*1fa6dee9SAndroid Build Coastguard Worker } 136*1fa6dee9SAndroid Build Coastguard Worker 137*1fa6dee9SAndroid Build Coastguard Worker directCopy = slices.Clone(direct) 138*1fa6dee9SAndroid Build Coastguard Worker if nonEmptyTransitiveCount > 0 { 139*1fa6dee9SAndroid Build Coastguard Worker transitiveCopy = make([]DepSet[T], 0, nonEmptyTransitiveCount) 140*1fa6dee9SAndroid Build Coastguard Worker } 141*1fa6dee9SAndroid Build Coastguard Worker var transitiveIter iter.Seq2[int, DepSet[T]] 142*1fa6dee9SAndroid Build Coastguard Worker if order == TOPOLOGICAL { 143*1fa6dee9SAndroid Build Coastguard Worker // TOPOLOGICAL is implemented as a postorder traversal followed by reversing the output. 144*1fa6dee9SAndroid Build Coastguard Worker // Pre-reverse the inputs here so their order is maintained in the output. 145*1fa6dee9SAndroid Build Coastguard Worker slices.Reverse(directCopy) 146*1fa6dee9SAndroid Build Coastguard Worker transitiveIter = slices.Backward(transitive) 147*1fa6dee9SAndroid Build Coastguard Worker } else { 148*1fa6dee9SAndroid Build Coastguard Worker transitiveIter = slices.All(transitive) 149*1fa6dee9SAndroid Build Coastguard Worker } 150*1fa6dee9SAndroid Build Coastguard Worker for _, t := range transitiveIter { 151*1fa6dee9SAndroid Build Coastguard Worker if t.handle != nil { 152*1fa6dee9SAndroid Build Coastguard Worker transitiveCopy = append(transitiveCopy, t) 153*1fa6dee9SAndroid Build Coastguard Worker } 154*1fa6dee9SAndroid Build Coastguard Worker } 155*1fa6dee9SAndroid Build Coastguard Worker 156*1fa6dee9SAndroid Build Coastguard Worker if len(directCopy) == 0 && len(transitive) == 0 { 157*1fa6dee9SAndroid Build Coastguard Worker return DepSet[T]{nil} 158*1fa6dee9SAndroid Build Coastguard Worker } 159*1fa6dee9SAndroid Build Coastguard Worker 160*1fa6dee9SAndroid Build Coastguard Worker depSet := &depSet[T]{ 161*1fa6dee9SAndroid Build Coastguard Worker preorder: order == PREORDER, 162*1fa6dee9SAndroid Build Coastguard Worker reverse: order == TOPOLOGICAL, 163*1fa6dee9SAndroid Build Coastguard Worker order: order, 164*1fa6dee9SAndroid Build Coastguard Worker direct: directCopy, 165*1fa6dee9SAndroid Build Coastguard Worker transitive: transitiveCopy, 166*1fa6dee9SAndroid Build Coastguard Worker } 167*1fa6dee9SAndroid Build Coastguard Worker 168*1fa6dee9SAndroid Build Coastguard Worker return DepSet[T]{depSet} 169*1fa6dee9SAndroid Build Coastguard Worker} 170*1fa6dee9SAndroid Build Coastguard Worker 171*1fa6dee9SAndroid Build Coastguard Worker// Builder is used to create an immutable DepSet. 172*1fa6dee9SAndroid Build Coastguard Workertype Builder[T depSettableType] struct { 173*1fa6dee9SAndroid Build Coastguard Worker order Order 174*1fa6dee9SAndroid Build Coastguard Worker direct []T 175*1fa6dee9SAndroid Build Coastguard Worker transitive []DepSet[T] 176*1fa6dee9SAndroid Build Coastguard Worker} 177*1fa6dee9SAndroid Build Coastguard Worker 178*1fa6dee9SAndroid Build Coastguard Worker// NewBuilder returns a Builder to create an immutable DepSet with the given order and 179*1fa6dee9SAndroid Build Coastguard Worker// type, represented by a slice of type that will be in the DepSet. 180*1fa6dee9SAndroid Build Coastguard Workerfunc NewBuilder[T depSettableType](order Order) *Builder[T] { 181*1fa6dee9SAndroid Build Coastguard Worker return &Builder[T]{ 182*1fa6dee9SAndroid Build Coastguard Worker order: order, 183*1fa6dee9SAndroid Build Coastguard Worker } 184*1fa6dee9SAndroid Build Coastguard Worker} 185*1fa6dee9SAndroid Build Coastguard Worker 186*1fa6dee9SAndroid Build Coastguard Worker// DirectSlice adds direct contents to the DepSet being built by a Builder. Newly added direct 187*1fa6dee9SAndroid Build Coastguard Worker// contents are to the right of any existing direct contents. 188*1fa6dee9SAndroid Build Coastguard Workerfunc (b *Builder[T]) DirectSlice(direct []T) *Builder[T] { 189*1fa6dee9SAndroid Build Coastguard Worker b.direct = append(b.direct, direct...) 190*1fa6dee9SAndroid Build Coastguard Worker return b 191*1fa6dee9SAndroid Build Coastguard Worker} 192*1fa6dee9SAndroid Build Coastguard Worker 193*1fa6dee9SAndroid Build Coastguard Worker// Direct adds direct contents to the DepSet being built by a Builder. Newly added direct 194*1fa6dee9SAndroid Build Coastguard Worker// contents are to the right of any existing direct contents. 195*1fa6dee9SAndroid Build Coastguard Workerfunc (b *Builder[T]) Direct(direct ...T) *Builder[T] { 196*1fa6dee9SAndroid Build Coastguard Worker b.direct = append(b.direct, direct...) 197*1fa6dee9SAndroid Build Coastguard Worker return b 198*1fa6dee9SAndroid Build Coastguard Worker} 199*1fa6dee9SAndroid Build Coastguard Worker 200*1fa6dee9SAndroid Build Coastguard Worker// Transitive adds transitive contents to the DepSet being built by a Builder. Newly added 201*1fa6dee9SAndroid Build Coastguard Worker// transitive contents are to the right of any existing transitive contents. 202*1fa6dee9SAndroid Build Coastguard Workerfunc (b *Builder[T]) Transitive(transitive ...DepSet[T]) *Builder[T] { 203*1fa6dee9SAndroid Build Coastguard Worker for _, t := range transitive { 204*1fa6dee9SAndroid Build Coastguard Worker if t.handle != nil && t.order() != b.order { 205*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s", 206*1fa6dee9SAndroid Build Coastguard Worker b.order, t.order())) 207*1fa6dee9SAndroid Build Coastguard Worker } 208*1fa6dee9SAndroid Build Coastguard Worker } 209*1fa6dee9SAndroid Build Coastguard Worker b.transitive = append(b.transitive, transitive...) 210*1fa6dee9SAndroid Build Coastguard Worker return b 211*1fa6dee9SAndroid Build Coastguard Worker} 212*1fa6dee9SAndroid Build Coastguard Worker 213*1fa6dee9SAndroid Build Coastguard Worker// Build returns the DepSet being built by this Builder. The Builder retains its contents 214*1fa6dee9SAndroid Build Coastguard Worker// for creating more depSets. 215*1fa6dee9SAndroid Build Coastguard Workerfunc (b *Builder[T]) Build() DepSet[T] { 216*1fa6dee9SAndroid Build Coastguard Worker return New(b.order, b.direct, b.transitive) 217*1fa6dee9SAndroid Build Coastguard Worker} 218*1fa6dee9SAndroid Build Coastguard Worker 219*1fa6dee9SAndroid Build Coastguard Worker// walk calls the visit method in depth-first order on a DepSet, preordered if d.preorder is set, 220*1fa6dee9SAndroid Build Coastguard Worker// otherwise postordered. 221*1fa6dee9SAndroid Build Coastguard Workerfunc (d DepSet[T]) walk(visit func([]T)) { 222*1fa6dee9SAndroid Build Coastguard Worker visited := make(map[DepSet[T]]bool) 223*1fa6dee9SAndroid Build Coastguard Worker 224*1fa6dee9SAndroid Build Coastguard Worker var dfs func(d DepSet[T]) 225*1fa6dee9SAndroid Build Coastguard Worker dfs = func(d DepSet[T]) { 226*1fa6dee9SAndroid Build Coastguard Worker impl := d.impl() 227*1fa6dee9SAndroid Build Coastguard Worker visited[d] = true 228*1fa6dee9SAndroid Build Coastguard Worker if impl.preorder { 229*1fa6dee9SAndroid Build Coastguard Worker visit(impl.direct) 230*1fa6dee9SAndroid Build Coastguard Worker } 231*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range impl.transitive { 232*1fa6dee9SAndroid Build Coastguard Worker if !visited[dep] { 233*1fa6dee9SAndroid Build Coastguard Worker dfs(dep) 234*1fa6dee9SAndroid Build Coastguard Worker } 235*1fa6dee9SAndroid Build Coastguard Worker } 236*1fa6dee9SAndroid Build Coastguard Worker 237*1fa6dee9SAndroid Build Coastguard Worker if !impl.preorder { 238*1fa6dee9SAndroid Build Coastguard Worker visit(impl.direct) 239*1fa6dee9SAndroid Build Coastguard Worker } 240*1fa6dee9SAndroid Build Coastguard Worker } 241*1fa6dee9SAndroid Build Coastguard Worker 242*1fa6dee9SAndroid Build Coastguard Worker dfs(d) 243*1fa6dee9SAndroid Build Coastguard Worker} 244*1fa6dee9SAndroid Build Coastguard Worker 245*1fa6dee9SAndroid Build Coastguard Worker// ToList returns the DepSet flattened to a list. The order in the list is based on the order 246*1fa6dee9SAndroid Build Coastguard Worker// of the DepSet. POSTORDER and PREORDER orders return a postordered or preordered left to right 247*1fa6dee9SAndroid Build Coastguard Worker// flattened list. TOPOLOGICAL returns a list that guarantees that elements of children are listed 248*1fa6dee9SAndroid Build Coastguard Worker// after all of their parents (unless there are duplicate direct elements in the DepSet or any of 249*1fa6dee9SAndroid Build Coastguard Worker// its transitive dependencies, in which case the ordering of the duplicated element is not 250*1fa6dee9SAndroid Build Coastguard Worker// guaranteed). 251*1fa6dee9SAndroid Build Coastguard Workerfunc (d DepSet[T]) ToList() []T { 252*1fa6dee9SAndroid Build Coastguard Worker if d.handle == nil { 253*1fa6dee9SAndroid Build Coastguard Worker return nil 254*1fa6dee9SAndroid Build Coastguard Worker } 255*1fa6dee9SAndroid Build Coastguard Worker impl := d.impl() 256*1fa6dee9SAndroid Build Coastguard Worker var list []T 257*1fa6dee9SAndroid Build Coastguard Worker d.walk(func(paths []T) { 258*1fa6dee9SAndroid Build Coastguard Worker list = append(list, paths...) 259*1fa6dee9SAndroid Build Coastguard Worker }) 260*1fa6dee9SAndroid Build Coastguard Worker list = firstUniqueInPlace(list) 261*1fa6dee9SAndroid Build Coastguard Worker if impl.reverse { 262*1fa6dee9SAndroid Build Coastguard Worker slices.Reverse(list) 263*1fa6dee9SAndroid Build Coastguard Worker } 264*1fa6dee9SAndroid Build Coastguard Worker return list 265*1fa6dee9SAndroid Build Coastguard Worker} 266*1fa6dee9SAndroid Build Coastguard Worker 267*1fa6dee9SAndroid Build Coastguard Worker// firstUniqueInPlace returns all unique elements of a slice, keeping the first copy of 268*1fa6dee9SAndroid Build Coastguard Worker// each. It modifies the slice contents in place, and returns a subslice of the original 269*1fa6dee9SAndroid Build Coastguard Worker// slice. 270*1fa6dee9SAndroid Build Coastguard Workerfunc firstUniqueInPlace[T comparable](slice []T) []T { 271*1fa6dee9SAndroid Build Coastguard Worker // 128 was chosen based on BenchmarkFirstUniqueStrings results. 272*1fa6dee9SAndroid Build Coastguard Worker if len(slice) > 128 { 273*1fa6dee9SAndroid Build Coastguard Worker return firstUniqueMap(slice) 274*1fa6dee9SAndroid Build Coastguard Worker } 275*1fa6dee9SAndroid Build Coastguard Worker return firstUniqueList(slice) 276*1fa6dee9SAndroid Build Coastguard Worker} 277*1fa6dee9SAndroid Build Coastguard Worker 278*1fa6dee9SAndroid Build Coastguard Worker// firstUniqueList is an implementation of firstUnique using an O(N^2) list comparison to look for 279*1fa6dee9SAndroid Build Coastguard Worker// duplicates. 280*1fa6dee9SAndroid Build Coastguard Workerfunc firstUniqueList[T any](in []T) []T { 281*1fa6dee9SAndroid Build Coastguard Worker writeIndex := 0 282*1fa6dee9SAndroid Build Coastguard Workerouter: 283*1fa6dee9SAndroid Build Coastguard Worker for readIndex := 0; readIndex < len(in); readIndex++ { 284*1fa6dee9SAndroid Build Coastguard Worker for compareIndex := 0; compareIndex < writeIndex; compareIndex++ { 285*1fa6dee9SAndroid Build Coastguard Worker if interface{}(in[readIndex]) == interface{}(in[compareIndex]) { 286*1fa6dee9SAndroid Build Coastguard Worker // The value at readIndex already exists somewhere in the output region 287*1fa6dee9SAndroid Build Coastguard Worker // of the slice before writeIndex, skip it. 288*1fa6dee9SAndroid Build Coastguard Worker continue outer 289*1fa6dee9SAndroid Build Coastguard Worker } 290*1fa6dee9SAndroid Build Coastguard Worker } 291*1fa6dee9SAndroid Build Coastguard Worker if readIndex != writeIndex { 292*1fa6dee9SAndroid Build Coastguard Worker in[writeIndex] = in[readIndex] 293*1fa6dee9SAndroid Build Coastguard Worker } 294*1fa6dee9SAndroid Build Coastguard Worker writeIndex++ 295*1fa6dee9SAndroid Build Coastguard Worker } 296*1fa6dee9SAndroid Build Coastguard Worker return in[0:writeIndex] 297*1fa6dee9SAndroid Build Coastguard Worker} 298*1fa6dee9SAndroid Build Coastguard Worker 299*1fa6dee9SAndroid Build Coastguard Worker// firstUniqueMap is an implementation of firstUnique using an O(N) hash set lookup to look for 300*1fa6dee9SAndroid Build Coastguard Worker// duplicates. 301*1fa6dee9SAndroid Build Coastguard Workerfunc firstUniqueMap[T comparable](in []T) []T { 302*1fa6dee9SAndroid Build Coastguard Worker writeIndex := 0 303*1fa6dee9SAndroid Build Coastguard Worker seen := make(map[T]bool, len(in)) 304*1fa6dee9SAndroid Build Coastguard Worker for readIndex := 0; readIndex < len(in); readIndex++ { 305*1fa6dee9SAndroid Build Coastguard Worker if _, exists := seen[in[readIndex]]; exists { 306*1fa6dee9SAndroid Build Coastguard Worker continue 307*1fa6dee9SAndroid Build Coastguard Worker } 308*1fa6dee9SAndroid Build Coastguard Worker seen[in[readIndex]] = true 309*1fa6dee9SAndroid Build Coastguard Worker if readIndex != writeIndex { 310*1fa6dee9SAndroid Build Coastguard Worker in[writeIndex] = in[readIndex] 311*1fa6dee9SAndroid Build Coastguard Worker } 312*1fa6dee9SAndroid Build Coastguard Worker writeIndex++ 313*1fa6dee9SAndroid Build Coastguard Worker } 314*1fa6dee9SAndroid Build Coastguard Worker return in[0:writeIndex] 315*1fa6dee9SAndroid Build Coastguard Worker} 316