xref: /aosp_15_r20/build/blueprint/depset/depset.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
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