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