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