xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/YAMLTraits.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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_v<T>> class has_FlowTraits {
510 public:
511    static const bool value = false;
512 };
513 
514 // Some older gcc compilers don't support straight forward tests
515 // for members, so test for ambiguity cause by the base and derived
516 // classes both defining the member.
517 template <class T>
518 struct has_FlowTraits<T, true>
519 {
520   struct Fallback { bool flow; };
521   struct Derived : T, Fallback { };
522 
523   template<typename C>
524   static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
525 
526   template<typename C>
527   static char (&f(...))[2];
528 
529   static bool const value = sizeof(f<Derived>(nullptr)) == 2;
530 };
531 
532 // Test if SequenceTraits<T> is defined on type T
533 template<typename T>
534 struct has_SequenceTraits : public std::integral_constant<bool,
535                                       has_SequenceMethodTraits<T>::value > { };
536 
537 // Test if DocumentListTraits<T> is defined on type T
538 template <class T>
539 struct has_DocumentListTraits
540 {
541   using Signature_size = size_t (*)(class IO &, T &);
542 
543   template <typename U>
544   static char test(SameType<Signature_size, &U::size>*);
545 
546   template <typename U>
547   static double test(...);
548 
549   static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1);
550 };
551 
552 template <class T> struct has_PolymorphicTraits {
553   using Signature_getKind = NodeKind (*)(const T &);
554 
555   template <typename U>
556   static char test(SameType<Signature_getKind, &U::getKind> *);
557 
558   template <typename U> static double test(...);
559 
560   static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1);
561 };
562 
563 inline bool isNumeric(StringRef S) {
564   const auto skipDigits = [](StringRef Input) {
565     return Input.ltrim("0123456789");
566   };
567 
568   // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls
569   // safe.
570   if (S.empty() || S == "+" || S == "-")
571     return false;
572 
573   if (S == ".nan" || S == ".NaN" || S == ".NAN")
574     return true;
575 
576   // Infinity and decimal numbers can be prefixed with sign.
577   StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S;
578 
579   // Check for infinity first, because checking for hex and oct numbers is more
580   // expensive.
581   if (Tail == ".inf" || Tail == ".Inf" || Tail == ".INF")
582     return true;
583 
584   // Section 10.3.2 Tag Resolution
585   // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with
586   // [-+], so S should be used instead of Tail.
587   if (S.starts_with("0o"))
588     return S.size() > 2 &&
589            S.drop_front(2).find_first_not_of("01234567") == StringRef::npos;
590 
591   if (S.starts_with("0x"))
592     return S.size() > 2 && S.drop_front(2).find_first_not_of(
593                                "0123456789abcdefABCDEF") == StringRef::npos;
594 
595   // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)?
596   S = Tail;
597 
598   // Handle cases when the number starts with '.' and hence needs at least one
599   // digit after dot (as opposed by number which has digits before the dot), but
600   // doesn't have one.
601   if (S.starts_with(".") &&
602       (S == "." ||
603        (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr)))
604     return false;
605 
606   if (S.starts_with("E") || S.starts_with("e"))
607     return false;
608 
609   enum ParseState {
610     Default,
611     FoundDot,
612     FoundExponent,
613   };
614   ParseState State = Default;
615 
616   S = skipDigits(S);
617 
618   // Accept decimal integer.
619   if (S.empty())
620     return true;
621 
622   if (S.front() == '.') {
623     State = FoundDot;
624     S = S.drop_front();
625   } else if (S.front() == 'e' || S.front() == 'E') {
626     State = FoundExponent;
627     S = S.drop_front();
628   } else {
629     return false;
630   }
631 
632   if (State == FoundDot) {
633     S = skipDigits(S);
634     if (S.empty())
635       return true;
636 
637     if (S.front() == 'e' || S.front() == 'E') {
638       State = FoundExponent;
639       S = S.drop_front();
640     } else {
641       return false;
642     }
643   }
644 
645   assert(State == FoundExponent && "Should have found exponent at this point.");
646   if (S.empty())
647     return false;
648 
649   if (S.front() == '+' || S.front() == '-') {
650     S = S.drop_front();
651     if (S.empty())
652       return false;
653   }
654 
655   return skipDigits(S).empty();
656 }
657 
658 inline bool isNull(StringRef S) {
659   return S == "null" || S == "Null" || S == "NULL" || S == "~";
660 }
661 
662 inline bool isBool(StringRef S) {
663   // FIXME: using parseBool is causing multiple tests to fail.
664   return S == "true" || S == "True" || S == "TRUE" || S == "false" ||
665          S == "False" || S == "FALSE";
666 }
667 
668 // 5.1. Character Set
669 // The allowed character range explicitly excludes the C0 control block #x0-#x1F
670 // (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1
671 // control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate
672 // block #xD800-#xDFFF, #xFFFE, and #xFFFF.
673 //
674 // Some strings are valid YAML values even unquoted, but without quotes are
675 // interpreted as non-string type, for instance null, boolean or numeric values.
676 // If ForcePreserveAsString is set, such strings are quoted.
677 inline QuotingType needsQuotes(StringRef S, bool ForcePreserveAsString = true) {
678   if (S.empty())
679     return QuotingType::Single;
680 
681   QuotingType MaxQuotingNeeded = QuotingType::None;
682   if (isSpace(static_cast<unsigned char>(S.front())) ||
683       isSpace(static_cast<unsigned char>(S.back())))
684     MaxQuotingNeeded = QuotingType::Single;
685   if (ForcePreserveAsString) {
686     if (isNull(S))
687       MaxQuotingNeeded = QuotingType::Single;
688     if (isBool(S))
689       MaxQuotingNeeded = QuotingType::Single;
690     if (isNumeric(S))
691       MaxQuotingNeeded = QuotingType::Single;
692   }
693 
694   // 7.3.3 Plain Style
695   // Plain scalars must not begin with most indicators, as this would cause
696   // ambiguity with other YAML constructs.
697   if (std::strchr(R"(-?:\,[]{}#&*!|>'"%@`)", S[0]) != nullptr)
698     MaxQuotingNeeded = QuotingType::Single;
699 
700   for (unsigned char C : S) {
701     // Alphanum is safe.
702     if (isAlnum(C))
703       continue;
704 
705     switch (C) {
706     // Safe scalar characters.
707     case '_':
708     case '-':
709     case '^':
710     case '.':
711     case ',':
712     case ' ':
713     // TAB (0x9) is allowed in unquoted strings.
714     case 0x9:
715       continue;
716     // LF(0xA) and CR(0xD) may delimit values and so require at least single
717     // quotes. LLVM YAML parser cannot handle single quoted multiline so use
718     // double quoting to produce valid YAML.
719     case 0xA:
720     case 0xD:
721       return QuotingType::Double;
722     // DEL (0x7F) are excluded from the allowed character range.
723     case 0x7F:
724       return QuotingType::Double;
725     // Forward slash is allowed to be unquoted, but we quote it anyway.  We have
726     // many tests that use FileCheck against YAML output, and this output often
727     // contains paths.  If we quote backslashes but not forward slashes then
728     // paths will come out either quoted or unquoted depending on which platform
729     // the test is run on, making FileCheck comparisons difficult.
730     case '/':
731     default: {
732       // C0 control block (0x0 - 0x1F) is excluded from the allowed character
733       // range.
734       if (C <= 0x1F)
735         return QuotingType::Double;
736 
737       // Always double quote UTF-8.
738       if ((C & 0x80) != 0)
739         return QuotingType::Double;
740 
741       // The character is not safe, at least simple quoting needed.
742       MaxQuotingNeeded = QuotingType::Single;
743     }
744     }
745   }
746 
747   return MaxQuotingNeeded;
748 }
749 
750 template <typename T, typename Context>
751 struct missingTraits
752     : public std::integral_constant<bool,
753                                     !has_ScalarEnumerationTraits<T>::value &&
754                                         !has_ScalarBitSetTraits<T>::value &&
755                                         !has_ScalarTraits<T>::value &&
756                                         !has_BlockScalarTraits<T>::value &&
757                                         !has_TaggedScalarTraits<T>::value &&
758                                         !has_MappingTraits<T, Context>::value &&
759                                         !has_SequenceTraits<T>::value &&
760                                         !has_CustomMappingTraits<T>::value &&
761                                         !has_DocumentListTraits<T>::value &&
762                                         !has_PolymorphicTraits<T>::value> {};
763 
764 template <typename T, typename Context>
765 struct validatedMappingTraits
766     : public std::integral_constant<
767           bool, has_MappingTraits<T, Context>::value &&
768                     has_MappingValidateTraits<T, Context>::value> {};
769 
770 template <typename T, typename Context>
771 struct unvalidatedMappingTraits
772     : public std::integral_constant<
773           bool, has_MappingTraits<T, Context>::value &&
774                     !has_MappingValidateTraits<T, Context>::value> {};
775 
776 // Base class for Input and Output.
777 class IO {
778 public:
779   IO(void *Ctxt = nullptr);
780   virtual ~IO();
781 
782   virtual bool outputting() const = 0;
783 
784   virtual unsigned beginSequence() = 0;
785   virtual bool preflightElement(unsigned, void *&) = 0;
786   virtual void postflightElement(void*) = 0;
787   virtual void endSequence() = 0;
788   virtual bool canElideEmptySequence() = 0;
789 
790   virtual unsigned beginFlowSequence() = 0;
791   virtual bool preflightFlowElement(unsigned, void *&) = 0;
792   virtual void postflightFlowElement(void*) = 0;
793   virtual void endFlowSequence() = 0;
794 
795   virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
796   virtual void beginMapping() = 0;
797   virtual void endMapping() = 0;
798   virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
799   virtual void postflightKey(void*) = 0;
800   virtual std::vector<StringRef> keys() = 0;
801 
802   virtual void beginFlowMapping() = 0;
803   virtual void endFlowMapping() = 0;
804 
805   virtual void beginEnumScalar() = 0;
806   virtual bool matchEnumScalar(const char*, bool) = 0;
807   virtual bool matchEnumFallback() = 0;
808   virtual void endEnumScalar() = 0;
809 
810   virtual bool beginBitSetScalar(bool &) = 0;
811   virtual bool bitSetMatch(const char*, bool) = 0;
812   virtual void endBitSetScalar() = 0;
813 
814   virtual void scalarString(StringRef &, QuotingType) = 0;
815   virtual void blockScalarString(StringRef &) = 0;
816   virtual void scalarTag(std::string &) = 0;
817 
818   virtual NodeKind getNodeKind() = 0;
819 
820   virtual void setError(const Twine &) = 0;
821   virtual void setAllowUnknownKeys(bool Allow);
822 
823   template <typename T>
824   void enumCase(T &Val, const char* Str, const T ConstVal) {
825     if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
826       Val = ConstVal;
827     }
828   }
829 
830   // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
831   template <typename T>
832   void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
833     if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
834       Val = ConstVal;
835     }
836   }
837 
838   template <typename FBT, typename T>
839   void enumFallback(T &Val) {
840     if (matchEnumFallback()) {
841       EmptyContext Context;
842       // FIXME: Force integral conversion to allow strong typedefs to convert.
843       FBT Res = static_cast<typename FBT::BaseType>(Val);
844       yamlize(*this, Res, true, Context);
845       Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res));
846     }
847   }
848 
849   template <typename T>
850   void bitSetCase(T &Val, const char* Str, const T ConstVal) {
851     if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
852       Val = static_cast<T>(Val | ConstVal);
853     }
854   }
855 
856   // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
857   template <typename T>
858   void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
859     if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
860       Val = static_cast<T>(Val | ConstVal);
861     }
862   }
863 
864   template <typename T>
865   void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) {
866     if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
867       Val = Val | ConstVal;
868   }
869 
870   template <typename T>
871   void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal,
872                         uint32_t Mask) {
873     if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
874       Val = Val | ConstVal;
875   }
876 
877   void *getContext() const;
878   void setContext(void *);
879 
880   template <typename T> void mapRequired(const char *Key, T &Val) {
881     EmptyContext Ctx;
882     this->processKey(Key, Val, true, Ctx);
883   }
884 
885   template <typename T, typename Context>
886   void mapRequired(const char *Key, T &Val, Context &Ctx) {
887     this->processKey(Key, Val, true, Ctx);
888   }
889 
890   template <typename T> void mapOptional(const char *Key, T &Val) {
891     EmptyContext Ctx;
892     mapOptionalWithContext(Key, Val, Ctx);
893   }
894 
895   template <typename T, typename DefaultT>
896   void mapOptional(const char *Key, T &Val, const DefaultT &Default) {
897     EmptyContext Ctx;
898     mapOptionalWithContext(Key, Val, Default, Ctx);
899   }
900 
901   template <typename T, typename Context>
902   std::enable_if_t<has_SequenceTraits<T>::value, void>
903   mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
904     // omit key/value instead of outputting empty sequence
905     if (this->canElideEmptySequence() && !(Val.begin() != Val.end()))
906       return;
907     this->processKey(Key, Val, false, Ctx);
908   }
909 
910   template <typename T, typename Context>
911   void mapOptionalWithContext(const char *Key, std::optional<T> &Val,
912                               Context &Ctx) {
913     this->processKeyWithDefault(Key, Val, std::optional<T>(),
914                                 /*Required=*/false, Ctx);
915   }
916 
917   template <typename T, typename Context>
918   std::enable_if_t<!has_SequenceTraits<T>::value, void>
919   mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
920     this->processKey(Key, Val, false, Ctx);
921   }
922 
923   template <typename T, typename Context, typename DefaultT>
924   void mapOptionalWithContext(const char *Key, T &Val, const DefaultT &Default,
925                               Context &Ctx) {
926     static_assert(std::is_convertible<DefaultT, T>::value,
927                   "Default type must be implicitly convertible to value type!");
928     this->processKeyWithDefault(Key, Val, static_cast<const T &>(Default),
929                                 false, Ctx);
930   }
931 
932 private:
933   template <typename T, typename Context>
934   void processKeyWithDefault(const char *Key, std::optional<T> &Val,
935                              const std::optional<T> &DefaultValue,
936                              bool Required, Context &Ctx);
937 
938   template <typename T, typename Context>
939   void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
940                              bool Required, Context &Ctx) {
941     void *SaveInfo;
942     bool UseDefault;
943     const bool sameAsDefault = outputting() && Val == DefaultValue;
944     if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
945                                                                   SaveInfo) ) {
946       yamlize(*this, Val, Required, Ctx);
947       this->postflightKey(SaveInfo);
948     }
949     else {
950       if ( UseDefault )
951         Val = DefaultValue;
952     }
953   }
954 
955   template <typename T, typename Context>
956   void processKey(const char *Key, T &Val, bool Required, Context &Ctx) {
957     void *SaveInfo;
958     bool UseDefault;
959     if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
960       yamlize(*this, Val, Required, Ctx);
961       this->postflightKey(SaveInfo);
962     }
963   }
964 
965 private:
966   void *Ctxt;
967 };
968 
969 namespace detail {
970 
971 template <typename T, typename Context>
972 void doMapping(IO &io, T &Val, Context &Ctx) {
973   MappingContextTraits<T, Context>::mapping(io, Val, Ctx);
974 }
975 
976 template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) {
977   MappingTraits<T>::mapping(io, Val);
978 }
979 
980 } // end namespace detail
981 
982 template <typename T>
983 std::enable_if_t<has_ScalarEnumerationTraits<T>::value, void>
984 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
985   io.beginEnumScalar();
986   ScalarEnumerationTraits<T>::enumeration(io, Val);
987   io.endEnumScalar();
988 }
989 
990 template <typename T>
991 std::enable_if_t<has_ScalarBitSetTraits<T>::value, void>
992 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
993   bool DoClear;
994   if ( io.beginBitSetScalar(DoClear) ) {
995     if ( DoClear )
996       Val = T();
997     ScalarBitSetTraits<T>::bitset(io, Val);
998     io.endBitSetScalar();
999   }
1000 }
1001 
1002 template <typename T>
1003 std::enable_if_t<has_ScalarTraits<T>::value, void> yamlize(IO &io, T &Val, bool,
1004                                                            EmptyContext &Ctx) {
1005   if ( io.outputting() ) {
1006     SmallString<128> Storage;
1007     raw_svector_ostream Buffer(Storage);
1008     ScalarTraits<T>::output(Val, io.getContext(), Buffer);
1009     StringRef Str = Buffer.str();
1010     io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
1011   }
1012   else {
1013     StringRef Str;
1014     io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
1015     StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
1016     if ( !Result.empty() ) {
1017       io.setError(Twine(Result));
1018     }
1019   }
1020 }
1021 
1022 template <typename T>
1023 std::enable_if_t<has_BlockScalarTraits<T>::value, void>
1024 yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) {
1025   if (YamlIO.outputting()) {
1026     std::string Storage;
1027     raw_string_ostream Buffer(Storage);
1028     BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer);
1029     StringRef Str(Storage);
1030     YamlIO.blockScalarString(Str);
1031   } else {
1032     StringRef Str;
1033     YamlIO.blockScalarString(Str);
1034     StringRef Result =
1035         BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val);
1036     if (!Result.empty())
1037       YamlIO.setError(Twine(Result));
1038   }
1039 }
1040 
1041 template <typename T>
1042 std::enable_if_t<has_TaggedScalarTraits<T>::value, void>
1043 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
1044   if (io.outputting()) {
1045     std::string ScalarStorage, TagStorage;
1046     raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage);
1047     TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer,
1048                                   TagBuffer);
1049     io.scalarTag(TagStorage);
1050     StringRef ScalarStr(ScalarStorage);
1051     io.scalarString(ScalarStr,
1052                     TaggedScalarTraits<T>::mustQuote(Val, ScalarStr));
1053   } else {
1054     std::string Tag;
1055     io.scalarTag(Tag);
1056     StringRef Str;
1057     io.scalarString(Str, QuotingType::None);
1058     StringRef Result =
1059         TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val);
1060     if (!Result.empty()) {
1061       io.setError(Twine(Result));
1062     }
1063   }
1064 }
1065 
1066 namespace detail {
1067 
1068 template <typename T, typename Context>
1069 std::string doValidate(IO &io, T &Val, Context &Ctx) {
1070   return MappingContextTraits<T, Context>::validate(io, Val, Ctx);
1071 }
1072 
1073 template <typename T> std::string doValidate(IO &io, T &Val, EmptyContext &) {
1074   return MappingTraits<T>::validate(io, Val);
1075 }
1076 
1077 } // namespace detail
1078 
1079 template <typename T, typename Context>
1080 std::enable_if_t<validatedMappingTraits<T, Context>::value, void>
1081 yamlize(IO &io, T &Val, bool, Context &Ctx) {
1082   if (has_FlowTraits<MappingTraits<T>>::value)
1083     io.beginFlowMapping();
1084   else
1085     io.beginMapping();
1086   if (io.outputting()) {
1087     std::string Err = detail::doValidate(io, Val, Ctx);
1088     if (!Err.empty()) {
1089       errs() << Err << "\n";
1090       assert(Err.empty() && "invalid struct trying to be written as yaml");
1091     }
1092   }
1093   detail::doMapping(io, Val, Ctx);
1094   if (!io.outputting()) {
1095     std::string Err = detail::doValidate(io, Val, Ctx);
1096     if (!Err.empty())
1097       io.setError(Err);
1098   }
1099   if (has_FlowTraits<MappingTraits<T>>::value)
1100     io.endFlowMapping();
1101   else
1102     io.endMapping();
1103 }
1104 
1105 template <typename T, typename Context>
1106 std::enable_if_t<!has_MappingEnumInputTraits<T, Context>::value, bool>
1107 yamlizeMappingEnumInput(IO &io, T &Val) {
1108   return false;
1109 }
1110 
1111 template <typename T, typename Context>
1112 std::enable_if_t<has_MappingEnumInputTraits<T, Context>::value, bool>
1113 yamlizeMappingEnumInput(IO &io, T &Val) {
1114   if (io.outputting())
1115     return false;
1116 
1117   io.beginEnumScalar();
1118   MappingTraits<T>::enumInput(io, Val);
1119   bool Matched = !io.matchEnumFallback();
1120   io.endEnumScalar();
1121   return Matched;
1122 }
1123 
1124 template <typename T, typename Context>
1125 std::enable_if_t<unvalidatedMappingTraits<T, Context>::value, void>
1126 yamlize(IO &io, T &Val, bool, Context &Ctx) {
1127   if (yamlizeMappingEnumInput<T, Context>(io, Val))
1128     return;
1129   if (has_FlowTraits<MappingTraits<T>>::value) {
1130     io.beginFlowMapping();
1131     detail::doMapping(io, Val, Ctx);
1132     io.endFlowMapping();
1133   } else {
1134     io.beginMapping();
1135     detail::doMapping(io, Val, Ctx);
1136     io.endMapping();
1137   }
1138 }
1139 
1140 template <typename T>
1141 std::enable_if_t<has_CustomMappingTraits<T>::value, void>
1142 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
1143   if ( io.outputting() ) {
1144     io.beginMapping();
1145     CustomMappingTraits<T>::output(io, Val);
1146     io.endMapping();
1147   } else {
1148     io.beginMapping();
1149     for (StringRef key : io.keys())
1150       CustomMappingTraits<T>::inputOne(io, key, Val);
1151     io.endMapping();
1152   }
1153 }
1154 
1155 template <typename T>
1156 std::enable_if_t<has_PolymorphicTraits<T>::value, void>
1157 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
1158   switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val)
1159                           : io.getNodeKind()) {
1160   case NodeKind::Scalar:
1161     return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx);
1162   case NodeKind::Map:
1163     return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx);
1164   case NodeKind::Sequence:
1165     return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx);
1166   }
1167 }
1168 
1169 template <typename T>
1170 std::enable_if_t<missingTraits<T, EmptyContext>::value, void>
1171 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
1172   char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1173 }
1174 
1175 template <typename T, typename Context>
1176 std::enable_if_t<has_SequenceTraits<T>::value, void>
1177 yamlize(IO &io, T &Seq, bool, Context &Ctx) {
1178   if ( has_FlowTraits< SequenceTraits<T>>::value ) {
1179     unsigned incnt = io.beginFlowSequence();
1180     unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
1181     for(unsigned i=0; i < count; ++i) {
1182       void *SaveInfo;
1183       if ( io.preflightFlowElement(i, SaveInfo) ) {
1184         yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
1185         io.postflightFlowElement(SaveInfo);
1186       }
1187     }
1188     io.endFlowSequence();
1189   }
1190   else {
1191     unsigned incnt = io.beginSequence();
1192     unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
1193     for(unsigned i=0; i < count; ++i) {
1194       void *SaveInfo;
1195       if ( io.preflightElement(i, SaveInfo) ) {
1196         yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
1197         io.postflightElement(SaveInfo);
1198       }
1199     }
1200     io.endSequence();
1201   }
1202 }
1203 
1204 template<>
1205 struct ScalarTraits<bool> {
1206   static void output(const bool &, void* , raw_ostream &);
1207   static StringRef input(StringRef, void *, bool &);
1208   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1209 };
1210 
1211 template<>
1212 struct ScalarTraits<StringRef> {
1213   static void output(const StringRef &, void *, raw_ostream &);
1214   static StringRef input(StringRef, void *, StringRef &);
1215   static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
1216 };
1217 
1218 template<>
1219 struct ScalarTraits<std::string> {
1220   static void output(const std::string &, void *, raw_ostream &);
1221   static StringRef input(StringRef, void *, std::string &);
1222   static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
1223 };
1224 
1225 template<>
1226 struct ScalarTraits<uint8_t> {
1227   static void output(const uint8_t &, void *, raw_ostream &);
1228   static StringRef input(StringRef, void *, uint8_t &);
1229   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1230 };
1231 
1232 template<>
1233 struct ScalarTraits<uint16_t> {
1234   static void output(const uint16_t &, void *, raw_ostream &);
1235   static StringRef input(StringRef, void *, uint16_t &);
1236   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1237 };
1238 
1239 template<>
1240 struct ScalarTraits<uint32_t> {
1241   static void output(const uint32_t &, void *, raw_ostream &);
1242   static StringRef input(StringRef, void *, uint32_t &);
1243   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1244 };
1245 
1246 template<>
1247 struct ScalarTraits<uint64_t> {
1248   static void output(const uint64_t &, void *, raw_ostream &);
1249   static StringRef input(StringRef, void *, uint64_t &);
1250   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1251 };
1252 
1253 template<>
1254 struct ScalarTraits<int8_t> {
1255   static void output(const int8_t &, void *, raw_ostream &);
1256   static StringRef input(StringRef, void *, int8_t &);
1257   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1258 };
1259 
1260 template<>
1261 struct ScalarTraits<int16_t> {
1262   static void output(const int16_t &, void *, raw_ostream &);
1263   static StringRef input(StringRef, void *, int16_t &);
1264   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1265 };
1266 
1267 template<>
1268 struct ScalarTraits<int32_t> {
1269   static void output(const int32_t &, void *, raw_ostream &);
1270   static StringRef input(StringRef, void *, int32_t &);
1271   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1272 };
1273 
1274 template<>
1275 struct ScalarTraits<int64_t> {
1276   static void output(const int64_t &, void *, raw_ostream &);
1277   static StringRef input(StringRef, void *, int64_t &);
1278   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1279 };
1280 
1281 template<>
1282 struct ScalarTraits<float> {
1283   static void output(const float &, void *, raw_ostream &);
1284   static StringRef input(StringRef, void *, float &);
1285   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1286 };
1287 
1288 template<>
1289 struct ScalarTraits<double> {
1290   static void output(const double &, void *, raw_ostream &);
1291   static StringRef input(StringRef, void *, double &);
1292   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1293 };
1294 
1295 // For endian types, we use existing scalar Traits class for the underlying
1296 // type.  This way endian aware types are supported whenever the traits are
1297 // defined for the underlying type.
1298 template <typename value_type, llvm::endianness endian, size_t alignment>
1299 struct ScalarTraits<support::detail::packed_endian_specific_integral<
1300                         value_type, endian, alignment>,
1301                     std::enable_if_t<has_ScalarTraits<value_type>::value>> {
1302   using endian_type =
1303       support::detail::packed_endian_specific_integral<value_type, endian,
1304                                                        alignment>;
1305 
1306   static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) {
1307     ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream);
1308   }
1309 
1310   static StringRef input(StringRef Str, void *Ctx, endian_type &E) {
1311     value_type V;
1312     auto R = ScalarTraits<value_type>::input(Str, Ctx, V);
1313     E = static_cast<endian_type>(V);
1314     return R;
1315   }
1316 
1317   static QuotingType mustQuote(StringRef Str) {
1318     return ScalarTraits<value_type>::mustQuote(Str);
1319   }
1320 };
1321 
1322 template <typename value_type, llvm::endianness endian, size_t alignment>
1323 struct ScalarEnumerationTraits<
1324     support::detail::packed_endian_specific_integral<value_type, endian,
1325                                                      alignment>,
1326     std::enable_if_t<has_ScalarEnumerationTraits<value_type>::value>> {
1327   using endian_type =
1328       support::detail::packed_endian_specific_integral<value_type, endian,
1329                                                        alignment>;
1330 
1331   static void enumeration(IO &io, endian_type &E) {
1332     value_type V = E;
1333     ScalarEnumerationTraits<value_type>::enumeration(io, V);
1334     E = V;
1335   }
1336 };
1337 
1338 template <typename value_type, llvm::endianness endian, size_t alignment>
1339 struct ScalarBitSetTraits<
1340     support::detail::packed_endian_specific_integral<value_type, endian,
1341                                                      alignment>,
1342     std::enable_if_t<has_ScalarBitSetTraits<value_type>::value>> {
1343   using endian_type =
1344       support::detail::packed_endian_specific_integral<value_type, endian,
1345                                                        alignment>;
1346   static void bitset(IO &io, endian_type &E) {
1347     value_type V = E;
1348     ScalarBitSetTraits<value_type>::bitset(io, V);
1349     E = V;
1350   }
1351 };
1352 
1353 // Utility for use within MappingTraits<>::mapping() method
1354 // to [de]normalize an object for use with YAML conversion.
1355 template <typename TNorm, typename TFinal>
1356 struct MappingNormalization {
1357   MappingNormalization(IO &i_o, TFinal &Obj)
1358       : io(i_o), BufPtr(nullptr), Result(Obj) {
1359     if ( io.outputting() ) {
1360       BufPtr = new (&Buffer) TNorm(io, Obj);
1361     }
1362     else {
1363       BufPtr = new (&Buffer) TNorm(io);
1364     }
1365   }
1366 
1367   ~MappingNormalization() {
1368     if ( ! io.outputting() ) {
1369       Result = BufPtr->denormalize(io);
1370     }
1371     BufPtr->~TNorm();
1372   }
1373 
1374   TNorm* operator->() { return BufPtr; }
1375 
1376 private:
1377   using Storage = AlignedCharArrayUnion<TNorm>;
1378 
1379   Storage       Buffer;
1380   IO           &io;
1381   TNorm        *BufPtr;
1382   TFinal       &Result;
1383 };
1384 
1385 // Utility for use within MappingTraits<>::mapping() method
1386 // to [de]normalize an object for use with YAML conversion.
1387 template <typename TNorm, typename TFinal>
1388 struct MappingNormalizationHeap {
1389   MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator)
1390     : io(i_o), Result(Obj) {
1391     if ( io.outputting() ) {
1392       BufPtr = new (&Buffer) TNorm(io, Obj);
1393     }
1394     else if (allocator) {
1395       BufPtr = allocator->Allocate<TNorm>();
1396       new (BufPtr) TNorm(io);
1397     } else {
1398       BufPtr = new TNorm(io);
1399     }
1400   }
1401 
1402   ~MappingNormalizationHeap() {
1403     if ( io.outputting() ) {
1404       BufPtr->~TNorm();
1405     }
1406     else {
1407       Result = BufPtr->denormalize(io);
1408     }
1409   }
1410 
1411   TNorm* operator->() { return BufPtr; }
1412 
1413 private:
1414   using Storage = AlignedCharArrayUnion<TNorm>;
1415 
1416   Storage       Buffer;
1417   IO           &io;
1418   TNorm        *BufPtr = nullptr;
1419   TFinal       &Result;
1420 };
1421 
1422 ///
1423 /// The Input class is used to parse a yaml document into in-memory structs
1424 /// and vectors.
1425 ///
1426 /// It works by using YAMLParser to do a syntax parse of the entire yaml
1427 /// document, then the Input class builds a graph of HNodes which wraps
1428 /// each yaml Node.  The extra layer is buffering.  The low level yaml
1429 /// parser only lets you look at each node once.  The buffering layer lets
1430 /// you search and interate multiple times.  This is necessary because
1431 /// the mapRequired() method calls may not be in the same order
1432 /// as the keys in the document.
1433 ///
1434 class Input : public IO {
1435 public:
1436   // Construct a yaml Input object from a StringRef and optional
1437   // user-data. The DiagHandler can be specified to provide
1438   // alternative error reporting.
1439   Input(StringRef InputContent,
1440         void *Ctxt = nullptr,
1441         SourceMgr::DiagHandlerTy DiagHandler = nullptr,
1442         void *DiagHandlerCtxt = nullptr);
1443   Input(MemoryBufferRef Input,
1444         void *Ctxt = nullptr,
1445         SourceMgr::DiagHandlerTy DiagHandler = nullptr,
1446         void *DiagHandlerCtxt = nullptr);
1447   ~Input() override;
1448 
1449   // Check if there was an syntax or semantic error during parsing.
1450   std::error_code error();
1451 
1452 private:
1453   bool outputting() const override;
1454   bool mapTag(StringRef, bool) override;
1455   void beginMapping() override;
1456   void endMapping() override;
1457   bool preflightKey(const char *, bool, bool, bool &, void *&) override;
1458   void postflightKey(void *) override;
1459   std::vector<StringRef> keys() override;
1460   void beginFlowMapping() override;
1461   void endFlowMapping() override;
1462   unsigned beginSequence() override;
1463   void endSequence() override;
1464   bool preflightElement(unsigned index, void *&) override;
1465   void postflightElement(void *) override;
1466   unsigned beginFlowSequence() override;
1467   bool preflightFlowElement(unsigned , void *&) override;
1468   void postflightFlowElement(void *) override;
1469   void endFlowSequence() override;
1470   void beginEnumScalar() override;
1471   bool matchEnumScalar(const char*, bool) override;
1472   bool matchEnumFallback() override;
1473   void endEnumScalar() override;
1474   bool beginBitSetScalar(bool &) override;
1475   bool bitSetMatch(const char *, bool ) override;
1476   void endBitSetScalar() override;
1477   void scalarString(StringRef &, QuotingType) override;
1478   void blockScalarString(StringRef &) override;
1479   void scalarTag(std::string &) override;
1480   NodeKind getNodeKind() override;
1481   void setError(const Twine &message) override;
1482   bool canElideEmptySequence() override;
1483 
1484   class HNode {
1485   public:
1486     HNode(Node *n) : _node(n) {}
1487 
1488     static bool classof(const HNode *) { return true; }
1489 
1490     Node *_node;
1491   };
1492 
1493   class EmptyHNode : public HNode {
1494   public:
1495     EmptyHNode(Node *n) : HNode(n) { }
1496 
1497     static bool classof(const HNode *n) { return NullNode::classof(n->_node); }
1498 
1499     static bool classof(const EmptyHNode *) { return true; }
1500   };
1501 
1502   class ScalarHNode : public HNode {
1503   public:
1504     ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
1505 
1506     StringRef value() const { return _value; }
1507 
1508     static bool classof(const HNode *n) {
1509       return ScalarNode::classof(n->_node) ||
1510              BlockScalarNode::classof(n->_node);
1511     }
1512 
1513     static bool classof(const ScalarHNode *) { return true; }
1514 
1515   protected:
1516     StringRef _value;
1517   };
1518 
1519   class MapHNode : public HNode {
1520   public:
1521     MapHNode(Node *n) : HNode(n) { }
1522 
1523     static bool classof(const HNode *n) {
1524       return MappingNode::classof(n->_node);
1525     }
1526 
1527     static bool classof(const MapHNode *) { return true; }
1528 
1529     using NameToNodeAndLoc = StringMap<std::pair<HNode *, SMRange>>;
1530 
1531     NameToNodeAndLoc Mapping;
1532     SmallVector<std::string, 6> ValidKeys;
1533   };
1534 
1535   class SequenceHNode : public HNode {
1536   public:
1537     SequenceHNode(Node *n) : HNode(n) { }
1538 
1539     static bool classof(const HNode *n) {
1540       return SequenceNode::classof(n->_node);
1541     }
1542 
1543     static bool classof(const SequenceHNode *) { return true; }
1544 
1545     std::vector<HNode *> Entries;
1546   };
1547 
1548   Input::HNode *createHNodes(Node *node);
1549   void setError(HNode *hnode, const Twine &message);
1550   void setError(Node *node, const Twine &message);
1551   void setError(const SMRange &Range, const Twine &message);
1552 
1553   void reportWarning(HNode *hnode, const Twine &message);
1554   void reportWarning(Node *hnode, const Twine &message);
1555   void reportWarning(const SMRange &Range, const Twine &message);
1556 
1557   /// Release memory used by HNodes.
1558   void releaseHNodeBuffers();
1559 
1560 public:
1561   // These are only used by operator>>. They could be private
1562   // if those templated things could be made friends.
1563   bool setCurrentDocument();
1564   bool nextDocument();
1565 
1566   /// Returns the current node that's being parsed by the YAML Parser.
1567   const Node *getCurrentNode() const;
1568 
1569   void setAllowUnknownKeys(bool Allow) override;
1570 
1571 private:
1572   SourceMgr                           SrcMgr; // must be before Strm
1573   std::unique_ptr<llvm::yaml::Stream> Strm;
1574   HNode *TopNode = nullptr;
1575   std::error_code                     EC;
1576   BumpPtrAllocator                    StringAllocator;
1577   SpecificBumpPtrAllocator<EmptyHNode> EmptyHNodeAllocator;
1578   SpecificBumpPtrAllocator<ScalarHNode> ScalarHNodeAllocator;
1579   SpecificBumpPtrAllocator<MapHNode> MapHNodeAllocator;
1580   SpecificBumpPtrAllocator<SequenceHNode> SequenceHNodeAllocator;
1581   document_iterator                   DocIterator;
1582   llvm::BitVector                     BitValuesUsed;
1583   HNode *CurrentNode = nullptr;
1584   bool                                ScalarMatchFound = false;
1585   bool AllowUnknownKeys = false;
1586 };
1587 
1588 ///
1589 /// The Output class is used to generate a yaml document from in-memory structs
1590 /// and vectors.
1591 ///
1592 class Output : public IO {
1593 public:
1594   Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
1595   ~Output() override;
1596 
1597   /// Set whether or not to output optional values which are equal
1598   /// to the default value.  By default, when outputting if you attempt
1599   /// to write a value that is equal to the default, the value gets ignored.
1600   /// Sometimes, it is useful to be able to see these in the resulting YAML
1601   /// anyway.
1602   void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; }
1603 
1604   bool outputting() const override;
1605   bool mapTag(StringRef, bool) override;
1606   void beginMapping() override;
1607   void endMapping() override;
1608   bool preflightKey(const char *key, bool, bool, bool &, void *&) override;
1609   void postflightKey(void *) override;
1610   std::vector<StringRef> keys() override;
1611   void beginFlowMapping() override;
1612   void endFlowMapping() override;
1613   unsigned beginSequence() override;
1614   void endSequence() override;
1615   bool preflightElement(unsigned, void *&) override;
1616   void postflightElement(void *) override;
1617   unsigned beginFlowSequence() override;
1618   bool preflightFlowElement(unsigned, void *&) override;
1619   void postflightFlowElement(void *) override;
1620   void endFlowSequence() override;
1621   void beginEnumScalar() override;
1622   bool matchEnumScalar(const char*, bool) override;
1623   bool matchEnumFallback() override;
1624   void endEnumScalar() override;
1625   bool beginBitSetScalar(bool &) override;
1626   bool bitSetMatch(const char *, bool ) override;
1627   void endBitSetScalar() override;
1628   void scalarString(StringRef &, QuotingType) override;
1629   void blockScalarString(StringRef &) override;
1630   void scalarTag(std::string &) override;
1631   NodeKind getNodeKind() override;
1632   void setError(const Twine &message) override;
1633   bool canElideEmptySequence() override;
1634 
1635   // These are only used by operator<<. They could be private
1636   // if that templated operator could be made a friend.
1637   void beginDocuments();
1638   bool preflightDocument(unsigned);
1639   void postflightDocument();
1640   void endDocuments();
1641 
1642 private:
1643   void output(StringRef s);
1644   void output(StringRef, QuotingType);
1645   void outputUpToEndOfLine(StringRef s);
1646   void newLineCheck(bool EmptySequence = false);
1647   void outputNewLine();
1648   void paddedKey(StringRef key);
1649   void flowKey(StringRef Key);
1650 
1651   enum InState {
1652     inSeqFirstElement,
1653     inSeqOtherElement,
1654     inFlowSeqFirstElement,
1655     inFlowSeqOtherElement,
1656     inMapFirstKey,
1657     inMapOtherKey,
1658     inFlowMapFirstKey,
1659     inFlowMapOtherKey
1660   };
1661 
1662   static bool inSeqAnyElement(InState State);
1663   static bool inFlowSeqAnyElement(InState State);
1664   static bool inMapAnyKey(InState State);
1665   static bool inFlowMapAnyKey(InState State);
1666 
1667   raw_ostream &Out;
1668   int WrapColumn;
1669   SmallVector<InState, 8> StateStack;
1670   int Column = 0;
1671   int ColumnAtFlowStart = 0;
1672   int ColumnAtMapFlowStart = 0;
1673   bool NeedBitValueComma = false;
1674   bool NeedFlowSequenceComma = false;
1675   bool EnumerationMatchFound = false;
1676   bool WriteDefaultValues = false;
1677   StringRef Padding;
1678   StringRef PaddingBeforeContainer;
1679 };
1680 
1681 template <typename T, typename Context>
1682 void IO::processKeyWithDefault(const char *Key, std::optional<T> &Val,
1683                                const std::optional<T> &DefaultValue,
1684                                bool Required, Context &Ctx) {
1685   assert(!DefaultValue && "std::optional<T> shouldn't have a value!");
1686   void *SaveInfo;
1687   bool UseDefault = true;
1688   const bool sameAsDefault = outputting() && !Val;
1689   if (!outputting() && !Val)
1690     Val = T();
1691   if (Val &&
1692       this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) {
1693 
1694     // When reading an std::optional<X> key from a YAML description, we allow
1695     // the special "<none>" value, which can be used to specify that no value
1696     // was requested, i.e. the DefaultValue will be assigned. The DefaultValue
1697     // is usually None.
1698     bool IsNone = false;
1699     if (!outputting())
1700       if (const auto *Node =
1701               dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode()))
1702         // We use rtrim to ignore possible white spaces that might exist when a
1703         // comment is present on the same line.
1704         IsNone = Node->getRawValue().rtrim(' ') == "<none>";
1705 
1706     if (IsNone)
1707       Val = DefaultValue;
1708     else
1709       yamlize(*this, *Val, Required, Ctx);
1710     this->postflightKey(SaveInfo);
1711   } else {
1712     if (UseDefault)
1713       Val = DefaultValue;
1714   }
1715 }
1716 
1717 /// YAML I/O does conversion based on types. But often native data types
1718 /// are just a typedef of built in intergral types (e.g. int).  But the C++
1719 /// type matching system sees through the typedef and all the typedefed types
1720 /// look like a built in type. This will cause the generic YAML I/O conversion
1721 /// to be used. To provide better control over the YAML conversion, you can
1722 /// use this macro instead of typedef.  It will create a class with one field
1723 /// and automatic conversion operators to and from the base type.
1724 /// Based on BOOST_STRONG_TYPEDEF
1725 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type)                                 \
1726     struct _type {                                                             \
1727         _type() = default;                                                     \
1728         _type(const _base v) : value(v) {}                                     \
1729         _type(const _type &v) = default;                                       \
1730         _type &operator=(const _type &rhs) = default;                          \
1731         _type &operator=(const _base &rhs) { value = rhs; return *this; }      \
1732         operator const _base & () const { return value; }                      \
1733         bool operator==(const _type &rhs) const { return value == rhs.value; } \
1734         bool operator==(const _base &rhs) const { return value == rhs; }       \
1735         bool operator<(const _type &rhs) const { return value < rhs.value; }   \
1736         _base value;                                                           \
1737         using BaseType = _base;                                                \
1738     };
1739 
1740 ///
1741 /// Use these types instead of uintXX_t in any mapping to have
1742 /// its yaml output formatted as hexadecimal.
1743 ///
1744 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
1745 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
1746 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
1747 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
1748 
1749 template<>
1750 struct ScalarTraits<Hex8> {
1751   static void output(const Hex8 &, void *, raw_ostream &);
1752   static StringRef input(StringRef, void *, Hex8 &);
1753   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1754 };
1755 
1756 template<>
1757 struct ScalarTraits<Hex16> {
1758   static void output(const Hex16 &, void *, raw_ostream &);
1759   static StringRef input(StringRef, void *, Hex16 &);
1760   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1761 };
1762 
1763 template<>
1764 struct ScalarTraits<Hex32> {
1765   static void output(const Hex32 &, void *, raw_ostream &);
1766   static StringRef input(StringRef, void *, Hex32 &);
1767   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1768 };
1769 
1770 template<>
1771 struct ScalarTraits<Hex64> {
1772   static void output(const Hex64 &, void *, raw_ostream &);
1773   static StringRef input(StringRef, void *, Hex64 &);
1774   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1775 };
1776 
1777 template <> struct ScalarTraits<VersionTuple> {
1778   static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out);
1779   static StringRef input(StringRef, void *, VersionTuple &);
1780   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1781 };
1782 
1783 // Define non-member operator>> so that Input can stream in a document list.
1784 template <typename T>
1785 inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &>
1786 operator>>(Input &yin, T &docList) {
1787   int i = 0;
1788   EmptyContext Ctx;
1789   while ( yin.setCurrentDocument() ) {
1790     yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx);
1791     if ( yin.error() )
1792       return yin;
1793     yin.nextDocument();
1794     ++i;
1795   }
1796   return yin;
1797 }
1798 
1799 // Define non-member operator>> so that Input can stream in a map as a document.
1800 template <typename T>
1801 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &>
1802 operator>>(Input &yin, T &docMap) {
1803   EmptyContext Ctx;
1804   yin.setCurrentDocument();
1805   yamlize(yin, docMap, true, Ctx);
1806   return yin;
1807 }
1808 
1809 // Define non-member operator>> so that Input can stream in a sequence as
1810 // a document.
1811 template <typename T>
1812 inline std::enable_if_t<has_SequenceTraits<T>::value, Input &>
1813 operator>>(Input &yin, T &docSeq) {
1814   EmptyContext Ctx;
1815   if (yin.setCurrentDocument())
1816     yamlize(yin, docSeq, true, Ctx);
1817   return yin;
1818 }
1819 
1820 // Define non-member operator>> so that Input can stream in a block scalar.
1821 template <typename T>
1822 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &>
1823 operator>>(Input &In, T &Val) {
1824   EmptyContext Ctx;
1825   if (In.setCurrentDocument())
1826     yamlize(In, Val, true, Ctx);
1827   return In;
1828 }
1829 
1830 // Define non-member operator>> so that Input can stream in a string map.
1831 template <typename T>
1832 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &>
1833 operator>>(Input &In, T &Val) {
1834   EmptyContext Ctx;
1835   if (In.setCurrentDocument())
1836     yamlize(In, Val, true, Ctx);
1837   return In;
1838 }
1839 
1840 // Define non-member operator>> so that Input can stream in a polymorphic type.
1841 template <typename T>
1842 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &>
1843 operator>>(Input &In, T &Val) {
1844   EmptyContext Ctx;
1845   if (In.setCurrentDocument())
1846     yamlize(In, Val, true, Ctx);
1847   return In;
1848 }
1849 
1850 // Provide better error message about types missing a trait specialization
1851 template <typename T>
1852 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &>
1853 operator>>(Input &yin, T &docSeq) {
1854   char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1855   return yin;
1856 }
1857 
1858 // Define non-member operator<< so that Output can stream out document list.
1859 template <typename T>
1860 inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &>
1861 operator<<(Output &yout, T &docList) {
1862   EmptyContext Ctx;
1863   yout.beginDocuments();
1864   const size_t count = DocumentListTraits<T>::size(yout, docList);
1865   for(size_t i=0; i < count; ++i) {
1866     if ( yout.preflightDocument(i) ) {
1867       yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true,
1868               Ctx);
1869       yout.postflightDocument();
1870     }
1871   }
1872   yout.endDocuments();
1873   return yout;
1874 }
1875 
1876 // Define non-member operator<< so that Output can stream out a map.
1877 template <typename T>
1878 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &>
1879 operator<<(Output &yout, T &map) {
1880   EmptyContext Ctx;
1881   yout.beginDocuments();
1882   if ( yout.preflightDocument(0) ) {
1883     yamlize(yout, map, true, Ctx);
1884     yout.postflightDocument();
1885   }
1886   yout.endDocuments();
1887   return yout;
1888 }
1889 
1890 // Define non-member operator<< so that Output can stream out a sequence.
1891 template <typename T>
1892 inline std::enable_if_t<has_SequenceTraits<T>::value, Output &>
1893 operator<<(Output &yout, T &seq) {
1894   EmptyContext Ctx;
1895   yout.beginDocuments();
1896   if ( yout.preflightDocument(0) ) {
1897     yamlize(yout, seq, true, Ctx);
1898     yout.postflightDocument();
1899   }
1900   yout.endDocuments();
1901   return yout;
1902 }
1903 
1904 // Define non-member operator<< so that Output can stream out a block scalar.
1905 template <typename T>
1906 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &>
1907 operator<<(Output &Out, T &Val) {
1908   EmptyContext Ctx;
1909   Out.beginDocuments();
1910   if (Out.preflightDocument(0)) {
1911     yamlize(Out, Val, true, Ctx);
1912     Out.postflightDocument();
1913   }
1914   Out.endDocuments();
1915   return Out;
1916 }
1917 
1918 // Define non-member operator<< so that Output can stream out a string map.
1919 template <typename T>
1920 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &>
1921 operator<<(Output &Out, T &Val) {
1922   EmptyContext Ctx;
1923   Out.beginDocuments();
1924   if (Out.preflightDocument(0)) {
1925     yamlize(Out, Val, true, Ctx);
1926     Out.postflightDocument();
1927   }
1928   Out.endDocuments();
1929   return Out;
1930 }
1931 
1932 // Define non-member operator<< so that Output can stream out a polymorphic
1933 // type.
1934 template <typename T>
1935 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &>
1936 operator<<(Output &Out, T &Val) {
1937   EmptyContext Ctx;
1938   Out.beginDocuments();
1939   if (Out.preflightDocument(0)) {
1940     // FIXME: The parser does not support explicit documents terminated with a
1941     // plain scalar; the end-marker is included as part of the scalar token.
1942     assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported");
1943     yamlize(Out, Val, true, Ctx);
1944     Out.postflightDocument();
1945   }
1946   Out.endDocuments();
1947   return Out;
1948 }
1949 
1950 // Provide better error message about types missing a trait specialization
1951 template <typename T>
1952 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &>
1953 operator<<(Output &yout, T &seq) {
1954   char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1955   return yout;
1956 }
1957 
1958 template <bool B> struct IsFlowSequenceBase {};
1959 template <> struct IsFlowSequenceBase<true> { static const bool flow = true; };
1960 
1961 template <typename T, typename U = void>
1962 struct IsResizable : std::false_type {};
1963 
1964 template <typename T>
1965 struct IsResizable<T, std::void_t<decltype(std::declval<T>().resize(0))>>
1966     : public std::true_type {};
1967 
1968 template <typename T, bool B> struct IsResizableBase {
1969   using type = typename T::value_type;
1970 
1971   static type &element(IO &io, T &seq, size_t index) {
1972     if (index >= seq.size())
1973       seq.resize(index + 1);
1974     return seq[index];
1975   }
1976 };
1977 
1978 template <typename T> struct IsResizableBase<T, false> {
1979   using type = typename T::value_type;
1980 
1981   static type &element(IO &io, T &seq, size_t index) {
1982     if (index >= seq.size()) {
1983       io.setError(Twine("value sequence extends beyond static size (") +
1984                   Twine(seq.size()) + ")");
1985       return seq[0];
1986     }
1987     return seq[index];
1988   }
1989 };
1990 
1991 template <typename T, bool Flow>
1992 struct SequenceTraitsImpl
1993     : IsFlowSequenceBase<Flow>, IsResizableBase<T, IsResizable<T>::value> {
1994   static size_t size(IO &io, T &seq) { return seq.size(); }
1995 };
1996 
1997 // Simple helper to check an expression can be used as a bool-valued template
1998 // argument.
1999 template <bool> struct CheckIsBool { static const bool value = true; };
2000 
2001 // If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have
2002 // SequenceTraits that do the obvious thing.
2003 template <typename T>
2004 struct SequenceTraits<
2005     std::vector<T>,
2006     std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
2007     : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {};
2008 template <typename T, unsigned N>
2009 struct SequenceTraits<
2010     SmallVector<T, N>,
2011     std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
2012     : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {};
2013 template <typename T>
2014 struct SequenceTraits<
2015     SmallVectorImpl<T>,
2016     std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
2017     : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {};
2018 template <typename T>
2019 struct SequenceTraits<
2020     MutableArrayRef<T>,
2021     std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
2022     : SequenceTraitsImpl<MutableArrayRef<T>, SequenceElementTraits<T>::flow> {};
2023 
2024 // Sequences of fundamental types use flow formatting.
2025 template <typename T>
2026 struct SequenceElementTraits<T, std::enable_if_t<std::is_fundamental_v<T>>> {
2027   static const bool flow = true;
2028 };
2029 
2030 // Sequences of strings use block formatting.
2031 template<> struct SequenceElementTraits<std::string> {
2032   static const bool flow = false;
2033 };
2034 template<> struct SequenceElementTraits<StringRef> {
2035   static const bool flow = false;
2036 };
2037 template<> struct SequenceElementTraits<std::pair<std::string, std::string>> {
2038   static const bool flow = false;
2039 };
2040 
2041 /// Implementation of CustomMappingTraits for std::map<std::string, T>.
2042 template <typename T> struct StdMapStringCustomMappingTraitsImpl {
2043   using map_type = std::map<std::string, T>;
2044 
2045   static void inputOne(IO &io, StringRef key, map_type &v) {
2046     io.mapRequired(key.str().c_str(), v[std::string(key)]);
2047   }
2048 
2049   static void output(IO &io, map_type &v) {
2050     for (auto &p : v)
2051       io.mapRequired(p.first.c_str(), p.second);
2052   }
2053 };
2054 
2055 } // end namespace yaml
2056 } // end namespace llvm
2057 
2058 #define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW)                          \
2059   namespace llvm {                                                             \
2060   namespace yaml {                                                             \
2061   static_assert(                                                               \
2062       !std::is_fundamental_v<TYPE> && !std::is_same_v<TYPE, std::string> &&    \
2063           !std::is_same_v<TYPE, llvm::StringRef>,                              \
2064       "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control");          \
2065   template <> struct SequenceElementTraits<TYPE> {                             \
2066     static const bool flow = FLOW;                                             \
2067   };                                                                           \
2068   }                                                                            \
2069   }
2070 
2071 /// Utility for declaring that a std::vector of a particular type
2072 /// should be considered a YAML sequence.
2073 #define LLVM_YAML_IS_SEQUENCE_VECTOR(type)                                     \
2074   LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false)
2075 
2076 /// Utility for declaring that a std::vector of a particular type
2077 /// should be considered a YAML flow sequence.
2078 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type)                                \
2079   LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true)
2080 
2081 #define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type)                                 \
2082   namespace llvm {                                                             \
2083   namespace yaml {                                                             \
2084   template <> struct MappingTraits<Type> {                                     \
2085     static void mapping(IO &IO, Type &Obj);                                    \
2086   };                                                                           \
2087   }                                                                            \
2088   }
2089 
2090 #define LLVM_YAML_DECLARE_ENUM_TRAITS(Type)                                    \
2091   namespace llvm {                                                             \
2092   namespace yaml {                                                             \
2093   template <> struct ScalarEnumerationTraits<Type> {                           \
2094     static void enumeration(IO &io, Type &Value);                              \
2095   };                                                                           \
2096   }                                                                            \
2097   }
2098 
2099 #define LLVM_YAML_DECLARE_BITSET_TRAITS(Type)                                  \
2100   namespace llvm {                                                             \
2101   namespace yaml {                                                             \
2102   template <> struct ScalarBitSetTraits<Type> {                                \
2103     static void bitset(IO &IO, Type &Options);                                 \
2104   };                                                                           \
2105   }                                                                            \
2106   }
2107 
2108 #define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote)                       \
2109   namespace llvm {                                                             \
2110   namespace yaml {                                                             \
2111   template <> struct ScalarTraits<Type> {                                      \
2112     static void output(const Type &Value, void *ctx, raw_ostream &Out);        \
2113     static StringRef input(StringRef Scalar, void *ctxt, Type &Value);         \
2114     static QuotingType mustQuote(StringRef) { return MustQuote; }              \
2115   };                                                                           \
2116   }                                                                            \
2117   }
2118 
2119 /// Utility for declaring that a std::vector of a particular type
2120 /// should be considered a YAML document list.
2121 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type)                               \
2122   namespace llvm {                                                             \
2123   namespace yaml {                                                             \
2124   template <unsigned N>                                                        \
2125   struct DocumentListTraits<SmallVector<_type, N>>                             \
2126       : public SequenceTraitsImpl<SmallVector<_type, N>, false> {};            \
2127   template <>                                                                  \
2128   struct DocumentListTraits<std::vector<_type>>                                \
2129       : public SequenceTraitsImpl<std::vector<_type>, false> {};               \
2130   }                                                                            \
2131   }
2132 
2133 /// Utility for declaring that std::map<std::string, _type> should be considered
2134 /// a YAML map.
2135 #define LLVM_YAML_IS_STRING_MAP(_type)                                         \
2136   namespace llvm {                                                             \
2137   namespace yaml {                                                             \
2138   template <>                                                                  \
2139   struct CustomMappingTraits<std::map<std::string, _type>>                     \
2140       : public StdMapStringCustomMappingTraitsImpl<_type> {};                  \
2141   }                                                                            \
2142   }
2143 
2144 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)
2145 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32)
2146 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16)
2147 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8)
2148 
2149 #endif // LLVM_SUPPORT_YAMLTRAITS_H
2150