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