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