File: | build/source/clang-tools-extra/clangd/index/YAMLSerialization.cpp |
Warning: | line 144, column 5 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- YAMLSerialization.cpp ------------------------------------*- C++-*-===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // A YAML index file is a sequence of tagged entries. | |||
10 | // Each entry either encodes a Symbol or the list of references to a symbol | |||
11 | // (a "ref bundle"). | |||
12 | // | |||
13 | //===----------------------------------------------------------------------===// | |||
14 | ||||
15 | #include "Headers.h" | |||
16 | #include "index/Ref.h" | |||
17 | #include "index/Relation.h" | |||
18 | #include "index/Serialization.h" | |||
19 | #include "index/Symbol.h" | |||
20 | #include "index/SymbolLocation.h" | |||
21 | #include "index/SymbolOrigin.h" | |||
22 | #include "clang/Tooling/CompilationDatabase.h" | |||
23 | #include "llvm/ADT/StringRef.h" | |||
24 | #include "llvm/Support/Allocator.h" | |||
25 | #include "llvm/Support/StringSaver.h" | |||
26 | #include "llvm/Support/YAMLTraits.h" | |||
27 | #include "llvm/Support/raw_ostream.h" | |||
28 | #include <cstdint> | |||
29 | #include <optional> | |||
30 | ||||
31 | namespace { | |||
32 | struct YIncludeHeaderWithReferences; | |||
33 | } | |||
34 | ||||
35 | LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <clang::clangd::Symbol::IncludeHeaderWithReferences> && !std::is_same_v<clang::clangd::Symbol::IncludeHeaderWithReferences , std::string> && !std::is_same_v<clang::clangd ::Symbol::IncludeHeaderWithReferences, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<clang::clangd ::Symbol::IncludeHeaderWithReferences> { static const bool flow = false; }; } } | |||
36 | LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <clang::clangd::Ref> && !std::is_same_v<clang ::clangd::Ref, std::string> && !std::is_same_v< clang::clangd::Ref, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<clang::clangd ::Ref> { static const bool flow = false; }; } } | |||
37 | LLVM_YAML_IS_SEQUENCE_VECTOR(YIncludeHeaderWithReferences)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <YIncludeHeaderWithReferences> && !std::is_same_v <YIncludeHeaderWithReferences, std::string> && ! std::is_same_v<YIncludeHeaderWithReferences, llvm::StringRef >, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<YIncludeHeaderWithReferences > { static const bool flow = false; }; } } | |||
38 | ||||
39 | namespace { | |||
40 | using RefBundle = | |||
41 | std::pair<clang::clangd::SymbolID, std::vector<clang::clangd::Ref>>; | |||
42 | // This is a pale imitation of std::variant<Symbol, RefBundle, Relation> | |||
43 | struct VariantEntry { | |||
44 | std::optional<clang::clangd::Symbol> Symbol; | |||
45 | std::optional<RefBundle> Refs; | |||
46 | std::optional<clang::clangd::Relation> Relation; | |||
47 | std::optional<clang::clangd::IncludeGraphNode> Source; | |||
48 | std::optional<clang::tooling::CompileCommand> Cmd; | |||
49 | }; | |||
50 | // A class helps YAML to serialize the 32-bit encoded position (Line&Column), | |||
51 | // as YAMLIO can't directly map bitfields. | |||
52 | struct YPosition { | |||
53 | uint32_t Line; | |||
54 | uint32_t Column; | |||
55 | }; | |||
56 | // A class helps YAML to serialize the IncludeHeaderWithReferences as YAMLIO | |||
57 | // can't directly map bitfields. | |||
58 | struct YIncludeHeaderWithReferences { | |||
59 | llvm::StringRef IncludeHeader; | |||
60 | uint32_t References; | |||
61 | clang::clangd::Symbol::IncludeDirective SupportedDirectives; | |||
62 | ||||
63 | YIncludeHeaderWithReferences() = default; | |||
64 | ||||
65 | YIncludeHeaderWithReferences( | |||
66 | llvm::StringRef IncludeHeader, uint32_t References, | |||
67 | clang::clangd::Symbol::IncludeDirective SupportedDirectives) | |||
68 | : IncludeHeader(IncludeHeader), References(References), | |||
69 | SupportedDirectives(SupportedDirectives) {} | |||
70 | }; | |||
71 | ||||
72 | // avoid ODR violation of specialization for non-owned CompileCommand | |||
73 | struct CompileCommandYAML : clang::tooling::CompileCommand {}; | |||
74 | ||||
75 | } // namespace | |||
76 | namespace llvm { | |||
77 | namespace yaml { | |||
78 | ||||
79 | using clang::clangd::FileDigest; | |||
80 | using clang::clangd::IncludeGraph; | |||
81 | using clang::clangd::IncludeGraphNode; | |||
82 | using clang::clangd::Ref; | |||
83 | using clang::clangd::RefKind; | |||
84 | using clang::clangd::Relation; | |||
85 | using clang::clangd::RelationKind; | |||
86 | using clang::clangd::Symbol; | |||
87 | using clang::clangd::SymbolID; | |||
88 | using clang::clangd::SymbolLocation; | |||
89 | using clang::index::SymbolInfo; | |||
90 | using clang::index::SymbolKind; | |||
91 | using clang::index::SymbolLanguage; | |||
92 | using clang::tooling::CompileCommand; | |||
93 | ||||
94 | // Helper to (de)serialize the SymbolID. We serialize it as a hex string. | |||
95 | struct NormalizedSymbolID { | |||
96 | NormalizedSymbolID(IO &) {} | |||
97 | NormalizedSymbolID(IO &, const SymbolID &ID) { | |||
98 | llvm::raw_string_ostream OS(HexString); | |||
99 | OS << ID; | |||
100 | } | |||
101 | ||||
102 | SymbolID denormalize(IO &I) { | |||
103 | auto ID = SymbolID::fromStr(HexString); | |||
104 | if (!ID) { | |||
105 | I.setError(llvm::toString(ID.takeError())); | |||
106 | return SymbolID(); | |||
107 | } | |||
108 | return *ID; | |||
109 | } | |||
110 | ||||
111 | std::string HexString; | |||
112 | }; | |||
113 | ||||
114 | struct NormalizedSymbolFlag { | |||
115 | NormalizedSymbolFlag(IO &) {} | |||
116 | NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F) { | |||
117 | Flag = static_cast<uint8_t>(F); | |||
118 | } | |||
119 | ||||
120 | Symbol::SymbolFlag denormalize(IO &) { | |||
121 | return static_cast<Symbol::SymbolFlag>(Flag); | |||
122 | } | |||
123 | ||||
124 | uint8_t Flag = 0; | |||
125 | }; | |||
126 | ||||
127 | template <> struct MappingTraits<YPosition> { | |||
128 | static void mapping(IO &IO, YPosition &Value) { | |||
129 | IO.mapRequired("Line", Value.Line); | |||
130 | IO.mapRequired("Column", Value.Column); | |||
131 | } | |||
132 | }; | |||
133 | ||||
134 | struct NormalizedPosition { | |||
135 | using Position = clang::clangd::SymbolLocation::Position; | |||
136 | NormalizedPosition(IO &) {} | |||
137 | NormalizedPosition(IO &, const Position &Pos) { | |||
138 | P.Line = Pos.line(); | |||
139 | P.Column = Pos.column(); | |||
140 | } | |||
141 | ||||
142 | Position denormalize(IO &) { | |||
143 | Position Pos; | |||
144 | Pos.setLine(P.Line); | |||
| ||||
145 | Pos.setColumn(P.Column); | |||
146 | return Pos; | |||
147 | } | |||
148 | YPosition P; | |||
149 | }; | |||
150 | ||||
151 | struct NormalizedFileURI { | |||
152 | NormalizedFileURI(IO &) {} | |||
153 | NormalizedFileURI(IO &, const char *FileURI) { URI = FileURI; } | |||
154 | ||||
155 | const char *denormalize(IO &IO) { | |||
156 | assert(IO.getContext() &&(static_cast <bool> (IO.getContext() && "Expecting an UniqueStringSaver to allocate data" ) ? void (0) : __assert_fail ("IO.getContext() && \"Expecting an UniqueStringSaver to allocate data\"" , "clang-tools-extra/clangd/index/YAMLSerialization.cpp", 157 , __extension__ __PRETTY_FUNCTION__)) | |||
157 | "Expecting an UniqueStringSaver to allocate data")(static_cast <bool> (IO.getContext() && "Expecting an UniqueStringSaver to allocate data" ) ? void (0) : __assert_fail ("IO.getContext() && \"Expecting an UniqueStringSaver to allocate data\"" , "clang-tools-extra/clangd/index/YAMLSerialization.cpp", 157 , __extension__ __PRETTY_FUNCTION__)); | |||
158 | return static_cast<llvm::UniqueStringSaver *>(IO.getContext()) | |||
159 | ->save(URI) | |||
160 | .data(); | |||
161 | } | |||
162 | ||||
163 | std::string URI; | |||
164 | }; | |||
165 | ||||
166 | template <> struct MappingTraits<SymbolLocation> { | |||
167 | static void mapping(IO &IO, SymbolLocation &Value) { | |||
168 | MappingNormalization<NormalizedFileURI, const char *> NFile(IO, | |||
169 | Value.FileURI); | |||
170 | IO.mapRequired("FileURI", NFile->URI); | |||
171 | MappingNormalization<NormalizedPosition, SymbolLocation::Position> NStart( | |||
172 | IO, Value.Start); | |||
173 | IO.mapRequired("Start", NStart->P); | |||
174 | MappingNormalization<NormalizedPosition, SymbolLocation::Position> NEnd( | |||
175 | IO, Value.End); | |||
176 | IO.mapRequired("End", NEnd->P); | |||
177 | } | |||
178 | }; | |||
179 | ||||
180 | template <> struct MappingTraits<SymbolInfo> { | |||
181 | static void mapping(IO &IO, SymbolInfo &SymInfo) { | |||
182 | // FIXME: expose other fields? | |||
183 | IO.mapRequired("Kind", SymInfo.Kind); | |||
184 | IO.mapRequired("Lang", SymInfo.Lang); | |||
185 | } | |||
186 | }; | |||
187 | ||||
188 | template <> struct ScalarBitSetTraits<clang::clangd::Symbol::IncludeDirective> { | |||
189 | static void bitset(IO &IO, clang::clangd::Symbol::IncludeDirective &Value) { | |||
190 | IO.bitSetCase(Value, "Include", clang::clangd::Symbol::Include); | |||
191 | IO.bitSetCase(Value, "Import", clang::clangd::Symbol::Import); | |||
192 | } | |||
193 | }; | |||
194 | ||||
195 | template <> struct MappingTraits<YIncludeHeaderWithReferences> { | |||
196 | static void mapping(IO &IO, YIncludeHeaderWithReferences &Inc) { | |||
197 | IO.mapRequired("Header", Inc.IncludeHeader); | |||
198 | IO.mapRequired("References", Inc.References); | |||
199 | IO.mapOptional("Directives", Inc.SupportedDirectives, | |||
200 | clang::clangd::Symbol::Include); | |||
201 | } | |||
202 | }; | |||
203 | ||||
204 | struct NormalizedIncludeHeaders { | |||
205 | using IncludeHeader = clang::clangd::Symbol::IncludeHeaderWithReferences; | |||
206 | NormalizedIncludeHeaders(IO &) {} | |||
207 | NormalizedIncludeHeaders( | |||
208 | IO &, const llvm::SmallVector<IncludeHeader, 1> &IncludeHeaders) { | |||
209 | for (auto &I : IncludeHeaders) { | |||
210 | Headers.emplace_back(I.IncludeHeader, I.References, | |||
211 | I.supportedDirectives()); | |||
212 | } | |||
213 | } | |||
214 | ||||
215 | llvm::SmallVector<IncludeHeader, 1> denormalize(IO &) { | |||
216 | llvm::SmallVector<IncludeHeader, 1> Result; | |||
217 | for (auto &H : Headers) | |||
218 | Result.emplace_back(H.IncludeHeader, H.References, H.SupportedDirectives); | |||
219 | return Result; | |||
220 | } | |||
221 | llvm::SmallVector<YIncludeHeaderWithReferences, 1> Headers; | |||
222 | }; | |||
223 | ||||
224 | template <> struct MappingTraits<Symbol> { | |||
225 | static void mapping(IO &IO, Symbol &Sym) { | |||
226 | MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID); | |||
227 | MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag( | |||
228 | IO, Sym.Flags); | |||
229 | MappingNormalization< | |||
230 | NormalizedIncludeHeaders, | |||
231 | llvm::SmallVector<Symbol::IncludeHeaderWithReferences, 1>> | |||
232 | NIncludeHeaders(IO, Sym.IncludeHeaders); | |||
233 | IO.mapRequired("ID", NSymbolID->HexString); | |||
234 | IO.mapRequired("Name", Sym.Name); | |||
235 | IO.mapRequired("Scope", Sym.Scope); | |||
236 | IO.mapRequired("SymInfo", Sym.SymInfo); | |||
237 | IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration, | |||
238 | SymbolLocation()); | |||
239 | IO.mapOptional("Definition", Sym.Definition, SymbolLocation()); | |||
240 | IO.mapOptional("References", Sym.References, 0u); | |||
241 | IO.mapOptional("Flags", NSymbolFlag->Flag); | |||
242 | IO.mapOptional("Signature", Sym.Signature); | |||
243 | IO.mapOptional("TemplateSpecializationArgs", | |||
244 | Sym.TemplateSpecializationArgs); | |||
245 | IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix); | |||
246 | IO.mapOptional("Documentation", Sym.Documentation); | |||
247 | IO.mapOptional("ReturnType", Sym.ReturnType); | |||
248 | IO.mapOptional("Type", Sym.Type); | |||
249 | IO.mapOptional("IncludeHeaders", NIncludeHeaders->Headers); | |||
250 | } | |||
251 | }; | |||
252 | ||||
253 | template <> struct ScalarEnumerationTraits<SymbolLanguage> { | |||
254 | static void enumeration(IO &IO, SymbolLanguage &Value) { | |||
255 | IO.enumCase(Value, "C", SymbolLanguage::C); | |||
256 | IO.enumCase(Value, "Cpp", SymbolLanguage::CXX); | |||
257 | IO.enumCase(Value, "ObjC", SymbolLanguage::ObjC); | |||
258 | IO.enumCase(Value, "Swift", SymbolLanguage::Swift); | |||
259 | } | |||
260 | }; | |||
261 | ||||
262 | template <> struct ScalarEnumerationTraits<SymbolKind> { | |||
263 | static void enumeration(IO &IO, SymbolKind &Value) { | |||
264 | #define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name) | |||
265 | ||||
266 | DEFINE_ENUM(Unknown); | |||
267 | DEFINE_ENUM(Function); | |||
268 | DEFINE_ENUM(Module); | |||
269 | DEFINE_ENUM(Namespace); | |||
270 | DEFINE_ENUM(NamespaceAlias); | |||
271 | DEFINE_ENUM(Macro); | |||
272 | DEFINE_ENUM(Enum); | |||
273 | DEFINE_ENUM(Struct); | |||
274 | DEFINE_ENUM(Class); | |||
275 | DEFINE_ENUM(Protocol); | |||
276 | DEFINE_ENUM(Extension); | |||
277 | DEFINE_ENUM(Union); | |||
278 | DEFINE_ENUM(TypeAlias); | |||
279 | DEFINE_ENUM(Function); | |||
280 | DEFINE_ENUM(Variable); | |||
281 | DEFINE_ENUM(Field); | |||
282 | DEFINE_ENUM(EnumConstant); | |||
283 | DEFINE_ENUM(InstanceMethod); | |||
284 | DEFINE_ENUM(ClassMethod); | |||
285 | DEFINE_ENUM(StaticMethod); | |||
286 | DEFINE_ENUM(InstanceProperty); | |||
287 | DEFINE_ENUM(ClassProperty); | |||
288 | DEFINE_ENUM(StaticProperty); | |||
289 | DEFINE_ENUM(Constructor); | |||
290 | DEFINE_ENUM(Destructor); | |||
291 | DEFINE_ENUM(ConversionFunction); | |||
292 | DEFINE_ENUM(Parameter); | |||
293 | DEFINE_ENUM(Using); | |||
294 | ||||
295 | #undef DEFINE_ENUM | |||
296 | } | |||
297 | }; | |||
298 | ||||
299 | template <> struct MappingTraits<RefBundle> { | |||
300 | static void mapping(IO &IO, RefBundle &Refs) { | |||
301 | MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, | |||
302 | Refs.first); | |||
303 | IO.mapRequired("ID", NSymbolID->HexString); | |||
304 | IO.mapRequired("References", Refs.second); | |||
305 | } | |||
306 | }; | |||
307 | ||||
308 | struct NormalizedRefKind { | |||
309 | NormalizedRefKind(IO &) {} | |||
310 | NormalizedRefKind(IO &, RefKind O) { Kind = static_cast<uint8_t>(O); } | |||
311 | ||||
312 | RefKind denormalize(IO &) { return static_cast<RefKind>(Kind); } | |||
313 | ||||
314 | uint8_t Kind = 0; | |||
315 | }; | |||
316 | ||||
317 | template <> struct MappingTraits<Ref> { | |||
318 | static void mapping(IO &IO, Ref &R) { | |||
319 | MappingNormalization<NormalizedRefKind, RefKind> NKind(IO, R.Kind); | |||
320 | IO.mapRequired("Kind", NKind->Kind); | |||
321 | IO.mapRequired("Location", R.Location); | |||
322 | } | |||
323 | }; | |||
324 | ||||
325 | struct NormalizedSymbolRole { | |||
326 | NormalizedSymbolRole(IO &) {} | |||
327 | NormalizedSymbolRole(IO &IO, RelationKind R) { | |||
328 | Kind = static_cast<uint8_t>(R); | |||
329 | } | |||
330 | ||||
331 | RelationKind denormalize(IO &IO) { return static_cast<RelationKind>(Kind); } | |||
332 | ||||
333 | uint8_t Kind = 0; | |||
334 | }; | |||
335 | ||||
336 | template <> struct MappingTraits<SymbolID> { | |||
337 | static void mapping(IO &IO, SymbolID &ID) { | |||
338 | MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, ID); | |||
339 | IO.mapRequired("ID", NSymbolID->HexString); | |||
340 | } | |||
341 | }; | |||
342 | ||||
343 | template <> struct MappingTraits<Relation> { | |||
344 | static void mapping(IO &IO, Relation &Relation) { | |||
345 | MappingNormalization<NormalizedSymbolRole, RelationKind> NRole( | |||
346 | IO, Relation.Predicate); | |||
347 | IO.mapRequired("Subject", Relation.Subject); | |||
348 | IO.mapRequired("Predicate", NRole->Kind); | |||
349 | IO.mapRequired("Object", Relation.Object); | |||
350 | } | |||
351 | }; | |||
352 | ||||
353 | struct NormalizedSourceFlag { | |||
354 | NormalizedSourceFlag(IO &) {} | |||
355 | NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) { | |||
356 | Flag = static_cast<uint8_t>(O); | |||
357 | } | |||
358 | ||||
359 | IncludeGraphNode::SourceFlag denormalize(IO &) { | |||
360 | return static_cast<IncludeGraphNode::SourceFlag>(Flag); | |||
361 | } | |||
362 | ||||
363 | uint8_t Flag = 0; | |||
364 | }; | |||
365 | ||||
366 | struct NormalizedFileDigest { | |||
367 | NormalizedFileDigest(IO &) {} | |||
368 | NormalizedFileDigest(IO &, const FileDigest &Digest) { | |||
369 | HexString = llvm::toHex(Digest); | |||
370 | } | |||
371 | ||||
372 | FileDigest denormalize(IO &I) { | |||
373 | FileDigest Digest; | |||
374 | if (HexString.size() == Digest.size() * 2 && | |||
375 | llvm::all_of(HexString, llvm::isHexDigit)) { | |||
376 | memcpy(Digest.data(), llvm::fromHex(HexString).data(), Digest.size()); | |||
377 | } else { | |||
378 | I.setError(std::string("Bad hex file digest: ") + HexString); | |||
379 | } | |||
380 | return Digest; | |||
381 | } | |||
382 | ||||
383 | std::string HexString; | |||
384 | }; | |||
385 | ||||
386 | template <> struct MappingTraits<IncludeGraphNode> { | |||
387 | static void mapping(IO &IO, IncludeGraphNode &Node) { | |||
388 | IO.mapRequired("URI", Node.URI); | |||
389 | MappingNormalization<NormalizedSourceFlag, IncludeGraphNode::SourceFlag> | |||
390 | NSourceFlag(IO, Node.Flags); | |||
391 | IO.mapRequired("Flags", NSourceFlag->Flag); | |||
392 | MappingNormalization<NormalizedFileDigest, FileDigest> NDigest(IO, | |||
393 | Node.Digest); | |||
394 | IO.mapRequired("Digest", NDigest->HexString); | |||
395 | IO.mapRequired("DirectIncludes", Node.DirectIncludes); | |||
396 | } | |||
397 | }; | |||
398 | ||||
399 | template <> struct MappingTraits<CompileCommandYAML> { | |||
400 | static void mapping(IO &IO, CompileCommandYAML &Cmd) { | |||
401 | IO.mapRequired("Directory", Cmd.Directory); | |||
402 | IO.mapRequired("CommandLine", Cmd.CommandLine); | |||
403 | } | |||
404 | }; | |||
405 | ||||
406 | template <> struct MappingTraits<VariantEntry> { | |||
407 | static void mapping(IO &IO, VariantEntry &Variant) { | |||
408 | if (IO.mapTag("!Symbol", Variant.Symbol.has_value())) { | |||
409 | if (!IO.outputting()) | |||
410 | Variant.Symbol.emplace(); | |||
411 | MappingTraits<Symbol>::mapping(IO, *Variant.Symbol); | |||
412 | } else if (IO.mapTag("!Refs", Variant.Refs.has_value())) { | |||
413 | if (!IO.outputting()) | |||
414 | Variant.Refs.emplace(); | |||
415 | MappingTraits<RefBundle>::mapping(IO, *Variant.Refs); | |||
416 | } else if (IO.mapTag("!Relations", Variant.Relation.has_value())) { | |||
417 | if (!IO.outputting()) | |||
418 | Variant.Relation.emplace(); | |||
419 | MappingTraits<Relation>::mapping(IO, *Variant.Relation); | |||
420 | } else if (IO.mapTag("!Source", Variant.Source.has_value())) { | |||
421 | if (!IO.outputting()) | |||
422 | Variant.Source.emplace(); | |||
423 | MappingTraits<IncludeGraphNode>::mapping(IO, *Variant.Source); | |||
424 | } else if (IO.mapTag("!Cmd", Variant.Cmd.has_value())) { | |||
425 | if (!IO.outputting()) | |||
426 | Variant.Cmd.emplace(); | |||
427 | MappingTraits<CompileCommandYAML>::mapping( | |||
428 | IO, static_cast<CompileCommandYAML &>(*Variant.Cmd)); | |||
429 | } | |||
430 | } | |||
431 | }; | |||
432 | ||||
433 | } // namespace yaml | |||
434 | } // namespace llvm | |||
435 | ||||
436 | namespace clang { | |||
437 | namespace clangd { | |||
438 | ||||
439 | void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) { | |||
440 | llvm::yaml::Output Yout(OS); | |||
441 | for (const auto &Sym : *O.Symbols) { | |||
442 | VariantEntry Entry; | |||
443 | Entry.Symbol = Sym; | |||
444 | Yout << Entry; | |||
445 | } | |||
446 | if (O.Refs) | |||
447 | for (auto &Sym : *O.Refs) { | |||
448 | VariantEntry Entry; | |||
449 | Entry.Refs = Sym; | |||
450 | Yout << Entry; | |||
451 | } | |||
452 | if (O.Relations) | |||
453 | for (auto &R : *O.Relations) { | |||
454 | VariantEntry Entry; | |||
455 | Entry.Relation = R; | |||
456 | Yout << Entry; | |||
457 | } | |||
458 | if (O.Sources) { | |||
459 | for (const auto &Source : *O.Sources) { | |||
460 | VariantEntry Entry; | |||
461 | Entry.Source = Source.getValue(); | |||
462 | Yout << Entry; | |||
463 | } | |||
464 | } | |||
465 | if (O.Cmd) { | |||
466 | VariantEntry Entry; | |||
467 | Entry.Cmd = *O.Cmd; | |||
468 | Yout << Entry; | |||
469 | } | |||
470 | } | |||
471 | ||||
472 | llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data, | |||
473 | SymbolOrigin Origin) { | |||
474 | SymbolSlab::Builder Symbols; | |||
475 | RefSlab::Builder Refs; | |||
476 | RelationSlab::Builder Relations; | |||
477 | llvm::BumpPtrAllocator | |||
478 | Arena; // store the underlying data of Position::FileURI. | |||
479 | llvm::UniqueStringSaver Strings(Arena); | |||
480 | llvm::yaml::Input Yin(Data, &Strings); | |||
481 | IncludeGraph Sources; | |||
482 | std::optional<tooling::CompileCommand> Cmd; | |||
483 | while (Yin.setCurrentDocument()) { | |||
484 | llvm::yaml::EmptyContext Ctx; | |||
485 | VariantEntry Variant; | |||
486 | yamlize(Yin, Variant, true, Ctx); | |||
487 | if (Yin.error()) | |||
488 | return llvm::errorCodeToError(Yin.error()); | |||
489 | ||||
490 | if (Variant.Symbol) { | |||
491 | Variant.Symbol->Origin = Origin; | |||
492 | Symbols.insert(*Variant.Symbol); | |||
493 | } | |||
494 | if (Variant.Refs) | |||
495 | for (const auto &Ref : Variant.Refs->second) | |||
496 | Refs.insert(Variant.Refs->first, Ref); | |||
497 | if (Variant.Relation) | |||
498 | Relations.insert(*Variant.Relation); | |||
499 | if (Variant.Source) { | |||
500 | auto &IGN = *Variant.Source; | |||
501 | auto Entry = Sources.try_emplace(IGN.URI).first; | |||
502 | Entry->getValue() = std::move(IGN); | |||
503 | // Fixup refs to refer to map keys which will live on | |||
504 | Entry->getValue().URI = Entry->getKey(); | |||
505 | for (auto &Include : Entry->getValue().DirectIncludes) | |||
506 | Include = Sources.try_emplace(Include).first->getKey(); | |||
507 | } | |||
508 | if (Variant.Cmd) | |||
509 | Cmd = *Variant.Cmd; | |||
510 | Yin.nextDocument(); | |||
511 | } | |||
512 | ||||
513 | IndexFileIn Result; | |||
514 | Result.Symbols.emplace(std::move(Symbols).build()); | |||
515 | Result.Refs.emplace(std::move(Refs).build()); | |||
516 | Result.Relations.emplace(std::move(Relations).build()); | |||
517 | if (Sources.size()) | |||
518 | Result.Sources = std::move(Sources); | |||
519 | Result.Cmd = std::move(Cmd); | |||
520 | return std::move(Result); | |||
521 | } | |||
522 | ||||
523 | std::string toYAML(const Symbol &S) { | |||
524 | std::string Buf; | |||
525 | { | |||
526 | llvm::raw_string_ostream OS(Buf); | |||
527 | llvm::yaml::Output Yout(OS); | |||
528 | Symbol Sym = S; // copy: Yout<< requires mutability. | |||
529 | Yout << Sym; | |||
530 | } | |||
531 | return Buf; | |||
532 | } | |||
533 | ||||
534 | std::string toYAML(const std::pair<SymbolID, llvm::ArrayRef<Ref>> &Data) { | |||
535 | RefBundle Refs = {Data.first, Data.second}; | |||
536 | std::string Buf; | |||
537 | { | |||
538 | llvm::raw_string_ostream OS(Buf); | |||
539 | llvm::yaml::Output Yout(OS); | |||
540 | Yout << Refs; | |||
541 | } | |||
542 | return Buf; | |||
543 | } | |||
544 | ||||
545 | std::string toYAML(const Relation &R) { | |||
546 | std::string Buf; | |||
547 | { | |||
548 | llvm::raw_string_ostream OS(Buf); | |||
549 | llvm::yaml::Output Yout(OS); | |||
550 | Relation Rel = R; // copy: Yout<< requires mutability. | |||
551 | Yout << Rel; | |||
552 | } | |||
553 | return Buf; | |||
554 | } | |||
555 | ||||
556 | std::string toYAML(const Ref &R) { | |||
557 | std::string Buf; | |||
558 | { | |||
559 | llvm::raw_string_ostream OS(Buf); | |||
560 | llvm::yaml::Output Yout(OS); | |||
561 | Ref Reference = R; // copy: Yout<< requires mutability. | |||
562 | Yout << Reference; | |||
| ||||
563 | } | |||
564 | return Buf; | |||
565 | } | |||
566 | ||||
567 | } // namespace clangd | |||
568 | } // namespace clang |
1 | //===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===// | ||||||||||||
2 | // | ||||||||||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||||||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||||||||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||||||||
6 | // | ||||||||||||
7 | //===----------------------------------------------------------------------===// | ||||||||||||
8 | |||||||||||||
9 | #ifndef LLVM_SUPPORT_YAMLTRAITS_H | ||||||||||||
10 | #define LLVM_SUPPORT_YAMLTRAITS_H | ||||||||||||
11 | |||||||||||||
12 | #include "llvm/ADT/ArrayRef.h" | ||||||||||||
13 | #include "llvm/ADT/BitVector.h" | ||||||||||||
14 | #include "llvm/ADT/SmallVector.h" | ||||||||||||
15 | #include "llvm/ADT/StringExtras.h" | ||||||||||||
16 | #include "llvm/ADT/StringMap.h" | ||||||||||||
17 | #include "llvm/ADT/StringRef.h" | ||||||||||||
18 | #include "llvm/ADT/Twine.h" | ||||||||||||
19 | #include "llvm/Support/AlignOf.h" | ||||||||||||
20 | #include "llvm/Support/Allocator.h" | ||||||||||||
21 | #include "llvm/Support/Endian.h" | ||||||||||||
22 | #include "llvm/Support/SMLoc.h" | ||||||||||||
23 | #include "llvm/Support/SourceMgr.h" | ||||||||||||
24 | #include "llvm/Support/YAMLParser.h" | ||||||||||||
25 | #include "llvm/Support/raw_ostream.h" | ||||||||||||
26 | #include <cassert> | ||||||||||||
27 | #include <map> | ||||||||||||
28 | #include <memory> | ||||||||||||
29 | #include <new> | ||||||||||||
30 | #include <optional> | ||||||||||||
31 | #include <string> | ||||||||||||
32 | #include <system_error> | ||||||||||||
33 | #include <type_traits> | ||||||||||||
34 | #include <vector> | ||||||||||||
35 | |||||||||||||
36 | namespace llvm { | ||||||||||||
37 | |||||||||||||
38 | class VersionTuple; | ||||||||||||
39 | |||||||||||||
40 | namespace yaml { | ||||||||||||
41 | |||||||||||||
42 | enum class NodeKind : uint8_t { | ||||||||||||
43 | Scalar, | ||||||||||||
44 | Map, | ||||||||||||
45 | Sequence, | ||||||||||||
46 | }; | ||||||||||||
47 | |||||||||||||
48 | struct EmptyContext {}; | ||||||||||||
49 | |||||||||||||
50 | /// This class should be specialized by any type that needs to be converted | ||||||||||||
51 | /// to/from a YAML mapping. For example: | ||||||||||||
52 | /// | ||||||||||||
53 | /// struct MappingTraits<MyStruct> { | ||||||||||||
54 | /// static void mapping(IO &io, MyStruct &s) { | ||||||||||||
55 | /// io.mapRequired("name", s.name); | ||||||||||||
56 | /// io.mapRequired("size", s.size); | ||||||||||||
57 | /// io.mapOptional("age", s.age); | ||||||||||||
58 | /// } | ||||||||||||
59 | /// }; | ||||||||||||
60 | template<class T> | ||||||||||||
61 | struct MappingTraits { | ||||||||||||
62 | // Must provide: | ||||||||||||
63 | // static void mapping(IO &io, T &fields); | ||||||||||||
64 | // Optionally may provide: | ||||||||||||
65 | // static std::string validate(IO &io, T &fields); | ||||||||||||
66 | // static void enumInput(IO &io, T &value); | ||||||||||||
67 | // | ||||||||||||
68 | // The optional flow flag will cause generated YAML to use a flow mapping | ||||||||||||
69 | // (e.g. { a: 0, b: 1 }): | ||||||||||||
70 | // static const bool flow = true; | ||||||||||||
71 | }; | ||||||||||||
72 | |||||||||||||
73 | /// This class is similar to MappingTraits<T> but allows you to pass in | ||||||||||||
74 | /// additional context for each map operation. For example: | ||||||||||||
75 | /// | ||||||||||||
76 | /// struct MappingContextTraits<MyStruct, MyContext> { | ||||||||||||
77 | /// static void mapping(IO &io, MyStruct &s, MyContext &c) { | ||||||||||||
78 | /// io.mapRequired("name", s.name); | ||||||||||||
79 | /// io.mapRequired("size", s.size); | ||||||||||||
80 | /// io.mapOptional("age", s.age); | ||||||||||||
81 | /// ++c.TimesMapped; | ||||||||||||
82 | /// } | ||||||||||||
83 | /// }; | ||||||||||||
84 | template <class T, class Context> struct MappingContextTraits { | ||||||||||||
85 | // Must provide: | ||||||||||||
86 | // static void mapping(IO &io, T &fields, Context &Ctx); | ||||||||||||
87 | // Optionally may provide: | ||||||||||||
88 | // static std::string validate(IO &io, T &fields, Context &Ctx); | ||||||||||||
89 | // | ||||||||||||
90 | // The optional flow flag will cause generated YAML to use a flow mapping | ||||||||||||
91 | // (e.g. { a: 0, b: 1 }): | ||||||||||||
92 | // static const bool flow = true; | ||||||||||||
93 | }; | ||||||||||||
94 | |||||||||||||
95 | /// This class should be specialized by any integral type that converts | ||||||||||||
96 | /// to/from a YAML scalar where there is a one-to-one mapping between | ||||||||||||
97 | /// in-memory values and a string in YAML. For example: | ||||||||||||
98 | /// | ||||||||||||
99 | /// struct ScalarEnumerationTraits<Colors> { | ||||||||||||
100 | /// static void enumeration(IO &io, Colors &value) { | ||||||||||||
101 | /// io.enumCase(value, "red", cRed); | ||||||||||||
102 | /// io.enumCase(value, "blue", cBlue); | ||||||||||||
103 | /// io.enumCase(value, "green", cGreen); | ||||||||||||
104 | /// } | ||||||||||||
105 | /// }; | ||||||||||||
106 | template <typename T, typename Enable = void> struct ScalarEnumerationTraits { | ||||||||||||
107 | // Must provide: | ||||||||||||
108 | // static void enumeration(IO &io, T &value); | ||||||||||||
109 | }; | ||||||||||||
110 | |||||||||||||
111 | /// This class should be specialized by any integer type that is a union | ||||||||||||
112 | /// of bit values and the YAML representation is a flow sequence of | ||||||||||||
113 | /// strings. For example: | ||||||||||||
114 | /// | ||||||||||||
115 | /// struct ScalarBitSetTraits<MyFlags> { | ||||||||||||
116 | /// static void bitset(IO &io, MyFlags &value) { | ||||||||||||
117 | /// io.bitSetCase(value, "big", flagBig); | ||||||||||||
118 | /// io.bitSetCase(value, "flat", flagFlat); | ||||||||||||
119 | /// io.bitSetCase(value, "round", flagRound); | ||||||||||||
120 | /// } | ||||||||||||
121 | /// }; | ||||||||||||
122 | template <typename T, typename Enable = void> struct ScalarBitSetTraits { | ||||||||||||
123 | // Must provide: | ||||||||||||
124 | // static void bitset(IO &io, T &value); | ||||||||||||
125 | }; | ||||||||||||
126 | |||||||||||||
127 | /// Describe which type of quotes should be used when quoting is necessary. | ||||||||||||
128 | /// Some non-printable characters need to be double-quoted, while some others | ||||||||||||
129 | /// are fine with simple-quoting, and some don't need any quoting. | ||||||||||||
130 | enum class QuotingType { None, Single, Double }; | ||||||||||||
131 | |||||||||||||
132 | /// This class should be specialized by type that requires custom conversion | ||||||||||||
133 | /// to/from a yaml scalar. For example: | ||||||||||||
134 | /// | ||||||||||||
135 | /// template<> | ||||||||||||
136 | /// struct ScalarTraits<MyType> { | ||||||||||||
137 | /// static void output(const MyType &val, void*, llvm::raw_ostream &out) { | ||||||||||||
138 | /// // stream out custom formatting | ||||||||||||
139 | /// out << llvm::format("%x", val); | ||||||||||||
140 | /// } | ||||||||||||
141 | /// static StringRef input(StringRef scalar, void*, MyType &value) { | ||||||||||||
142 | /// // parse scalar and set `value` | ||||||||||||
143 | /// // return empty string on success, or error string | ||||||||||||
144 | /// return StringRef(); | ||||||||||||
145 | /// } | ||||||||||||
146 | /// static QuotingType mustQuote(StringRef) { return QuotingType::Single; } | ||||||||||||
147 | /// }; | ||||||||||||
148 | template <typename T, typename Enable = void> struct ScalarTraits { | ||||||||||||
149 | // Must provide: | ||||||||||||
150 | // | ||||||||||||
151 | // Function to write the value as a string: | ||||||||||||
152 | // static void output(const T &value, void *ctxt, llvm::raw_ostream &out); | ||||||||||||
153 | // | ||||||||||||
154 | // Function to convert a string to a value. Returns the empty | ||||||||||||
155 | // StringRef on success or an error string if string is malformed: | ||||||||||||
156 | // static StringRef input(StringRef scalar, void *ctxt, T &value); | ||||||||||||
157 | // | ||||||||||||
158 | // Function to determine if the value should be quoted. | ||||||||||||
159 | // static QuotingType mustQuote(StringRef); | ||||||||||||
160 | }; | ||||||||||||
161 | |||||||||||||
162 | /// This class should be specialized by type that requires custom conversion | ||||||||||||
163 | /// to/from a YAML literal block scalar. For example: | ||||||||||||
164 | /// | ||||||||||||
165 | /// template <> | ||||||||||||
166 | /// struct BlockScalarTraits<MyType> { | ||||||||||||
167 | /// static void output(const MyType &Value, void*, llvm::raw_ostream &Out) | ||||||||||||
168 | /// { | ||||||||||||
169 | /// // stream out custom formatting | ||||||||||||
170 | /// Out << Value; | ||||||||||||
171 | /// } | ||||||||||||
172 | /// static StringRef input(StringRef Scalar, void*, MyType &Value) { | ||||||||||||
173 | /// // parse scalar and set `value` | ||||||||||||
174 | /// // return empty string on success, or error string | ||||||||||||
175 | /// return StringRef(); | ||||||||||||
176 | /// } | ||||||||||||
177 | /// }; | ||||||||||||
178 | template <typename T> | ||||||||||||
179 | struct BlockScalarTraits { | ||||||||||||
180 | // Must provide: | ||||||||||||
181 | // | ||||||||||||
182 | // Function to write the value as a string: | ||||||||||||
183 | // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out); | ||||||||||||
184 | // | ||||||||||||
185 | // Function to convert a string to a value. Returns the empty | ||||||||||||
186 | // StringRef on success or an error string if string is malformed: | ||||||||||||
187 | // static StringRef input(StringRef Scalar, void *ctxt, T &Value); | ||||||||||||
188 | // | ||||||||||||
189 | // Optional: | ||||||||||||
190 | // static StringRef inputTag(T &Val, std::string Tag) | ||||||||||||
191 | // static void outputTag(const T &Val, raw_ostream &Out) | ||||||||||||
192 | }; | ||||||||||||
193 | |||||||||||||
194 | /// This class should be specialized by type that requires custom conversion | ||||||||||||
195 | /// to/from a YAML scalar with optional tags. For example: | ||||||||||||
196 | /// | ||||||||||||
197 | /// template <> | ||||||||||||
198 | /// struct TaggedScalarTraits<MyType> { | ||||||||||||
199 | /// static void output(const MyType &Value, void*, llvm::raw_ostream | ||||||||||||
200 | /// &ScalarOut, llvm::raw_ostream &TagOut) | ||||||||||||
201 | /// { | ||||||||||||
202 | /// // stream out custom formatting including optional Tag | ||||||||||||
203 | /// Out << Value; | ||||||||||||
204 | /// } | ||||||||||||
205 | /// static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType | ||||||||||||
206 | /// &Value) { | ||||||||||||
207 | /// // parse scalar and set `value` | ||||||||||||
208 | /// // return empty string on success, or error string | ||||||||||||
209 | /// return StringRef(); | ||||||||||||
210 | /// } | ||||||||||||
211 | /// static QuotingType mustQuote(const MyType &Value, StringRef) { | ||||||||||||
212 | /// return QuotingType::Single; | ||||||||||||
213 | /// } | ||||||||||||
214 | /// }; | ||||||||||||
215 | template <typename T> struct TaggedScalarTraits { | ||||||||||||
216 | // Must provide: | ||||||||||||
217 | // | ||||||||||||
218 | // Function to write the value and tag as strings: | ||||||||||||
219 | // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut, | ||||||||||||
220 | // llvm::raw_ostream &TagOut); | ||||||||||||
221 | // | ||||||||||||
222 | // Function to convert a string to a value. Returns the empty | ||||||||||||
223 | // StringRef on success or an error string if string is malformed: | ||||||||||||
224 | // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T | ||||||||||||
225 | // &Value); | ||||||||||||
226 | // | ||||||||||||
227 | // Function to determine if the value should be quoted. | ||||||||||||
228 | // static QuotingType mustQuote(const T &Value, StringRef Scalar); | ||||||||||||
229 | }; | ||||||||||||
230 | |||||||||||||
231 | /// This class should be specialized by any type that needs to be converted | ||||||||||||
232 | /// to/from a YAML sequence. For example: | ||||||||||||
233 | /// | ||||||||||||
234 | /// template<> | ||||||||||||
235 | /// struct SequenceTraits<MyContainer> { | ||||||||||||
236 | /// static size_t size(IO &io, MyContainer &seq) { | ||||||||||||
237 | /// return seq.size(); | ||||||||||||
238 | /// } | ||||||||||||
239 | /// static MyType& element(IO &, MyContainer &seq, size_t index) { | ||||||||||||
240 | /// if ( index >= seq.size() ) | ||||||||||||
241 | /// seq.resize(index+1); | ||||||||||||
242 | /// return seq[index]; | ||||||||||||
243 | /// } | ||||||||||||
244 | /// }; | ||||||||||||
245 | template<typename T, typename EnableIf = void> | ||||||||||||
246 | struct SequenceTraits { | ||||||||||||
247 | // Must provide: | ||||||||||||
248 | // static size_t size(IO &io, T &seq); | ||||||||||||
249 | // static T::value_type& element(IO &io, T &seq, size_t index); | ||||||||||||
250 | // | ||||||||||||
251 | // The following is option and will cause generated YAML to use | ||||||||||||
252 | // a flow sequence (e.g. [a,b,c]). | ||||||||||||
253 | // static const bool flow = true; | ||||||||||||
254 | }; | ||||||||||||
255 | |||||||||||||
256 | /// This class should be specialized by any type for which vectors of that | ||||||||||||
257 | /// type need to be converted to/from a YAML sequence. | ||||||||||||
258 | template<typename T, typename EnableIf = void> | ||||||||||||
259 | struct SequenceElementTraits { | ||||||||||||
260 | // Must provide: | ||||||||||||
261 | // static const bool flow; | ||||||||||||
262 | }; | ||||||||||||
263 | |||||||||||||
264 | /// This class should be specialized by any type that needs to be converted | ||||||||||||
265 | /// to/from a list of YAML documents. | ||||||||||||
266 | template<typename T> | ||||||||||||
267 | struct DocumentListTraits { | ||||||||||||
268 | // Must provide: | ||||||||||||
269 | // static size_t size(IO &io, T &seq); | ||||||||||||
270 | // static T::value_type& element(IO &io, T &seq, size_t index); | ||||||||||||
271 | }; | ||||||||||||
272 | |||||||||||||
273 | /// This class should be specialized by any type that needs to be converted | ||||||||||||
274 | /// to/from a YAML mapping in the case where the names of the keys are not known | ||||||||||||
275 | /// in advance, e.g. a string map. | ||||||||||||
276 | template <typename T> | ||||||||||||
277 | struct CustomMappingTraits { | ||||||||||||
278 | // static void inputOne(IO &io, StringRef key, T &elem); | ||||||||||||
279 | // static void output(IO &io, T &elem); | ||||||||||||
280 | }; | ||||||||||||
281 | |||||||||||||
282 | /// This class should be specialized by any type that can be represented as | ||||||||||||
283 | /// a scalar, map, or sequence, decided dynamically. For example: | ||||||||||||
284 | /// | ||||||||||||
285 | /// typedef std::unique_ptr<MyBase> MyPoly; | ||||||||||||
286 | /// | ||||||||||||
287 | /// template<> | ||||||||||||
288 | /// struct PolymorphicTraits<MyPoly> { | ||||||||||||
289 | /// static NodeKind getKind(const MyPoly &poly) { | ||||||||||||
290 | /// return poly->getKind(); | ||||||||||||
291 | /// } | ||||||||||||
292 | /// static MyScalar& getAsScalar(MyPoly &poly) { | ||||||||||||
293 | /// if (!poly || !isa<MyScalar>(poly)) | ||||||||||||
294 | /// poly.reset(new MyScalar()); | ||||||||||||
295 | /// return *cast<MyScalar>(poly.get()); | ||||||||||||
296 | /// } | ||||||||||||
297 | /// // ... | ||||||||||||
298 | /// }; | ||||||||||||
299 | template <typename T> struct PolymorphicTraits { | ||||||||||||
300 | // Must provide: | ||||||||||||
301 | // static NodeKind getKind(const T &poly); | ||||||||||||
302 | // static scalar_type &getAsScalar(T &poly); | ||||||||||||
303 | // static map_type &getAsMap(T &poly); | ||||||||||||
304 | // static sequence_type &getAsSequence(T &poly); | ||||||||||||
305 | }; | ||||||||||||
306 | |||||||||||||
307 | // Only used for better diagnostics of missing traits | ||||||||||||
308 | template <typename T> | ||||||||||||
309 | struct MissingTrait; | ||||||||||||
310 | |||||||||||||
311 | // Test if ScalarEnumerationTraits<T> is defined on type T. | ||||||||||||
312 | template <class T> | ||||||||||||
313 | struct has_ScalarEnumerationTraits | ||||||||||||
314 | { | ||||||||||||
315 | using Signature_enumeration = void (*)(class IO&, T&); | ||||||||||||
316 | |||||||||||||
317 | template <typename U> | ||||||||||||
318 | static char test(SameType<Signature_enumeration, &U::enumeration>*); | ||||||||||||
319 | |||||||||||||
320 | template <typename U> | ||||||||||||
321 | static double test(...); | ||||||||||||
322 | |||||||||||||
323 | static bool const value = | ||||||||||||
324 | (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); | ||||||||||||
325 | }; | ||||||||||||
326 | |||||||||||||
327 | // Test if ScalarBitSetTraits<T> is defined on type T. | ||||||||||||
328 | template <class T> | ||||||||||||
329 | struct has_ScalarBitSetTraits | ||||||||||||
330 | { | ||||||||||||
331 | using Signature_bitset = void (*)(class IO&, T&); | ||||||||||||
332 | |||||||||||||
333 | template <typename U> | ||||||||||||
334 | static char test(SameType<Signature_bitset, &U::bitset>*); | ||||||||||||
335 | |||||||||||||
336 | template <typename U> | ||||||||||||
337 | static double test(...); | ||||||||||||
338 | |||||||||||||
339 | static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); | ||||||||||||
340 | }; | ||||||||||||
341 | |||||||||||||
342 | // Test if ScalarTraits<T> is defined on type T. | ||||||||||||
343 | template <class T> | ||||||||||||
344 | struct has_ScalarTraits | ||||||||||||
345 | { | ||||||||||||
346 | using Signature_input = StringRef (*)(StringRef, void*, T&); | ||||||||||||
347 | using Signature_output = void (*)(const T&, void*, raw_ostream&); | ||||||||||||
348 | using Signature_mustQuote = QuotingType (*)(StringRef); | ||||||||||||
349 | |||||||||||||
350 | template <typename U> | ||||||||||||
351 | static char test(SameType<Signature_input, &U::input> *, | ||||||||||||
352 | SameType<Signature_output, &U::output> *, | ||||||||||||
353 | SameType<Signature_mustQuote, &U::mustQuote> *); | ||||||||||||
354 | |||||||||||||
355 | template <typename U> | ||||||||||||
356 | static double test(...); | ||||||||||||
357 | |||||||||||||
358 | static bool const value = | ||||||||||||
359 | (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); | ||||||||||||
360 | }; | ||||||||||||
361 | |||||||||||||
362 | // Test if BlockScalarTraits<T> is defined on type T. | ||||||||||||
363 | template <class T> | ||||||||||||
364 | struct has_BlockScalarTraits | ||||||||||||
365 | { | ||||||||||||
366 | using Signature_input = StringRef (*)(StringRef, void *, T &); | ||||||||||||
367 | using Signature_output = void (*)(const T &, void *, raw_ostream &); | ||||||||||||
368 | |||||||||||||
369 | template <typename U> | ||||||||||||
370 | static char test(SameType<Signature_input, &U::input> *, | ||||||||||||
371 | SameType<Signature_output, &U::output> *); | ||||||||||||
372 | |||||||||||||
373 | template <typename U> | ||||||||||||
374 | static double test(...); | ||||||||||||
375 | |||||||||||||
376 | static bool const value = | ||||||||||||
377 | (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1); | ||||||||||||
378 | }; | ||||||||||||
379 | |||||||||||||
380 | // Test if TaggedScalarTraits<T> is defined on type T. | ||||||||||||
381 | template <class T> struct has_TaggedScalarTraits { | ||||||||||||
382 | using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &); | ||||||||||||
383 | using Signature_output = void (*)(const T &, void *, raw_ostream &, | ||||||||||||
384 | raw_ostream &); | ||||||||||||
385 | using Signature_mustQuote = QuotingType (*)(const T &, StringRef); | ||||||||||||
386 | |||||||||||||
387 | template <typename U> | ||||||||||||
388 | static char test(SameType<Signature_input, &U::input> *, | ||||||||||||
389 | SameType<Signature_output, &U::output> *, | ||||||||||||
390 | SameType<Signature_mustQuote, &U::mustQuote> *); | ||||||||||||
391 | |||||||||||||
392 | template <typename U> static double test(...); | ||||||||||||
393 | |||||||||||||
394 | static bool const value = | ||||||||||||
395 | (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); | ||||||||||||
396 | }; | ||||||||||||
397 | |||||||||||||
398 | // Test if MappingContextTraits<T> is defined on type T. | ||||||||||||
399 | template <class T, class Context> struct has_MappingTraits { | ||||||||||||
400 | using Signature_mapping = void (*)(class IO &, T &, Context &); | ||||||||||||
401 | |||||||||||||
402 | template <typename U> | ||||||||||||
403 | static char test(SameType<Signature_mapping, &U::mapping>*); | ||||||||||||
404 | |||||||||||||
405 | template <typename U> | ||||||||||||
406 | static double test(...); | ||||||||||||
407 | |||||||||||||
408 | static bool const value = | ||||||||||||
409 | (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); | ||||||||||||
410 | }; | ||||||||||||
411 | |||||||||||||
412 | // Test if MappingTraits<T> is defined on type T. | ||||||||||||
413 | template <class T> struct has_MappingTraits<T, EmptyContext> { | ||||||||||||
414 | using Signature_mapping = void (*)(class IO &, T &); | ||||||||||||
415 | |||||||||||||
416 | template <typename U> | ||||||||||||
417 | static char test(SameType<Signature_mapping, &U::mapping> *); | ||||||||||||
418 | |||||||||||||
419 | template <typename U> static double test(...); | ||||||||||||
420 | |||||||||||||
421 | static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); | ||||||||||||
422 | }; | ||||||||||||
423 | |||||||||||||
424 | // Test if MappingContextTraits<T>::validate() is defined on type T. | ||||||||||||
425 | template <class T, class Context> struct has_MappingValidateTraits { | ||||||||||||
426 | using Signature_validate = std::string (*)(class IO &, T &, Context &); | ||||||||||||
427 | |||||||||||||
428 | template <typename U> | ||||||||||||
429 | static char test(SameType<Signature_validate, &U::validate>*); | ||||||||||||
430 | |||||||||||||
431 | template <typename U> | ||||||||||||
432 | static double test(...); | ||||||||||||
433 | |||||||||||||
434 | static bool const value = | ||||||||||||
435 | (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); | ||||||||||||
436 | }; | ||||||||||||
437 | |||||||||||||
438 | // Test if MappingTraits<T>::validate() is defined on type T. | ||||||||||||
439 | template <class T> struct has_MappingValidateTraits<T, EmptyContext> { | ||||||||||||
440 | using Signature_validate = std::string (*)(class IO &, T &); | ||||||||||||
441 | |||||||||||||
442 | template <typename U> | ||||||||||||
443 | static char test(SameType<Signature_validate, &U::validate> *); | ||||||||||||
444 | |||||||||||||
445 | template <typename U> static double test(...); | ||||||||||||
446 | |||||||||||||
447 | static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); | ||||||||||||
448 | }; | ||||||||||||
449 | |||||||||||||
450 | // Test if MappingContextTraits<T>::enumInput() is defined on type T. | ||||||||||||
451 | template <class T, class Context> struct has_MappingEnumInputTraits { | ||||||||||||
452 | using Signature_validate = void (*)(class IO &, T &); | ||||||||||||
453 | |||||||||||||
454 | template <typename U> | ||||||||||||
455 | static char test(SameType<Signature_validate, &U::enumInput> *); | ||||||||||||
456 | |||||||||||||
457 | template <typename U> static double test(...); | ||||||||||||
458 | |||||||||||||
459 | static bool const value = | ||||||||||||
460 | (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); | ||||||||||||
461 | }; | ||||||||||||
462 | |||||||||||||
463 | // Test if MappingTraits<T>::enumInput() is defined on type T. | ||||||||||||
464 | template <class T> struct has_MappingEnumInputTraits<T, EmptyContext> { | ||||||||||||
465 | using Signature_validate = void (*)(class IO &, T &); | ||||||||||||
466 | |||||||||||||
467 | template <typename U> | ||||||||||||
468 | static char test(SameType<Signature_validate, &U::enumInput> *); | ||||||||||||
469 | |||||||||||||
470 | template <typename U> static double test(...); | ||||||||||||
471 | |||||||||||||
472 | static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); | ||||||||||||
473 | }; | ||||||||||||
474 | |||||||||||||
475 | // Test if SequenceTraits<T> is defined on type T. | ||||||||||||
476 | template <class T> | ||||||||||||
477 | struct has_SequenceMethodTraits | ||||||||||||
478 | { | ||||||||||||
479 | using Signature_size = size_t (*)(class IO&, T&); | ||||||||||||
480 | |||||||||||||
481 | template <typename U> | ||||||||||||
482 | static char test(SameType<Signature_size, &U::size>*); | ||||||||||||
483 | |||||||||||||
484 | template <typename U> | ||||||||||||
485 | static double test(...); | ||||||||||||
486 | |||||||||||||
487 | static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); | ||||||||||||
488 | }; | ||||||||||||
489 | |||||||||||||
490 | // Test if CustomMappingTraits<T> is defined on type T. | ||||||||||||
491 | template <class T> | ||||||||||||
492 | struct has_CustomMappingTraits | ||||||||||||
493 | { | ||||||||||||
494 | using Signature_input = void (*)(IO &io, StringRef key, T &v); | ||||||||||||
495 | |||||||||||||
496 | template <typename U> | ||||||||||||
497 | static char test(SameType<Signature_input, &U::inputOne>*); | ||||||||||||
498 | |||||||||||||
499 | template <typename U> | ||||||||||||
500 | static double test(...); | ||||||||||||
501 | |||||||||||||
502 | static bool const value = | ||||||||||||
503 | (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1); | ||||||||||||
504 | }; | ||||||||||||
505 | |||||||||||||
506 | // has_FlowTraits<int> will cause an error with some compilers because | ||||||||||||
507 | // it subclasses int. Using this wrapper only instantiates the | ||||||||||||
508 | // real has_FlowTraits only if the template type is a class. | ||||||||||||
509 | template <typename T, bool Enabled = std::is_class<T>::value> | ||||||||||||
510 | class has_FlowTraits | ||||||||||||
511 | { | ||||||||||||
512 | public: | ||||||||||||
513 | static const bool value = false; | ||||||||||||
514 | }; | ||||||||||||
515 | |||||||||||||
516 | // Some older gcc compilers don't support straight forward tests | ||||||||||||
517 | // for members, so test for ambiguity cause by the base and derived | ||||||||||||
518 | // classes both defining the member. | ||||||||||||
519 | template <class T> | ||||||||||||
520 | struct has_FlowTraits<T, true> | ||||||||||||
521 | { | ||||||||||||
522 | struct Fallback { bool flow; }; | ||||||||||||
523 | struct Derived : T, Fallback { }; | ||||||||||||
524 | |||||||||||||
525 | template<typename C> | ||||||||||||
526 | static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; | ||||||||||||
527 | |||||||||||||
528 | template<typename C> | ||||||||||||
529 | static char (&f(...))[2]; | ||||||||||||
530 | |||||||||||||
531 | static bool const value = sizeof(f<Derived>(nullptr)) == 2; | ||||||||||||
532 | }; | ||||||||||||
533 | |||||||||||||
534 | // Test if SequenceTraits<T> is defined on type T | ||||||||||||
535 | template<typename T> | ||||||||||||
536 | struct has_SequenceTraits : public std::integral_constant<bool, | ||||||||||||
537 | has_SequenceMethodTraits<T>::value > { }; | ||||||||||||
538 | |||||||||||||
539 | // Test if DocumentListTraits<T> is defined on type T | ||||||||||||
540 | template <class T> | ||||||||||||
541 | struct has_DocumentListTraits | ||||||||||||
542 | { | ||||||||||||
543 | using Signature_size = size_t (*)(class IO &, T &); | ||||||||||||
544 | |||||||||||||
545 | template <typename U> | ||||||||||||
546 | static char test(SameType<Signature_size, &U::size>*); | ||||||||||||
547 | |||||||||||||
548 | template <typename U> | ||||||||||||
549 | static double test(...); | ||||||||||||
550 | |||||||||||||
551 | static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); | ||||||||||||
552 | }; | ||||||||||||
553 | |||||||||||||
554 | template <class T> struct has_PolymorphicTraits { | ||||||||||||
555 | using Signature_getKind = NodeKind (*)(const T &); | ||||||||||||
556 | |||||||||||||
557 | template <typename U> | ||||||||||||
558 | static char test(SameType<Signature_getKind, &U::getKind> *); | ||||||||||||
559 | |||||||||||||
560 | template <typename U> static double test(...); | ||||||||||||
561 | |||||||||||||
562 | static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1); | ||||||||||||
563 | }; | ||||||||||||
564 | |||||||||||||
565 | inline bool isNumeric(StringRef S) { | ||||||||||||
566 | const auto skipDigits = [](StringRef Input) { | ||||||||||||
567 | return Input.ltrim("0123456789"); | ||||||||||||
568 | }; | ||||||||||||
569 | |||||||||||||
570 | // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls | ||||||||||||
571 | // safe. | ||||||||||||
572 | if (S.empty() || S.equals("+") || S.equals("-")) | ||||||||||||
573 | return false; | ||||||||||||
574 | |||||||||||||
575 | if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) | ||||||||||||
576 | return true; | ||||||||||||
577 | |||||||||||||
578 | // Infinity and decimal numbers can be prefixed with sign. | ||||||||||||
579 | StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S; | ||||||||||||
580 | |||||||||||||
581 | // Check for infinity first, because checking for hex and oct numbers is more | ||||||||||||
582 | // expensive. | ||||||||||||
583 | if (Tail.equals(".inf") || Tail.equals(".Inf") || Tail.equals(".INF")) | ||||||||||||
584 | return true; | ||||||||||||
585 | |||||||||||||
586 | // Section 10.3.2 Tag Resolution | ||||||||||||
587 | // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with | ||||||||||||
588 | // [-+], so S should be used instead of Tail. | ||||||||||||
589 | if (S.startswith("0o")) | ||||||||||||
590 | return S.size() > 2 && | ||||||||||||
591 | S.drop_front(2).find_first_not_of("01234567") == StringRef::npos; | ||||||||||||
592 | |||||||||||||
593 | if (S.startswith("0x")) | ||||||||||||
594 | return S.size() > 2 && S.drop_front(2).find_first_not_of( | ||||||||||||
595 | "0123456789abcdefABCDEF") == StringRef::npos; | ||||||||||||
596 | |||||||||||||
597 | // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)? | ||||||||||||
598 | S = Tail; | ||||||||||||
599 | |||||||||||||
600 | // Handle cases when the number starts with '.' and hence needs at least one | ||||||||||||
601 | // digit after dot (as opposed by number which has digits before the dot), but | ||||||||||||
602 | // doesn't have one. | ||||||||||||
603 | if (S.startswith(".") && | ||||||||||||
604 | (S.equals(".") || | ||||||||||||
605 | (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr))) | ||||||||||||
606 | return false; | ||||||||||||
607 | |||||||||||||
608 | if (S.startswith("E") || S.startswith("e")) | ||||||||||||
609 | return false; | ||||||||||||
610 | |||||||||||||
611 | enum ParseState { | ||||||||||||
612 | Default, | ||||||||||||
613 | FoundDot, | ||||||||||||
614 | FoundExponent, | ||||||||||||
615 | }; | ||||||||||||
616 | ParseState State = Default; | ||||||||||||
617 | |||||||||||||
618 | S = skipDigits(S); | ||||||||||||
619 | |||||||||||||
620 | // Accept decimal integer. | ||||||||||||
621 | if (S.empty()) | ||||||||||||
622 | return true; | ||||||||||||
623 | |||||||||||||
624 | if (S.front() == '.') { | ||||||||||||
625 | State = FoundDot; | ||||||||||||
626 | S = S.drop_front(); | ||||||||||||
627 | } else if (S.front() == 'e' || S.front() == 'E') { | ||||||||||||
628 | State = FoundExponent; | ||||||||||||
629 | S = S.drop_front(); | ||||||||||||
630 | } else { | ||||||||||||
631 | return false; | ||||||||||||
632 | } | ||||||||||||
633 | |||||||||||||
634 | if (State == FoundDot) { | ||||||||||||
635 | S = skipDigits(S); | ||||||||||||
636 | if (S.empty()) | ||||||||||||
637 | return true; | ||||||||||||
638 | |||||||||||||
639 | if (S.front() == 'e' || S.front() == 'E') { | ||||||||||||
640 | State = FoundExponent; | ||||||||||||
641 | S = S.drop_front(); | ||||||||||||
642 | } else { | ||||||||||||
643 | return false; | ||||||||||||
644 | } | ||||||||||||
645 | } | ||||||||||||
646 | |||||||||||||
647 | assert(State == FoundExponent && "Should have found exponent at this point.")(static_cast <bool> (State == FoundExponent && "Should have found exponent at this point." ) ? void (0) : __assert_fail ("State == FoundExponent && \"Should have found exponent at this point.\"" , "llvm/include/llvm/Support/YAMLTraits.h", 647, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
648 | if (S.empty()) | ||||||||||||
649 | return false; | ||||||||||||
650 | |||||||||||||
651 | if (S.front() == '+' || S.front() == '-') { | ||||||||||||
652 | S = S.drop_front(); | ||||||||||||
653 | if (S.empty()) | ||||||||||||
654 | return false; | ||||||||||||
655 | } | ||||||||||||
656 | |||||||||||||
657 | return skipDigits(S).empty(); | ||||||||||||
658 | } | ||||||||||||
659 | |||||||||||||
660 | inline bool isNull(StringRef S) { | ||||||||||||
661 | return S.equals("null") || S.equals("Null") || S.equals("NULL") || | ||||||||||||
662 | S.equals("~"); | ||||||||||||
663 | } | ||||||||||||
664 | |||||||||||||
665 | inline bool isBool(StringRef S) { | ||||||||||||
666 | // FIXME: using parseBool is causing multiple tests to fail. | ||||||||||||
667 | return S.equals("true") || S.equals("True") || S.equals("TRUE") || | ||||||||||||
668 | S.equals("false") || S.equals("False") || S.equals("FALSE"); | ||||||||||||
669 | } | ||||||||||||
670 | |||||||||||||
671 | // 5.1. Character Set | ||||||||||||
672 | // The allowed character range explicitly excludes the C0 control block #x0-#x1F | ||||||||||||
673 | // (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1 | ||||||||||||
674 | // control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate | ||||||||||||
675 | // block #xD800-#xDFFF, #xFFFE, and #xFFFF. | ||||||||||||
676 | inline QuotingType needsQuotes(StringRef S) { | ||||||||||||
677 | if (S.empty()) | ||||||||||||
678 | return QuotingType::Single; | ||||||||||||
679 | |||||||||||||
680 | QuotingType MaxQuotingNeeded = QuotingType::None; | ||||||||||||
681 | if (isSpace(static_cast<unsigned char>(S.front())) || | ||||||||||||
682 | isSpace(static_cast<unsigned char>(S.back()))) | ||||||||||||
683 | MaxQuotingNeeded = QuotingType::Single; | ||||||||||||
684 | if (isNull(S)) | ||||||||||||
685 | MaxQuotingNeeded = QuotingType::Single; | ||||||||||||
686 | if (isBool(S)) | ||||||||||||
687 | MaxQuotingNeeded = QuotingType::Single; | ||||||||||||
688 | if (isNumeric(S)) | ||||||||||||
689 | MaxQuotingNeeded = QuotingType::Single; | ||||||||||||
690 | |||||||||||||
691 | // 7.3.3 Plain Style | ||||||||||||
692 | // Plain scalars must not begin with most indicators, as this would cause | ||||||||||||
693 | // ambiguity with other YAML constructs. | ||||||||||||
694 | if (std::strchr(R"(-?:\,[]{}#&*!|>'"%@`)", S[0]) != nullptr) | ||||||||||||
695 | MaxQuotingNeeded = QuotingType::Single; | ||||||||||||
696 | |||||||||||||
697 | for (unsigned char C : S) { | ||||||||||||
698 | // Alphanum is safe. | ||||||||||||
699 | if (isAlnum(C)) | ||||||||||||
700 | continue; | ||||||||||||
701 | |||||||||||||
702 | switch (C) { | ||||||||||||
703 | // Safe scalar characters. | ||||||||||||
704 | case '_': | ||||||||||||
705 | case '-': | ||||||||||||
706 | case '^': | ||||||||||||
707 | case '.': | ||||||||||||
708 | case ',': | ||||||||||||
709 | case ' ': | ||||||||||||
710 | // TAB (0x9) is allowed in unquoted strings. | ||||||||||||
711 | case 0x9: | ||||||||||||
712 | continue; | ||||||||||||
713 | // LF(0xA) and CR(0xD) may delimit values and so require at least single | ||||||||||||
714 | // quotes. LLVM YAML parser cannot handle single quoted multiline so use | ||||||||||||
715 | // double quoting to produce valid YAML. | ||||||||||||
716 | case 0xA: | ||||||||||||
717 | case 0xD: | ||||||||||||
718 | return QuotingType::Double; | ||||||||||||
719 | // DEL (0x7F) are excluded from the allowed character range. | ||||||||||||
720 | case 0x7F: | ||||||||||||
721 | return QuotingType::Double; | ||||||||||||
722 | // Forward slash is allowed to be unquoted, but we quote it anyway. We have | ||||||||||||
723 | // many tests that use FileCheck against YAML output, and this output often | ||||||||||||
724 | // contains paths. If we quote backslashes but not forward slashes then | ||||||||||||
725 | // paths will come out either quoted or unquoted depending on which platform | ||||||||||||
726 | // the test is run on, making FileCheck comparisons difficult. | ||||||||||||
727 | case '/': | ||||||||||||
728 | default: { | ||||||||||||
729 | // C0 control block (0x0 - 0x1F) is excluded from the allowed character | ||||||||||||
730 | // range. | ||||||||||||
731 | if (C <= 0x1F) | ||||||||||||
732 | return QuotingType::Double; | ||||||||||||
733 | |||||||||||||
734 | // Always double quote UTF-8. | ||||||||||||
735 | if ((C & 0x80) != 0) | ||||||||||||
736 | return QuotingType::Double; | ||||||||||||
737 | |||||||||||||
738 | // The character is not safe, at least simple quoting needed. | ||||||||||||
739 | MaxQuotingNeeded = QuotingType::Single; | ||||||||||||
740 | } | ||||||||||||
741 | } | ||||||||||||
742 | } | ||||||||||||
743 | |||||||||||||
744 | return MaxQuotingNeeded; | ||||||||||||
745 | } | ||||||||||||
746 | |||||||||||||
747 | template <typename T, typename Context> | ||||||||||||
748 | struct missingTraits | ||||||||||||
749 | : public std::integral_constant<bool, | ||||||||||||
750 | !has_ScalarEnumerationTraits<T>::value && | ||||||||||||
751 | !has_ScalarBitSetTraits<T>::value && | ||||||||||||
752 | !has_ScalarTraits<T>::value && | ||||||||||||
753 | !has_BlockScalarTraits<T>::value && | ||||||||||||
754 | !has_TaggedScalarTraits<T>::value && | ||||||||||||
755 | !has_MappingTraits<T, Context>::value && | ||||||||||||
756 | !has_SequenceTraits<T>::value && | ||||||||||||
757 | !has_CustomMappingTraits<T>::value && | ||||||||||||
758 | !has_DocumentListTraits<T>::value && | ||||||||||||
759 | !has_PolymorphicTraits<T>::value> {}; | ||||||||||||
760 | |||||||||||||
761 | template <typename T, typename Context> | ||||||||||||
762 | struct validatedMappingTraits | ||||||||||||
763 | : public std::integral_constant< | ||||||||||||
764 | bool, has_MappingTraits<T, Context>::value && | ||||||||||||
765 | has_MappingValidateTraits<T, Context>::value> {}; | ||||||||||||
766 | |||||||||||||
767 | template <typename T, typename Context> | ||||||||||||
768 | struct unvalidatedMappingTraits | ||||||||||||
769 | : public std::integral_constant< | ||||||||||||
770 | bool, has_MappingTraits<T, Context>::value && | ||||||||||||
771 | !has_MappingValidateTraits<T, Context>::value> {}; | ||||||||||||
772 | |||||||||||||
773 | // Base class for Input and Output. | ||||||||||||
774 | class IO { | ||||||||||||
775 | public: | ||||||||||||
776 | IO(void *Ctxt = nullptr); | ||||||||||||
777 | virtual ~IO(); | ||||||||||||
778 | |||||||||||||
779 | virtual bool outputting() const = 0; | ||||||||||||
780 | |||||||||||||
781 | virtual unsigned beginSequence() = 0; | ||||||||||||
782 | virtual bool preflightElement(unsigned, void *&) = 0; | ||||||||||||
783 | virtual void postflightElement(void*) = 0; | ||||||||||||
784 | virtual void endSequence() = 0; | ||||||||||||
785 | virtual bool canElideEmptySequence() = 0; | ||||||||||||
786 | |||||||||||||
787 | virtual unsigned beginFlowSequence() = 0; | ||||||||||||
788 | virtual bool preflightFlowElement(unsigned, void *&) = 0; | ||||||||||||
789 | virtual void postflightFlowElement(void*) = 0; | ||||||||||||
790 | virtual void endFlowSequence() = 0; | ||||||||||||
791 | |||||||||||||
792 | virtual bool mapTag(StringRef Tag, bool Default=false) = 0; | ||||||||||||
793 | virtual void beginMapping() = 0; | ||||||||||||
794 | virtual void endMapping() = 0; | ||||||||||||
795 | virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; | ||||||||||||
796 | virtual void postflightKey(void*) = 0; | ||||||||||||
797 | virtual std::vector<StringRef> keys() = 0; | ||||||||||||
798 | |||||||||||||
799 | virtual void beginFlowMapping() = 0; | ||||||||||||
800 | virtual void endFlowMapping() = 0; | ||||||||||||
801 | |||||||||||||
802 | virtual void beginEnumScalar() = 0; | ||||||||||||
803 | virtual bool matchEnumScalar(const char*, bool) = 0; | ||||||||||||
804 | virtual bool matchEnumFallback() = 0; | ||||||||||||
805 | virtual void endEnumScalar() = 0; | ||||||||||||
806 | |||||||||||||
807 | virtual bool beginBitSetScalar(bool &) = 0; | ||||||||||||
808 | virtual bool bitSetMatch(const char*, bool) = 0; | ||||||||||||
809 | virtual void endBitSetScalar() = 0; | ||||||||||||
810 | |||||||||||||
811 | virtual void scalarString(StringRef &, QuotingType) = 0; | ||||||||||||
812 | virtual void blockScalarString(StringRef &) = 0; | ||||||||||||
813 | virtual void scalarTag(std::string &) = 0; | ||||||||||||
814 | |||||||||||||
815 | virtual NodeKind getNodeKind() = 0; | ||||||||||||
816 | |||||||||||||
817 | virtual void setError(const Twine &) = 0; | ||||||||||||
818 | virtual void setAllowUnknownKeys(bool Allow); | ||||||||||||
819 | |||||||||||||
820 | template <typename T> | ||||||||||||
821 | void enumCase(T &Val, const char* Str, const T ConstVal) { | ||||||||||||
822 | if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { | ||||||||||||
823 | Val = ConstVal; | ||||||||||||
824 | } | ||||||||||||
825 | } | ||||||||||||
826 | |||||||||||||
827 | // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF | ||||||||||||
828 | template <typename T> | ||||||||||||
829 | void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { | ||||||||||||
830 | if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { | ||||||||||||
831 | Val = ConstVal; | ||||||||||||
832 | } | ||||||||||||
833 | } | ||||||||||||
834 | |||||||||||||
835 | template <typename FBT, typename T> | ||||||||||||
836 | void enumFallback(T &Val) { | ||||||||||||
837 | if (matchEnumFallback()) { | ||||||||||||
838 | EmptyContext Context; | ||||||||||||
839 | // FIXME: Force integral conversion to allow strong typedefs to convert. | ||||||||||||
840 | FBT Res = static_cast<typename FBT::BaseType>(Val); | ||||||||||||
841 | yamlize(*this, Res, true, Context); | ||||||||||||
842 | Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); | ||||||||||||
843 | } | ||||||||||||
844 | } | ||||||||||||
845 | |||||||||||||
846 | template <typename T> | ||||||||||||
847 | void bitSetCase(T &Val, const char* Str, const T ConstVal) { | ||||||||||||
848 | if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { | ||||||||||||
849 | Val = static_cast<T>(Val | ConstVal); | ||||||||||||
850 | } | ||||||||||||
851 | } | ||||||||||||
852 | |||||||||||||
853 | // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF | ||||||||||||
854 | template <typename T> | ||||||||||||
855 | void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { | ||||||||||||
856 | if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { | ||||||||||||
857 | Val = static_cast<T>(Val | ConstVal); | ||||||||||||
858 | } | ||||||||||||
859 | } | ||||||||||||
860 | |||||||||||||
861 | template <typename T> | ||||||||||||
862 | void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { | ||||||||||||
863 | if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) | ||||||||||||
864 | Val = Val | ConstVal; | ||||||||||||
865 | } | ||||||||||||
866 | |||||||||||||
867 | template <typename T> | ||||||||||||
868 | void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, | ||||||||||||
869 | uint32_t Mask) { | ||||||||||||
870 | if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) | ||||||||||||
871 | Val = Val | ConstVal; | ||||||||||||
872 | } | ||||||||||||
873 | |||||||||||||
874 | void *getContext() const; | ||||||||||||
875 | void setContext(void *); | ||||||||||||
876 | |||||||||||||
877 | template <typename T> void mapRequired(const char *Key, T &Val) { | ||||||||||||
878 | EmptyContext Ctx; | ||||||||||||
879 | this->processKey(Key, Val, true, Ctx); | ||||||||||||
880 | } | ||||||||||||
881 | |||||||||||||
882 | template <typename T, typename Context> | ||||||||||||
883 | void mapRequired(const char *Key, T &Val, Context &Ctx) { | ||||||||||||
884 | this->processKey(Key, Val, true, Ctx); | ||||||||||||
885 | } | ||||||||||||
886 | |||||||||||||
887 | template <typename T> void mapOptional(const char *Key, T &Val) { | ||||||||||||
888 | EmptyContext Ctx; | ||||||||||||
889 | mapOptionalWithContext(Key, Val, Ctx); | ||||||||||||
890 | } | ||||||||||||
891 | |||||||||||||
892 | template <typename T, typename DefaultT> | ||||||||||||
893 | void mapOptional(const char *Key, T &Val, const DefaultT &Default) { | ||||||||||||
894 | EmptyContext Ctx; | ||||||||||||
895 | mapOptionalWithContext(Key, Val, Default, Ctx); | ||||||||||||
896 | } | ||||||||||||
897 | |||||||||||||
898 | template <typename T, typename Context> | ||||||||||||
899 | std::enable_if_t<has_SequenceTraits<T>::value, void> | ||||||||||||
900 | mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { | ||||||||||||
901 | // omit key/value instead of outputting empty sequence | ||||||||||||
902 | if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) | ||||||||||||
903 | return; | ||||||||||||
904 | this->processKey(Key, Val, false, Ctx); | ||||||||||||
905 | } | ||||||||||||
906 | |||||||||||||
907 | template <typename T, typename Context> | ||||||||||||
908 | void mapOptionalWithContext(const char *Key, std::optional<T> &Val, | ||||||||||||
909 | Context &Ctx) { | ||||||||||||
910 | this->processKeyWithDefault(Key, Val, std::optional<T>(), | ||||||||||||
911 | /*Required=*/false, Ctx); | ||||||||||||
912 | } | ||||||||||||
913 | |||||||||||||
914 | template <typename T, typename Context> | ||||||||||||
915 | std::enable_if_t<!has_SequenceTraits<T>::value, void> | ||||||||||||
916 | mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { | ||||||||||||
917 | this->processKey(Key, Val, false, Ctx); | ||||||||||||
918 | } | ||||||||||||
919 | |||||||||||||
920 | template <typename T, typename Context, typename DefaultT> | ||||||||||||
921 | void mapOptionalWithContext(const char *Key, T &Val, const DefaultT &Default, | ||||||||||||
922 | Context &Ctx) { | ||||||||||||
923 | static_assert(std::is_convertible<DefaultT, T>::value, | ||||||||||||
924 | "Default type must be implicitly convertible to value type!"); | ||||||||||||
925 | this->processKeyWithDefault(Key, Val, static_cast<const T &>(Default), | ||||||||||||
926 | false, Ctx); | ||||||||||||
927 | } | ||||||||||||
928 | |||||||||||||
929 | private: | ||||||||||||
930 | template <typename T, typename Context> | ||||||||||||
931 | void processKeyWithDefault(const char *Key, std::optional<T> &Val, | ||||||||||||
932 | const std::optional<T> &DefaultValue, | ||||||||||||
933 | bool Required, Context &Ctx); | ||||||||||||
934 | |||||||||||||
935 | template <typename T, typename Context> | ||||||||||||
936 | void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue, | ||||||||||||
937 | bool Required, Context &Ctx) { | ||||||||||||
938 | void *SaveInfo; | ||||||||||||
939 | bool UseDefault; | ||||||||||||
940 | const bool sameAsDefault = outputting() && Val == DefaultValue; | ||||||||||||
941 | if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, | ||||||||||||
942 | SaveInfo) ) { | ||||||||||||
943 | yamlize(*this, Val, Required, Ctx); | ||||||||||||
944 | this->postflightKey(SaveInfo); | ||||||||||||
945 | } | ||||||||||||
946 | else { | ||||||||||||
947 | if ( UseDefault ) | ||||||||||||
948 | Val = DefaultValue; | ||||||||||||
949 | } | ||||||||||||
950 | } | ||||||||||||
951 | |||||||||||||
952 | template <typename T, typename Context> | ||||||||||||
953 | void processKey(const char *Key, T &Val, bool Required, Context &Ctx) { | ||||||||||||
954 | void *SaveInfo; | ||||||||||||
955 | bool UseDefault; | ||||||||||||
956 | if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { | ||||||||||||
957 | yamlize(*this, Val, Required, Ctx); | ||||||||||||
958 | this->postflightKey(SaveInfo); | ||||||||||||
959 | } | ||||||||||||
960 | } | ||||||||||||
961 | |||||||||||||
962 | private: | ||||||||||||
963 | void *Ctxt; | ||||||||||||
964 | }; | ||||||||||||
965 | |||||||||||||
966 | namespace detail { | ||||||||||||
967 | |||||||||||||
968 | template <typename T, typename Context> | ||||||||||||
969 | void doMapping(IO &io, T &Val, Context &Ctx) { | ||||||||||||
970 | MappingContextTraits<T, Context>::mapping(io, Val, Ctx); | ||||||||||||
971 | } | ||||||||||||
972 | |||||||||||||
973 | template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) { | ||||||||||||
974 | MappingTraits<T>::mapping(io, Val); | ||||||||||||
975 | } | ||||||||||||
976 | |||||||||||||
977 | } // end namespace detail | ||||||||||||
978 | |||||||||||||
979 | template <typename T> | ||||||||||||
980 | std::enable_if_t<has_ScalarEnumerationTraits<T>::value, void> | ||||||||||||
981 | yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
982 | io.beginEnumScalar(); | ||||||||||||
983 | ScalarEnumerationTraits<T>::enumeration(io, Val); | ||||||||||||
984 | io.endEnumScalar(); | ||||||||||||
985 | } | ||||||||||||
986 | |||||||||||||
987 | template <typename T> | ||||||||||||
988 | std::enable_if_t<has_ScalarBitSetTraits<T>::value, void> | ||||||||||||
989 | yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
990 | bool DoClear; | ||||||||||||
991 | if ( io.beginBitSetScalar(DoClear) ) { | ||||||||||||
992 | if ( DoClear ) | ||||||||||||
993 | Val = T(); | ||||||||||||
994 | ScalarBitSetTraits<T>::bitset(io, Val); | ||||||||||||
995 | io.endBitSetScalar(); | ||||||||||||
996 | } | ||||||||||||
997 | } | ||||||||||||
998 | |||||||||||||
999 | template <typename T> | ||||||||||||
1000 | std::enable_if_t<has_ScalarTraits<T>::value, void> yamlize(IO &io, T &Val, bool, | ||||||||||||
1001 | EmptyContext &Ctx) { | ||||||||||||
1002 | if ( io.outputting() ) { | ||||||||||||
1003 | SmallString<128> Storage; | ||||||||||||
1004 | raw_svector_ostream Buffer(Storage); | ||||||||||||
1005 | ScalarTraits<T>::output(Val, io.getContext(), Buffer); | ||||||||||||
1006 | StringRef Str = Buffer.str(); | ||||||||||||
1007 | io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); | ||||||||||||
1008 | } | ||||||||||||
1009 | else { | ||||||||||||
1010 | StringRef Str; | ||||||||||||
1011 | io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); | ||||||||||||
1012 | StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); | ||||||||||||
1013 | if ( !Result.empty() ) { | ||||||||||||
1014 | io.setError(Twine(Result)); | ||||||||||||
1015 | } | ||||||||||||
1016 | } | ||||||||||||
1017 | } | ||||||||||||
1018 | |||||||||||||
1019 | template <typename T> | ||||||||||||
1020 | std::enable_if_t<has_BlockScalarTraits<T>::value, void> | ||||||||||||
1021 | yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
1022 | if (YamlIO.outputting()) { | ||||||||||||
1023 | std::string Storage; | ||||||||||||
1024 | raw_string_ostream Buffer(Storage); | ||||||||||||
1025 | BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer); | ||||||||||||
1026 | StringRef Str = Buffer.str(); | ||||||||||||
1027 | YamlIO.blockScalarString(Str); | ||||||||||||
1028 | } else { | ||||||||||||
1029 | StringRef Str; | ||||||||||||
1030 | YamlIO.blockScalarString(Str); | ||||||||||||
1031 | StringRef Result = | ||||||||||||
1032 | BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val); | ||||||||||||
1033 | if (!Result.empty()) | ||||||||||||
1034 | YamlIO.setError(Twine(Result)); | ||||||||||||
1035 | } | ||||||||||||
1036 | } | ||||||||||||
1037 | |||||||||||||
1038 | template <typename T> | ||||||||||||
1039 | std::enable_if_t<has_TaggedScalarTraits<T>::value, void> | ||||||||||||
1040 | yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
1041 | if (io.outputting()) { | ||||||||||||
1042 | std::string ScalarStorage, TagStorage; | ||||||||||||
1043 | raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage); | ||||||||||||
1044 | TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer, | ||||||||||||
1045 | TagBuffer); | ||||||||||||
1046 | io.scalarTag(TagBuffer.str()); | ||||||||||||
1047 | StringRef ScalarStr = ScalarBuffer.str(); | ||||||||||||
1048 | io.scalarString(ScalarStr, | ||||||||||||
1049 | TaggedScalarTraits<T>::mustQuote(Val, ScalarStr)); | ||||||||||||
1050 | } else { | ||||||||||||
1051 | std::string Tag; | ||||||||||||
1052 | io.scalarTag(Tag); | ||||||||||||
1053 | StringRef Str; | ||||||||||||
1054 | io.scalarString(Str, QuotingType::None); | ||||||||||||
1055 | StringRef Result = | ||||||||||||
1056 | TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val); | ||||||||||||
1057 | if (!Result.empty()) { | ||||||||||||
1058 | io.setError(Twine(Result)); | ||||||||||||
1059 | } | ||||||||||||
1060 | } | ||||||||||||
1061 | } | ||||||||||||
1062 | |||||||||||||
1063 | template <typename T, typename Context> | ||||||||||||
1064 | std::enable_if_t<validatedMappingTraits<T, Context>::value, void> | ||||||||||||
1065 | yamlize(IO &io, T &Val, bool, Context &Ctx) { | ||||||||||||
1066 | if (has_FlowTraits<MappingTraits<T>>::value) | ||||||||||||
1067 | io.beginFlowMapping(); | ||||||||||||
1068 | else | ||||||||||||
1069 | io.beginMapping(); | ||||||||||||
1070 | if (io.outputting()) { | ||||||||||||
1071 | std::string Err = MappingTraits<T>::validate(io, Val); | ||||||||||||
1072 | if (!Err.empty()) { | ||||||||||||
1073 | errs() << Err << "\n"; | ||||||||||||
1074 | assert(Err.empty() && "invalid struct trying to be written as yaml")(static_cast <bool> (Err.empty() && "invalid struct trying to be written as yaml" ) ? void (0) : __assert_fail ("Err.empty() && \"invalid struct trying to be written as yaml\"" , "llvm/include/llvm/Support/YAMLTraits.h", 1074, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
1075 | } | ||||||||||||
1076 | } | ||||||||||||
1077 | detail::doMapping(io, Val, Ctx); | ||||||||||||
1078 | if (!io.outputting()) { | ||||||||||||
1079 | std::string Err = MappingTraits<T>::validate(io, Val); | ||||||||||||
1080 | if (!Err.empty()) | ||||||||||||
1081 | io.setError(Err); | ||||||||||||
1082 | } | ||||||||||||
1083 | if (has_FlowTraits<MappingTraits<T>>::value) | ||||||||||||
1084 | io.endFlowMapping(); | ||||||||||||
1085 | else | ||||||||||||
1086 | io.endMapping(); | ||||||||||||
1087 | } | ||||||||||||
1088 | |||||||||||||
1089 | template <typename T, typename Context> | ||||||||||||
1090 | std::enable_if_t<!has_MappingEnumInputTraits<T, Context>::value, bool> | ||||||||||||
1091 | yamlizeMappingEnumInput(IO &io, T &Val) { | ||||||||||||
1092 | return false; | ||||||||||||
1093 | } | ||||||||||||
1094 | |||||||||||||
1095 | template <typename T, typename Context> | ||||||||||||
1096 | std::enable_if_t<has_MappingEnumInputTraits<T, Context>::value, bool> | ||||||||||||
1097 | yamlizeMappingEnumInput(IO &io, T &Val) { | ||||||||||||
1098 | if (io.outputting()) | ||||||||||||
1099 | return false; | ||||||||||||
1100 | |||||||||||||
1101 | io.beginEnumScalar(); | ||||||||||||
1102 | MappingTraits<T>::enumInput(io, Val); | ||||||||||||
1103 | bool Matched = !io.matchEnumFallback(); | ||||||||||||
1104 | io.endEnumScalar(); | ||||||||||||
1105 | return Matched; | ||||||||||||
1106 | } | ||||||||||||
1107 | |||||||||||||
1108 | template <typename T, typename Context> | ||||||||||||
1109 | std::enable_if_t<unvalidatedMappingTraits<T, Context>::value, void> | ||||||||||||
1110 | yamlize(IO &io, T &Val, bool, Context &Ctx) { | ||||||||||||
1111 | if (yamlizeMappingEnumInput<T, Context>(io, Val)) | ||||||||||||
1112 | return; | ||||||||||||
1113 | if (has_FlowTraits<MappingTraits<T>>::value
| ||||||||||||
1114 | io.beginFlowMapping(); | ||||||||||||
1115 | detail::doMapping(io, Val, Ctx); | ||||||||||||
1116 | io.endFlowMapping(); | ||||||||||||
1117 | } else { | ||||||||||||
1118 | io.beginMapping(); | ||||||||||||
1119 | detail::doMapping(io, Val, Ctx); | ||||||||||||
1120 | io.endMapping(); | ||||||||||||
1121 | } | ||||||||||||
1122 | } | ||||||||||||
1123 | |||||||||||||
1124 | template <typename T> | ||||||||||||
1125 | std::enable_if_t<has_CustomMappingTraits<T>::value, void> | ||||||||||||
1126 | yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
1127 | if ( io.outputting() ) { | ||||||||||||
1128 | io.beginMapping(); | ||||||||||||
1129 | CustomMappingTraits<T>::output(io, Val); | ||||||||||||
1130 | io.endMapping(); | ||||||||||||
1131 | } else { | ||||||||||||
1132 | io.beginMapping(); | ||||||||||||
1133 | for (StringRef key : io.keys()) | ||||||||||||
1134 | CustomMappingTraits<T>::inputOne(io, key, Val); | ||||||||||||
1135 | io.endMapping(); | ||||||||||||
1136 | } | ||||||||||||
1137 | } | ||||||||||||
1138 | |||||||||||||
1139 | template <typename T> | ||||||||||||
1140 | std::enable_if_t<has_PolymorphicTraits<T>::value, void> | ||||||||||||
1141 | yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
1142 | switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val) | ||||||||||||
1143 | : io.getNodeKind()) { | ||||||||||||
1144 | case NodeKind::Scalar: | ||||||||||||
1145 | return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx); | ||||||||||||
1146 | case NodeKind::Map: | ||||||||||||
1147 | return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx); | ||||||||||||
1148 | case NodeKind::Sequence: | ||||||||||||
1149 | return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx); | ||||||||||||
1150 | } | ||||||||||||
1151 | } | ||||||||||||
1152 | |||||||||||||
1153 | template <typename T> | ||||||||||||
1154 | std::enable_if_t<missingTraits<T, EmptyContext>::value, void> | ||||||||||||
1155 | yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { | ||||||||||||
1156 | char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; | ||||||||||||
1157 | } | ||||||||||||
1158 | |||||||||||||
1159 | template <typename T, typename Context> | ||||||||||||
1160 | std::enable_if_t<has_SequenceTraits<T>::value, void> | ||||||||||||
1161 | yamlize(IO &io, T &Seq, bool, Context &Ctx) { | ||||||||||||
1162 | if ( has_FlowTraits< SequenceTraits<T>>::value ) { | ||||||||||||
1163 | unsigned incnt = io.beginFlowSequence(); | ||||||||||||
1164 | unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; | ||||||||||||
1165 | for(unsigned i=0; i < count; ++i) { | ||||||||||||
1166 | void *SaveInfo; | ||||||||||||
1167 | if ( io.preflightFlowElement(i, SaveInfo) ) { | ||||||||||||
1168 | yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); | ||||||||||||
1169 | io.postflightFlowElement(SaveInfo); | ||||||||||||
1170 | } | ||||||||||||
1171 | } | ||||||||||||
1172 | io.endFlowSequence(); | ||||||||||||
1173 | } | ||||||||||||
1174 | else { | ||||||||||||
1175 | unsigned incnt = io.beginSequence(); | ||||||||||||
1176 | unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; | ||||||||||||
1177 | for(unsigned i=0; i < count; ++i) { | ||||||||||||
1178 | void *SaveInfo; | ||||||||||||
1179 | if ( io.preflightElement(i, SaveInfo) ) { | ||||||||||||
1180 | yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); | ||||||||||||
1181 | io.postflightElement(SaveInfo); | ||||||||||||
1182 | } | ||||||||||||
1183 | } | ||||||||||||
1184 | io.endSequence(); | ||||||||||||
1185 | } | ||||||||||||
1186 | } | ||||||||||||
1187 | |||||||||||||
1188 | template<> | ||||||||||||
1189 | struct ScalarTraits<bool> { | ||||||||||||
1190 | static void output(const bool &, void* , raw_ostream &); | ||||||||||||
1191 | static StringRef input(StringRef, void *, bool &); | ||||||||||||
1192 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1193 | }; | ||||||||||||
1194 | |||||||||||||
1195 | template<> | ||||||||||||
1196 | struct ScalarTraits<StringRef> { | ||||||||||||
1197 | static void output(const StringRef &, void *, raw_ostream &); | ||||||||||||
1198 | static StringRef input(StringRef, void *, StringRef &); | ||||||||||||
1199 | static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } | ||||||||||||
1200 | }; | ||||||||||||
1201 | |||||||||||||
1202 | template<> | ||||||||||||
1203 | struct ScalarTraits<std::string> { | ||||||||||||
1204 | static void output(const std::string &, void *, raw_ostream &); | ||||||||||||
1205 | static StringRef input(StringRef, void *, std::string &); | ||||||||||||
1206 | static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } | ||||||||||||
1207 | }; | ||||||||||||
1208 | |||||||||||||
1209 | template<> | ||||||||||||
1210 | struct ScalarTraits<uint8_t> { | ||||||||||||
1211 | static void output(const uint8_t &, void *, raw_ostream &); | ||||||||||||
1212 | static StringRef input(StringRef, void *, uint8_t &); | ||||||||||||
1213 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1214 | }; | ||||||||||||
1215 | |||||||||||||
1216 | template<> | ||||||||||||
1217 | struct ScalarTraits<uint16_t> { | ||||||||||||
1218 | static void output(const uint16_t &, void *, raw_ostream &); | ||||||||||||
1219 | static StringRef input(StringRef, void *, uint16_t &); | ||||||||||||
1220 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1221 | }; | ||||||||||||
1222 | |||||||||||||
1223 | template<> | ||||||||||||
1224 | struct ScalarTraits<uint32_t> { | ||||||||||||
1225 | static void output(const uint32_t &, void *, raw_ostream &); | ||||||||||||
1226 | static StringRef input(StringRef, void *, uint32_t &); | ||||||||||||
1227 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1228 | }; | ||||||||||||
1229 | |||||||||||||
1230 | template<> | ||||||||||||
1231 | struct ScalarTraits<uint64_t> { | ||||||||||||
1232 | static void output(const uint64_t &, void *, raw_ostream &); | ||||||||||||
1233 | static StringRef input(StringRef, void *, uint64_t &); | ||||||||||||
1234 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1235 | }; | ||||||||||||
1236 | |||||||||||||
1237 | template<> | ||||||||||||
1238 | struct ScalarTraits<int8_t> { | ||||||||||||
1239 | static void output(const int8_t &, void *, raw_ostream &); | ||||||||||||
1240 | static StringRef input(StringRef, void *, int8_t &); | ||||||||||||
1241 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1242 | }; | ||||||||||||
1243 | |||||||||||||
1244 | template<> | ||||||||||||
1245 | struct ScalarTraits<int16_t> { | ||||||||||||
1246 | static void output(const int16_t &, void *, raw_ostream &); | ||||||||||||
1247 | static StringRef input(StringRef, void *, int16_t &); | ||||||||||||
1248 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1249 | }; | ||||||||||||
1250 | |||||||||||||
1251 | template<> | ||||||||||||
1252 | struct ScalarTraits<int32_t> { | ||||||||||||
1253 | static void output(const int32_t &, void *, raw_ostream &); | ||||||||||||
1254 | static StringRef input(StringRef, void *, int32_t &); | ||||||||||||
1255 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1256 | }; | ||||||||||||
1257 | |||||||||||||
1258 | template<> | ||||||||||||
1259 | struct ScalarTraits<int64_t> { | ||||||||||||
1260 | static void output(const int64_t &, void *, raw_ostream &); | ||||||||||||
1261 | static StringRef input(StringRef, void *, int64_t &); | ||||||||||||
1262 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1263 | }; | ||||||||||||
1264 | |||||||||||||
1265 | template<> | ||||||||||||
1266 | struct ScalarTraits<float> { | ||||||||||||
1267 | static void output(const float &, void *, raw_ostream &); | ||||||||||||
1268 | static StringRef input(StringRef, void *, float &); | ||||||||||||
1269 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1270 | }; | ||||||||||||
1271 | |||||||||||||
1272 | template<> | ||||||||||||
1273 | struct ScalarTraits<double> { | ||||||||||||
1274 | static void output(const double &, void *, raw_ostream &); | ||||||||||||
1275 | static StringRef input(StringRef, void *, double &); | ||||||||||||
1276 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1277 | }; | ||||||||||||
1278 | |||||||||||||
1279 | // For endian types, we use existing scalar Traits class for the underlying | ||||||||||||
1280 | // type. This way endian aware types are supported whenever the traits are | ||||||||||||
1281 | // defined for the underlying type. | ||||||||||||
1282 | template <typename value_type, support::endianness endian, size_t alignment> | ||||||||||||
1283 | struct ScalarTraits<support::detail::packed_endian_specific_integral< | ||||||||||||
1284 | value_type, endian, alignment>, | ||||||||||||
1285 | std::enable_if_t<has_ScalarTraits<value_type>::value>> { | ||||||||||||
1286 | using endian_type = | ||||||||||||
1287 | support::detail::packed_endian_specific_integral<value_type, endian, | ||||||||||||
1288 | alignment>; | ||||||||||||
1289 | |||||||||||||
1290 | static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) { | ||||||||||||
1291 | ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); | ||||||||||||
1292 | } | ||||||||||||
1293 | |||||||||||||
1294 | static StringRef input(StringRef Str, void *Ctx, endian_type &E) { | ||||||||||||
1295 | value_type V; | ||||||||||||
1296 | auto R = ScalarTraits<value_type>::input(Str, Ctx, V); | ||||||||||||
1297 | E = static_cast<endian_type>(V); | ||||||||||||
1298 | return R; | ||||||||||||
1299 | } | ||||||||||||
1300 | |||||||||||||
1301 | static QuotingType mustQuote(StringRef Str) { | ||||||||||||
1302 | return ScalarTraits<value_type>::mustQuote(Str); | ||||||||||||
1303 | } | ||||||||||||
1304 | }; | ||||||||||||
1305 | |||||||||||||
1306 | template <typename value_type, support::endianness endian, size_t alignment> | ||||||||||||
1307 | struct ScalarEnumerationTraits< | ||||||||||||
1308 | support::detail::packed_endian_specific_integral<value_type, endian, | ||||||||||||
1309 | alignment>, | ||||||||||||
1310 | std::enable_if_t<has_ScalarEnumerationTraits<value_type>::value>> { | ||||||||||||
1311 | using endian_type = | ||||||||||||
1312 | support::detail::packed_endian_specific_integral<value_type, endian, | ||||||||||||
1313 | alignment>; | ||||||||||||
1314 | |||||||||||||
1315 | static void enumeration(IO &io, endian_type &E) { | ||||||||||||
1316 | value_type V = E; | ||||||||||||
1317 | ScalarEnumerationTraits<value_type>::enumeration(io, V); | ||||||||||||
1318 | E = V; | ||||||||||||
1319 | } | ||||||||||||
1320 | }; | ||||||||||||
1321 | |||||||||||||
1322 | template <typename value_type, support::endianness endian, size_t alignment> | ||||||||||||
1323 | struct ScalarBitSetTraits< | ||||||||||||
1324 | support::detail::packed_endian_specific_integral<value_type, endian, | ||||||||||||
1325 | alignment>, | ||||||||||||
1326 | std::enable_if_t<has_ScalarBitSetTraits<value_type>::value>> { | ||||||||||||
1327 | using endian_type = | ||||||||||||
1328 | support::detail::packed_endian_specific_integral<value_type, endian, | ||||||||||||
1329 | alignment>; | ||||||||||||
1330 | static void bitset(IO &io, endian_type &E) { | ||||||||||||
1331 | value_type V = E; | ||||||||||||
1332 | ScalarBitSetTraits<value_type>::bitset(io, V); | ||||||||||||
1333 | E = V; | ||||||||||||
1334 | } | ||||||||||||
1335 | }; | ||||||||||||
1336 | |||||||||||||
1337 | // Utility for use within MappingTraits<>::mapping() method | ||||||||||||
1338 | // to [de]normalize an object for use with YAML conversion. | ||||||||||||
1339 | template <typename TNorm, typename TFinal> | ||||||||||||
1340 | struct MappingNormalization { | ||||||||||||
1341 | MappingNormalization(IO &i_o, TFinal &Obj) | ||||||||||||
1342 | : io(i_o), BufPtr(nullptr), Result(Obj) { | ||||||||||||
1343 | if ( io.outputting() ) { | ||||||||||||
1344 | BufPtr = new (&Buffer) TNorm(io, Obj); | ||||||||||||
1345 | } | ||||||||||||
1346 | else { | ||||||||||||
1347 | BufPtr = new (&Buffer) TNorm(io); | ||||||||||||
1348 | } | ||||||||||||
1349 | } | ||||||||||||
1350 | |||||||||||||
1351 | ~MappingNormalization() { | ||||||||||||
1352 | if ( ! io.outputting() ) { | ||||||||||||
1353 | Result = BufPtr->denormalize(io); | ||||||||||||
1354 | } | ||||||||||||
1355 | BufPtr->~TNorm(); | ||||||||||||
1356 | } | ||||||||||||
1357 | |||||||||||||
1358 | TNorm* operator->() { return BufPtr; } | ||||||||||||
1359 | |||||||||||||
1360 | private: | ||||||||||||
1361 | using Storage = AlignedCharArrayUnion<TNorm>; | ||||||||||||
1362 | |||||||||||||
1363 | Storage Buffer; | ||||||||||||
1364 | IO &io; | ||||||||||||
1365 | TNorm *BufPtr; | ||||||||||||
1366 | TFinal &Result; | ||||||||||||
1367 | }; | ||||||||||||
1368 | |||||||||||||
1369 | // Utility for use within MappingTraits<>::mapping() method | ||||||||||||
1370 | // to [de]normalize an object for use with YAML conversion. | ||||||||||||
1371 | template <typename TNorm, typename TFinal> | ||||||||||||
1372 | struct MappingNormalizationHeap { | ||||||||||||
1373 | MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator) | ||||||||||||
1374 | : io(i_o), Result(Obj) { | ||||||||||||
1375 | if ( io.outputting() ) { | ||||||||||||
1376 | BufPtr = new (&Buffer) TNorm(io, Obj); | ||||||||||||
1377 | } | ||||||||||||
1378 | else if (allocator) { | ||||||||||||
1379 | BufPtr = allocator->Allocate<TNorm>(); | ||||||||||||
1380 | new (BufPtr) TNorm(io); | ||||||||||||
1381 | } else { | ||||||||||||
1382 | BufPtr = new TNorm(io); | ||||||||||||
1383 | } | ||||||||||||
1384 | } | ||||||||||||
1385 | |||||||||||||
1386 | ~MappingNormalizationHeap() { | ||||||||||||
1387 | if ( io.outputting() ) { | ||||||||||||
1388 | BufPtr->~TNorm(); | ||||||||||||
1389 | } | ||||||||||||
1390 | else { | ||||||||||||
1391 | Result = BufPtr->denormalize(io); | ||||||||||||
1392 | } | ||||||||||||
1393 | } | ||||||||||||
1394 | |||||||||||||
1395 | TNorm* operator->() { return BufPtr; } | ||||||||||||
1396 | |||||||||||||
1397 | private: | ||||||||||||
1398 | using Storage = AlignedCharArrayUnion<TNorm>; | ||||||||||||
1399 | |||||||||||||
1400 | Storage Buffer; | ||||||||||||
1401 | IO &io; | ||||||||||||
1402 | TNorm *BufPtr = nullptr; | ||||||||||||
1403 | TFinal &Result; | ||||||||||||
1404 | }; | ||||||||||||
1405 | |||||||||||||
1406 | /// | ||||||||||||
1407 | /// The Input class is used to parse a yaml document into in-memory structs | ||||||||||||
1408 | /// and vectors. | ||||||||||||
1409 | /// | ||||||||||||
1410 | /// It works by using YAMLParser to do a syntax parse of the entire yaml | ||||||||||||
1411 | /// document, then the Input class builds a graph of HNodes which wraps | ||||||||||||
1412 | /// each yaml Node. The extra layer is buffering. The low level yaml | ||||||||||||
1413 | /// parser only lets you look at each node once. The buffering layer lets | ||||||||||||
1414 | /// you search and interate multiple times. This is necessary because | ||||||||||||
1415 | /// the mapRequired() method calls may not be in the same order | ||||||||||||
1416 | /// as the keys in the document. | ||||||||||||
1417 | /// | ||||||||||||
1418 | class Input : public IO { | ||||||||||||
1419 | public: | ||||||||||||
1420 | // Construct a yaml Input object from a StringRef and optional | ||||||||||||
1421 | // user-data. The DiagHandler can be specified to provide | ||||||||||||
1422 | // alternative error reporting. | ||||||||||||
1423 | Input(StringRef InputContent, | ||||||||||||
1424 | void *Ctxt = nullptr, | ||||||||||||
1425 | SourceMgr::DiagHandlerTy DiagHandler = nullptr, | ||||||||||||
1426 | void *DiagHandlerCtxt = nullptr); | ||||||||||||
1427 | Input(MemoryBufferRef Input, | ||||||||||||
1428 | void *Ctxt = nullptr, | ||||||||||||
1429 | SourceMgr::DiagHandlerTy DiagHandler = nullptr, | ||||||||||||
1430 | void *DiagHandlerCtxt = nullptr); | ||||||||||||
1431 | ~Input() override; | ||||||||||||
1432 | |||||||||||||
1433 | // Check if there was an syntax or semantic error during parsing. | ||||||||||||
1434 | std::error_code error(); | ||||||||||||
1435 | |||||||||||||
1436 | private: | ||||||||||||
1437 | bool outputting() const override; | ||||||||||||
1438 | bool mapTag(StringRef, bool) override; | ||||||||||||
1439 | void beginMapping() override; | ||||||||||||
1440 | void endMapping() override; | ||||||||||||
1441 | bool preflightKey(const char *, bool, bool, bool &, void *&) override; | ||||||||||||
1442 | void postflightKey(void *) override; | ||||||||||||
1443 | std::vector<StringRef> keys() override; | ||||||||||||
1444 | void beginFlowMapping() override; | ||||||||||||
1445 | void endFlowMapping() override; | ||||||||||||
1446 | unsigned beginSequence() override; | ||||||||||||
1447 | void endSequence() override; | ||||||||||||
1448 | bool preflightElement(unsigned index, void *&) override; | ||||||||||||
1449 | void postflightElement(void *) override; | ||||||||||||
1450 | unsigned beginFlowSequence() override; | ||||||||||||
1451 | bool preflightFlowElement(unsigned , void *&) override; | ||||||||||||
1452 | void postflightFlowElement(void *) override; | ||||||||||||
1453 | void endFlowSequence() override; | ||||||||||||
1454 | void beginEnumScalar() override; | ||||||||||||
1455 | bool matchEnumScalar(const char*, bool) override; | ||||||||||||
1456 | bool matchEnumFallback() override; | ||||||||||||
1457 | void endEnumScalar() override; | ||||||||||||
1458 | bool beginBitSetScalar(bool &) override; | ||||||||||||
1459 | bool bitSetMatch(const char *, bool ) override; | ||||||||||||
1460 | void endBitSetScalar() override; | ||||||||||||
1461 | void scalarString(StringRef &, QuotingType) override; | ||||||||||||
1462 | void blockScalarString(StringRef &) override; | ||||||||||||
1463 | void scalarTag(std::string &) override; | ||||||||||||
1464 | NodeKind getNodeKind() override; | ||||||||||||
1465 | void setError(const Twine &message) override; | ||||||||||||
1466 | bool canElideEmptySequence() override; | ||||||||||||
1467 | |||||||||||||
1468 | class HNode { | ||||||||||||
1469 | virtual void anchor(); | ||||||||||||
1470 | |||||||||||||
1471 | public: | ||||||||||||
1472 | HNode(Node *n) : _node(n) { } | ||||||||||||
1473 | virtual ~HNode() = default; | ||||||||||||
1474 | |||||||||||||
1475 | static bool classof(const HNode *) { return true; } | ||||||||||||
1476 | |||||||||||||
1477 | Node *_node; | ||||||||||||
1478 | }; | ||||||||||||
1479 | |||||||||||||
1480 | class EmptyHNode : public HNode { | ||||||||||||
1481 | void anchor() override; | ||||||||||||
1482 | |||||||||||||
1483 | public: | ||||||||||||
1484 | EmptyHNode(Node *n) : HNode(n) { } | ||||||||||||
1485 | |||||||||||||
1486 | static bool classof(const HNode *n) { return NullNode::classof(n->_node); } | ||||||||||||
1487 | |||||||||||||
1488 | static bool classof(const EmptyHNode *) { return true; } | ||||||||||||
1489 | }; | ||||||||||||
1490 | |||||||||||||
1491 | class ScalarHNode : public HNode { | ||||||||||||
1492 | void anchor() override; | ||||||||||||
1493 | |||||||||||||
1494 | public: | ||||||||||||
1495 | ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } | ||||||||||||
1496 | |||||||||||||
1497 | StringRef value() const { return _value; } | ||||||||||||
1498 | |||||||||||||
1499 | static bool classof(const HNode *n) { | ||||||||||||
1500 | return ScalarNode::classof(n->_node) || | ||||||||||||
1501 | BlockScalarNode::classof(n->_node); | ||||||||||||
1502 | } | ||||||||||||
1503 | |||||||||||||
1504 | static bool classof(const ScalarHNode *) { return true; } | ||||||||||||
1505 | |||||||||||||
1506 | protected: | ||||||||||||
1507 | StringRef _value; | ||||||||||||
1508 | }; | ||||||||||||
1509 | |||||||||||||
1510 | class MapHNode : public HNode { | ||||||||||||
1511 | void anchor() override; | ||||||||||||
1512 | |||||||||||||
1513 | public: | ||||||||||||
1514 | MapHNode(Node *n) : HNode(n) { } | ||||||||||||
1515 | |||||||||||||
1516 | static bool classof(const HNode *n) { | ||||||||||||
1517 | return MappingNode::classof(n->_node); | ||||||||||||
1518 | } | ||||||||||||
1519 | |||||||||||||
1520 | static bool classof(const MapHNode *) { return true; } | ||||||||||||
1521 | |||||||||||||
1522 | using NameToNodeAndLoc = | ||||||||||||
1523 | StringMap<std::pair<std::unique_ptr<HNode>, SMRange>>; | ||||||||||||
1524 | |||||||||||||
1525 | NameToNodeAndLoc Mapping; | ||||||||||||
1526 | SmallVector<std::string, 6> ValidKeys; | ||||||||||||
1527 | }; | ||||||||||||
1528 | |||||||||||||
1529 | class SequenceHNode : public HNode { | ||||||||||||
1530 | void anchor() override; | ||||||||||||
1531 | |||||||||||||
1532 | public: | ||||||||||||
1533 | SequenceHNode(Node *n) : HNode(n) { } | ||||||||||||
1534 | |||||||||||||
1535 | static bool classof(const HNode *n) { | ||||||||||||
1536 | return SequenceNode::classof(n->_node); | ||||||||||||
1537 | } | ||||||||||||
1538 | |||||||||||||
1539 | static bool classof(const SequenceHNode *) { return true; } | ||||||||||||
1540 | |||||||||||||
1541 | std::vector<std::unique_ptr<HNode>> Entries; | ||||||||||||
1542 | }; | ||||||||||||
1543 | |||||||||||||
1544 | std::unique_ptr<Input::HNode> createHNodes(Node *node); | ||||||||||||
1545 | void setError(HNode *hnode, const Twine &message); | ||||||||||||
1546 | void setError(Node *node, const Twine &message); | ||||||||||||
1547 | void setError(const SMRange &Range, const Twine &message); | ||||||||||||
1548 | |||||||||||||
1549 | void reportWarning(HNode *hnode, const Twine &message); | ||||||||||||
1550 | void reportWarning(Node *hnode, const Twine &message); | ||||||||||||
1551 | void reportWarning(const SMRange &Range, const Twine &message); | ||||||||||||
1552 | |||||||||||||
1553 | public: | ||||||||||||
1554 | // These are only used by operator>>. They could be private | ||||||||||||
1555 | // if those templated things could be made friends. | ||||||||||||
1556 | bool setCurrentDocument(); | ||||||||||||
1557 | bool nextDocument(); | ||||||||||||
1558 | |||||||||||||
1559 | /// Returns the current node that's being parsed by the YAML Parser. | ||||||||||||
1560 | const Node *getCurrentNode() const; | ||||||||||||
1561 | |||||||||||||
1562 | void setAllowUnknownKeys(bool Allow) override; | ||||||||||||
1563 | |||||||||||||
1564 | private: | ||||||||||||
1565 | SourceMgr SrcMgr; // must be before Strm | ||||||||||||
1566 | std::unique_ptr<llvm::yaml::Stream> Strm; | ||||||||||||
1567 | std::unique_ptr<HNode> TopNode; | ||||||||||||
1568 | std::error_code EC; | ||||||||||||
1569 | BumpPtrAllocator StringAllocator; | ||||||||||||
1570 | document_iterator DocIterator; | ||||||||||||
1571 | llvm::BitVector BitValuesUsed; | ||||||||||||
1572 | HNode *CurrentNode = nullptr; | ||||||||||||
1573 | bool ScalarMatchFound = false; | ||||||||||||
1574 | bool AllowUnknownKeys = false; | ||||||||||||
1575 | }; | ||||||||||||
1576 | |||||||||||||
1577 | /// | ||||||||||||
1578 | /// The Output class is used to generate a yaml document from in-memory structs | ||||||||||||
1579 | /// and vectors. | ||||||||||||
1580 | /// | ||||||||||||
1581 | class Output : public IO { | ||||||||||||
1582 | public: | ||||||||||||
1583 | Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); | ||||||||||||
1584 | ~Output() override; | ||||||||||||
1585 | |||||||||||||
1586 | /// Set whether or not to output optional values which are equal | ||||||||||||
1587 | /// to the default value. By default, when outputting if you attempt | ||||||||||||
1588 | /// to write a value that is equal to the default, the value gets ignored. | ||||||||||||
1589 | /// Sometimes, it is useful to be able to see these in the resulting YAML | ||||||||||||
1590 | /// anyway. | ||||||||||||
1591 | void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } | ||||||||||||
1592 | |||||||||||||
1593 | bool outputting() const override; | ||||||||||||
1594 | bool mapTag(StringRef, bool) override; | ||||||||||||
1595 | void beginMapping() override; | ||||||||||||
1596 | void endMapping() override; | ||||||||||||
1597 | bool preflightKey(const char *key, bool, bool, bool &, void *&) override; | ||||||||||||
1598 | void postflightKey(void *) override; | ||||||||||||
1599 | std::vector<StringRef> keys() override; | ||||||||||||
1600 | void beginFlowMapping() override; | ||||||||||||
1601 | void endFlowMapping() override; | ||||||||||||
1602 | unsigned beginSequence() override; | ||||||||||||
1603 | void endSequence() override; | ||||||||||||
1604 | bool preflightElement(unsigned, void *&) override; | ||||||||||||
1605 | void postflightElement(void *) override; | ||||||||||||
1606 | unsigned beginFlowSequence() override; | ||||||||||||
1607 | bool preflightFlowElement(unsigned, void *&) override; | ||||||||||||
1608 | void postflightFlowElement(void *) override; | ||||||||||||
1609 | void endFlowSequence() override; | ||||||||||||
1610 | void beginEnumScalar() override; | ||||||||||||
1611 | bool matchEnumScalar(const char*, bool) override; | ||||||||||||
1612 | bool matchEnumFallback() override; | ||||||||||||
1613 | void endEnumScalar() override; | ||||||||||||
1614 | bool beginBitSetScalar(bool &) override; | ||||||||||||
1615 | bool bitSetMatch(const char *, bool ) override; | ||||||||||||
1616 | void endBitSetScalar() override; | ||||||||||||
1617 | void scalarString(StringRef &, QuotingType) override; | ||||||||||||
1618 | void blockScalarString(StringRef &) override; | ||||||||||||
1619 | void scalarTag(std::string &) override; | ||||||||||||
1620 | NodeKind getNodeKind() override; | ||||||||||||
1621 | void setError(const Twine &message) override; | ||||||||||||
1622 | bool canElideEmptySequence() override; | ||||||||||||
1623 | |||||||||||||
1624 | // These are only used by operator<<. They could be private | ||||||||||||
1625 | // if that templated operator could be made a friend. | ||||||||||||
1626 | void beginDocuments(); | ||||||||||||
1627 | bool preflightDocument(unsigned); | ||||||||||||
1628 | void postflightDocument(); | ||||||||||||
1629 | void endDocuments(); | ||||||||||||
1630 | |||||||||||||
1631 | private: | ||||||||||||
1632 | void output(StringRef s); | ||||||||||||
1633 | void outputUpToEndOfLine(StringRef s); | ||||||||||||
1634 | void newLineCheck(bool EmptySequence = false); | ||||||||||||
1635 | void outputNewLine(); | ||||||||||||
1636 | void paddedKey(StringRef key); | ||||||||||||
1637 | void flowKey(StringRef Key); | ||||||||||||
1638 | |||||||||||||
1639 | enum InState { | ||||||||||||
1640 | inSeqFirstElement, | ||||||||||||
1641 | inSeqOtherElement, | ||||||||||||
1642 | inFlowSeqFirstElement, | ||||||||||||
1643 | inFlowSeqOtherElement, | ||||||||||||
1644 | inMapFirstKey, | ||||||||||||
1645 | inMapOtherKey, | ||||||||||||
1646 | inFlowMapFirstKey, | ||||||||||||
1647 | inFlowMapOtherKey | ||||||||||||
1648 | }; | ||||||||||||
1649 | |||||||||||||
1650 | static bool inSeqAnyElement(InState State); | ||||||||||||
1651 | static bool inFlowSeqAnyElement(InState State); | ||||||||||||
1652 | static bool inMapAnyKey(InState State); | ||||||||||||
1653 | static bool inFlowMapAnyKey(InState State); | ||||||||||||
1654 | |||||||||||||
1655 | raw_ostream &Out; | ||||||||||||
1656 | int WrapColumn; | ||||||||||||
1657 | SmallVector<InState, 8> StateStack; | ||||||||||||
1658 | int Column = 0; | ||||||||||||
1659 | int ColumnAtFlowStart = 0; | ||||||||||||
1660 | int ColumnAtMapFlowStart = 0; | ||||||||||||
1661 | bool NeedBitValueComma = false; | ||||||||||||
1662 | bool NeedFlowSequenceComma = false; | ||||||||||||
1663 | bool EnumerationMatchFound = false; | ||||||||||||
1664 | bool WriteDefaultValues = false; | ||||||||||||
1665 | StringRef Padding; | ||||||||||||
1666 | StringRef PaddingBeforeContainer; | ||||||||||||
1667 | }; | ||||||||||||
1668 | |||||||||||||
1669 | template <typename T, typename Context> | ||||||||||||
1670 | void IO::processKeyWithDefault(const char *Key, std::optional<T> &Val, | ||||||||||||
1671 | const std::optional<T> &DefaultValue, | ||||||||||||
1672 | bool Required, Context &Ctx) { | ||||||||||||
1673 | assert(!DefaultValue && "std::optional<T> shouldn't have a value!")(static_cast <bool> (!DefaultValue && "std::optional<T> shouldn't have a value!" ) ? void (0) : __assert_fail ("!DefaultValue && \"std::optional<T> shouldn't have a value!\"" , "llvm/include/llvm/Support/YAMLTraits.h", 1673, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
1674 | void *SaveInfo; | ||||||||||||
1675 | bool UseDefault = true; | ||||||||||||
1676 | const bool sameAsDefault = outputting() && !Val; | ||||||||||||
1677 | if (!outputting() && !Val) | ||||||||||||
1678 | Val = T(); | ||||||||||||
1679 | if (Val && | ||||||||||||
1680 | this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) { | ||||||||||||
1681 | |||||||||||||
1682 | // When reading an std::optional<X> key from a YAML description, we allow | ||||||||||||
1683 | // the special "<none>" value, which can be used to specify that no value | ||||||||||||
1684 | // was requested, i.e. the DefaultValue will be assigned. The DefaultValue | ||||||||||||
1685 | // is usually None. | ||||||||||||
1686 | bool IsNone = false; | ||||||||||||
1687 | if (!outputting()) | ||||||||||||
1688 | if (const auto *Node = | ||||||||||||
1689 | dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode())) | ||||||||||||
1690 | // We use rtrim to ignore possible white spaces that might exist when a | ||||||||||||
1691 | // comment is present on the same line. | ||||||||||||
1692 | IsNone = Node->getRawValue().rtrim(' ') == "<none>"; | ||||||||||||
1693 | |||||||||||||
1694 | if (IsNone) | ||||||||||||
1695 | Val = DefaultValue; | ||||||||||||
1696 | else | ||||||||||||
1697 | yamlize(*this, *Val, Required, Ctx); | ||||||||||||
1698 | this->postflightKey(SaveInfo); | ||||||||||||
1699 | } else { | ||||||||||||
1700 | if (UseDefault) | ||||||||||||
1701 | Val = DefaultValue; | ||||||||||||
1702 | } | ||||||||||||
1703 | } | ||||||||||||
1704 | |||||||||||||
1705 | /// YAML I/O does conversion based on types. But often native data types | ||||||||||||
1706 | /// are just a typedef of built in intergral types (e.g. int). But the C++ | ||||||||||||
1707 | /// type matching system sees through the typedef and all the typedefed types | ||||||||||||
1708 | /// look like a built in type. This will cause the generic YAML I/O conversion | ||||||||||||
1709 | /// to be used. To provide better control over the YAML conversion, you can | ||||||||||||
1710 | /// use this macro instead of typedef. It will create a class with one field | ||||||||||||
1711 | /// and automatic conversion operators to and from the base type. | ||||||||||||
1712 | /// Based on BOOST_STRONG_TYPEDEF | ||||||||||||
1713 | #define LLVM_YAML_STRONG_TYPEDEF(_base, _type)struct _type { _type() = default; _type(const _base v) : value (v) {} _type(const _type &v) = default; _type &operator =(const _type &rhs) = default; _type &operator=(const _base &rhs) { value = rhs; return *this; } operator const _base & () const { return value; } bool operator==(const _type &rhs) const { return value == rhs.value; } bool operator ==(const _base &rhs) const { return value == rhs; } bool operator <(const _type &rhs) const { return value < rhs.value ; } _base value; using BaseType = _base; }; \ | ||||||||||||
1714 | struct _type { \ | ||||||||||||
1715 | _type() = default; \ | ||||||||||||
1716 | _type(const _base v) : value(v) {} \ | ||||||||||||
1717 | _type(const _type &v) = default; \ | ||||||||||||
1718 | _type &operator=(const _type &rhs) = default; \ | ||||||||||||
1719 | _type &operator=(const _base &rhs) { value = rhs; return *this; } \ | ||||||||||||
1720 | operator const _base & () const { return value; } \ | ||||||||||||
1721 | bool operator==(const _type &rhs) const { return value == rhs.value; } \ | ||||||||||||
1722 | bool operator==(const _base &rhs) const { return value == rhs; } \ | ||||||||||||
1723 | bool operator<(const _type &rhs) const { return value < rhs.value; } \ | ||||||||||||
1724 | _base value; \ | ||||||||||||
1725 | using BaseType = _base; \ | ||||||||||||
1726 | }; | ||||||||||||
1727 | |||||||||||||
1728 | /// | ||||||||||||
1729 | /// Use these types instead of uintXX_t in any mapping to have | ||||||||||||
1730 | /// its yaml output formatted as hexadecimal. | ||||||||||||
1731 | /// | ||||||||||||
1732 | LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)struct Hex8 { Hex8() = default; Hex8(const uint8_t v) : value (v) {} Hex8(const Hex8 &v) = default; Hex8 &operator= (const Hex8 &rhs) = default; Hex8 &operator=(const uint8_t &rhs) { value = rhs; return *this; } operator const uint8_t & () const { return value; } bool operator==(const Hex8 & rhs) const { return value == rhs.value; } bool operator==(const uint8_t &rhs) const { return value == rhs; } bool operator <(const Hex8 &rhs) const { return value < rhs.value ; } uint8_t value; using BaseType = uint8_t; }; | ||||||||||||
1733 | LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)struct Hex16 { Hex16() = default; Hex16(const uint16_t v) : value (v) {} Hex16(const Hex16 &v) = default; Hex16 &operator =(const Hex16 &rhs) = default; Hex16 &operator=(const uint16_t &rhs) { value = rhs; return *this; } operator const uint16_t & () const { return value; } bool operator==(const Hex16 &rhs) const { return value == rhs.value; } bool operator ==(const uint16_t &rhs) const { return value == rhs; } bool operator<(const Hex16 &rhs) const { return value < rhs.value; } uint16_t value; using BaseType = uint16_t; }; | ||||||||||||
1734 | LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)struct Hex32 { Hex32() = default; Hex32(const uint32_t v) : value (v) {} Hex32(const Hex32 &v) = default; Hex32 &operator =(const Hex32 &rhs) = default; Hex32 &operator=(const uint32_t &rhs) { value = rhs; return *this; } operator const uint32_t & () const { return value; } bool operator==(const Hex32 &rhs) const { return value == rhs.value; } bool operator ==(const uint32_t &rhs) const { return value == rhs; } bool operator<(const Hex32 &rhs) const { return value < rhs.value; } uint32_t value; using BaseType = uint32_t; }; | ||||||||||||
1735 | LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)struct Hex64 { Hex64() = default; Hex64(const uint64_t v) : value (v) {} Hex64(const Hex64 &v) = default; Hex64 &operator =(const Hex64 &rhs) = default; Hex64 &operator=(const uint64_t &rhs) { value = rhs; return *this; } operator const uint64_t & () const { return value; } bool operator==(const Hex64 &rhs) const { return value == rhs.value; } bool operator ==(const uint64_t &rhs) const { return value == rhs; } bool operator<(const Hex64 &rhs) const { return value < rhs.value; } uint64_t value; using BaseType = uint64_t; }; | ||||||||||||
1736 | |||||||||||||
1737 | template<> | ||||||||||||
1738 | struct ScalarTraits<Hex8> { | ||||||||||||
1739 | static void output(const Hex8 &, void *, raw_ostream &); | ||||||||||||
1740 | static StringRef input(StringRef, void *, Hex8 &); | ||||||||||||
1741 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1742 | }; | ||||||||||||
1743 | |||||||||||||
1744 | template<> | ||||||||||||
1745 | struct ScalarTraits<Hex16> { | ||||||||||||
1746 | static void output(const Hex16 &, void *, raw_ostream &); | ||||||||||||
1747 | static StringRef input(StringRef, void *, Hex16 &); | ||||||||||||
1748 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1749 | }; | ||||||||||||
1750 | |||||||||||||
1751 | template<> | ||||||||||||
1752 | struct ScalarTraits<Hex32> { | ||||||||||||
1753 | static void output(const Hex32 &, void *, raw_ostream &); | ||||||||||||
1754 | static StringRef input(StringRef, void *, Hex32 &); | ||||||||||||
1755 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1756 | }; | ||||||||||||
1757 | |||||||||||||
1758 | template<> | ||||||||||||
1759 | struct ScalarTraits<Hex64> { | ||||||||||||
1760 | static void output(const Hex64 &, void *, raw_ostream &); | ||||||||||||
1761 | static StringRef input(StringRef, void *, Hex64 &); | ||||||||||||
1762 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1763 | }; | ||||||||||||
1764 | |||||||||||||
1765 | template <> struct ScalarTraits<VersionTuple> { | ||||||||||||
1766 | static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out); | ||||||||||||
1767 | static StringRef input(StringRef, void *, VersionTuple &); | ||||||||||||
1768 | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | ||||||||||||
1769 | }; | ||||||||||||
1770 | |||||||||||||
1771 | // Define non-member operator>> so that Input can stream in a document list. | ||||||||||||
1772 | template <typename T> | ||||||||||||
1773 | inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &> | ||||||||||||
1774 | operator>>(Input &yin, T &docList) { | ||||||||||||
1775 | int i = 0; | ||||||||||||
1776 | EmptyContext Ctx; | ||||||||||||
1777 | while ( yin.setCurrentDocument() ) { | ||||||||||||
1778 | yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); | ||||||||||||
1779 | if ( yin.error() ) | ||||||||||||
1780 | return yin; | ||||||||||||
1781 | yin.nextDocument(); | ||||||||||||
1782 | ++i; | ||||||||||||
1783 | } | ||||||||||||
1784 | return yin; | ||||||||||||
1785 | } | ||||||||||||
1786 | |||||||||||||
1787 | // Define non-member operator>> so that Input can stream in a map as a document. | ||||||||||||
1788 | template <typename T> | ||||||||||||
1789 | inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &> | ||||||||||||
1790 | operator>>(Input &yin, T &docMap) { | ||||||||||||
1791 | EmptyContext Ctx; | ||||||||||||
1792 | yin.setCurrentDocument(); | ||||||||||||
1793 | yamlize(yin, docMap, true, Ctx); | ||||||||||||
1794 | return yin; | ||||||||||||
1795 | } | ||||||||||||
1796 | |||||||||||||
1797 | // Define non-member operator>> so that Input can stream in a sequence as | ||||||||||||
1798 | // a document. | ||||||||||||
1799 | template <typename T> | ||||||||||||
1800 | inline std::enable_if_t<has_SequenceTraits<T>::value, Input &> | ||||||||||||
1801 | operator>>(Input &yin, T &docSeq) { | ||||||||||||
1802 | EmptyContext Ctx; | ||||||||||||
1803 | if (yin.setCurrentDocument()) | ||||||||||||
1804 | yamlize(yin, docSeq, true, Ctx); | ||||||||||||
1805 | return yin; | ||||||||||||
1806 | } | ||||||||||||
1807 | |||||||||||||
1808 | // Define non-member operator>> so that Input can stream in a block scalar. | ||||||||||||
1809 | template <typename T> | ||||||||||||
1810 | inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &> | ||||||||||||
1811 | operator>>(Input &In, T &Val) { | ||||||||||||
1812 | EmptyContext Ctx; | ||||||||||||
1813 | if (In.setCurrentDocument()) | ||||||||||||
1814 | yamlize(In, Val, true, Ctx); | ||||||||||||
1815 | return In; | ||||||||||||
1816 | } | ||||||||||||
1817 | |||||||||||||
1818 | // Define non-member operator>> so that Input can stream in a string map. | ||||||||||||
1819 | template <typename T> | ||||||||||||
1820 | inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &> | ||||||||||||
1821 | operator>>(Input &In, T &Val) { | ||||||||||||
1822 | EmptyContext Ctx; | ||||||||||||
1823 | if (In.setCurrentDocument()) | ||||||||||||
1824 | yamlize(In, Val, true, Ctx); | ||||||||||||
1825 | return In; | ||||||||||||
1826 | } | ||||||||||||
1827 | |||||||||||||
1828 | // Define non-member operator>> so that Input can stream in a polymorphic type. | ||||||||||||
1829 | template <typename T> | ||||||||||||
1830 | inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &> | ||||||||||||
1831 | operator>>(Input &In, T &Val) { | ||||||||||||
1832 | EmptyContext Ctx; | ||||||||||||
1833 | if (In.setCurrentDocument()) | ||||||||||||
1834 | yamlize(In, Val, true, Ctx); | ||||||||||||
1835 | return In; | ||||||||||||
1836 | } | ||||||||||||
1837 | |||||||||||||
1838 | // Provide better error message about types missing a trait specialization | ||||||||||||
1839 | template <typename T> | ||||||||||||
1840 | inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &> | ||||||||||||
1841 | operator>>(Input &yin, T &docSeq) { | ||||||||||||
1842 | char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; | ||||||||||||
1843 | return yin; | ||||||||||||
1844 | } | ||||||||||||
1845 | |||||||||||||
1846 | // Define non-member operator<< so that Output can stream out document list. | ||||||||||||
1847 | template <typename T> | ||||||||||||
1848 | inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &> | ||||||||||||
1849 | operator<<(Output &yout, T &docList) { | ||||||||||||
1850 | EmptyContext Ctx; | ||||||||||||
1851 | yout.beginDocuments(); | ||||||||||||
1852 | const size_t count = DocumentListTraits<T>::size(yout, docList); | ||||||||||||
1853 | for(size_t i=0; i < count; ++i) { | ||||||||||||
1854 | if ( yout.preflightDocument(i) ) { | ||||||||||||
1855 | yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, | ||||||||||||
1856 | Ctx); | ||||||||||||
1857 | yout.postflightDocument(); | ||||||||||||
1858 | } | ||||||||||||
1859 | } | ||||||||||||
1860 | yout.endDocuments(); | ||||||||||||
1861 | return yout; | ||||||||||||
1862 | } | ||||||||||||
1863 | |||||||||||||
1864 | // Define non-member operator<< so that Output can stream out a map. | ||||||||||||
1865 | template <typename T> | ||||||||||||
1866 | inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &> | ||||||||||||
1867 | operator<<(Output &yout, T &map) { | ||||||||||||
1868 | EmptyContext Ctx; | ||||||||||||
1869 | yout.beginDocuments(); | ||||||||||||
1870 | if ( yout.preflightDocument(0) ) { | ||||||||||||
1871 | yamlize(yout, map, true, Ctx); | ||||||||||||
1872 | yout.postflightDocument(); | ||||||||||||
1873 | } | ||||||||||||
1874 | yout.endDocuments(); | ||||||||||||
1875 | return yout; | ||||||||||||
1876 | } | ||||||||||||
1877 | |||||||||||||
1878 | // Define non-member operator<< so that Output can stream out a sequence. | ||||||||||||
1879 | template <typename T> | ||||||||||||
1880 | inline std::enable_if_t<has_SequenceTraits<T>::value, Output &> | ||||||||||||
1881 | operator<<(Output &yout, T &seq) { | ||||||||||||
1882 | EmptyContext Ctx; | ||||||||||||
1883 | yout.beginDocuments(); | ||||||||||||
1884 | if ( yout.preflightDocument(0) ) { | ||||||||||||
1885 | yamlize(yout, seq, true, Ctx); | ||||||||||||
1886 | yout.postflightDocument(); | ||||||||||||
1887 | } | ||||||||||||
1888 | yout.endDocuments(); | ||||||||||||
1889 | return yout; | ||||||||||||
1890 | } | ||||||||||||
1891 | |||||||||||||
1892 | // Define non-member operator<< so that Output can stream out a block scalar. | ||||||||||||
1893 | template <typename T> | ||||||||||||
1894 | inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &> | ||||||||||||
1895 | operator<<(Output &Out, T &Val) { | ||||||||||||
1896 | EmptyContext Ctx; | ||||||||||||
1897 | Out.beginDocuments(); | ||||||||||||
1898 | if (Out.preflightDocument(0)) { | ||||||||||||
1899 | yamlize(Out, Val, true, Ctx); | ||||||||||||
1900 | Out.postflightDocument(); | ||||||||||||
1901 | } | ||||||||||||
1902 | Out.endDocuments(); | ||||||||||||
1903 | return Out; | ||||||||||||
1904 | } | ||||||||||||
1905 | |||||||||||||
1906 | // Define non-member operator<< so that Output can stream out a string map. | ||||||||||||
1907 | template <typename T> | ||||||||||||
1908 | inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &> | ||||||||||||
1909 | operator<<(Output &Out, T &Val) { | ||||||||||||
1910 | EmptyContext Ctx; | ||||||||||||
1911 | Out.beginDocuments(); | ||||||||||||
1912 | if (Out.preflightDocument(0)) { | ||||||||||||
1913 | yamlize(Out, Val, true, Ctx); | ||||||||||||
1914 | Out.postflightDocument(); | ||||||||||||
1915 | } | ||||||||||||
1916 | Out.endDocuments(); | ||||||||||||
1917 | return Out; | ||||||||||||
1918 | } | ||||||||||||
1919 | |||||||||||||
1920 | // Define non-member operator<< so that Output can stream out a polymorphic | ||||||||||||
1921 | // type. | ||||||||||||
1922 | template <typename T> | ||||||||||||
1923 | inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &> | ||||||||||||
1924 | operator<<(Output &Out, T &Val) { | ||||||||||||
1925 | EmptyContext Ctx; | ||||||||||||
1926 | Out.beginDocuments(); | ||||||||||||
1927 | if (Out.preflightDocument(0)) { | ||||||||||||
1928 | // FIXME: The parser does not support explicit documents terminated with a | ||||||||||||
1929 | // plain scalar; the end-marker is included as part of the scalar token. | ||||||||||||
1930 | assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported")(static_cast <bool> (PolymorphicTraits<T>::getKind (Val) != NodeKind::Scalar && "plain scalar documents are not supported" ) ? void (0) : __assert_fail ("PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && \"plain scalar documents are not supported\"" , "llvm/include/llvm/Support/YAMLTraits.h", 1930, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
1931 | yamlize(Out, Val, true, Ctx); | ||||||||||||
1932 | Out.postflightDocument(); | ||||||||||||
1933 | } | ||||||||||||
1934 | Out.endDocuments(); | ||||||||||||
1935 | return Out; | ||||||||||||
1936 | } | ||||||||||||
1937 | |||||||||||||
1938 | // Provide better error message about types missing a trait specialization | ||||||||||||
1939 | template <typename T> | ||||||||||||
1940 | inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &> | ||||||||||||
1941 | operator<<(Output &yout, T &seq) { | ||||||||||||
1942 | char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; | ||||||||||||
1943 | return yout; | ||||||||||||
1944 | } | ||||||||||||
1945 | |||||||||||||
1946 | template <bool B> struct IsFlowSequenceBase {}; | ||||||||||||
1947 | template <> struct IsFlowSequenceBase<true> { static const bool flow = true; }; | ||||||||||||
1948 | |||||||||||||
1949 | template <typename T, typename U = void> | ||||||||||||
1950 | struct IsResizable : std::false_type {}; | ||||||||||||
1951 | |||||||||||||
1952 | template <typename T> | ||||||||||||
1953 | struct IsResizable<T, std::void_t<decltype(std::declval<T>().resize(0))>> | ||||||||||||
1954 | : public std::true_type {}; | ||||||||||||
1955 | |||||||||||||
1956 | template <typename T, bool B> struct IsResizableBase { | ||||||||||||
1957 | using type = typename T::value_type; | ||||||||||||
1958 | |||||||||||||
1959 | static type &element(IO &io, T &seq, size_t index) { | ||||||||||||
1960 | if (index >= seq.size()) | ||||||||||||
1961 | seq.resize(index + 1); | ||||||||||||
1962 | return seq[index]; | ||||||||||||
1963 | } | ||||||||||||
1964 | }; | ||||||||||||
1965 | |||||||||||||
1966 | template <typename T> struct IsResizableBase<T, false> { | ||||||||||||
1967 | using type = typename T::value_type; | ||||||||||||
1968 | |||||||||||||
1969 | static type &element(IO &io, T &seq, size_t index) { | ||||||||||||
1970 | if (index >= seq.size()) { | ||||||||||||
1971 | io.setError(Twine("value sequence extends beyond static size (") + | ||||||||||||
1972 | Twine(seq.size()) + ")"); | ||||||||||||
1973 | return seq[0]; | ||||||||||||
1974 | } | ||||||||||||
1975 | return seq[index]; | ||||||||||||
1976 | } | ||||||||||||
1977 | }; | ||||||||||||
1978 | |||||||||||||
1979 | template <typename T, bool Flow> | ||||||||||||
1980 | struct SequenceTraitsImpl | ||||||||||||
1981 | : IsFlowSequenceBase<Flow>, IsResizableBase<T, IsResizable<T>::value> { | ||||||||||||
1982 | static size_t size(IO &io, T &seq) { return seq.size(); } | ||||||||||||
1983 | }; | ||||||||||||
1984 | |||||||||||||
1985 | // Simple helper to check an expression can be used as a bool-valued template | ||||||||||||
1986 | // argument. | ||||||||||||
1987 | template <bool> struct CheckIsBool { static const bool value = true; }; | ||||||||||||
1988 | |||||||||||||
1989 | // If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have | ||||||||||||
1990 | // SequenceTraits that do the obvious thing. | ||||||||||||
1991 | template <typename T> | ||||||||||||
1992 | struct SequenceTraits< | ||||||||||||
1993 | std::vector<T>, | ||||||||||||
1994 | std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> | ||||||||||||
1995 | : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {}; | ||||||||||||
1996 | template <typename T, unsigned N> | ||||||||||||
1997 | struct SequenceTraits< | ||||||||||||
1998 | SmallVector<T, N>, | ||||||||||||
1999 | std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> | ||||||||||||
2000 | : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {}; | ||||||||||||
2001 | template <typename T> | ||||||||||||
2002 | struct SequenceTraits< | ||||||||||||
2003 | SmallVectorImpl<T>, | ||||||||||||
2004 | std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> | ||||||||||||
2005 | : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {}; | ||||||||||||
2006 | template <typename T> | ||||||||||||
2007 | struct SequenceTraits< | ||||||||||||
2008 | MutableArrayRef<T>, | ||||||||||||
2009 | std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> | ||||||||||||
2010 | : SequenceTraitsImpl<MutableArrayRef<T>, SequenceElementTraits<T>::flow> {}; | ||||||||||||
2011 | |||||||||||||
2012 | // Sequences of fundamental types use flow formatting. | ||||||||||||
2013 | template <typename T> | ||||||||||||
2014 | struct SequenceElementTraits<T, | ||||||||||||
2015 | std::enable_if_t<std::is_fundamental<T>::value>> { | ||||||||||||
2016 | static const bool flow = true; | ||||||||||||
2017 | }; | ||||||||||||
2018 | |||||||||||||
2019 | // Sequences of strings use block formatting. | ||||||||||||
2020 | template<> struct SequenceElementTraits<std::string> { | ||||||||||||
2021 | static const bool flow = false; | ||||||||||||
2022 | }; | ||||||||||||
2023 | template<> struct SequenceElementTraits<StringRef> { | ||||||||||||
2024 | static const bool flow = false; | ||||||||||||
2025 | }; | ||||||||||||
2026 | template<> struct SequenceElementTraits<std::pair<std::string, std::string>> { | ||||||||||||
2027 | static const bool flow = false; | ||||||||||||
2028 | }; | ||||||||||||
2029 | |||||||||||||
2030 | /// Implementation of CustomMappingTraits for std::map<std::string, T>. | ||||||||||||
2031 | template <typename T> struct StdMapStringCustomMappingTraitsImpl { | ||||||||||||
2032 | using map_type = std::map<std::string, T>; | ||||||||||||
2033 | |||||||||||||
2034 | static void inputOne(IO &io, StringRef key, map_type &v) { | ||||||||||||
2035 | io.mapRequired(key.str().c_str(), v[std::string(key)]); | ||||||||||||
2036 | } | ||||||||||||
2037 | |||||||||||||
2038 | static void output(IO &io, map_type &v) { | ||||||||||||
2039 | for (auto &p : v) | ||||||||||||
2040 | io.mapRequired(p.first.c_str(), p.second); | ||||||||||||
2041 | } | ||||||||||||
2042 | }; | ||||||||||||
2043 | |||||||||||||
2044 | } // end namespace yaml | ||||||||||||
2045 | } // end namespace llvm | ||||||||||||
2046 | |||||||||||||
2047 | #define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <TYPE> && !std::is_same_v<TYPE, std::string> && !std::is_same_v<TYPE, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<TYPE> { static const bool flow = FLOW; }; } } \ | ||||||||||||
2048 | namespace llvm { \ | ||||||||||||
2049 | namespace yaml { \ | ||||||||||||
2050 | static_assert( \ | ||||||||||||
2051 | !std::is_fundamental_v<TYPE> && !std::is_same_v<TYPE, std::string> && \ | ||||||||||||
2052 | !std::is_same_v<TYPE, llvm::StringRef>, \ | ||||||||||||
2053 | "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \ | ||||||||||||
2054 | template <> struct SequenceElementTraits<TYPE> { \ | ||||||||||||
2055 | static const bool flow = FLOW; \ | ||||||||||||
2056 | }; \ | ||||||||||||
2057 | } \ | ||||||||||||
2058 | } | ||||||||||||
2059 | |||||||||||||
2060 | /// Utility for declaring that a std::vector of a particular type | ||||||||||||
2061 | /// should be considered a YAML sequence. | ||||||||||||
2062 | #define LLVM_YAML_IS_SEQUENCE_VECTOR(type)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <type> && !std::is_same_v<type, std::string> && !std::is_same_v<type, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<type> { static const bool flow = false; }; } } \ | ||||||||||||
2063 | LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <type> && !std::is_same_v<type, std::string> && !std::is_same_v<type, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<type> { static const bool flow = false; }; } } | ||||||||||||
2064 | |||||||||||||
2065 | /// Utility for declaring that a std::vector of a particular type | ||||||||||||
2066 | /// should be considered a YAML flow sequence. | ||||||||||||
2067 | #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <type> && !std::is_same_v<type, std::string> && !std::is_same_v<type, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<type> { static const bool flow = true; }; } } \ | ||||||||||||
2068 | LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <type> && !std::is_same_v<type, std::string> && !std::is_same_v<type, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<type> { static const bool flow = true; }; } } | ||||||||||||
2069 | |||||||||||||
2070 | #define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type)namespace llvm { namespace yaml { template <> struct MappingTraits <Type> { static void mapping(IO &IO, Type &Obj) ; }; } } \ | ||||||||||||
2071 | namespace llvm { \ | ||||||||||||
2072 | namespace yaml { \ | ||||||||||||
2073 | template <> struct MappingTraits<Type> { \ | ||||||||||||
2074 | static void mapping(IO &IO, Type &Obj); \ | ||||||||||||
2075 | }; \ | ||||||||||||
2076 | } \ | ||||||||||||
2077 | } | ||||||||||||
2078 | |||||||||||||
2079 | #define LLVM_YAML_DECLARE_ENUM_TRAITS(Type)namespace llvm { namespace yaml { template <> struct ScalarEnumerationTraits <Type> { static void enumeration(IO &io, Type & Value); }; } } \ | ||||||||||||
2080 | namespace llvm { \ | ||||||||||||
2081 | namespace yaml { \ | ||||||||||||
2082 | template <> struct ScalarEnumerationTraits<Type> { \ | ||||||||||||
2083 | static void enumeration(IO &io, Type &Value); \ | ||||||||||||
2084 | }; \ | ||||||||||||
2085 | } \ | ||||||||||||
2086 | } | ||||||||||||
2087 | |||||||||||||
2088 | #define LLVM_YAML_DECLARE_BITSET_TRAITS(Type)namespace llvm { namespace yaml { template <> struct ScalarBitSetTraits <Type> { static void bitset(IO &IO, Type &Options ); }; } } \ | ||||||||||||
2089 | namespace llvm { \ | ||||||||||||
2090 | namespace yaml { \ | ||||||||||||
2091 | template <> struct ScalarBitSetTraits<Type> { \ | ||||||||||||
2092 | static void bitset(IO &IO, Type &Options); \ | ||||||||||||
2093 | }; \ | ||||||||||||
2094 | } \ | ||||||||||||
2095 | } | ||||||||||||
2096 | |||||||||||||
2097 | #define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote)namespace llvm { namespace yaml { template <> struct ScalarTraits <Type> { static void output(const Type &Value, void *ctx, raw_ostream &Out); static StringRef input(StringRef Scalar, void *ctxt, Type &Value); static QuotingType mustQuote (StringRef) { return MustQuote; } }; } } \ | ||||||||||||
2098 | namespace llvm { \ | ||||||||||||
2099 | namespace yaml { \ | ||||||||||||
2100 | template <> struct ScalarTraits<Type> { \ | ||||||||||||
2101 | static void output(const Type &Value, void *ctx, raw_ostream &Out); \ | ||||||||||||
2102 | static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ | ||||||||||||
2103 | static QuotingType mustQuote(StringRef) { return MustQuote; } \ | ||||||||||||
2104 | }; \ | ||||||||||||
2105 | } \ | ||||||||||||
2106 | } | ||||||||||||
2107 | |||||||||||||
2108 | /// Utility for declaring that a std::vector of a particular type | ||||||||||||
2109 | /// should be considered a YAML document list. | ||||||||||||
2110 | #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type)namespace llvm { namespace yaml { template <unsigned N> struct DocumentListTraits<SmallVector<_type, N>> : public SequenceTraitsImpl<SmallVector<_type, N>, false > {}; template <> struct DocumentListTraits<std:: vector<_type>> : public SequenceTraitsImpl<std::vector <_type>, false> {}; } } \ | ||||||||||||
2111 | namespace llvm { \ | ||||||||||||
2112 | namespace yaml { \ | ||||||||||||
2113 | template <unsigned N> \ | ||||||||||||
2114 | struct DocumentListTraits<SmallVector<_type, N>> \ | ||||||||||||
2115 | : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \ | ||||||||||||
2116 | template <> \ | ||||||||||||
2117 | struct DocumentListTraits<std::vector<_type>> \ | ||||||||||||
2118 | : public SequenceTraitsImpl<std::vector<_type>, false> {}; \ | ||||||||||||
2119 | } \ | ||||||||||||
2120 | } | ||||||||||||
2121 | |||||||||||||
2122 | /// Utility for declaring that std::map<std::string, _type> should be considered | ||||||||||||
2123 | /// a YAML map. | ||||||||||||
2124 | #define LLVM_YAML_IS_STRING_MAP(_type)namespace llvm { namespace yaml { template <> struct CustomMappingTraits <std::map<std::string, _type>> : public StdMapStringCustomMappingTraitsImpl <_type> {}; } } \ | ||||||||||||
2125 | namespace llvm { \ | ||||||||||||
2126 | namespace yaml { \ | ||||||||||||
2127 | template <> \ | ||||||||||||
2128 | struct CustomMappingTraits<std::map<std::string, _type>> \ | ||||||||||||
2129 | : public StdMapStringCustomMappingTraitsImpl<_type> {}; \ | ||||||||||||
2130 | } \ | ||||||||||||
2131 | } | ||||||||||||
2132 | |||||||||||||
2133 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <llvm::yaml::Hex64> && !std::is_same_v<llvm:: yaml::Hex64, std::string> && !std::is_same_v<llvm ::yaml::Hex64, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<llvm::yaml ::Hex64> { static const bool flow = true; }; } } | ||||||||||||
2134 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <llvm::yaml::Hex32> && !std::is_same_v<llvm:: yaml::Hex32, std::string> && !std::is_same_v<llvm ::yaml::Hex32, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<llvm::yaml ::Hex32> { static const bool flow = true; }; } } | ||||||||||||
2135 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <llvm::yaml::Hex16> && !std::is_same_v<llvm:: yaml::Hex16, std::string> && !std::is_same_v<llvm ::yaml::Hex16, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<llvm::yaml ::Hex16> { static const bool flow = true; }; } } | ||||||||||||
2136 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8)namespace llvm { namespace yaml { static_assert( !std::is_fundamental_v <llvm::yaml::Hex8> && !std::is_same_v<llvm:: yaml::Hex8, std::string> && !std::is_same_v<llvm ::yaml::Hex8, llvm::StringRef>, "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control" ); template <> struct SequenceElementTraits<llvm::yaml ::Hex8> { static const bool flow = true; }; } } | ||||||||||||
2137 | |||||||||||||
2138 | #endif // LLVM_SUPPORT_YAMLTRAITS_H |
1 | // The -*- C++ -*- dynamic memory management header. |
2 | |
3 | // Copyright (C) 1994-2020 Free Software Foundation, Inc. |
4 | |
5 | // This file is part of GCC. |
6 | // |
7 | // GCC is free software; you can redistribute it and/or modify |
8 | // it under the terms of the GNU General Public License as published by |
9 | // the Free Software Foundation; either version 3, or (at your option) |
10 | // any later version. |
11 | // |
12 | // GCC is distributed in the hope that it will be useful, |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | // GNU General Public License for more details. |
16 | // |
17 | // Under Section 7 of GPL version 3, you are granted additional |
18 | // permissions described in the GCC Runtime Library Exception, version |
19 | // 3.1, as published by the Free Software Foundation. |
20 | |
21 | // You should have received a copy of the GNU General Public License and |
22 | // a copy of the GCC Runtime Library Exception along with this program; |
23 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
24 | // <http://www.gnu.org/licenses/>. |
25 | |
26 | /** @file new |
27 | * This is a Standard C++ Library header. |
28 | * |
29 | * The header @c new defines several functions to manage dynamic memory and |
30 | * handling memory allocation errors; see |
31 | * https://gcc.gnu.org/onlinedocs/libstdc++/manual/dynamic_memory.html |
32 | * for more. |
33 | */ |
34 | |
35 | #ifndef _NEW |
36 | #define _NEW |
37 | |
38 | #pragma GCC system_header |
39 | |
40 | #include <bits/c++config.h> |
41 | #include <exception> |
42 | |
43 | #pragma GCC visibility push(default) |
44 | |
45 | extern "C++" { |
46 | |
47 | namespace std |
48 | { |
49 | /** |
50 | * @brief Exception possibly thrown by @c new. |
51 | * @ingroup exceptions |
52 | * |
53 | * @c bad_alloc (or classes derived from it) is used to report allocation |
54 | * errors from the throwing forms of @c new. */ |
55 | class bad_alloc : public exception |
56 | { |
57 | public: |
58 | bad_alloc() throw() { } |
59 | |
60 | #if __cplusplus201703L >= 201103L |
61 | bad_alloc(const bad_alloc&) = default; |
62 | bad_alloc& operator=(const bad_alloc&) = default; |
63 | #endif |
64 | |
65 | // This declaration is not useless: |
66 | // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118 |
67 | virtual ~bad_alloc() throw(); |
68 | |
69 | // See comment in eh_exception.cc. |
70 | virtual const char* what() const throw(); |
71 | }; |
72 | |
73 | #if __cplusplus201703L >= 201103L |
74 | class bad_array_new_length : public bad_alloc |
75 | { |
76 | public: |
77 | bad_array_new_length() throw() { } |
78 | |
79 | // This declaration is not useless: |
80 | // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118 |
81 | virtual ~bad_array_new_length() throw(); |
82 | |
83 | // See comment in eh_exception.cc. |
84 | virtual const char* what() const throw(); |
85 | }; |
86 | #endif |
87 | |
88 | #if __cpp_aligned_new201606L |
89 | enum class align_val_t: size_t {}; |
90 | #endif |
91 | |
92 | struct nothrow_t |
93 | { |
94 | #if __cplusplus201703L >= 201103L |
95 | explicit nothrow_t() = default; |
96 | #endif |
97 | }; |
98 | |
99 | extern const nothrow_t nothrow; |
100 | |
101 | /** If you write your own error handler to be called by @c new, it must |
102 | * be of this type. */ |
103 | typedef void (*new_handler)(); |
104 | |
105 | /// Takes a replacement handler as the argument, returns the |
106 | /// previous handler. |
107 | new_handler set_new_handler(new_handler) throw(); |
108 | |
109 | #if __cplusplus201703L >= 201103L |
110 | /// Return the current new handler. |
111 | new_handler get_new_handler() noexcept; |
112 | #endif |
113 | } // namespace std |
114 | |
115 | //@{ |
116 | /** These are replaceable signatures: |
117 | * - normal single new and delete (no arguments, throw @c bad_alloc on error) |
118 | * - normal array new and delete (same) |
119 | * - @c nothrow single new and delete (take a @c nothrow argument, return |
120 | * @c NULL on error) |
121 | * - @c nothrow array new and delete (same) |
122 | * |
123 | * Placement new and delete signatures (take a memory address argument, |
124 | * does nothing) may not be replaced by a user's program. |
125 | */ |
126 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc) |
127 | __attribute__((__externally_visible__)); |
128 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new[](std::size_t) _GLIBCXX_THROW (std::bad_alloc) |
129 | __attribute__((__externally_visible__)); |
130 | void operator delete(void*) _GLIBCXX_USE_NOEXCEPTnoexcept |
131 | __attribute__((__externally_visible__)); |
132 | void operator delete[](void*) _GLIBCXX_USE_NOEXCEPTnoexcept |
133 | __attribute__((__externally_visible__)); |
134 | #if __cpp_sized_deallocation |
135 | void operator delete(void*, std::size_t) _GLIBCXX_USE_NOEXCEPTnoexcept |
136 | __attribute__((__externally_visible__)); |
137 | void operator delete[](void*, std::size_t) _GLIBCXX_USE_NOEXCEPTnoexcept |
138 | __attribute__((__externally_visible__)); |
139 | #endif |
140 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new(std::size_t, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPTnoexcept |
141 | __attribute__((__externally_visible__, __malloc__)); |
142 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new[](std::size_t, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPTnoexcept |
143 | __attribute__((__externally_visible__, __malloc__)); |
144 | void operator delete(void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPTnoexcept |
145 | __attribute__((__externally_visible__)); |
146 | void operator delete[](void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPTnoexcept |
147 | __attribute__((__externally_visible__)); |
148 | #if __cpp_aligned_new201606L |
149 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new(std::size_t, std::align_val_t) |
150 | __attribute__((__externally_visible__)); |
151 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new(std::size_t, std::align_val_t, const std::nothrow_t&) |
152 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__, __malloc__)); |
153 | void operator delete(void*, std::align_val_t) |
154 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__)); |
155 | void operator delete(void*, std::align_val_t, const std::nothrow_t&) |
156 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__)); |
157 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new[](std::size_t, std::align_val_t) |
158 | __attribute__((__externally_visible__)); |
159 | _GLIBCXX_NODISCARD[[__nodiscard__]] void* operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) |
160 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__, __malloc__)); |
161 | void operator delete[](void*, std::align_val_t) |
162 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__)); |
163 | void operator delete[](void*, std::align_val_t, const std::nothrow_t&) |
164 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__)); |
165 | #if __cpp_sized_deallocation |
166 | void operator delete(void*, std::size_t, std::align_val_t) |
167 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__)); |
168 | void operator delete[](void*, std::size_t, std::align_val_t) |
169 | _GLIBCXX_USE_NOEXCEPTnoexcept __attribute__((__externally_visible__)); |
170 | #endif // __cpp_sized_deallocation |
171 | #endif // __cpp_aligned_new |
172 | |
173 | // Default placement versions of operator new. |
174 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPTnoexcept |
175 | { return __p; } |
176 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPTnoexcept |
177 | { return __p; } |
178 | |
179 | // Default placement versions of operator delete. |
180 | inline void operator delete (void*, void*) _GLIBCXX_USE_NOEXCEPTnoexcept { } |
181 | inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPTnoexcept { } |
182 | //@} |
183 | } // extern "C++" |
184 | |
185 | #if __cplusplus201703L >= 201703L |
186 | #ifdef _GLIBCXX_HAVE_BUILTIN_LAUNDER1 |
187 | namespace std |
188 | { |
189 | #define __cpp_lib_launder201606 201606 |
190 | /// Pointer optimization barrier [ptr.launder] |
191 | template<typename _Tp> |
192 | [[nodiscard]] constexpr _Tp* |
193 | launder(_Tp* __p) noexcept |
194 | { return __builtin_launder(__p); } |
195 | |
196 | // The program is ill-formed if T is a function type or |
197 | // (possibly cv-qualified) void. |
198 | |
199 | template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM, bool _NE> |
200 | void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUALnoexcept (_NE)) = delete; |
201 | template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM, bool _NE> |
202 | void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUALnoexcept (_NE)) = delete; |
203 | |
204 | void launder(void*) = delete; |
205 | void launder(const void*) = delete; |
206 | void launder(volatile void*) = delete; |
207 | void launder(const volatile void*) = delete; |
208 | } |
209 | #endif // _GLIBCXX_HAVE_BUILTIN_LAUNDER |
210 | #endif // C++17 |
211 | |
212 | #if __cplusplus201703L > 201703L |
213 | namespace std |
214 | { |
215 | /// Tag type used to declare a class-specific operator delete that can |
216 | /// invoke the destructor before deallocating the memory. |
217 | struct destroying_delete_t |
218 | { |
219 | explicit destroying_delete_t() = default; |
220 | }; |
221 | /// Tag variable of type destroying_delete_t. |
222 | inline constexpr destroying_delete_t destroying_delete{}; |
223 | } |
224 | // Only define the feature test macro if the compiler supports the feature: |
225 | #if __cpp_impl_destroying_delete201806L |
226 | # define __cpp_lib_destroying_delete 201806L |
227 | #endif |
228 | #endif // C++20 |
229 | |
230 | #pragma GCC visibility pop |
231 | |
232 | #endif |