blob: d04f88b5b3a9dae7d2fce0e90a489d1317c7851c [file] [log] [blame]
Colin Cross96c44122020-11-25 14:29:50 -08001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18 "fmt"
Yu Liu467d7c52024-09-18 21:54:44 +000019
20 "github.com/google/blueprint"
Colin Cross96c44122020-11-25 14:29:50 -080021)
22
Colin Crossc85750b2022-04-21 12:50:51 -070023// DepSet is designed to be conceptually compatible with Bazel's depsets:
Colin Cross96c44122020-11-25 14:29:50 -080024// https://docs.bazel.build/versions/master/skylark/depsets.html
25
26type DepSetOrder int
27
28const (
29 PREORDER DepSetOrder = iota
30 POSTORDER
31 TOPOLOGICAL
32)
33
34func (o DepSetOrder) String() string {
35 switch o {
36 case PREORDER:
37 return "PREORDER"
38 case POSTORDER:
39 return "POSTORDER"
40 case TOPOLOGICAL:
41 return "TOPOLOGICAL"
42 default:
43 panic(fmt.Errorf("Invalid DepSetOrder %d", o))
44 }
45}
46
Colin Crossc85750b2022-04-21 12:50:51 -070047type depSettableType comparable
48
49// A DepSet efficiently stores a slice of an arbitrary type from transitive dependencies without
50// copying. It is stored as a DAG of DepSet nodes, each of which has some direct contents and a list
51// of dependency DepSet nodes.
Colin Cross96c44122020-11-25 14:29:50 -080052//
Colin Crossc85750b2022-04-21 12:50:51 -070053// A DepSet has an order that will be used to walk the DAG when ToList() is called. The order
Colin Cross96c44122020-11-25 14:29:50 -080054// can be POSTORDER, PREORDER, or TOPOLOGICAL. POSTORDER and PREORDER orders return a postordered
55// or preordered left to right flattened list. TOPOLOGICAL returns a list that guarantees that
56// elements of children are listed after all of their parents (unless there are duplicate direct
Colin Crossc85750b2022-04-21 12:50:51 -070057// elements in the DepSet or any of its transitive dependencies, in which case the ordering of the
Colin Cross96c44122020-11-25 14:29:50 -080058// duplicated element is not guaranteed).
59//
Colin Crossc85750b2022-04-21 12:50:51 -070060// A DepSet is created by NewDepSet or NewDepSetBuilder.Build from the slice for direct contents
61// and the *DepSets of dependencies. A DepSet is immutable once created.
62type DepSet[T depSettableType] struct {
Colin Cross96c44122020-11-25 14:29:50 -080063 preorder bool
64 reverse bool
65 order DepSetOrder
Colin Crossc85750b2022-04-21 12:50:51 -070066 direct []T
67 transitive []*DepSet[T]
Colin Cross96c44122020-11-25 14:29:50 -080068}
69
Yu Liu467d7c52024-09-18 21:54:44 +000070type depSetGob[T depSettableType] struct {
71 Preorder bool
72 Reverse bool
73 Order DepSetOrder
74 Direct []T
75 Transitive []*DepSet[T]
76}
Yu Liu26a716d2024-08-30 23:40:32 +000077
Yu Liu467d7c52024-09-18 21:54:44 +000078func (d *DepSet[T]) ToGob() *depSetGob[T] {
79 return &depSetGob[T]{
80 Preorder: d.preorder,
81 Reverse: d.reverse,
82 Order: d.order,
83 Direct: d.direct,
84 Transitive: d.transitive,
85 }
86}
87
88func (d *DepSet[T]) FromGob(data *depSetGob[T]) {
89 d.preorder = data.Preorder
90 d.reverse = data.Reverse
91 d.order = data.Order
92 d.direct = data.Direct
93 d.transitive = data.Transitive
94}
95
96func (d *DepSet[T]) GobEncode() ([]byte, error) {
97 return blueprint.CustomGobEncode[depSetGob[T]](d)
Yu Liu26a716d2024-08-30 23:40:32 +000098}
99
100func (d *DepSet[T]) GobDecode(data []byte) error {
Yu Liu467d7c52024-09-18 21:54:44 +0000101 return blueprint.CustomGobDecode[depSetGob[T]](data, d)
Yu Liu26a716d2024-08-30 23:40:32 +0000102}
103
Colin Crossc85750b2022-04-21 12:50:51 -0700104// NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
105func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*DepSet[T]) *DepSet[T] {
106 var directCopy []T
107 var transitiveCopy []*DepSet[T]
108 for _, t := range transitive {
109 if t.order != order {
110 panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
111 order, t.order))
112 }
Colin Cross96c44122020-11-25 14:29:50 -0800113 }
114
Colin Crossc85750b2022-04-21 12:50:51 -0700115 if order == TOPOLOGICAL {
116 // TOPOLOGICAL is implemented as a postorder traversal followed by reversing the output.
117 // Pre-reverse the inputs here so their order is maintained in the output.
Colin Crossb5e3f7d2023-07-06 15:37:53 -0700118 directCopy = ReverseSlice(direct)
119 transitiveCopy = ReverseSlice(transitive)
Colin Crossc85750b2022-04-21 12:50:51 -0700120 } else {
121 directCopy = append([]T(nil), direct...)
122 transitiveCopy = append([]*DepSet[T](nil), transitive...)
123 }
124
125 return &DepSet[T]{
Colin Cross96c44122020-11-25 14:29:50 -0800126 preorder: order == PREORDER,
127 reverse: order == TOPOLOGICAL,
128 order: order,
129 direct: directCopy,
Colin Crossc85750b2022-04-21 12:50:51 -0700130 transitive: transitiveCopy,
Colin Cross96c44122020-11-25 14:29:50 -0800131 }
132}
133
Colin Crossc85750b2022-04-21 12:50:51 -0700134// DepSetBuilder is used to create an immutable DepSet.
135type DepSetBuilder[T depSettableType] struct {
Colin Cross96c44122020-11-25 14:29:50 -0800136 order DepSetOrder
Colin Crossc85750b2022-04-21 12:50:51 -0700137 direct []T
138 transitive []*DepSet[T]
Colin Cross96c44122020-11-25 14:29:50 -0800139}
140
Colin Crossc85750b2022-04-21 12:50:51 -0700141// NewDepSetBuilder returns a DepSetBuilder to create an immutable DepSet with the given order and
142// type, represented by a slice of type that will be in the DepSet.
143func NewDepSetBuilder[T depSettableType](order DepSetOrder) *DepSetBuilder[T] {
144 return &DepSetBuilder[T]{
145 order: order,
Colin Cross96c44122020-11-25 14:29:50 -0800146 }
147}
148
Colin Crossc85750b2022-04-21 12:50:51 -0700149// DirectSlice adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
150// contents are to the right of any existing direct contents.
151func (b *DepSetBuilder[T]) DirectSlice(direct []T) *DepSetBuilder[T] {
152 b.direct = append(b.direct, direct...)
Colin Cross96c44122020-11-25 14:29:50 -0800153 return b
154}
155
Colin Crossc85750b2022-04-21 12:50:51 -0700156// Direct adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
157// contents are to the right of any existing direct contents.
158func (b *DepSetBuilder[T]) Direct(direct ...T) *DepSetBuilder[T] {
159 b.direct = append(b.direct, direct...)
Colin Cross96c44122020-11-25 14:29:50 -0800160 return b
161}
162
163// Transitive adds transitive contents to the DepSet being built by a DepSetBuilder. Newly added
Colin Crossc85750b2022-04-21 12:50:51 -0700164// transitive contents are to the right of any existing transitive contents.
165func (b *DepSetBuilder[T]) Transitive(transitive ...*DepSet[T]) *DepSetBuilder[T] {
166 for _, t := range transitive {
167 if t.order != b.order {
168 panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
169 b.order, t.order))
170 }
171 }
172 b.transitive = append(b.transitive, transitive...)
Colin Cross96c44122020-11-25 14:29:50 -0800173 return b
174}
175
Colin Crossc85750b2022-04-21 12:50:51 -0700176// Returns the DepSet being built by this DepSetBuilder. The DepSetBuilder retains its contents
Colin Cross96c44122020-11-25 14:29:50 -0800177// for creating more depSets.
Colin Crossc85750b2022-04-21 12:50:51 -0700178func (b *DepSetBuilder[T]) Build() *DepSet[T] {
179 return NewDepSet(b.order, b.direct, b.transitive)
Colin Cross96c44122020-11-25 14:29:50 -0800180}
181
182// walk calls the visit method in depth-first order on a DepSet, preordered if d.preorder is set,
183// otherwise postordered.
Colin Crossc85750b2022-04-21 12:50:51 -0700184func (d *DepSet[T]) walk(visit func([]T)) {
185 visited := make(map[*DepSet[T]]bool)
Colin Cross96c44122020-11-25 14:29:50 -0800186
Colin Crossc85750b2022-04-21 12:50:51 -0700187 var dfs func(d *DepSet[T])
188 dfs = func(d *DepSet[T]) {
Colin Cross96c44122020-11-25 14:29:50 -0800189 visited[d] = true
190 if d.preorder {
191 visit(d.direct)
192 }
193 for _, dep := range d.transitive {
194 if !visited[dep] {
195 dfs(dep)
196 }
197 }
198
199 if !d.preorder {
200 visit(d.direct)
201 }
202 }
203
204 dfs(d)
205}
206
Colin Crossc85750b2022-04-21 12:50:51 -0700207// ToList returns the DepSet flattened to a list. The order in the list is based on the order
208// of the DepSet. POSTORDER and PREORDER orders return a postordered or preordered left to right
Colin Cross96c44122020-11-25 14:29:50 -0800209// flattened list. TOPOLOGICAL returns a list that guarantees that elements of children are listed
210// after all of their parents (unless there are duplicate direct elements in the DepSet or any of
211// its transitive dependencies, in which case the ordering of the duplicated element is not
212// guaranteed).
Colin Crossc85750b2022-04-21 12:50:51 -0700213func (d *DepSet[T]) ToList() []T {
Colin Cross96c44122020-11-25 14:29:50 -0800214 if d == nil {
215 return nil
216 }
Colin Crossc85750b2022-04-21 12:50:51 -0700217 var list []T
218 d.walk(func(paths []T) {
219 list = append(list, paths...)
Colin Cross96c44122020-11-25 14:29:50 -0800220 })
Colin Cross48016d52023-06-27 09:45:26 -0700221 list = firstUniqueInPlace(list)
Colin Cross96c44122020-11-25 14:29:50 -0800222 if d.reverse {
Colin Crossb5e3f7d2023-07-06 15:37:53 -0700223 ReverseSliceInPlace(list)
Colin Cross96c44122020-11-25 14:29:50 -0800224 }
225 return list
226}