xref: /aosp_15_r20/external/stg/graph.h (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2020-2024 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Maria Teguiani
19*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
20*9e3b08aeSAndroid Build Coastguard Worker // Author: Ignes Simeonova
21*9e3b08aeSAndroid Build Coastguard Worker 
22*9e3b08aeSAndroid Build Coastguard Worker #ifndef STG_GRAPH_H_
23*9e3b08aeSAndroid Build Coastguard Worker #define STG_GRAPH_H_
24*9e3b08aeSAndroid Build Coastguard Worker 
25*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
26*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint>
27*9e3b08aeSAndroid Build Coastguard Worker #include <exception>
28*9e3b08aeSAndroid Build Coastguard Worker #include <functional>
29*9e3b08aeSAndroid Build Coastguard Worker #include <map>
30*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
31*9e3b08aeSAndroid Build Coastguard Worker #include <ostream>
32*9e3b08aeSAndroid Build Coastguard Worker #include <sstream>
33*9e3b08aeSAndroid Build Coastguard Worker #include <string>
34*9e3b08aeSAndroid Build Coastguard Worker #include <type_traits>
35*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
36*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
37*9e3b08aeSAndroid Build Coastguard Worker 
38*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
39*9e3b08aeSAndroid Build Coastguard Worker 
40*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
41*9e3b08aeSAndroid Build Coastguard Worker 
42*9e3b08aeSAndroid Build Coastguard Worker // A wrapped (for type safety) array index.
43*9e3b08aeSAndroid Build Coastguard Worker struct Id {
44*9e3b08aeSAndroid Build Coastguard Worker   // defined in graph.cc as maximum value for index type
45*9e3b08aeSAndroid Build Coastguard Worker   static const Id kInvalid;
IdId46*9e3b08aeSAndroid Build Coastguard Worker   explicit Id(size_t ix) : ix_(ix) {}
47*9e3b08aeSAndroid Build Coastguard Worker   auto operator<=>(const Id&) const = default;
48*9e3b08aeSAndroid Build Coastguard Worker   size_t ix_;
49*9e3b08aeSAndroid Build Coastguard Worker };
50*9e3b08aeSAndroid Build Coastguard Worker 
51*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Id id);
52*9e3b08aeSAndroid Build Coastguard Worker 
53*9e3b08aeSAndroid Build Coastguard Worker using Pair = std::pair<Id, Id>;
54*9e3b08aeSAndroid Build Coastguard Worker 
55*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
56*9e3b08aeSAndroid Build Coastguard Worker 
57*9e3b08aeSAndroid Build Coastguard Worker namespace std {
58*9e3b08aeSAndroid Build Coastguard Worker 
59*9e3b08aeSAndroid Build Coastguard Worker template <>
60*9e3b08aeSAndroid Build Coastguard Worker struct hash<stg::Id> {
61*9e3b08aeSAndroid Build Coastguard Worker   size_t operator()(const stg::Id& id) const {
62*9e3b08aeSAndroid Build Coastguard Worker     return hash<decltype(id.ix_)>()(id.ix_);
63*9e3b08aeSAndroid Build Coastguard Worker   }
64*9e3b08aeSAndroid Build Coastguard Worker };
65*9e3b08aeSAndroid Build Coastguard Worker 
66*9e3b08aeSAndroid Build Coastguard Worker template <>
67*9e3b08aeSAndroid Build Coastguard Worker struct hash<stg::Pair> {
68*9e3b08aeSAndroid Build Coastguard Worker   size_t operator()(const stg::Pair& comparison) const {
69*9e3b08aeSAndroid Build Coastguard Worker     const hash<stg::Id> h;
70*9e3b08aeSAndroid Build Coastguard Worker     auto h1 = h(comparison.first);
71*9e3b08aeSAndroid Build Coastguard Worker     auto h2 = h(comparison.second);
72*9e3b08aeSAndroid Build Coastguard Worker     // assumes 64-bit size_t, would be better if std::hash_combine existed
73*9e3b08aeSAndroid Build Coastguard Worker     return h1 ^ (h2 + 0x9e3779b97f4a7c15 + (h1 << 12) + (h1 >> 4));
74*9e3b08aeSAndroid Build Coastguard Worker   }
75*9e3b08aeSAndroid Build Coastguard Worker };
76*9e3b08aeSAndroid Build Coastguard Worker 
77*9e3b08aeSAndroid Build Coastguard Worker }  // namespace std
78*9e3b08aeSAndroid Build Coastguard Worker 
79*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
80*9e3b08aeSAndroid Build Coastguard Worker 
81*9e3b08aeSAndroid Build Coastguard Worker struct Special {
82*9e3b08aeSAndroid Build Coastguard Worker   enum class Kind {
83*9e3b08aeSAndroid Build Coastguard Worker     VOID,
84*9e3b08aeSAndroid Build Coastguard Worker     VARIADIC,
85*9e3b08aeSAndroid Build Coastguard Worker     NULLPTR,
86*9e3b08aeSAndroid Build Coastguard Worker   };
87*9e3b08aeSAndroid Build Coastguard Worker   explicit Special(Kind kind)
88*9e3b08aeSAndroid Build Coastguard Worker       : kind(kind) {}
89*9e3b08aeSAndroid Build Coastguard Worker 
90*9e3b08aeSAndroid Build Coastguard Worker   Kind kind;
91*9e3b08aeSAndroid Build Coastguard Worker };
92*9e3b08aeSAndroid Build Coastguard Worker 
93*9e3b08aeSAndroid Build Coastguard Worker struct PointerReference {
94*9e3b08aeSAndroid Build Coastguard Worker   enum class Kind {
95*9e3b08aeSAndroid Build Coastguard Worker     POINTER,
96*9e3b08aeSAndroid Build Coastguard Worker     LVALUE_REFERENCE,
97*9e3b08aeSAndroid Build Coastguard Worker     RVALUE_REFERENCE,
98*9e3b08aeSAndroid Build Coastguard Worker   };
99*9e3b08aeSAndroid Build Coastguard Worker   PointerReference(Kind kind, Id pointee_type_id)
100*9e3b08aeSAndroid Build Coastguard Worker       : kind(kind), pointee_type_id(pointee_type_id) {}
101*9e3b08aeSAndroid Build Coastguard Worker 
102*9e3b08aeSAndroid Build Coastguard Worker   Kind kind;
103*9e3b08aeSAndroid Build Coastguard Worker   Id pointee_type_id;
104*9e3b08aeSAndroid Build Coastguard Worker };
105*9e3b08aeSAndroid Build Coastguard Worker 
106*9e3b08aeSAndroid Build Coastguard Worker struct PointerToMember {
107*9e3b08aeSAndroid Build Coastguard Worker   PointerToMember(Id containing_type_id, Id pointee_type_id)
108*9e3b08aeSAndroid Build Coastguard Worker       : containing_type_id(containing_type_id), pointee_type_id(pointee_type_id)
109*9e3b08aeSAndroid Build Coastguard Worker   {}
110*9e3b08aeSAndroid Build Coastguard Worker 
111*9e3b08aeSAndroid Build Coastguard Worker   Id containing_type_id;
112*9e3b08aeSAndroid Build Coastguard Worker   Id pointee_type_id;
113*9e3b08aeSAndroid Build Coastguard Worker };
114*9e3b08aeSAndroid Build Coastguard Worker 
115*9e3b08aeSAndroid Build Coastguard Worker struct Typedef {
116*9e3b08aeSAndroid Build Coastguard Worker   Typedef(const std::string& name, Id referred_type_id)
117*9e3b08aeSAndroid Build Coastguard Worker       : name(name), referred_type_id(referred_type_id) {}
118*9e3b08aeSAndroid Build Coastguard Worker 
119*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
120*9e3b08aeSAndroid Build Coastguard Worker   Id referred_type_id;
121*9e3b08aeSAndroid Build Coastguard Worker };
122*9e3b08aeSAndroid Build Coastguard Worker 
123*9e3b08aeSAndroid Build Coastguard Worker enum class Qualifier { CONST, VOLATILE, RESTRICT, ATOMIC };
124*9e3b08aeSAndroid Build Coastguard Worker 
125*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Qualifier qualifier);
126*9e3b08aeSAndroid Build Coastguard Worker 
127*9e3b08aeSAndroid Build Coastguard Worker struct Qualified {
128*9e3b08aeSAndroid Build Coastguard Worker   Qualified(Qualifier qualifier, Id qualified_type_id)
129*9e3b08aeSAndroid Build Coastguard Worker       : qualifier(qualifier), qualified_type_id(qualified_type_id) {}
130*9e3b08aeSAndroid Build Coastguard Worker 
131*9e3b08aeSAndroid Build Coastguard Worker   Qualifier qualifier;
132*9e3b08aeSAndroid Build Coastguard Worker   Id qualified_type_id;
133*9e3b08aeSAndroid Build Coastguard Worker };
134*9e3b08aeSAndroid Build Coastguard Worker 
135*9e3b08aeSAndroid Build Coastguard Worker struct Primitive {
136*9e3b08aeSAndroid Build Coastguard Worker   enum class Encoding {
137*9e3b08aeSAndroid Build Coastguard Worker     BOOLEAN,
138*9e3b08aeSAndroid Build Coastguard Worker     SIGNED_INTEGER,
139*9e3b08aeSAndroid Build Coastguard Worker     UNSIGNED_INTEGER,
140*9e3b08aeSAndroid Build Coastguard Worker     SIGNED_CHARACTER,
141*9e3b08aeSAndroid Build Coastguard Worker     UNSIGNED_CHARACTER,
142*9e3b08aeSAndroid Build Coastguard Worker     REAL_NUMBER,
143*9e3b08aeSAndroid Build Coastguard Worker     COMPLEX_NUMBER,
144*9e3b08aeSAndroid Build Coastguard Worker     UTF,
145*9e3b08aeSAndroid Build Coastguard Worker   };
146*9e3b08aeSAndroid Build Coastguard Worker   Primitive(const std::string& name, std::optional<Encoding> encoding,
147*9e3b08aeSAndroid Build Coastguard Worker             uint32_t bytesize)
148*9e3b08aeSAndroid Build Coastguard Worker       : name(name), encoding(encoding), bytesize(bytesize) {}
149*9e3b08aeSAndroid Build Coastguard Worker 
150*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
151*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Encoding> encoding;
152*9e3b08aeSAndroid Build Coastguard Worker   uint32_t bytesize;
153*9e3b08aeSAndroid Build Coastguard Worker };
154*9e3b08aeSAndroid Build Coastguard Worker 
155*9e3b08aeSAndroid Build Coastguard Worker struct Array {
156*9e3b08aeSAndroid Build Coastguard Worker   Array(uint64_t number_of_elements, Id element_type_id)
157*9e3b08aeSAndroid Build Coastguard Worker       : number_of_elements(number_of_elements),
158*9e3b08aeSAndroid Build Coastguard Worker         element_type_id(element_type_id)  {}
159*9e3b08aeSAndroid Build Coastguard Worker 
160*9e3b08aeSAndroid Build Coastguard Worker   uint64_t number_of_elements;
161*9e3b08aeSAndroid Build Coastguard Worker   Id element_type_id;
162*9e3b08aeSAndroid Build Coastguard Worker };
163*9e3b08aeSAndroid Build Coastguard Worker 
164*9e3b08aeSAndroid Build Coastguard Worker struct BaseClass {
165*9e3b08aeSAndroid Build Coastguard Worker   enum class Inheritance { NON_VIRTUAL, VIRTUAL };
166*9e3b08aeSAndroid Build Coastguard Worker   BaseClass(Id type_id, uint64_t offset, Inheritance inheritance)
167*9e3b08aeSAndroid Build Coastguard Worker       : type_id(type_id), offset(offset), inheritance(inheritance) {}
168*9e3b08aeSAndroid Build Coastguard Worker 
169*9e3b08aeSAndroid Build Coastguard Worker   Id type_id;
170*9e3b08aeSAndroid Build Coastguard Worker   uint64_t offset;
171*9e3b08aeSAndroid Build Coastguard Worker   Inheritance inheritance;
172*9e3b08aeSAndroid Build Coastguard Worker };
173*9e3b08aeSAndroid Build Coastguard Worker 
174*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, BaseClass::Inheritance inheritance);
175*9e3b08aeSAndroid Build Coastguard Worker 
176*9e3b08aeSAndroid Build Coastguard Worker struct Method {
177*9e3b08aeSAndroid Build Coastguard Worker   Method(const std::string& mangled_name, const std::string& name,
178*9e3b08aeSAndroid Build Coastguard Worker          uint64_t vtable_offset, Id type_id)
179*9e3b08aeSAndroid Build Coastguard Worker       : mangled_name(mangled_name), name(name),
180*9e3b08aeSAndroid Build Coastguard Worker         vtable_offset(vtable_offset), type_id(type_id) {}
181*9e3b08aeSAndroid Build Coastguard Worker 
182*9e3b08aeSAndroid Build Coastguard Worker   std::string mangled_name;
183*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
184*9e3b08aeSAndroid Build Coastguard Worker   uint64_t vtable_offset;
185*9e3b08aeSAndroid Build Coastguard Worker   Id type_id;
186*9e3b08aeSAndroid Build Coastguard Worker };
187*9e3b08aeSAndroid Build Coastguard Worker 
188*9e3b08aeSAndroid Build Coastguard Worker struct Member {
189*9e3b08aeSAndroid Build Coastguard Worker   Member(const std::string& name, Id type_id, uint64_t offset, uint64_t bitsize)
190*9e3b08aeSAndroid Build Coastguard Worker       : name(name), type_id(type_id), offset(offset), bitsize(bitsize) {}
191*9e3b08aeSAndroid Build Coastguard Worker 
192*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
193*9e3b08aeSAndroid Build Coastguard Worker   Id type_id;
194*9e3b08aeSAndroid Build Coastguard Worker   uint64_t offset;
195*9e3b08aeSAndroid Build Coastguard Worker   uint64_t bitsize;
196*9e3b08aeSAndroid Build Coastguard Worker };
197*9e3b08aeSAndroid Build Coastguard Worker 
198*9e3b08aeSAndroid Build Coastguard Worker struct VariantMember {
199*9e3b08aeSAndroid Build Coastguard Worker   VariantMember(const std::string& name,
200*9e3b08aeSAndroid Build Coastguard Worker                 std::optional<int64_t> discriminant_value, Id type_id)
201*9e3b08aeSAndroid Build Coastguard Worker       : name(name), discriminant_value(discriminant_value), type_id(type_id) {}
202*9e3b08aeSAndroid Build Coastguard Worker 
203*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
204*9e3b08aeSAndroid Build Coastguard Worker   std::optional<int64_t> discriminant_value;
205*9e3b08aeSAndroid Build Coastguard Worker   Id type_id;
206*9e3b08aeSAndroid Build Coastguard Worker };
207*9e3b08aeSAndroid Build Coastguard Worker 
208*9e3b08aeSAndroid Build Coastguard Worker struct StructUnion {
209*9e3b08aeSAndroid Build Coastguard Worker   enum class Kind { STRUCT, UNION };
210*9e3b08aeSAndroid Build Coastguard Worker   struct Definition {
211*9e3b08aeSAndroid Build Coastguard Worker     uint64_t bytesize;
212*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> base_classes;
213*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> methods;
214*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> members;
215*9e3b08aeSAndroid Build Coastguard Worker   };
216*9e3b08aeSAndroid Build Coastguard Worker   StructUnion(Kind kind, const std::string& name) : kind(kind), name(name) {}
217*9e3b08aeSAndroid Build Coastguard Worker   StructUnion(Kind kind, const std::string& name, uint64_t bytesize,
218*9e3b08aeSAndroid Build Coastguard Worker               const std::vector<Id>& base_classes,
219*9e3b08aeSAndroid Build Coastguard Worker               const std::vector<Id>& methods, const std::vector<Id>& members)
220*9e3b08aeSAndroid Build Coastguard Worker       : kind(kind), name(name),
221*9e3b08aeSAndroid Build Coastguard Worker         definition({bytesize, base_classes, methods, members}) {}
222*9e3b08aeSAndroid Build Coastguard Worker 
223*9e3b08aeSAndroid Build Coastguard Worker   Kind kind;
224*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
225*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Definition> definition;
226*9e3b08aeSAndroid Build Coastguard Worker };
227*9e3b08aeSAndroid Build Coastguard Worker 
228*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, StructUnion::Kind kind);
229*9e3b08aeSAndroid Build Coastguard Worker std::string& operator+=(std::string& os, StructUnion::Kind kind);
230*9e3b08aeSAndroid Build Coastguard Worker 
231*9e3b08aeSAndroid Build Coastguard Worker struct Enumeration {
232*9e3b08aeSAndroid Build Coastguard Worker   using Enumerators = std::vector<std::pair<std::string, int64_t>>;
233*9e3b08aeSAndroid Build Coastguard Worker   struct Definition {
234*9e3b08aeSAndroid Build Coastguard Worker     Id underlying_type_id;
235*9e3b08aeSAndroid Build Coastguard Worker     Enumerators enumerators;
236*9e3b08aeSAndroid Build Coastguard Worker   };
237*9e3b08aeSAndroid Build Coastguard Worker   explicit Enumeration(const std::string& name) : name(name) {}
238*9e3b08aeSAndroid Build Coastguard Worker   Enumeration(const std::string& name, Id underlying_type_id,
239*9e3b08aeSAndroid Build Coastguard Worker               const Enumerators& enumerators)
240*9e3b08aeSAndroid Build Coastguard Worker       : name(name), definition({underlying_type_id, enumerators}) {}
241*9e3b08aeSAndroid Build Coastguard Worker 
242*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
243*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Definition> definition;
244*9e3b08aeSAndroid Build Coastguard Worker };
245*9e3b08aeSAndroid Build Coastguard Worker 
246*9e3b08aeSAndroid Build Coastguard Worker struct Variant {
247*9e3b08aeSAndroid Build Coastguard Worker   Variant(const std::string& name, uint64_t bytesize,
248*9e3b08aeSAndroid Build Coastguard Worker           std::optional<Id> discriminant, const std::vector<Id>& members)
249*9e3b08aeSAndroid Build Coastguard Worker       : name(name),
250*9e3b08aeSAndroid Build Coastguard Worker         bytesize(bytesize),
251*9e3b08aeSAndroid Build Coastguard Worker         discriminant(discriminant),
252*9e3b08aeSAndroid Build Coastguard Worker         members(members) {}
253*9e3b08aeSAndroid Build Coastguard Worker 
254*9e3b08aeSAndroid Build Coastguard Worker   std::string name;
255*9e3b08aeSAndroid Build Coastguard Worker   uint64_t bytesize;
256*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Id> discriminant;
257*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> members;
258*9e3b08aeSAndroid Build Coastguard Worker };
259*9e3b08aeSAndroid Build Coastguard Worker 
260*9e3b08aeSAndroid Build Coastguard Worker struct Function {
261*9e3b08aeSAndroid Build Coastguard Worker   Function(Id return_type_id, const std::vector<Id>& parameters)
262*9e3b08aeSAndroid Build Coastguard Worker       : return_type_id(return_type_id), parameters(parameters) {}
263*9e3b08aeSAndroid Build Coastguard Worker 
264*9e3b08aeSAndroid Build Coastguard Worker   Id return_type_id;
265*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> parameters;
266*9e3b08aeSAndroid Build Coastguard Worker };
267*9e3b08aeSAndroid Build Coastguard Worker 
268*9e3b08aeSAndroid Build Coastguard Worker struct ElfSymbol {
269*9e3b08aeSAndroid Build Coastguard Worker   enum class SymbolType { NOTYPE, OBJECT, FUNCTION, COMMON, TLS, GNU_IFUNC };
270*9e3b08aeSAndroid Build Coastguard Worker   enum class Binding { GLOBAL, LOCAL, WEAK, GNU_UNIQUE };
271*9e3b08aeSAndroid Build Coastguard Worker   enum class Visibility { DEFAULT, PROTECTED, HIDDEN, INTERNAL };
272*9e3b08aeSAndroid Build Coastguard Worker   struct VersionInfo {
273*9e3b08aeSAndroid Build Coastguard Worker     auto operator<=>(const VersionInfo&) const = default;
274*9e3b08aeSAndroid Build Coastguard Worker     bool is_default;
275*9e3b08aeSAndroid Build Coastguard Worker     std::string name;
276*9e3b08aeSAndroid Build Coastguard Worker   };
277*9e3b08aeSAndroid Build Coastguard Worker   struct CRC {
278*9e3b08aeSAndroid Build Coastguard Worker     explicit CRC(uint32_t number) : number(number) {}
279*9e3b08aeSAndroid Build Coastguard Worker     auto operator<=>(const CRC&) const = default;
280*9e3b08aeSAndroid Build Coastguard Worker     uint32_t number;
281*9e3b08aeSAndroid Build Coastguard Worker   };
282*9e3b08aeSAndroid Build Coastguard Worker   ElfSymbol(const std::string& symbol_name,
283*9e3b08aeSAndroid Build Coastguard Worker             std::optional<VersionInfo> version_info,
284*9e3b08aeSAndroid Build Coastguard Worker             bool is_defined,
285*9e3b08aeSAndroid Build Coastguard Worker             SymbolType symbol_type,
286*9e3b08aeSAndroid Build Coastguard Worker             Binding binding,
287*9e3b08aeSAndroid Build Coastguard Worker             Visibility visibility,
288*9e3b08aeSAndroid Build Coastguard Worker             std::optional<CRC> crc,
289*9e3b08aeSAndroid Build Coastguard Worker             std::optional<std::string> ns,
290*9e3b08aeSAndroid Build Coastguard Worker             std::optional<Id> type_id,
291*9e3b08aeSAndroid Build Coastguard Worker             const std::optional<std::string>& full_name)
292*9e3b08aeSAndroid Build Coastguard Worker       : symbol_name(symbol_name),
293*9e3b08aeSAndroid Build Coastguard Worker         version_info(version_info),
294*9e3b08aeSAndroid Build Coastguard Worker         is_defined(is_defined),
295*9e3b08aeSAndroid Build Coastguard Worker         symbol_type(symbol_type),
296*9e3b08aeSAndroid Build Coastguard Worker         binding(binding),
297*9e3b08aeSAndroid Build Coastguard Worker         visibility(visibility),
298*9e3b08aeSAndroid Build Coastguard Worker         crc(crc),
299*9e3b08aeSAndroid Build Coastguard Worker         ns(ns),
300*9e3b08aeSAndroid Build Coastguard Worker         type_id(type_id),
301*9e3b08aeSAndroid Build Coastguard Worker         full_name(full_name) {}
302*9e3b08aeSAndroid Build Coastguard Worker 
303*9e3b08aeSAndroid Build Coastguard Worker   std::string symbol_name;
304*9e3b08aeSAndroid Build Coastguard Worker   std::optional<VersionInfo> version_info;
305*9e3b08aeSAndroid Build Coastguard Worker   bool is_defined;
306*9e3b08aeSAndroid Build Coastguard Worker   SymbolType symbol_type;
307*9e3b08aeSAndroid Build Coastguard Worker   Binding binding;
308*9e3b08aeSAndroid Build Coastguard Worker   Visibility visibility;
309*9e3b08aeSAndroid Build Coastguard Worker   std::optional<CRC> crc;
310*9e3b08aeSAndroid Build Coastguard Worker   std::optional<std::string> ns;
311*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Id> type_id;
312*9e3b08aeSAndroid Build Coastguard Worker   std::optional<std::string> full_name;
313*9e3b08aeSAndroid Build Coastguard Worker };
314*9e3b08aeSAndroid Build Coastguard Worker 
315*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::SymbolType);
316*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::Binding);
317*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::Visibility);
318*9e3b08aeSAndroid Build Coastguard Worker 
319*9e3b08aeSAndroid Build Coastguard Worker std::string VersionInfoToString(const ElfSymbol::VersionInfo& version_info);
320*9e3b08aeSAndroid Build Coastguard Worker std::string VersionedSymbolName(const ElfSymbol&);
321*9e3b08aeSAndroid Build Coastguard Worker 
322*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::CRC crc);
323*9e3b08aeSAndroid Build Coastguard Worker 
324*9e3b08aeSAndroid Build Coastguard Worker struct Interface {
325*9e3b08aeSAndroid Build Coastguard Worker   explicit Interface(const std::map<std::string, Id>& symbols)
326*9e3b08aeSAndroid Build Coastguard Worker       : symbols(symbols) {}
327*9e3b08aeSAndroid Build Coastguard Worker   Interface(const std::map<std::string, Id>& symbols,
328*9e3b08aeSAndroid Build Coastguard Worker             const std::map<std::string, Id>& types)
329*9e3b08aeSAndroid Build Coastguard Worker       : symbols(symbols), types(types) {}
330*9e3b08aeSAndroid Build Coastguard Worker 
331*9e3b08aeSAndroid Build Coastguard Worker   std::map<std::string, Id> symbols;
332*9e3b08aeSAndroid Build Coastguard Worker   std::map<std::string, Id> types;
333*9e3b08aeSAndroid Build Coastguard Worker };
334*9e3b08aeSAndroid Build Coastguard Worker 
335*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Primitive::Encoding encoding);
336*9e3b08aeSAndroid Build Coastguard Worker 
337*9e3b08aeSAndroid Build Coastguard Worker // Concrete graph type.
338*9e3b08aeSAndroid Build Coastguard Worker class Graph {
339*9e3b08aeSAndroid Build Coastguard Worker  public:
340*9e3b08aeSAndroid Build Coastguard Worker   Id Limit() const {
341*9e3b08aeSAndroid Build Coastguard Worker     return Id(indirection_.size());
342*9e3b08aeSAndroid Build Coastguard Worker   }
343*9e3b08aeSAndroid Build Coastguard Worker 
344*9e3b08aeSAndroid Build Coastguard Worker   bool Is(Id id) const {
345*9e3b08aeSAndroid Build Coastguard Worker     return indirection_[id.ix_].first != Which::ABSENT;
346*9e3b08aeSAndroid Build Coastguard Worker   }
347*9e3b08aeSAndroid Build Coastguard Worker 
348*9e3b08aeSAndroid Build Coastguard Worker   Id Allocate() {
349*9e3b08aeSAndroid Build Coastguard Worker     const auto id = Limit();
350*9e3b08aeSAndroid Build Coastguard Worker     indirection_.emplace_back(Which::ABSENT, 0);
351*9e3b08aeSAndroid Build Coastguard Worker     return id;
352*9e3b08aeSAndroid Build Coastguard Worker   }
353*9e3b08aeSAndroid Build Coastguard Worker 
354*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
355*9e3b08aeSAndroid Build Coastguard Worker   void Set(Id id, Args&&... args) {
356*9e3b08aeSAndroid Build Coastguard Worker     auto& reference = indirection_[id.ix_];
357*9e3b08aeSAndroid Build Coastguard Worker     if (reference.first != Which::ABSENT) {
358*9e3b08aeSAndroid Build Coastguard Worker       Die() << "node value already set: " << id;
359*9e3b08aeSAndroid Build Coastguard Worker     }
360*9e3b08aeSAndroid Build Coastguard Worker     if constexpr (std::is_same_v<Node, Special>) {
361*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::SPECIAL, special_.size()};
362*9e3b08aeSAndroid Build Coastguard Worker       special_.emplace_back(std::forward<Args>(args)...);
363*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, PointerReference>) {
364*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::POINTER_REFERENCE, pointer_reference_.size()};
365*9e3b08aeSAndroid Build Coastguard Worker       pointer_reference_.emplace_back(std::forward<Args>(args)...);
366*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, PointerToMember>) {
367*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::POINTER_TO_MEMBER, pointer_to_member_.size()};
368*9e3b08aeSAndroid Build Coastguard Worker       pointer_to_member_.emplace_back(std::forward<Args>(args)...);
369*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Typedef>) {
370*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::TYPEDEF, typedef_.size()};
371*9e3b08aeSAndroid Build Coastguard Worker       typedef_.emplace_back(std::forward<Args>(args)...);
372*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Qualified>) {
373*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::QUALIFIED, qualified_.size()};
374*9e3b08aeSAndroid Build Coastguard Worker       qualified_.emplace_back(std::forward<Args>(args)...);
375*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Primitive>) {
376*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::PRIMITIVE, primitive_.size()};
377*9e3b08aeSAndroid Build Coastguard Worker       primitive_.emplace_back(std::forward<Args>(args)...);
378*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Array>) {
379*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::ARRAY, array_.size()};
380*9e3b08aeSAndroid Build Coastguard Worker       array_.emplace_back(std::forward<Args>(args)...);
381*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, BaseClass>) {
382*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::BASE_CLASS, base_class_.size()};
383*9e3b08aeSAndroid Build Coastguard Worker       base_class_.emplace_back(std::forward<Args>(args)...);
384*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Method>) {
385*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::METHOD, method_.size()};
386*9e3b08aeSAndroid Build Coastguard Worker       method_.emplace_back(std::forward<Args>(args)...);
387*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Member>) {
388*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::MEMBER, member_.size()};
389*9e3b08aeSAndroid Build Coastguard Worker       member_.emplace_back(std::forward<Args>(args)...);
390*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, VariantMember>) {
391*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::VARIANT_MEMBER, variant_member_.size()};
392*9e3b08aeSAndroid Build Coastguard Worker       variant_member_.emplace_back(std::forward<Args>(args)...);
393*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, StructUnion>) {
394*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::STRUCT_UNION, struct_union_.size()};
395*9e3b08aeSAndroid Build Coastguard Worker       struct_union_.emplace_back(std::forward<Args>(args)...);
396*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Enumeration>) {
397*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::ENUMERATION, enumeration_.size()};
398*9e3b08aeSAndroid Build Coastguard Worker       enumeration_.emplace_back(std::forward<Args>(args)...);
399*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Variant>) {
400*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::VARIANT, variant_.size()};
401*9e3b08aeSAndroid Build Coastguard Worker       variant_.emplace_back(std::forward<Args>(args)...);
402*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Function>) {
403*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::FUNCTION, function_.size()};
404*9e3b08aeSAndroid Build Coastguard Worker       function_.emplace_back(std::forward<Args>(args)...);
405*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, ElfSymbol>) {
406*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::ELF_SYMBOL, elf_symbol_.size()};
407*9e3b08aeSAndroid Build Coastguard Worker       elf_symbol_.emplace_back(std::forward<Args>(args)...);
408*9e3b08aeSAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Node, Interface>) {
409*9e3b08aeSAndroid Build Coastguard Worker       reference = {Which::INTERFACE, interface_.size()};
410*9e3b08aeSAndroid Build Coastguard Worker       interface_.emplace_back(std::forward<Args>(args)...);
411*9e3b08aeSAndroid Build Coastguard Worker     } else {
412*9e3b08aeSAndroid Build Coastguard Worker       // unfortunately we cannot static_assert(false, "missing case")
413*9e3b08aeSAndroid Build Coastguard Worker       static_assert(std::is_same<Node, Node*>::value, "missing case");
414*9e3b08aeSAndroid Build Coastguard Worker     }
415*9e3b08aeSAndroid Build Coastguard Worker   }
416*9e3b08aeSAndroid Build Coastguard Worker 
417*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
418*9e3b08aeSAndroid Build Coastguard Worker   Id Add(Args&&... args) {
419*9e3b08aeSAndroid Build Coastguard Worker     auto id = Allocate();
420*9e3b08aeSAndroid Build Coastguard Worker     Set<Node>(id, std::forward<Args>(args)...);
421*9e3b08aeSAndroid Build Coastguard Worker     return id;
422*9e3b08aeSAndroid Build Coastguard Worker   }
423*9e3b08aeSAndroid Build Coastguard Worker 
424*9e3b08aeSAndroid Build Coastguard Worker   void Deallocate(Id) {
425*9e3b08aeSAndroid Build Coastguard Worker     // don't actually do anything, not supported
426*9e3b08aeSAndroid Build Coastguard Worker   }
427*9e3b08aeSAndroid Build Coastguard Worker 
428*9e3b08aeSAndroid Build Coastguard Worker   void Unset(Id id) {
429*9e3b08aeSAndroid Build Coastguard Worker     auto& reference = indirection_[id.ix_];
430*9e3b08aeSAndroid Build Coastguard Worker     if (reference.first == Which::ABSENT) {
431*9e3b08aeSAndroid Build Coastguard Worker       Die() << "node value already unset: " << id;
432*9e3b08aeSAndroid Build Coastguard Worker     }
433*9e3b08aeSAndroid Build Coastguard Worker     reference = {Which::ABSENT, 0};
434*9e3b08aeSAndroid Build Coastguard Worker   }
435*9e3b08aeSAndroid Build Coastguard Worker 
436*9e3b08aeSAndroid Build Coastguard Worker   void Remove(Id id) {
437*9e3b08aeSAndroid Build Coastguard Worker     Unset(id);
438*9e3b08aeSAndroid Build Coastguard Worker     Deallocate(id);
439*9e3b08aeSAndroid Build Coastguard Worker   }
440*9e3b08aeSAndroid Build Coastguard Worker 
441*9e3b08aeSAndroid Build Coastguard Worker   template <typename FunctionObject, typename... Args>
442*9e3b08aeSAndroid Build Coastguard Worker   decltype(auto) Apply(FunctionObject&& function, Id id, Args&&... args) const;
443*9e3b08aeSAndroid Build Coastguard Worker 
444*9e3b08aeSAndroid Build Coastguard Worker   template <typename FunctionObject, typename... Args>
445*9e3b08aeSAndroid Build Coastguard Worker   decltype(auto) Apply2(
446*9e3b08aeSAndroid Build Coastguard Worker       FunctionObject&& function, Id id1, Id id2, Args&&... args) const;
447*9e3b08aeSAndroid Build Coastguard Worker 
448*9e3b08aeSAndroid Build Coastguard Worker   template <typename FunctionObject, typename... Args>
449*9e3b08aeSAndroid Build Coastguard Worker   decltype(auto) Apply(FunctionObject&& function, Id id, Args&&... args);
450*9e3b08aeSAndroid Build Coastguard Worker 
451*9e3b08aeSAndroid Build Coastguard Worker   template <typename FunctionObject>
452*9e3b08aeSAndroid Build Coastguard Worker   void ForEach(Id start, Id limit, FunctionObject&& function) const {
453*9e3b08aeSAndroid Build Coastguard Worker     for (size_t ix = start.ix_; ix < limit.ix_; ++ix) {
454*9e3b08aeSAndroid Build Coastguard Worker       const Id id(ix);
455*9e3b08aeSAndroid Build Coastguard Worker       if (Is(id)) {
456*9e3b08aeSAndroid Build Coastguard Worker         function(id);
457*9e3b08aeSAndroid Build Coastguard Worker       }
458*9e3b08aeSAndroid Build Coastguard Worker     }
459*9e3b08aeSAndroid Build Coastguard Worker   }
460*9e3b08aeSAndroid Build Coastguard Worker 
461*9e3b08aeSAndroid Build Coastguard Worker  private:
462*9e3b08aeSAndroid Build Coastguard Worker   enum class Which {
463*9e3b08aeSAndroid Build Coastguard Worker     ABSENT,
464*9e3b08aeSAndroid Build Coastguard Worker     SPECIAL,
465*9e3b08aeSAndroid Build Coastguard Worker     POINTER_REFERENCE,
466*9e3b08aeSAndroid Build Coastguard Worker     POINTER_TO_MEMBER,
467*9e3b08aeSAndroid Build Coastguard Worker     TYPEDEF,
468*9e3b08aeSAndroid Build Coastguard Worker     QUALIFIED,
469*9e3b08aeSAndroid Build Coastguard Worker     PRIMITIVE,
470*9e3b08aeSAndroid Build Coastguard Worker     ARRAY,
471*9e3b08aeSAndroid Build Coastguard Worker     BASE_CLASS,
472*9e3b08aeSAndroid Build Coastguard Worker     METHOD,
473*9e3b08aeSAndroid Build Coastguard Worker     MEMBER,
474*9e3b08aeSAndroid Build Coastguard Worker     VARIANT_MEMBER,
475*9e3b08aeSAndroid Build Coastguard Worker     STRUCT_UNION,
476*9e3b08aeSAndroid Build Coastguard Worker     ENUMERATION,
477*9e3b08aeSAndroid Build Coastguard Worker     VARIANT,
478*9e3b08aeSAndroid Build Coastguard Worker     FUNCTION,
479*9e3b08aeSAndroid Build Coastguard Worker     ELF_SYMBOL,
480*9e3b08aeSAndroid Build Coastguard Worker     INTERFACE,
481*9e3b08aeSAndroid Build Coastguard Worker   };
482*9e3b08aeSAndroid Build Coastguard Worker 
483*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<Which, size_t>> indirection_;
484*9e3b08aeSAndroid Build Coastguard Worker 
485*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Special> special_;
486*9e3b08aeSAndroid Build Coastguard Worker   std::vector<PointerReference> pointer_reference_;
487*9e3b08aeSAndroid Build Coastguard Worker   std::vector<PointerToMember> pointer_to_member_;
488*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Typedef> typedef_;
489*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Qualified> qualified_;
490*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Primitive> primitive_;
491*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Array> array_;
492*9e3b08aeSAndroid Build Coastguard Worker   std::vector<BaseClass> base_class_;
493*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Method> method_;
494*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Member> member_;
495*9e3b08aeSAndroid Build Coastguard Worker   std::vector<VariantMember> variant_member_;
496*9e3b08aeSAndroid Build Coastguard Worker   std::vector<StructUnion> struct_union_;
497*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Enumeration> enumeration_;
498*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Variant> variant_;
499*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Function> function_;
500*9e3b08aeSAndroid Build Coastguard Worker   std::vector<ElfSymbol> elf_symbol_;
501*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Interface> interface_;
502*9e3b08aeSAndroid Build Coastguard Worker };
503*9e3b08aeSAndroid Build Coastguard Worker 
504*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args>
505*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Graph::Apply(
506*9e3b08aeSAndroid Build Coastguard Worker     FunctionObject&& function, Id id, Args&&... args) const {
507*9e3b08aeSAndroid Build Coastguard Worker   const auto& [which, ix] = indirection_[id.ix_];
508*9e3b08aeSAndroid Build Coastguard Worker   switch (which) {
509*9e3b08aeSAndroid Build Coastguard Worker     case Which::ABSENT:
510*9e3b08aeSAndroid Build Coastguard Worker       Die() << "undefined node: " << id;
511*9e3b08aeSAndroid Build Coastguard Worker     case Which::SPECIAL:
512*9e3b08aeSAndroid Build Coastguard Worker       return function(special_[ix], std::forward<Args>(args)...);
513*9e3b08aeSAndroid Build Coastguard Worker     case Which::POINTER_REFERENCE:
514*9e3b08aeSAndroid Build Coastguard Worker       return function(pointer_reference_[ix], std::forward<Args>(args)...);
515*9e3b08aeSAndroid Build Coastguard Worker     case Which::POINTER_TO_MEMBER:
516*9e3b08aeSAndroid Build Coastguard Worker       return function(pointer_to_member_[ix], std::forward<Args>(args)...);
517*9e3b08aeSAndroid Build Coastguard Worker     case Which::TYPEDEF:
518*9e3b08aeSAndroid Build Coastguard Worker       return function(typedef_[ix], std::forward<Args>(args)...);
519*9e3b08aeSAndroid Build Coastguard Worker     case Which::QUALIFIED:
520*9e3b08aeSAndroid Build Coastguard Worker       return function(qualified_[ix], std::forward<Args>(args)...);
521*9e3b08aeSAndroid Build Coastguard Worker     case Which::PRIMITIVE:
522*9e3b08aeSAndroid Build Coastguard Worker       return function(primitive_[ix], std::forward<Args>(args)...);
523*9e3b08aeSAndroid Build Coastguard Worker     case Which::ARRAY:
524*9e3b08aeSAndroid Build Coastguard Worker       return function(array_[ix], std::forward<Args>(args)...);
525*9e3b08aeSAndroid Build Coastguard Worker     case Which::BASE_CLASS:
526*9e3b08aeSAndroid Build Coastguard Worker       return function(base_class_[ix], std::forward<Args>(args)...);
527*9e3b08aeSAndroid Build Coastguard Worker     case Which::METHOD:
528*9e3b08aeSAndroid Build Coastguard Worker       return function(method_[ix], std::forward<Args>(args)...);
529*9e3b08aeSAndroid Build Coastguard Worker     case Which::MEMBER:
530*9e3b08aeSAndroid Build Coastguard Worker       return function(member_[ix], std::forward<Args>(args)...);
531*9e3b08aeSAndroid Build Coastguard Worker     case Which::VARIANT_MEMBER:
532*9e3b08aeSAndroid Build Coastguard Worker       return function(variant_member_[ix], std::forward<Args>(args)...);
533*9e3b08aeSAndroid Build Coastguard Worker     case Which::STRUCT_UNION:
534*9e3b08aeSAndroid Build Coastguard Worker       return function(struct_union_[ix], std::forward<Args>(args)...);
535*9e3b08aeSAndroid Build Coastguard Worker     case Which::ENUMERATION:
536*9e3b08aeSAndroid Build Coastguard Worker       return function(enumeration_[ix], std::forward<Args>(args)...);
537*9e3b08aeSAndroid Build Coastguard Worker     case Which::VARIANT:
538*9e3b08aeSAndroid Build Coastguard Worker       return function(variant_[ix], std::forward<Args>(args)...);
539*9e3b08aeSAndroid Build Coastguard Worker     case Which::FUNCTION:
540*9e3b08aeSAndroid Build Coastguard Worker       return function(function_[ix], std::forward<Args>(args)...);
541*9e3b08aeSAndroid Build Coastguard Worker     case Which::ELF_SYMBOL:
542*9e3b08aeSAndroid Build Coastguard Worker       return function(elf_symbol_[ix], std::forward<Args>(args)...);
543*9e3b08aeSAndroid Build Coastguard Worker     case Which::INTERFACE:
544*9e3b08aeSAndroid Build Coastguard Worker       return function(interface_[ix], std::forward<Args>(args)...);
545*9e3b08aeSAndroid Build Coastguard Worker   }
546*9e3b08aeSAndroid Build Coastguard Worker }
547*9e3b08aeSAndroid Build Coastguard Worker 
548*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args>
549*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Graph::Apply2(
550*9e3b08aeSAndroid Build Coastguard Worker     FunctionObject&& function, Id id1, Id id2, Args&&... args) const {
551*9e3b08aeSAndroid Build Coastguard Worker   const auto& [which1, ix1] = indirection_[id1.ix_];
552*9e3b08aeSAndroid Build Coastguard Worker   const auto& [which2, ix2] = indirection_[id2.ix_];
553*9e3b08aeSAndroid Build Coastguard Worker   if (which1 != which2) {
554*9e3b08aeSAndroid Build Coastguard Worker     return function.Mismatch(std::forward<Args>(args)...);
555*9e3b08aeSAndroid Build Coastguard Worker   }
556*9e3b08aeSAndroid Build Coastguard Worker   switch (which1) {
557*9e3b08aeSAndroid Build Coastguard Worker     case Which::ABSENT:
558*9e3b08aeSAndroid Build Coastguard Worker       Die() << "undefined nodes: " << id1 << ", " << id2;
559*9e3b08aeSAndroid Build Coastguard Worker     case Which::SPECIAL:
560*9e3b08aeSAndroid Build Coastguard Worker       return function(special_[ix1], special_[ix2],
561*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
562*9e3b08aeSAndroid Build Coastguard Worker     case Which::POINTER_REFERENCE:
563*9e3b08aeSAndroid Build Coastguard Worker       return function(pointer_reference_[ix1], pointer_reference_[ix2],
564*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
565*9e3b08aeSAndroid Build Coastguard Worker     case Which::POINTER_TO_MEMBER:
566*9e3b08aeSAndroid Build Coastguard Worker       return function(pointer_to_member_[ix1], pointer_to_member_[ix2],
567*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
568*9e3b08aeSAndroid Build Coastguard Worker     case Which::TYPEDEF:
569*9e3b08aeSAndroid Build Coastguard Worker       return function(typedef_[ix1], typedef_[ix2],
570*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
571*9e3b08aeSAndroid Build Coastguard Worker     case Which::QUALIFIED:
572*9e3b08aeSAndroid Build Coastguard Worker       return function(qualified_[ix1], qualified_[ix2],
573*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
574*9e3b08aeSAndroid Build Coastguard Worker     case Which::PRIMITIVE:
575*9e3b08aeSAndroid Build Coastguard Worker       return function(primitive_[ix1], primitive_[ix2],
576*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
577*9e3b08aeSAndroid Build Coastguard Worker     case Which::ARRAY:
578*9e3b08aeSAndroid Build Coastguard Worker       return function(array_[ix1], array_[ix2],
579*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
580*9e3b08aeSAndroid Build Coastguard Worker     case Which::BASE_CLASS:
581*9e3b08aeSAndroid Build Coastguard Worker       return function(base_class_[ix1], base_class_[ix2],
582*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
583*9e3b08aeSAndroid Build Coastguard Worker     case Which::METHOD:
584*9e3b08aeSAndroid Build Coastguard Worker       return function(method_[ix1], method_[ix2],
585*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
586*9e3b08aeSAndroid Build Coastguard Worker     case Which::MEMBER:
587*9e3b08aeSAndroid Build Coastguard Worker       return function(member_[ix1], member_[ix2],
588*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
589*9e3b08aeSAndroid Build Coastguard Worker     case Which::VARIANT_MEMBER:
590*9e3b08aeSAndroid Build Coastguard Worker       return function(variant_member_[ix1], variant_member_[ix2],
591*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
592*9e3b08aeSAndroid Build Coastguard Worker     case Which::STRUCT_UNION:
593*9e3b08aeSAndroid Build Coastguard Worker       return function(struct_union_[ix1], struct_union_[ix2],
594*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
595*9e3b08aeSAndroid Build Coastguard Worker     case Which::ENUMERATION:
596*9e3b08aeSAndroid Build Coastguard Worker       return function(enumeration_[ix1], enumeration_[ix2],
597*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
598*9e3b08aeSAndroid Build Coastguard Worker     case Which::VARIANT:
599*9e3b08aeSAndroid Build Coastguard Worker       return function(variant_[ix1], variant_[ix2],
600*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
601*9e3b08aeSAndroid Build Coastguard Worker     case Which::FUNCTION:
602*9e3b08aeSAndroid Build Coastguard Worker       return function(function_[ix1], function_[ix2],
603*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
604*9e3b08aeSAndroid Build Coastguard Worker     case Which::ELF_SYMBOL:
605*9e3b08aeSAndroid Build Coastguard Worker       return function(elf_symbol_[ix1], elf_symbol_[ix2],
606*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
607*9e3b08aeSAndroid Build Coastguard Worker     case Which::INTERFACE:
608*9e3b08aeSAndroid Build Coastguard Worker       return function(interface_[ix1], interface_[ix2],
609*9e3b08aeSAndroid Build Coastguard Worker                       std::forward<Args>(args)...);
610*9e3b08aeSAndroid Build Coastguard Worker   }
611*9e3b08aeSAndroid Build Coastguard Worker }
612*9e3b08aeSAndroid Build Coastguard Worker 
613*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args>
614*9e3b08aeSAndroid Build Coastguard Worker struct ConstAdapter {
615*9e3b08aeSAndroid Build Coastguard Worker   explicit ConstAdapter(FunctionObject& function) : function(function) {}
616*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node>
617*9e3b08aeSAndroid Build Coastguard Worker   decltype(auto) operator()(const Node& node, Args&&... args) {
618*9e3b08aeSAndroid Build Coastguard Worker     return function(const_cast<Node&>(node), std::forward<Args>(args)...);
619*9e3b08aeSAndroid Build Coastguard Worker   }
620*9e3b08aeSAndroid Build Coastguard Worker   FunctionObject& function;
621*9e3b08aeSAndroid Build Coastguard Worker };
622*9e3b08aeSAndroid Build Coastguard Worker 
623*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args>
624*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Graph::Apply(FunctionObject&& function, Id id, Args&&... args) {
625*9e3b08aeSAndroid Build Coastguard Worker   ConstAdapter<FunctionObject, Args&&...> adapter(function);
626*9e3b08aeSAndroid Build Coastguard Worker   return static_cast<const Graph&>(*this).Apply(
627*9e3b08aeSAndroid Build Coastguard Worker       adapter, id, std::forward<Args>(args)...);
628*9e3b08aeSAndroid Build Coastguard Worker }
629*9e3b08aeSAndroid Build Coastguard Worker 
630*9e3b08aeSAndroid Build Coastguard Worker struct InterfaceKey {
631*9e3b08aeSAndroid Build Coastguard Worker   explicit InterfaceKey(const Graph& graph) : graph(graph) {}
632*9e3b08aeSAndroid Build Coastguard Worker 
633*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(Id id) const {
634*9e3b08aeSAndroid Build Coastguard Worker     return graph.Apply(*this, id);
635*9e3b08aeSAndroid Build Coastguard Worker   }
636*9e3b08aeSAndroid Build Coastguard Worker 
637*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(const stg::Typedef& x) const {
638*9e3b08aeSAndroid Build Coastguard Worker     return x.name;
639*9e3b08aeSAndroid Build Coastguard Worker   }
640*9e3b08aeSAndroid Build Coastguard Worker 
641*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(const stg::StructUnion& x) const {
642*9e3b08aeSAndroid Build Coastguard Worker     if (x.name.empty()) {
643*9e3b08aeSAndroid Build Coastguard Worker       Die() << "anonymous struct/union interface type";
644*9e3b08aeSAndroid Build Coastguard Worker     }
645*9e3b08aeSAndroid Build Coastguard Worker     std::ostringstream os;
646*9e3b08aeSAndroid Build Coastguard Worker     os << x.kind << ' ' << x.name;
647*9e3b08aeSAndroid Build Coastguard Worker     return os.str();
648*9e3b08aeSAndroid Build Coastguard Worker   }
649*9e3b08aeSAndroid Build Coastguard Worker 
650*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(const stg::Enumeration& x) const {
651*9e3b08aeSAndroid Build Coastguard Worker     if (x.name.empty()) {
652*9e3b08aeSAndroid Build Coastguard Worker       Die() << "anonymous enum interface type";
653*9e3b08aeSAndroid Build Coastguard Worker     }
654*9e3b08aeSAndroid Build Coastguard Worker     return "enum " + x.name;
655*9e3b08aeSAndroid Build Coastguard Worker   }
656*9e3b08aeSAndroid Build Coastguard Worker 
657*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(const stg::Variant& x) const {
658*9e3b08aeSAndroid Build Coastguard Worker     if (x.name.empty()) {
659*9e3b08aeSAndroid Build Coastguard Worker       Die() << "anonymous variant interface type";
660*9e3b08aeSAndroid Build Coastguard Worker     }
661*9e3b08aeSAndroid Build Coastguard Worker     return "variant " + x.name;
662*9e3b08aeSAndroid Build Coastguard Worker   }
663*9e3b08aeSAndroid Build Coastguard Worker 
664*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(const stg::ElfSymbol& x) const {
665*9e3b08aeSAndroid Build Coastguard Worker     return VersionedSymbolName(x);
666*9e3b08aeSAndroid Build Coastguard Worker   }
667*9e3b08aeSAndroid Build Coastguard Worker 
668*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node>
669*9e3b08aeSAndroid Build Coastguard Worker   std::string operator()(const Node&) const {
670*9e3b08aeSAndroid Build Coastguard Worker     Die() << "unexpected interface type";
671*9e3b08aeSAndroid Build Coastguard Worker   }
672*9e3b08aeSAndroid Build Coastguard Worker 
673*9e3b08aeSAndroid Build Coastguard Worker   const Graph& graph;
674*9e3b08aeSAndroid Build Coastguard Worker };
675*9e3b08aeSAndroid Build Coastguard Worker 
676*9e3b08aeSAndroid Build Coastguard Worker // Roughly equivalent to std::set<Id> but with constant time operations and
677*9e3b08aeSAndroid Build Coastguard Worker // key set limited to allocated Ids.
678*9e3b08aeSAndroid Build Coastguard Worker class DenseIdSet {
679*9e3b08aeSAndroid Build Coastguard Worker  public:
680*9e3b08aeSAndroid Build Coastguard Worker   explicit DenseIdSet(Id start) : offset_(start.ix_) {}
681*9e3b08aeSAndroid Build Coastguard Worker   void Reserve(Id limit) {
682*9e3b08aeSAndroid Build Coastguard Worker     ids_.reserve(limit.ix_ - offset_);
683*9e3b08aeSAndroid Build Coastguard Worker   }
684*9e3b08aeSAndroid Build Coastguard Worker   bool Insert(Id id) {
685*9e3b08aeSAndroid Build Coastguard Worker     const auto ix = id.ix_;
686*9e3b08aeSAndroid Build Coastguard Worker     if (ix < offset_) {
687*9e3b08aeSAndroid Build Coastguard Worker       Die() << "DenseIdSet: out of range access to " << id;
688*9e3b08aeSAndroid Build Coastguard Worker     }
689*9e3b08aeSAndroid Build Coastguard Worker     const auto offset_ix = ix - offset_;
690*9e3b08aeSAndroid Build Coastguard Worker     if (offset_ix >= ids_.size()) {
691*9e3b08aeSAndroid Build Coastguard Worker       ids_.resize(offset_ix + 1, false);
692*9e3b08aeSAndroid Build Coastguard Worker     }
693*9e3b08aeSAndroid Build Coastguard Worker     if (ids_[offset_ix]) {
694*9e3b08aeSAndroid Build Coastguard Worker       return false;
695*9e3b08aeSAndroid Build Coastguard Worker     }
696*9e3b08aeSAndroid Build Coastguard Worker     ids_[offset_ix] = true;
697*9e3b08aeSAndroid Build Coastguard Worker     return true;
698*9e3b08aeSAndroid Build Coastguard Worker   }
699*9e3b08aeSAndroid Build Coastguard Worker 
700*9e3b08aeSAndroid Build Coastguard Worker  private:
701*9e3b08aeSAndroid Build Coastguard Worker   size_t offset_;
702*9e3b08aeSAndroid Build Coastguard Worker   std::vector<bool> ids_;
703*9e3b08aeSAndroid Build Coastguard Worker };
704*9e3b08aeSAndroid Build Coastguard Worker 
705*9e3b08aeSAndroid Build Coastguard Worker // Roughly equivalent to std::map<Id, Id>, defaulted to the identity mapping,
706*9e3b08aeSAndroid Build Coastguard Worker // but with constant time operations and key set limited to allocated Ids.
707*9e3b08aeSAndroid Build Coastguard Worker class DenseIdMapping {
708*9e3b08aeSAndroid Build Coastguard Worker  public:
709*9e3b08aeSAndroid Build Coastguard Worker   explicit DenseIdMapping(Id start) : offset_(start.ix_) {}
710*9e3b08aeSAndroid Build Coastguard Worker   void Reserve(Id limit) {
711*9e3b08aeSAndroid Build Coastguard Worker     ids_.reserve(limit.ix_ - offset_);
712*9e3b08aeSAndroid Build Coastguard Worker   }
713*9e3b08aeSAndroid Build Coastguard Worker   Id& operator[](Id id) {
714*9e3b08aeSAndroid Build Coastguard Worker     const auto ix = id.ix_;
715*9e3b08aeSAndroid Build Coastguard Worker     if (ix < offset_) {
716*9e3b08aeSAndroid Build Coastguard Worker       Die() << "DenseIdMapping: out of range access to " << id;
717*9e3b08aeSAndroid Build Coastguard Worker     }
718*9e3b08aeSAndroid Build Coastguard Worker     Populate(ix + 1);
719*9e3b08aeSAndroid Build Coastguard Worker     return ids_[ix - offset_];
720*9e3b08aeSAndroid Build Coastguard Worker   }
721*9e3b08aeSAndroid Build Coastguard Worker 
722*9e3b08aeSAndroid Build Coastguard Worker  private:
723*9e3b08aeSAndroid Build Coastguard Worker   void Populate(size_t size) {
724*9e3b08aeSAndroid Build Coastguard Worker     for (size_t ix = offset_ + ids_.size(); ix < size; ++ix) {
725*9e3b08aeSAndroid Build Coastguard Worker       ids_.emplace_back(ix);
726*9e3b08aeSAndroid Build Coastguard Worker     }
727*9e3b08aeSAndroid Build Coastguard Worker   }
728*9e3b08aeSAndroid Build Coastguard Worker 
729*9e3b08aeSAndroid Build Coastguard Worker   size_t offset_;
730*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> ids_;
731*9e3b08aeSAndroid Build Coastguard Worker };
732*9e3b08aeSAndroid Build Coastguard Worker 
733*9e3b08aeSAndroid Build Coastguard Worker template <typename ExternalId>
734*9e3b08aeSAndroid Build Coastguard Worker class Maker {
735*9e3b08aeSAndroid Build Coastguard Worker  public:
736*9e3b08aeSAndroid Build Coastguard Worker   explicit Maker(Graph& graph) : graph_(graph) {}
737*9e3b08aeSAndroid Build Coastguard Worker 
738*9e3b08aeSAndroid Build Coastguard Worker   ~Maker() noexcept(false) {
739*9e3b08aeSAndroid Build Coastguard Worker     if (std::uncaught_exceptions() == 0) {
740*9e3b08aeSAndroid Build Coastguard Worker       if (undefined_ > 0) {
741*9e3b08aeSAndroid Build Coastguard Worker         Die die;
742*9e3b08aeSAndroid Build Coastguard Worker         die << "undefined nodes:";
743*9e3b08aeSAndroid Build Coastguard Worker         for (const auto& [external_id, id] : map_) {
744*9e3b08aeSAndroid Build Coastguard Worker           if (!graph_.Is(id)) {
745*9e3b08aeSAndroid Build Coastguard Worker             die << ' ' << external_id;
746*9e3b08aeSAndroid Build Coastguard Worker           }
747*9e3b08aeSAndroid Build Coastguard Worker         }
748*9e3b08aeSAndroid Build Coastguard Worker       }
749*9e3b08aeSAndroid Build Coastguard Worker     }
750*9e3b08aeSAndroid Build Coastguard Worker   }
751*9e3b08aeSAndroid Build Coastguard Worker 
752*9e3b08aeSAndroid Build Coastguard Worker   Id Get(const ExternalId& external_id) {
753*9e3b08aeSAndroid Build Coastguard Worker     auto [it, inserted] = map_.emplace(external_id, 0);
754*9e3b08aeSAndroid Build Coastguard Worker     if (inserted) {
755*9e3b08aeSAndroid Build Coastguard Worker       it->second = graph_.Allocate();
756*9e3b08aeSAndroid Build Coastguard Worker       ++undefined_;
757*9e3b08aeSAndroid Build Coastguard Worker     }
758*9e3b08aeSAndroid Build Coastguard Worker     return it->second;
759*9e3b08aeSAndroid Build Coastguard Worker   }
760*9e3b08aeSAndroid Build Coastguard Worker 
761*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
762*9e3b08aeSAndroid Build Coastguard Worker   Id Set(const ExternalId& external_id, Args&&... args) {
763*9e3b08aeSAndroid Build Coastguard Worker     return Set<Node>(DieDuplicate, external_id, std::forward<Args>(args)...);
764*9e3b08aeSAndroid Build Coastguard Worker   }
765*9e3b08aeSAndroid Build Coastguard Worker 
766*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
767*9e3b08aeSAndroid Build Coastguard Worker   Id MaybeSet(const ExternalId& external_id, Args&&... args) {
768*9e3b08aeSAndroid Build Coastguard Worker     return Set<Node>(WarnDuplicate, external_id, std::forward<Args>(args)...);
769*9e3b08aeSAndroid Build Coastguard Worker   }
770*9e3b08aeSAndroid Build Coastguard Worker 
771*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
772*9e3b08aeSAndroid Build Coastguard Worker   Id Add(Args&&... args) {
773*9e3b08aeSAndroid Build Coastguard Worker     return graph_.Add<Node>(std::forward<Args>(args)...);
774*9e3b08aeSAndroid Build Coastguard Worker   }
775*9e3b08aeSAndroid Build Coastguard Worker 
776*9e3b08aeSAndroid Build Coastguard Worker  private:
777*9e3b08aeSAndroid Build Coastguard Worker   Graph& graph_;
778*9e3b08aeSAndroid Build Coastguard Worker   size_t undefined_ = 0;
779*9e3b08aeSAndroid Build Coastguard Worker   std::unordered_map<ExternalId, Id> map_;
780*9e3b08aeSAndroid Build Coastguard Worker 
781*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
782*9e3b08aeSAndroid Build Coastguard Worker   Id Set(void(& fail)(const ExternalId&), const ExternalId& external_id,
783*9e3b08aeSAndroid Build Coastguard Worker          Args&&... args) {
784*9e3b08aeSAndroid Build Coastguard Worker     const Id id = Get(external_id);
785*9e3b08aeSAndroid Build Coastguard Worker     if (graph_.Is(id)) {
786*9e3b08aeSAndroid Build Coastguard Worker       fail(external_id);
787*9e3b08aeSAndroid Build Coastguard Worker     } else {
788*9e3b08aeSAndroid Build Coastguard Worker       graph_.Set<Node>(id, std::forward<Args>(args)...);
789*9e3b08aeSAndroid Build Coastguard Worker       --undefined_;
790*9e3b08aeSAndroid Build Coastguard Worker     }
791*9e3b08aeSAndroid Build Coastguard Worker     return id;
792*9e3b08aeSAndroid Build Coastguard Worker   }
793*9e3b08aeSAndroid Build Coastguard Worker 
794*9e3b08aeSAndroid Build Coastguard Worker   // These helpers should probably not be inlined.
795*9e3b08aeSAndroid Build Coastguard Worker   [[noreturn]] static void DieDuplicate(const ExternalId& external_id) {
796*9e3b08aeSAndroid Build Coastguard Worker     Die() << "duplicate definition of node: " << external_id;
797*9e3b08aeSAndroid Build Coastguard Worker   }
798*9e3b08aeSAndroid Build Coastguard Worker   static void WarnDuplicate(const ExternalId& external_id) {
799*9e3b08aeSAndroid Build Coastguard Worker     Warn() << "ignoring duplicate definition of node: " << external_id;
800*9e3b08aeSAndroid Build Coastguard Worker   }
801*9e3b08aeSAndroid Build Coastguard Worker };
802*9e3b08aeSAndroid Build Coastguard Worker 
803*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
804*9e3b08aeSAndroid Build Coastguard Worker 
805*9e3b08aeSAndroid Build Coastguard Worker #endif  // STG_GRAPH_H_
806