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