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.startswith("0o")) 588 return S.size() > 2 && 589 S.drop_front(2).find_first_not_of("01234567") == StringRef::npos; 590 591 if (S.startswith("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.startswith(".") && 602 (S.equals(".") || 603 (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr))) 604 return false; 605 606 if (S.startswith("E") || S.startswith("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 template <typename T, typename Context> 1062 std::enable_if_t<validatedMappingTraits<T, Context>::value, void> 1063 yamlize(IO &io, T &Val, bool, Context &Ctx) { 1064 if (has_FlowTraits<MappingTraits<T>>::value) 1065 io.beginFlowMapping(); 1066 else 1067 io.beginMapping(); 1068 if (io.outputting()) { 1069 std::string Err = MappingTraits<T>::validate(io, Val); 1070 if (!Err.empty()) { 1071 errs() << Err << "\n"; 1072 assert(Err.empty() && "invalid struct trying to be written as yaml"); 1073 } 1074 } 1075 detail::doMapping(io, Val, Ctx); 1076 if (!io.outputting()) { 1077 std::string Err = MappingTraits<T>::validate(io, Val); 1078 if (!Err.empty()) 1079 io.setError(Err); 1080 } 1081 if (has_FlowTraits<MappingTraits<T>>::value) 1082 io.endFlowMapping(); 1083 else 1084 io.endMapping(); 1085 } 1086 1087 template <typename T, typename Context> 1088 std::enable_if_t<!has_MappingEnumInputTraits<T, Context>::value, bool> 1089 yamlizeMappingEnumInput(IO &io, T &Val) { 1090 return false; 1091 } 1092 1093 template <typename T, typename Context> 1094 std::enable_if_t<has_MappingEnumInputTraits<T, Context>::value, bool> 1095 yamlizeMappingEnumInput(IO &io, T &Val) { 1096 if (io.outputting()) 1097 return false; 1098 1099 io.beginEnumScalar(); 1100 MappingTraits<T>::enumInput(io, Val); 1101 bool Matched = !io.matchEnumFallback(); 1102 io.endEnumScalar(); 1103 return Matched; 1104 } 1105 1106 template <typename T, typename Context> 1107 std::enable_if_t<unvalidatedMappingTraits<T, Context>::value, void> 1108 yamlize(IO &io, T &Val, bool, Context &Ctx) { 1109 if (yamlizeMappingEnumInput<T, Context>(io, Val)) 1110 return; 1111 if (has_FlowTraits<MappingTraits<T>>::value) { 1112 io.beginFlowMapping(); 1113 detail::doMapping(io, Val, Ctx); 1114 io.endFlowMapping(); 1115 } else { 1116 io.beginMapping(); 1117 detail::doMapping(io, Val, Ctx); 1118 io.endMapping(); 1119 } 1120 } 1121 1122 template <typename T> 1123 std::enable_if_t<has_CustomMappingTraits<T>::value, void> 1124 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1125 if ( io.outputting() ) { 1126 io.beginMapping(); 1127 CustomMappingTraits<T>::output(io, Val); 1128 io.endMapping(); 1129 } else { 1130 io.beginMapping(); 1131 for (StringRef key : io.keys()) 1132 CustomMappingTraits<T>::inputOne(io, key, Val); 1133 io.endMapping(); 1134 } 1135 } 1136 1137 template <typename T> 1138 std::enable_if_t<has_PolymorphicTraits<T>::value, void> 1139 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1140 switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val) 1141 : io.getNodeKind()) { 1142 case NodeKind::Scalar: 1143 return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx); 1144 case NodeKind::Map: 1145 return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx); 1146 case NodeKind::Sequence: 1147 return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx); 1148 } 1149 } 1150 1151 template <typename T> 1152 std::enable_if_t<missingTraits<T, EmptyContext>::value, void> 1153 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1154 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1155 } 1156 1157 template <typename T, typename Context> 1158 std::enable_if_t<has_SequenceTraits<T>::value, void> 1159 yamlize(IO &io, T &Seq, bool, Context &Ctx) { 1160 if ( has_FlowTraits< SequenceTraits<T>>::value ) { 1161 unsigned incnt = io.beginFlowSequence(); 1162 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 1163 for(unsigned i=0; i < count; ++i) { 1164 void *SaveInfo; 1165 if ( io.preflightFlowElement(i, SaveInfo) ) { 1166 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); 1167 io.postflightFlowElement(SaveInfo); 1168 } 1169 } 1170 io.endFlowSequence(); 1171 } 1172 else { 1173 unsigned incnt = io.beginSequence(); 1174 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 1175 for(unsigned i=0; i < count; ++i) { 1176 void *SaveInfo; 1177 if ( io.preflightElement(i, SaveInfo) ) { 1178 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); 1179 io.postflightElement(SaveInfo); 1180 } 1181 } 1182 io.endSequence(); 1183 } 1184 } 1185 1186 template<> 1187 struct ScalarTraits<bool> { 1188 static void output(const bool &, void* , raw_ostream &); 1189 static StringRef input(StringRef, void *, bool &); 1190 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1191 }; 1192 1193 template<> 1194 struct ScalarTraits<StringRef> { 1195 static void output(const StringRef &, void *, raw_ostream &); 1196 static StringRef input(StringRef, void *, StringRef &); 1197 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 1198 }; 1199 1200 template<> 1201 struct ScalarTraits<std::string> { 1202 static void output(const std::string &, void *, raw_ostream &); 1203 static StringRef input(StringRef, void *, std::string &); 1204 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 1205 }; 1206 1207 template<> 1208 struct ScalarTraits<uint8_t> { 1209 static void output(const uint8_t &, void *, raw_ostream &); 1210 static StringRef input(StringRef, void *, uint8_t &); 1211 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1212 }; 1213 1214 template<> 1215 struct ScalarTraits<uint16_t> { 1216 static void output(const uint16_t &, void *, raw_ostream &); 1217 static StringRef input(StringRef, void *, uint16_t &); 1218 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1219 }; 1220 1221 template<> 1222 struct ScalarTraits<uint32_t> { 1223 static void output(const uint32_t &, void *, raw_ostream &); 1224 static StringRef input(StringRef, void *, uint32_t &); 1225 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1226 }; 1227 1228 template<> 1229 struct ScalarTraits<uint64_t> { 1230 static void output(const uint64_t &, void *, raw_ostream &); 1231 static StringRef input(StringRef, void *, uint64_t &); 1232 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1233 }; 1234 1235 template<> 1236 struct ScalarTraits<int8_t> { 1237 static void output(const int8_t &, void *, raw_ostream &); 1238 static StringRef input(StringRef, void *, int8_t &); 1239 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1240 }; 1241 1242 template<> 1243 struct ScalarTraits<int16_t> { 1244 static void output(const int16_t &, void *, raw_ostream &); 1245 static StringRef input(StringRef, void *, int16_t &); 1246 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1247 }; 1248 1249 template<> 1250 struct ScalarTraits<int32_t> { 1251 static void output(const int32_t &, void *, raw_ostream &); 1252 static StringRef input(StringRef, void *, int32_t &); 1253 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1254 }; 1255 1256 template<> 1257 struct ScalarTraits<int64_t> { 1258 static void output(const int64_t &, void *, raw_ostream &); 1259 static StringRef input(StringRef, void *, int64_t &); 1260 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1261 }; 1262 1263 template<> 1264 struct ScalarTraits<float> { 1265 static void output(const float &, void *, raw_ostream &); 1266 static StringRef input(StringRef, void *, float &); 1267 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1268 }; 1269 1270 template<> 1271 struct ScalarTraits<double> { 1272 static void output(const double &, void *, raw_ostream &); 1273 static StringRef input(StringRef, void *, double &); 1274 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1275 }; 1276 1277 // For endian types, we use existing scalar Traits class for the underlying 1278 // type. This way endian aware types are supported whenever the traits are 1279 // defined for the underlying type. 1280 template <typename value_type, support::endianness endian, size_t alignment> 1281 struct ScalarTraits<support::detail::packed_endian_specific_integral< 1282 value_type, endian, alignment>, 1283 std::enable_if_t<has_ScalarTraits<value_type>::value>> { 1284 using endian_type = 1285 support::detail::packed_endian_specific_integral<value_type, endian, 1286 alignment>; 1287 1288 static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) { 1289 ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); 1290 } 1291 1292 static StringRef input(StringRef Str, void *Ctx, endian_type &E) { 1293 value_type V; 1294 auto R = ScalarTraits<value_type>::input(Str, Ctx, V); 1295 E = static_cast<endian_type>(V); 1296 return R; 1297 } 1298 1299 static QuotingType mustQuote(StringRef Str) { 1300 return ScalarTraits<value_type>::mustQuote(Str); 1301 } 1302 }; 1303 1304 template <typename value_type, support::endianness endian, size_t alignment> 1305 struct ScalarEnumerationTraits< 1306 support::detail::packed_endian_specific_integral<value_type, endian, 1307 alignment>, 1308 std::enable_if_t<has_ScalarEnumerationTraits<value_type>::value>> { 1309 using endian_type = 1310 support::detail::packed_endian_specific_integral<value_type, endian, 1311 alignment>; 1312 1313 static void enumeration(IO &io, endian_type &E) { 1314 value_type V = E; 1315 ScalarEnumerationTraits<value_type>::enumeration(io, V); 1316 E = V; 1317 } 1318 }; 1319 1320 template <typename value_type, support::endianness endian, size_t alignment> 1321 struct ScalarBitSetTraits< 1322 support::detail::packed_endian_specific_integral<value_type, endian, 1323 alignment>, 1324 std::enable_if_t<has_ScalarBitSetTraits<value_type>::value>> { 1325 using endian_type = 1326 support::detail::packed_endian_specific_integral<value_type, endian, 1327 alignment>; 1328 static void bitset(IO &io, endian_type &E) { 1329 value_type V = E; 1330 ScalarBitSetTraits<value_type>::bitset(io, V); 1331 E = V; 1332 } 1333 }; 1334 1335 // Utility for use within MappingTraits<>::mapping() method 1336 // to [de]normalize an object for use with YAML conversion. 1337 template <typename TNorm, typename TFinal> 1338 struct MappingNormalization { 1339 MappingNormalization(IO &i_o, TFinal &Obj) 1340 : io(i_o), BufPtr(nullptr), Result(Obj) { 1341 if ( io.outputting() ) { 1342 BufPtr = new (&Buffer) TNorm(io, Obj); 1343 } 1344 else { 1345 BufPtr = new (&Buffer) TNorm(io); 1346 } 1347 } 1348 1349 ~MappingNormalization() { 1350 if ( ! io.outputting() ) { 1351 Result = BufPtr->denormalize(io); 1352 } 1353 BufPtr->~TNorm(); 1354 } 1355 1356 TNorm* operator->() { return BufPtr; } 1357 1358 private: 1359 using Storage = AlignedCharArrayUnion<TNorm>; 1360 1361 Storage Buffer; 1362 IO &io; 1363 TNorm *BufPtr; 1364 TFinal &Result; 1365 }; 1366 1367 // Utility for use within MappingTraits<>::mapping() method 1368 // to [de]normalize an object for use with YAML conversion. 1369 template <typename TNorm, typename TFinal> 1370 struct MappingNormalizationHeap { 1371 MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator) 1372 : io(i_o), Result(Obj) { 1373 if ( io.outputting() ) { 1374 BufPtr = new (&Buffer) TNorm(io, Obj); 1375 } 1376 else if (allocator) { 1377 BufPtr = allocator->Allocate<TNorm>(); 1378 new (BufPtr) TNorm(io); 1379 } else { 1380 BufPtr = new TNorm(io); 1381 } 1382 } 1383 1384 ~MappingNormalizationHeap() { 1385 if ( io.outputting() ) { 1386 BufPtr->~TNorm(); 1387 } 1388 else { 1389 Result = BufPtr->denormalize(io); 1390 } 1391 } 1392 1393 TNorm* operator->() { return BufPtr; } 1394 1395 private: 1396 using Storage = AlignedCharArrayUnion<TNorm>; 1397 1398 Storage Buffer; 1399 IO &io; 1400 TNorm *BufPtr = nullptr; 1401 TFinal &Result; 1402 }; 1403 1404 /// 1405 /// The Input class is used to parse a yaml document into in-memory structs 1406 /// and vectors. 1407 /// 1408 /// It works by using YAMLParser to do a syntax parse of the entire yaml 1409 /// document, then the Input class builds a graph of HNodes which wraps 1410 /// each yaml Node. The extra layer is buffering. The low level yaml 1411 /// parser only lets you look at each node once. The buffering layer lets 1412 /// you search and interate multiple times. This is necessary because 1413 /// the mapRequired() method calls may not be in the same order 1414 /// as the keys in the document. 1415 /// 1416 class Input : public IO { 1417 public: 1418 // Construct a yaml Input object from a StringRef and optional 1419 // user-data. The DiagHandler can be specified to provide 1420 // alternative error reporting. 1421 Input(StringRef InputContent, 1422 void *Ctxt = nullptr, 1423 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 1424 void *DiagHandlerCtxt = nullptr); 1425 Input(MemoryBufferRef Input, 1426 void *Ctxt = nullptr, 1427 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 1428 void *DiagHandlerCtxt = nullptr); 1429 ~Input() override; 1430 1431 // Check if there was an syntax or semantic error during parsing. 1432 std::error_code error(); 1433 1434 private: 1435 bool outputting() const override; 1436 bool mapTag(StringRef, bool) override; 1437 void beginMapping() override; 1438 void endMapping() override; 1439 bool preflightKey(const char *, bool, bool, bool &, void *&) override; 1440 void postflightKey(void *) override; 1441 std::vector<StringRef> keys() override; 1442 void beginFlowMapping() override; 1443 void endFlowMapping() override; 1444 unsigned beginSequence() override; 1445 void endSequence() override; 1446 bool preflightElement(unsigned index, void *&) override; 1447 void postflightElement(void *) override; 1448 unsigned beginFlowSequence() override; 1449 bool preflightFlowElement(unsigned , void *&) override; 1450 void postflightFlowElement(void *) override; 1451 void endFlowSequence() override; 1452 void beginEnumScalar() override; 1453 bool matchEnumScalar(const char*, bool) override; 1454 bool matchEnumFallback() override; 1455 void endEnumScalar() override; 1456 bool beginBitSetScalar(bool &) override; 1457 bool bitSetMatch(const char *, bool ) override; 1458 void endBitSetScalar() override; 1459 void scalarString(StringRef &, QuotingType) override; 1460 void blockScalarString(StringRef &) override; 1461 void scalarTag(std::string &) override; 1462 NodeKind getNodeKind() override; 1463 void setError(const Twine &message) override; 1464 bool canElideEmptySequence() override; 1465 1466 class HNode { 1467 virtual void anchor(); 1468 1469 public: 1470 HNode(Node *n) : _node(n) { } 1471 virtual ~HNode() = default; 1472 1473 static bool classof(const HNode *) { return true; } 1474 1475 Node *_node; 1476 }; 1477 1478 class EmptyHNode : public HNode { 1479 void anchor() override; 1480 1481 public: 1482 EmptyHNode(Node *n) : HNode(n) { } 1483 1484 static bool classof(const HNode *n) { return NullNode::classof(n->_node); } 1485 1486 static bool classof(const EmptyHNode *) { return true; } 1487 }; 1488 1489 class ScalarHNode : public HNode { 1490 void anchor() override; 1491 1492 public: 1493 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } 1494 1495 StringRef value() const { return _value; } 1496 1497 static bool classof(const HNode *n) { 1498 return ScalarNode::classof(n->_node) || 1499 BlockScalarNode::classof(n->_node); 1500 } 1501 1502 static bool classof(const ScalarHNode *) { return true; } 1503 1504 protected: 1505 StringRef _value; 1506 }; 1507 1508 class MapHNode : public HNode { 1509 void anchor() override; 1510 1511 public: 1512 MapHNode(Node *n) : HNode(n) { } 1513 1514 static bool classof(const HNode *n) { 1515 return MappingNode::classof(n->_node); 1516 } 1517 1518 static bool classof(const MapHNode *) { return true; } 1519 1520 using NameToNodeAndLoc = 1521 StringMap<std::pair<std::unique_ptr<HNode>, SMRange>>; 1522 1523 NameToNodeAndLoc Mapping; 1524 SmallVector<std::string, 6> ValidKeys; 1525 }; 1526 1527 class SequenceHNode : public HNode { 1528 void anchor() override; 1529 1530 public: 1531 SequenceHNode(Node *n) : HNode(n) { } 1532 1533 static bool classof(const HNode *n) { 1534 return SequenceNode::classof(n->_node); 1535 } 1536 1537 static bool classof(const SequenceHNode *) { return true; } 1538 1539 std::vector<std::unique_ptr<HNode>> Entries; 1540 }; 1541 1542 std::unique_ptr<Input::HNode> createHNodes(Node *node); 1543 void setError(HNode *hnode, const Twine &message); 1544 void setError(Node *node, const Twine &message); 1545 void setError(const SMRange &Range, const Twine &message); 1546 1547 void reportWarning(HNode *hnode, const Twine &message); 1548 void reportWarning(Node *hnode, const Twine &message); 1549 void reportWarning(const SMRange &Range, const Twine &message); 1550 1551 public: 1552 // These are only used by operator>>. They could be private 1553 // if those templated things could be made friends. 1554 bool setCurrentDocument(); 1555 bool nextDocument(); 1556 1557 /// Returns the current node that's being parsed by the YAML Parser. 1558 const Node *getCurrentNode() const; 1559 1560 void setAllowUnknownKeys(bool Allow) override; 1561 1562 private: 1563 SourceMgr SrcMgr; // must be before Strm 1564 std::unique_ptr<llvm::yaml::Stream> Strm; 1565 std::unique_ptr<HNode> TopNode; 1566 std::error_code EC; 1567 BumpPtrAllocator StringAllocator; 1568 document_iterator DocIterator; 1569 llvm::BitVector BitValuesUsed; 1570 HNode *CurrentNode = nullptr; 1571 bool ScalarMatchFound = false; 1572 bool AllowUnknownKeys = false; 1573 }; 1574 1575 /// 1576 /// The Output class is used to generate a yaml document from in-memory structs 1577 /// and vectors. 1578 /// 1579 class Output : public IO { 1580 public: 1581 Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); 1582 ~Output() override; 1583 1584 /// Set whether or not to output optional values which are equal 1585 /// to the default value. By default, when outputting if you attempt 1586 /// to write a value that is equal to the default, the value gets ignored. 1587 /// Sometimes, it is useful to be able to see these in the resulting YAML 1588 /// anyway. 1589 void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } 1590 1591 bool outputting() const override; 1592 bool mapTag(StringRef, bool) override; 1593 void beginMapping() override; 1594 void endMapping() override; 1595 bool preflightKey(const char *key, bool, bool, bool &, void *&) override; 1596 void postflightKey(void *) override; 1597 std::vector<StringRef> keys() override; 1598 void beginFlowMapping() override; 1599 void endFlowMapping() override; 1600 unsigned beginSequence() override; 1601 void endSequence() override; 1602 bool preflightElement(unsigned, void *&) override; 1603 void postflightElement(void *) override; 1604 unsigned beginFlowSequence() override; 1605 bool preflightFlowElement(unsigned, void *&) override; 1606 void postflightFlowElement(void *) override; 1607 void endFlowSequence() override; 1608 void beginEnumScalar() override; 1609 bool matchEnumScalar(const char*, bool) override; 1610 bool matchEnumFallback() override; 1611 void endEnumScalar() override; 1612 bool beginBitSetScalar(bool &) override; 1613 bool bitSetMatch(const char *, bool ) override; 1614 void endBitSetScalar() override; 1615 void scalarString(StringRef &, QuotingType) override; 1616 void blockScalarString(StringRef &) override; 1617 void scalarTag(std::string &) override; 1618 NodeKind getNodeKind() override; 1619 void setError(const Twine &message) override; 1620 bool canElideEmptySequence() override; 1621 1622 // These are only used by operator<<. They could be private 1623 // if that templated operator could be made a friend. 1624 void beginDocuments(); 1625 bool preflightDocument(unsigned); 1626 void postflightDocument(); 1627 void endDocuments(); 1628 1629 private: 1630 void output(StringRef s); 1631 void outputUpToEndOfLine(StringRef s); 1632 void newLineCheck(bool EmptySequence = false); 1633 void outputNewLine(); 1634 void paddedKey(StringRef key); 1635 void flowKey(StringRef Key); 1636 1637 enum InState { 1638 inSeqFirstElement, 1639 inSeqOtherElement, 1640 inFlowSeqFirstElement, 1641 inFlowSeqOtherElement, 1642 inMapFirstKey, 1643 inMapOtherKey, 1644 inFlowMapFirstKey, 1645 inFlowMapOtherKey 1646 }; 1647 1648 static bool inSeqAnyElement(InState State); 1649 static bool inFlowSeqAnyElement(InState State); 1650 static bool inMapAnyKey(InState State); 1651 static bool inFlowMapAnyKey(InState State); 1652 1653 raw_ostream &Out; 1654 int WrapColumn; 1655 SmallVector<InState, 8> StateStack; 1656 int Column = 0; 1657 int ColumnAtFlowStart = 0; 1658 int ColumnAtMapFlowStart = 0; 1659 bool NeedBitValueComma = false; 1660 bool NeedFlowSequenceComma = false; 1661 bool EnumerationMatchFound = false; 1662 bool WriteDefaultValues = false; 1663 StringRef Padding; 1664 StringRef PaddingBeforeContainer; 1665 }; 1666 1667 template <typename T, typename Context> 1668 void IO::processKeyWithDefault(const char *Key, std::optional<T> &Val, 1669 const std::optional<T> &DefaultValue, 1670 bool Required, Context &Ctx) { 1671 assert(!DefaultValue && "std::optional<T> shouldn't have a value!"); 1672 void *SaveInfo; 1673 bool UseDefault = true; 1674 const bool sameAsDefault = outputting() && !Val; 1675 if (!outputting() && !Val) 1676 Val = T(); 1677 if (Val && 1678 this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) { 1679 1680 // When reading an std::optional<X> key from a YAML description, we allow 1681 // the special "<none>" value, which can be used to specify that no value 1682 // was requested, i.e. the DefaultValue will be assigned. The DefaultValue 1683 // is usually None. 1684 bool IsNone = false; 1685 if (!outputting()) 1686 if (const auto *Node = 1687 dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode())) 1688 // We use rtrim to ignore possible white spaces that might exist when a 1689 // comment is present on the same line. 1690 IsNone = Node->getRawValue().rtrim(' ') == "<none>"; 1691 1692 if (IsNone) 1693 Val = DefaultValue; 1694 else 1695 yamlize(*this, *Val, Required, Ctx); 1696 this->postflightKey(SaveInfo); 1697 } else { 1698 if (UseDefault) 1699 Val = DefaultValue; 1700 } 1701 } 1702 1703 /// YAML I/O does conversion based on types. But often native data types 1704 /// are just a typedef of built in intergral types (e.g. int). But the C++ 1705 /// type matching system sees through the typedef and all the typedefed types 1706 /// look like a built in type. This will cause the generic YAML I/O conversion 1707 /// to be used. To provide better control over the YAML conversion, you can 1708 /// use this macro instead of typedef. It will create a class with one field 1709 /// and automatic conversion operators to and from the base type. 1710 /// Based on BOOST_STRONG_TYPEDEF 1711 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 1712 struct _type { \ 1713 _type() = default; \ 1714 _type(const _base v) : value(v) {} \ 1715 _type(const _type &v) = default; \ 1716 _type &operator=(const _type &rhs) = default; \ 1717 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 1718 operator const _base & () const { return value; } \ 1719 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 1720 bool operator==(const _base &rhs) const { return value == rhs; } \ 1721 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 1722 _base value; \ 1723 using BaseType = _base; \ 1724 }; 1725 1726 /// 1727 /// Use these types instead of uintXX_t in any mapping to have 1728 /// its yaml output formatted as hexadecimal. 1729 /// 1730 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1731 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1732 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1733 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1734 1735 template<> 1736 struct ScalarTraits<Hex8> { 1737 static void output(const Hex8 &, void *, raw_ostream &); 1738 static StringRef input(StringRef, void *, Hex8 &); 1739 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1740 }; 1741 1742 template<> 1743 struct ScalarTraits<Hex16> { 1744 static void output(const Hex16 &, void *, raw_ostream &); 1745 static StringRef input(StringRef, void *, Hex16 &); 1746 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1747 }; 1748 1749 template<> 1750 struct ScalarTraits<Hex32> { 1751 static void output(const Hex32 &, void *, raw_ostream &); 1752 static StringRef input(StringRef, void *, Hex32 &); 1753 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1754 }; 1755 1756 template<> 1757 struct ScalarTraits<Hex64> { 1758 static void output(const Hex64 &, void *, raw_ostream &); 1759 static StringRef input(StringRef, void *, Hex64 &); 1760 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1761 }; 1762 1763 template <> struct ScalarTraits<VersionTuple> { 1764 static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out); 1765 static StringRef input(StringRef, void *, VersionTuple &); 1766 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1767 }; 1768 1769 // Define non-member operator>> so that Input can stream in a document list. 1770 template <typename T> 1771 inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &> 1772 operator>>(Input &yin, T &docList) { 1773 int i = 0; 1774 EmptyContext Ctx; 1775 while ( yin.setCurrentDocument() ) { 1776 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); 1777 if ( yin.error() ) 1778 return yin; 1779 yin.nextDocument(); 1780 ++i; 1781 } 1782 return yin; 1783 } 1784 1785 // Define non-member operator>> so that Input can stream in a map as a document. 1786 template <typename T> 1787 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &> 1788 operator>>(Input &yin, T &docMap) { 1789 EmptyContext Ctx; 1790 yin.setCurrentDocument(); 1791 yamlize(yin, docMap, true, Ctx); 1792 return yin; 1793 } 1794 1795 // Define non-member operator>> so that Input can stream in a sequence as 1796 // a document. 1797 template <typename T> 1798 inline std::enable_if_t<has_SequenceTraits<T>::value, Input &> 1799 operator>>(Input &yin, T &docSeq) { 1800 EmptyContext Ctx; 1801 if (yin.setCurrentDocument()) 1802 yamlize(yin, docSeq, true, Ctx); 1803 return yin; 1804 } 1805 1806 // Define non-member operator>> so that Input can stream in a block scalar. 1807 template <typename T> 1808 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &> 1809 operator>>(Input &In, T &Val) { 1810 EmptyContext Ctx; 1811 if (In.setCurrentDocument()) 1812 yamlize(In, Val, true, Ctx); 1813 return In; 1814 } 1815 1816 // Define non-member operator>> so that Input can stream in a string map. 1817 template <typename T> 1818 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &> 1819 operator>>(Input &In, T &Val) { 1820 EmptyContext Ctx; 1821 if (In.setCurrentDocument()) 1822 yamlize(In, Val, true, Ctx); 1823 return In; 1824 } 1825 1826 // Define non-member operator>> so that Input can stream in a polymorphic type. 1827 template <typename T> 1828 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &> 1829 operator>>(Input &In, T &Val) { 1830 EmptyContext Ctx; 1831 if (In.setCurrentDocument()) 1832 yamlize(In, Val, true, Ctx); 1833 return In; 1834 } 1835 1836 // Provide better error message about types missing a trait specialization 1837 template <typename T> 1838 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &> 1839 operator>>(Input &yin, T &docSeq) { 1840 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1841 return yin; 1842 } 1843 1844 // Define non-member operator<< so that Output can stream out document list. 1845 template <typename T> 1846 inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &> 1847 operator<<(Output &yout, T &docList) { 1848 EmptyContext Ctx; 1849 yout.beginDocuments(); 1850 const size_t count = DocumentListTraits<T>::size(yout, docList); 1851 for(size_t i=0; i < count; ++i) { 1852 if ( yout.preflightDocument(i) ) { 1853 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, 1854 Ctx); 1855 yout.postflightDocument(); 1856 } 1857 } 1858 yout.endDocuments(); 1859 return yout; 1860 } 1861 1862 // Define non-member operator<< so that Output can stream out a map. 1863 template <typename T> 1864 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &> 1865 operator<<(Output &yout, T &map) { 1866 EmptyContext Ctx; 1867 yout.beginDocuments(); 1868 if ( yout.preflightDocument(0) ) { 1869 yamlize(yout, map, true, Ctx); 1870 yout.postflightDocument(); 1871 } 1872 yout.endDocuments(); 1873 return yout; 1874 } 1875 1876 // Define non-member operator<< so that Output can stream out a sequence. 1877 template <typename T> 1878 inline std::enable_if_t<has_SequenceTraits<T>::value, Output &> 1879 operator<<(Output &yout, T &seq) { 1880 EmptyContext Ctx; 1881 yout.beginDocuments(); 1882 if ( yout.preflightDocument(0) ) { 1883 yamlize(yout, seq, true, Ctx); 1884 yout.postflightDocument(); 1885 } 1886 yout.endDocuments(); 1887 return yout; 1888 } 1889 1890 // Define non-member operator<< so that Output can stream out a block scalar. 1891 template <typename T> 1892 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &> 1893 operator<<(Output &Out, T &Val) { 1894 EmptyContext Ctx; 1895 Out.beginDocuments(); 1896 if (Out.preflightDocument(0)) { 1897 yamlize(Out, Val, true, Ctx); 1898 Out.postflightDocument(); 1899 } 1900 Out.endDocuments(); 1901 return Out; 1902 } 1903 1904 // Define non-member operator<< so that Output can stream out a string map. 1905 template <typename T> 1906 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &> 1907 operator<<(Output &Out, T &Val) { 1908 EmptyContext Ctx; 1909 Out.beginDocuments(); 1910 if (Out.preflightDocument(0)) { 1911 yamlize(Out, Val, true, Ctx); 1912 Out.postflightDocument(); 1913 } 1914 Out.endDocuments(); 1915 return Out; 1916 } 1917 1918 // Define non-member operator<< so that Output can stream out a polymorphic 1919 // type. 1920 template <typename T> 1921 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &> 1922 operator<<(Output &Out, T &Val) { 1923 EmptyContext Ctx; 1924 Out.beginDocuments(); 1925 if (Out.preflightDocument(0)) { 1926 // FIXME: The parser does not support explicit documents terminated with a 1927 // plain scalar; the end-marker is included as part of the scalar token. 1928 assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported"); 1929 yamlize(Out, Val, true, Ctx); 1930 Out.postflightDocument(); 1931 } 1932 Out.endDocuments(); 1933 return Out; 1934 } 1935 1936 // Provide better error message about types missing a trait specialization 1937 template <typename T> 1938 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &> 1939 operator<<(Output &yout, T &seq) { 1940 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1941 return yout; 1942 } 1943 1944 template <bool B> struct IsFlowSequenceBase {}; 1945 template <> struct IsFlowSequenceBase<true> { static const bool flow = true; }; 1946 1947 template <typename T, typename U = void> 1948 struct IsResizable : std::false_type {}; 1949 1950 template <typename T> 1951 struct IsResizable<T, std::void_t<decltype(std::declval<T>().resize(0))>> 1952 : public std::true_type {}; 1953 1954 template <typename T, bool B> struct IsResizableBase { 1955 using type = typename T::value_type; 1956 1957 static type &element(IO &io, T &seq, size_t index) { 1958 if (index >= seq.size()) 1959 seq.resize(index + 1); 1960 return seq[index]; 1961 } 1962 }; 1963 1964 template <typename T> struct IsResizableBase<T, false> { 1965 using type = typename T::value_type; 1966 1967 static type &element(IO &io, T &seq, size_t index) { 1968 if (index >= seq.size()) { 1969 io.setError(Twine("value sequence extends beyond static size (") + 1970 Twine(seq.size()) + ")"); 1971 return seq[0]; 1972 } 1973 return seq[index]; 1974 } 1975 }; 1976 1977 template <typename T, bool Flow> 1978 struct SequenceTraitsImpl 1979 : IsFlowSequenceBase<Flow>, IsResizableBase<T, IsResizable<T>::value> { 1980 static size_t size(IO &io, T &seq) { return seq.size(); } 1981 }; 1982 1983 // Simple helper to check an expression can be used as a bool-valued template 1984 // argument. 1985 template <bool> struct CheckIsBool { static const bool value = true; }; 1986 1987 // If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have 1988 // SequenceTraits that do the obvious thing. 1989 template <typename T> 1990 struct SequenceTraits< 1991 std::vector<T>, 1992 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 1993 : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {}; 1994 template <typename T, unsigned N> 1995 struct SequenceTraits< 1996 SmallVector<T, N>, 1997 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 1998 : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {}; 1999 template <typename T> 2000 struct SequenceTraits< 2001 SmallVectorImpl<T>, 2002 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 2003 : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {}; 2004 template <typename T> 2005 struct SequenceTraits< 2006 MutableArrayRef<T>, 2007 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 2008 : SequenceTraitsImpl<MutableArrayRef<T>, SequenceElementTraits<T>::flow> {}; 2009 2010 // Sequences of fundamental types use flow formatting. 2011 template <typename T> 2012 struct SequenceElementTraits<T, std::enable_if_t<std::is_fundamental_v<T>>> { 2013 static const bool flow = true; 2014 }; 2015 2016 // Sequences of strings use block formatting. 2017 template<> struct SequenceElementTraits<std::string> { 2018 static const bool flow = false; 2019 }; 2020 template<> struct SequenceElementTraits<StringRef> { 2021 static const bool flow = false; 2022 }; 2023 template<> struct SequenceElementTraits<std::pair<std::string, std::string>> { 2024 static const bool flow = false; 2025 }; 2026 2027 /// Implementation of CustomMappingTraits for std::map<std::string, T>. 2028 template <typename T> struct StdMapStringCustomMappingTraitsImpl { 2029 using map_type = std::map<std::string, T>; 2030 2031 static void inputOne(IO &io, StringRef key, map_type &v) { 2032 io.mapRequired(key.str().c_str(), v[std::string(key)]); 2033 } 2034 2035 static void output(IO &io, map_type &v) { 2036 for (auto &p : v) 2037 io.mapRequired(p.first.c_str(), p.second); 2038 } 2039 }; 2040 2041 } // end namespace yaml 2042 } // end namespace llvm 2043 2044 #define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW) \ 2045 namespace llvm { \ 2046 namespace yaml { \ 2047 static_assert( \ 2048 !std::is_fundamental_v<TYPE> && !std::is_same_v<TYPE, std::string> && \ 2049 !std::is_same_v<TYPE, llvm::StringRef>, \ 2050 "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \ 2051 template <> struct SequenceElementTraits<TYPE> { \ 2052 static const bool flow = FLOW; \ 2053 }; \ 2054 } \ 2055 } 2056 2057 /// Utility for declaring that a std::vector of a particular type 2058 /// should be considered a YAML sequence. 2059 #define LLVM_YAML_IS_SEQUENCE_VECTOR(type) \ 2060 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false) 2061 2062 /// Utility for declaring that a std::vector of a particular type 2063 /// should be considered a YAML flow sequence. 2064 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type) \ 2065 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true) 2066 2067 #define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \ 2068 namespace llvm { \ 2069 namespace yaml { \ 2070 template <> struct MappingTraits<Type> { \ 2071 static void mapping(IO &IO, Type &Obj); \ 2072 }; \ 2073 } \ 2074 } 2075 2076 #define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \ 2077 namespace llvm { \ 2078 namespace yaml { \ 2079 template <> struct ScalarEnumerationTraits<Type> { \ 2080 static void enumeration(IO &io, Type &Value); \ 2081 }; \ 2082 } \ 2083 } 2084 2085 #define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \ 2086 namespace llvm { \ 2087 namespace yaml { \ 2088 template <> struct ScalarBitSetTraits<Type> { \ 2089 static void bitset(IO &IO, Type &Options); \ 2090 }; \ 2091 } \ 2092 } 2093 2094 #define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \ 2095 namespace llvm { \ 2096 namespace yaml { \ 2097 template <> struct ScalarTraits<Type> { \ 2098 static void output(const Type &Value, void *ctx, raw_ostream &Out); \ 2099 static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ 2100 static QuotingType mustQuote(StringRef) { return MustQuote; } \ 2101 }; \ 2102 } \ 2103 } 2104 2105 /// Utility for declaring that a std::vector of a particular type 2106 /// should be considered a YAML document list. 2107 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 2108 namespace llvm { \ 2109 namespace yaml { \ 2110 template <unsigned N> \ 2111 struct DocumentListTraits<SmallVector<_type, N>> \ 2112 : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \ 2113 template <> \ 2114 struct DocumentListTraits<std::vector<_type>> \ 2115 : public SequenceTraitsImpl<std::vector<_type>, false> {}; \ 2116 } \ 2117 } 2118 2119 /// Utility for declaring that std::map<std::string, _type> should be considered 2120 /// a YAML map. 2121 #define LLVM_YAML_IS_STRING_MAP(_type) \ 2122 namespace llvm { \ 2123 namespace yaml { \ 2124 template <> \ 2125 struct CustomMappingTraits<std::map<std::string, _type>> \ 2126 : public StdMapStringCustomMappingTraitsImpl<_type> {}; \ 2127 } \ 2128 } 2129 2130 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64) 2131 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32) 2132 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16) 2133 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8) 2134 2135 #endif // LLVM_SUPPORT_YAMLTRAITS_H 2136