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/BitVector.h" 13 #include "llvm/ADT/Optional.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 <string> 31 #include <system_error> 32 #include <type_traits> 33 #include <vector> 34 35 namespace llvm { 36 37 class VersionTuple; 38 39 namespace yaml { 40 41 enum class NodeKind : uint8_t { 42 Scalar, 43 Map, 44 Sequence, 45 }; 46 47 struct EmptyContext {}; 48 49 /// This class should be specialized by any type that needs to be converted 50 /// to/from a YAML mapping. For example: 51 /// 52 /// struct MappingTraits<MyStruct> { 53 /// static void mapping(IO &io, MyStruct &s) { 54 /// io.mapRequired("name", s.name); 55 /// io.mapRequired("size", s.size); 56 /// io.mapOptional("age", s.age); 57 /// } 58 /// }; 59 template<class T> 60 struct MappingTraits { 61 // Must provide: 62 // static void mapping(IO &io, T &fields); 63 // Optionally may provide: 64 // static std::string validate(IO &io, T &fields); 65 // static void enumInput(IO &io, T &value); 66 // 67 // The optional flow flag will cause generated YAML to use a flow mapping 68 // (e.g. { a: 0, b: 1 }): 69 // static const bool flow = true; 70 }; 71 72 /// This class is similar to MappingTraits<T> but allows you to pass in 73 /// additional context for each map operation. For example: 74 /// 75 /// struct MappingContextTraits<MyStruct, MyContext> { 76 /// static void mapping(IO &io, MyStruct &s, MyContext &c) { 77 /// io.mapRequired("name", s.name); 78 /// io.mapRequired("size", s.size); 79 /// io.mapOptional("age", s.age); 80 /// ++c.TimesMapped; 81 /// } 82 /// }; 83 template <class T, class Context> struct MappingContextTraits { 84 // Must provide: 85 // static void mapping(IO &io, T &fields, Context &Ctx); 86 // Optionally may provide: 87 // static std::string validate(IO &io, T &fields, Context &Ctx); 88 // 89 // The optional flow flag will cause generated YAML to use a flow mapping 90 // (e.g. { a: 0, b: 1 }): 91 // static const bool flow = true; 92 }; 93 94 /// This class should be specialized by any integral type that converts 95 /// to/from a YAML scalar where there is a one-to-one mapping between 96 /// in-memory values and a string in YAML. For example: 97 /// 98 /// struct ScalarEnumerationTraits<Colors> { 99 /// static void enumeration(IO &io, Colors &value) { 100 /// io.enumCase(value, "red", cRed); 101 /// io.enumCase(value, "blue", cBlue); 102 /// io.enumCase(value, "green", cGreen); 103 /// } 104 /// }; 105 template <typename T, typename Enable = void> struct ScalarEnumerationTraits { 106 // Must provide: 107 // static void enumeration(IO &io, T &value); 108 }; 109 110 /// This class should be specialized by any integer type that is a union 111 /// of bit values and the YAML representation is a flow sequence of 112 /// strings. For example: 113 /// 114 /// struct ScalarBitSetTraits<MyFlags> { 115 /// static void bitset(IO &io, MyFlags &value) { 116 /// io.bitSetCase(value, "big", flagBig); 117 /// io.bitSetCase(value, "flat", flagFlat); 118 /// io.bitSetCase(value, "round", flagRound); 119 /// } 120 /// }; 121 template <typename T, typename Enable = void> struct ScalarBitSetTraits { 122 // Must provide: 123 // static void bitset(IO &io, T &value); 124 }; 125 126 /// Describe which type of quotes should be used when quoting is necessary. 127 /// Some non-printable characters need to be double-quoted, while some others 128 /// are fine with simple-quoting, and some don't need any quoting. 129 enum class QuotingType { None, Single, Double }; 130 131 /// This class should be specialized by type that requires custom conversion 132 /// to/from a yaml scalar. For example: 133 /// 134 /// template<> 135 /// struct ScalarTraits<MyType> { 136 /// static void output(const MyType &val, void*, llvm::raw_ostream &out) { 137 /// // stream out custom formatting 138 /// out << llvm::format("%x", val); 139 /// } 140 /// static StringRef input(StringRef scalar, void*, MyType &value) { 141 /// // parse scalar and set `value` 142 /// // return empty string on success, or error string 143 /// return StringRef(); 144 /// } 145 /// static QuotingType mustQuote(StringRef) { return QuotingType::Single; } 146 /// }; 147 template <typename T, typename Enable = void> struct ScalarTraits { 148 // Must provide: 149 // 150 // Function to write the value as a string: 151 // static void output(const T &value, void *ctxt, llvm::raw_ostream &out); 152 // 153 // Function to convert a string to a value. Returns the empty 154 // StringRef on success or an error string if string is malformed: 155 // static StringRef input(StringRef scalar, void *ctxt, T &value); 156 // 157 // Function to determine if the value should be quoted. 158 // static QuotingType mustQuote(StringRef); 159 }; 160 161 /// This class should be specialized by type that requires custom conversion 162 /// to/from a YAML literal block scalar. For example: 163 /// 164 /// template <> 165 /// struct BlockScalarTraits<MyType> { 166 /// static void output(const MyType &Value, void*, llvm::raw_ostream &Out) 167 /// { 168 /// // stream out custom formatting 169 /// Out << Value; 170 /// } 171 /// static StringRef input(StringRef Scalar, void*, MyType &Value) { 172 /// // parse scalar and set `value` 173 /// // return empty string on success, or error string 174 /// return StringRef(); 175 /// } 176 /// }; 177 template <typename T> 178 struct BlockScalarTraits { 179 // Must provide: 180 // 181 // Function to write the value as a string: 182 // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out); 183 // 184 // Function to convert a string to a value. Returns the empty 185 // StringRef on success or an error string if string is malformed: 186 // static StringRef input(StringRef Scalar, void *ctxt, T &Value); 187 // 188 // Optional: 189 // static StringRef inputTag(T &Val, std::string Tag) 190 // static void outputTag(const T &Val, raw_ostream &Out) 191 }; 192 193 /// This class should be specialized by type that requires custom conversion 194 /// to/from a YAML scalar with optional tags. For example: 195 /// 196 /// template <> 197 /// struct TaggedScalarTraits<MyType> { 198 /// static void output(const MyType &Value, void*, llvm::raw_ostream 199 /// &ScalarOut, llvm::raw_ostream &TagOut) 200 /// { 201 /// // stream out custom formatting including optional Tag 202 /// Out << Value; 203 /// } 204 /// static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType 205 /// &Value) { 206 /// // parse scalar and set `value` 207 /// // return empty string on success, or error string 208 /// return StringRef(); 209 /// } 210 /// static QuotingType mustQuote(const MyType &Value, StringRef) { 211 /// return QuotingType::Single; 212 /// } 213 /// }; 214 template <typename T> struct TaggedScalarTraits { 215 // Must provide: 216 // 217 // Function to write the value and tag as strings: 218 // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut, 219 // llvm::raw_ostream &TagOut); 220 // 221 // Function to convert a string to a value. Returns the empty 222 // StringRef on success or an error string if string is malformed: 223 // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T 224 // &Value); 225 // 226 // Function to determine if the value should be quoted. 227 // static QuotingType mustQuote(const T &Value, StringRef Scalar); 228 }; 229 230 /// This class should be specialized by any type that needs to be converted 231 /// to/from a YAML sequence. For example: 232 /// 233 /// template<> 234 /// struct SequenceTraits<MyContainer> { 235 /// static size_t size(IO &io, MyContainer &seq) { 236 /// return seq.size(); 237 /// } 238 /// static MyType& element(IO &, MyContainer &seq, size_t index) { 239 /// if ( index >= seq.size() ) 240 /// seq.resize(index+1); 241 /// return seq[index]; 242 /// } 243 /// }; 244 template<typename T, typename EnableIf = void> 245 struct SequenceTraits { 246 // Must provide: 247 // static size_t size(IO &io, T &seq); 248 // static T::value_type& element(IO &io, T &seq, size_t index); 249 // 250 // The following is option and will cause generated YAML to use 251 // a flow sequence (e.g. [a,b,c]). 252 // static const bool flow = true; 253 }; 254 255 /// This class should be specialized by any type for which vectors of that 256 /// type need to be converted to/from a YAML sequence. 257 template<typename T, typename EnableIf = void> 258 struct SequenceElementTraits { 259 // Must provide: 260 // static const bool flow; 261 }; 262 263 /// This class should be specialized by any type that needs to be converted 264 /// to/from a list of YAML documents. 265 template<typename T> 266 struct DocumentListTraits { 267 // Must provide: 268 // static size_t size(IO &io, T &seq); 269 // static T::value_type& element(IO &io, T &seq, size_t index); 270 }; 271 272 /// This class should be specialized by any type that needs to be converted 273 /// to/from a YAML mapping in the case where the names of the keys are not known 274 /// in advance, e.g. a string map. 275 template <typename T> 276 struct CustomMappingTraits { 277 // static void inputOne(IO &io, StringRef key, T &elem); 278 // static void output(IO &io, T &elem); 279 }; 280 281 /// This class should be specialized by any type that can be represented as 282 /// a scalar, map, or sequence, decided dynamically. For example: 283 /// 284 /// typedef std::unique_ptr<MyBase> MyPoly; 285 /// 286 /// template<> 287 /// struct PolymorphicTraits<MyPoly> { 288 /// static NodeKind getKind(const MyPoly &poly) { 289 /// return poly->getKind(); 290 /// } 291 /// static MyScalar& getAsScalar(MyPoly &poly) { 292 /// if (!poly || !isa<MyScalar>(poly)) 293 /// poly.reset(new MyScalar()); 294 /// return *cast<MyScalar>(poly.get()); 295 /// } 296 /// // ... 297 /// }; 298 template <typename T> struct PolymorphicTraits { 299 // Must provide: 300 // static NodeKind getKind(const T &poly); 301 // static scalar_type &getAsScalar(T &poly); 302 // static map_type &getAsMap(T &poly); 303 // static sequence_type &getAsSequence(T &poly); 304 }; 305 306 // Only used for better diagnostics of missing traits 307 template <typename T> 308 struct MissingTrait; 309 310 // Test if ScalarEnumerationTraits<T> is defined on type T. 311 template <class T> 312 struct has_ScalarEnumerationTraits 313 { 314 using Signature_enumeration = void (*)(class IO&, T&); 315 316 template <typename U> 317 static char test(SameType<Signature_enumeration, &U::enumeration>*); 318 319 template <typename U> 320 static double test(...); 321 322 static bool const value = 323 (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); 324 }; 325 326 // Test if ScalarBitSetTraits<T> is defined on type T. 327 template <class T> 328 struct has_ScalarBitSetTraits 329 { 330 using Signature_bitset = void (*)(class IO&, T&); 331 332 template <typename U> 333 static char test(SameType<Signature_bitset, &U::bitset>*); 334 335 template <typename U> 336 static double test(...); 337 338 static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); 339 }; 340 341 // Test if ScalarTraits<T> is defined on type T. 342 template <class T> 343 struct has_ScalarTraits 344 { 345 using Signature_input = StringRef (*)(StringRef, void*, T&); 346 using Signature_output = void (*)(const T&, void*, raw_ostream&); 347 using Signature_mustQuote = QuotingType (*)(StringRef); 348 349 template <typename U> 350 static char test(SameType<Signature_input, &U::input> *, 351 SameType<Signature_output, &U::output> *, 352 SameType<Signature_mustQuote, &U::mustQuote> *); 353 354 template <typename U> 355 static double test(...); 356 357 static bool const value = 358 (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); 359 }; 360 361 // Test if BlockScalarTraits<T> is defined on type T. 362 template <class T> 363 struct has_BlockScalarTraits 364 { 365 using Signature_input = StringRef (*)(StringRef, void *, T &); 366 using Signature_output = void (*)(const T &, void *, raw_ostream &); 367 368 template <typename U> 369 static char test(SameType<Signature_input, &U::input> *, 370 SameType<Signature_output, &U::output> *); 371 372 template <typename U> 373 static double test(...); 374 375 static bool const value = 376 (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1); 377 }; 378 379 // Test if TaggedScalarTraits<T> is defined on type T. 380 template <class T> struct has_TaggedScalarTraits { 381 using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &); 382 using Signature_output = void (*)(const T &, void *, raw_ostream &, 383 raw_ostream &); 384 using Signature_mustQuote = QuotingType (*)(const T &, StringRef); 385 386 template <typename U> 387 static char test(SameType<Signature_input, &U::input> *, 388 SameType<Signature_output, &U::output> *, 389 SameType<Signature_mustQuote, &U::mustQuote> *); 390 391 template <typename U> static double test(...); 392 393 static bool const value = 394 (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); 395 }; 396 397 // Test if MappingContextTraits<T> is defined on type T. 398 template <class T, class Context> struct has_MappingTraits { 399 using Signature_mapping = void (*)(class IO &, T &, Context &); 400 401 template <typename U> 402 static char test(SameType<Signature_mapping, &U::mapping>*); 403 404 template <typename U> 405 static double test(...); 406 407 static bool const value = 408 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 409 }; 410 411 // Test if MappingTraits<T> is defined on type T. 412 template <class T> struct has_MappingTraits<T, EmptyContext> { 413 using Signature_mapping = void (*)(class IO &, T &); 414 415 template <typename U> 416 static char test(SameType<Signature_mapping, &U::mapping> *); 417 418 template <typename U> static double test(...); 419 420 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 421 }; 422 423 // Test if MappingContextTraits<T>::validate() is defined on type T. 424 template <class T, class Context> struct has_MappingValidateTraits { 425 using Signature_validate = std::string (*)(class IO &, T &, Context &); 426 427 template <typename U> 428 static char test(SameType<Signature_validate, &U::validate>*); 429 430 template <typename U> 431 static double test(...); 432 433 static bool const value = 434 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 435 }; 436 437 // Test if MappingTraits<T>::validate() is defined on type T. 438 template <class T> struct has_MappingValidateTraits<T, EmptyContext> { 439 using Signature_validate = std::string (*)(class IO &, T &); 440 441 template <typename U> 442 static char test(SameType<Signature_validate, &U::validate> *); 443 444 template <typename U> static double test(...); 445 446 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 447 }; 448 449 // Test if MappingContextTraits<T>::enumInput() is defined on type T. 450 template <class T, class Context> struct has_MappingEnumInputTraits { 451 using Signature_validate = void (*)(class IO &, T &); 452 453 template <typename U> 454 static char test(SameType<Signature_validate, &U::enumInput> *); 455 456 template <typename U> static double test(...); 457 458 static bool const value = 459 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 460 }; 461 462 // Test if MappingTraits<T>::enumInput() is defined on type T. 463 template <class T> struct has_MappingEnumInputTraits<T, EmptyContext> { 464 using Signature_validate = void (*)(class IO &, T &); 465 466 template <typename U> 467 static char test(SameType<Signature_validate, &U::enumInput> *); 468 469 template <typename U> static double test(...); 470 471 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 472 }; 473 474 // Test if SequenceTraits<T> is defined on type T. 475 template <class T> 476 struct has_SequenceMethodTraits 477 { 478 using Signature_size = size_t (*)(class IO&, T&); 479 480 template <typename U> 481 static char test(SameType<Signature_size, &U::size>*); 482 483 template <typename U> 484 static double test(...); 485 486 static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); 487 }; 488 489 // Test if CustomMappingTraits<T> is defined on type T. 490 template <class T> 491 struct has_CustomMappingTraits 492 { 493 using Signature_input = void (*)(IO &io, StringRef key, T &v); 494 495 template <typename U> 496 static char test(SameType<Signature_input, &U::inputOne>*); 497 498 template <typename U> 499 static double test(...); 500 501 static bool const value = 502 (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1); 503 }; 504 505 // has_FlowTraits<int> will cause an error with some compilers because 506 // it subclasses int. Using this wrapper only instantiates the 507 // real has_FlowTraits only if the template type is a class. 508 template <typename T, bool Enabled = std::is_class<T>::value> 509 class has_FlowTraits 510 { 511 public: 512 static const bool value = false; 513 }; 514 515 // Some older gcc compilers don't support straight forward tests 516 // for members, so test for ambiguity cause by the base and derived 517 // classes both defining the member. 518 template <class T> 519 struct has_FlowTraits<T, true> 520 { 521 struct Fallback { bool flow; }; 522 struct Derived : T, Fallback { }; 523 524 template<typename C> 525 static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; 526 527 template<typename C> 528 static char (&f(...))[2]; 529 530 static bool const value = sizeof(f<Derived>(nullptr)) == 2; 531 }; 532 533 // Test if SequenceTraits<T> is defined on type T 534 template<typename T> 535 struct has_SequenceTraits : public std::integral_constant<bool, 536 has_SequenceMethodTraits<T>::value > { }; 537 538 // Test if DocumentListTraits<T> is defined on type T 539 template <class T> 540 struct has_DocumentListTraits 541 { 542 using Signature_size = size_t (*)(class IO &, T &); 543 544 template <typename U> 545 static char test(SameType<Signature_size, &U::size>*); 546 547 template <typename U> 548 static double test(...); 549 550 static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); 551 }; 552 553 template <class T> struct has_PolymorphicTraits { 554 using Signature_getKind = NodeKind (*)(const T &); 555 556 template <typename U> 557 static char test(SameType<Signature_getKind, &U::getKind> *); 558 559 template <typename U> static double test(...); 560 561 static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1); 562 }; 563 564 inline bool isNumeric(StringRef S) { 565 const auto skipDigits = [](StringRef Input) { 566 return Input.ltrim("0123456789"); 567 }; 568 569 // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls 570 // safe. 571 if (S.empty() || S.equals("+") || S.equals("-")) 572 return false; 573 574 if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) 575 return true; 576 577 // Infinity and decimal numbers can be prefixed with sign. 578 StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S; 579 580 // Check for infinity first, because checking for hex and oct numbers is more 581 // expensive. 582 if (Tail.equals(".inf") || Tail.equals(".Inf") || Tail.equals(".INF")) 583 return true; 584 585 // Section 10.3.2 Tag Resolution 586 // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with 587 // [-+], so S should be used instead of Tail. 588 if (S.startswith("0o")) 589 return S.size() > 2 && 590 S.drop_front(2).find_first_not_of("01234567") == StringRef::npos; 591 592 if (S.startswith("0x")) 593 return S.size() > 2 && S.drop_front(2).find_first_not_of( 594 "0123456789abcdefABCDEF") == StringRef::npos; 595 596 // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)? 597 S = Tail; 598 599 // Handle cases when the number starts with '.' and hence needs at least one 600 // digit after dot (as opposed by number which has digits before the dot), but 601 // doesn't have one. 602 if (S.startswith(".") && 603 (S.equals(".") || 604 (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr))) 605 return false; 606 607 if (S.startswith("E") || S.startswith("e")) 608 return false; 609 610 enum ParseState { 611 Default, 612 FoundDot, 613 FoundExponent, 614 }; 615 ParseState State = Default; 616 617 S = skipDigits(S); 618 619 // Accept decimal integer. 620 if (S.empty()) 621 return true; 622 623 if (S.front() == '.') { 624 State = FoundDot; 625 S = S.drop_front(); 626 } else if (S.front() == 'e' || S.front() == 'E') { 627 State = FoundExponent; 628 S = S.drop_front(); 629 } else { 630 return false; 631 } 632 633 if (State == FoundDot) { 634 S = skipDigits(S); 635 if (S.empty()) 636 return true; 637 638 if (S.front() == 'e' || S.front() == 'E') { 639 State = FoundExponent; 640 S = S.drop_front(); 641 } else { 642 return false; 643 } 644 } 645 646 assert(State == FoundExponent && "Should have found exponent at this point."); 647 if (S.empty()) 648 return false; 649 650 if (S.front() == '+' || S.front() == '-') { 651 S = S.drop_front(); 652 if (S.empty()) 653 return false; 654 } 655 656 return skipDigits(S).empty(); 657 } 658 659 inline bool isNull(StringRef S) { 660 return S.equals("null") || S.equals("Null") || S.equals("NULL") || 661 S.equals("~"); 662 } 663 664 inline bool isBool(StringRef S) { 665 // FIXME: using parseBool is causing multiple tests to fail. 666 return S.equals("true") || S.equals("True") || S.equals("TRUE") || 667 S.equals("false") || S.equals("False") || S.equals("FALSE"); 668 } 669 670 // 5.1. Character Set 671 // The allowed character range explicitly excludes the C0 control block #x0-#x1F 672 // (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1 673 // control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate 674 // block #xD800-#xDFFF, #xFFFE, and #xFFFF. 675 inline QuotingType needsQuotes(StringRef S) { 676 if (S.empty()) 677 return QuotingType::Single; 678 679 QuotingType MaxQuotingNeeded = QuotingType::None; 680 if (isSpace(static_cast<unsigned char>(S.front())) || 681 isSpace(static_cast<unsigned char>(S.back()))) 682 MaxQuotingNeeded = QuotingType::Single; 683 if (isNull(S)) 684 MaxQuotingNeeded = QuotingType::Single; 685 if (isBool(S)) 686 MaxQuotingNeeded = QuotingType::Single; 687 if (isNumeric(S)) 688 MaxQuotingNeeded = QuotingType::Single; 689 690 // 7.3.3 Plain Style 691 // Plain scalars must not begin with most indicators, as this would cause 692 // ambiguity with other YAML constructs. 693 if (std::strchr(R"(-?:\,[]{}#&*!|>'"%@`)", S[0]) != nullptr) 694 MaxQuotingNeeded = QuotingType::Single; 695 696 for (unsigned char C : S) { 697 // Alphanum is safe. 698 if (isAlnum(C)) 699 continue; 700 701 switch (C) { 702 // Safe scalar characters. 703 case '_': 704 case '-': 705 case '^': 706 case '.': 707 case ',': 708 case ' ': 709 // TAB (0x9) is allowed in unquoted strings. 710 case 0x9: 711 continue; 712 // LF(0xA) and CR(0xD) may delimit values and so require at least single 713 // quotes. LLVM YAML parser cannot handle single quoted multiline so use 714 // double quoting to produce valid YAML. 715 case 0xA: 716 case 0xD: 717 return QuotingType::Double; 718 // DEL (0x7F) are excluded from the allowed character range. 719 case 0x7F: 720 return QuotingType::Double; 721 // Forward slash is allowed to be unquoted, but we quote it anyway. We have 722 // many tests that use FileCheck against YAML output, and this output often 723 // contains paths. If we quote backslashes but not forward slashes then 724 // paths will come out either quoted or unquoted depending on which platform 725 // the test is run on, making FileCheck comparisons difficult. 726 case '/': 727 default: { 728 // C0 control block (0x0 - 0x1F) is excluded from the allowed character 729 // range. 730 if (C <= 0x1F) 731 return QuotingType::Double; 732 733 // Always double quote UTF-8. 734 if ((C & 0x80) != 0) 735 return QuotingType::Double; 736 737 // The character is not safe, at least simple quoting needed. 738 MaxQuotingNeeded = QuotingType::Single; 739 } 740 } 741 } 742 743 return MaxQuotingNeeded; 744 } 745 746 template <typename T, typename Context> 747 struct missingTraits 748 : public std::integral_constant<bool, 749 !has_ScalarEnumerationTraits<T>::value && 750 !has_ScalarBitSetTraits<T>::value && 751 !has_ScalarTraits<T>::value && 752 !has_BlockScalarTraits<T>::value && 753 !has_TaggedScalarTraits<T>::value && 754 !has_MappingTraits<T, Context>::value && 755 !has_SequenceTraits<T>::value && 756 !has_CustomMappingTraits<T>::value && 757 !has_DocumentListTraits<T>::value && 758 !has_PolymorphicTraits<T>::value> {}; 759 760 template <typename T, typename Context> 761 struct validatedMappingTraits 762 : public std::integral_constant< 763 bool, has_MappingTraits<T, Context>::value && 764 has_MappingValidateTraits<T, Context>::value> {}; 765 766 template <typename T, typename Context> 767 struct unvalidatedMappingTraits 768 : public std::integral_constant< 769 bool, has_MappingTraits<T, Context>::value && 770 !has_MappingValidateTraits<T, Context>::value> {}; 771 772 // Base class for Input and Output. 773 class IO { 774 public: 775 IO(void *Ctxt = nullptr); 776 virtual ~IO(); 777 778 virtual bool outputting() const = 0; 779 780 virtual unsigned beginSequence() = 0; 781 virtual bool preflightElement(unsigned, void *&) = 0; 782 virtual void postflightElement(void*) = 0; 783 virtual void endSequence() = 0; 784 virtual bool canElideEmptySequence() = 0; 785 786 virtual unsigned beginFlowSequence() = 0; 787 virtual bool preflightFlowElement(unsigned, void *&) = 0; 788 virtual void postflightFlowElement(void*) = 0; 789 virtual void endFlowSequence() = 0; 790 791 virtual bool mapTag(StringRef Tag, bool Default=false) = 0; 792 virtual void beginMapping() = 0; 793 virtual void endMapping() = 0; 794 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; 795 virtual void postflightKey(void*) = 0; 796 virtual std::vector<StringRef> keys() = 0; 797 798 virtual void beginFlowMapping() = 0; 799 virtual void endFlowMapping() = 0; 800 801 virtual void beginEnumScalar() = 0; 802 virtual bool matchEnumScalar(const char*, bool) = 0; 803 virtual bool matchEnumFallback() = 0; 804 virtual void endEnumScalar() = 0; 805 806 virtual bool beginBitSetScalar(bool &) = 0; 807 virtual bool bitSetMatch(const char*, bool) = 0; 808 virtual void endBitSetScalar() = 0; 809 810 virtual void scalarString(StringRef &, QuotingType) = 0; 811 virtual void blockScalarString(StringRef &) = 0; 812 virtual void scalarTag(std::string &) = 0; 813 814 virtual NodeKind getNodeKind() = 0; 815 816 virtual void setError(const Twine &) = 0; 817 virtual void setAllowUnknownKeys(bool Allow); 818 819 template <typename T> 820 void enumCase(T &Val, const char* Str, const T ConstVal) { 821 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { 822 Val = ConstVal; 823 } 824 } 825 826 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 827 template <typename T> 828 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { 829 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { 830 Val = ConstVal; 831 } 832 } 833 834 template <typename FBT, typename T> 835 void enumFallback(T &Val) { 836 if (matchEnumFallback()) { 837 EmptyContext Context; 838 // FIXME: Force integral conversion to allow strong typedefs to convert. 839 FBT Res = static_cast<typename FBT::BaseType>(Val); 840 yamlize(*this, Res, true, Context); 841 Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); 842 } 843 } 844 845 template <typename T> 846 void bitSetCase(T &Val, const char* Str, const T ConstVal) { 847 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 848 Val = static_cast<T>(Val | ConstVal); 849 } 850 } 851 852 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 853 template <typename T> 854 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { 855 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 856 Val = static_cast<T>(Val | ConstVal); 857 } 858 } 859 860 template <typename T> 861 void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { 862 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 863 Val = Val | ConstVal; 864 } 865 866 template <typename T> 867 void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, 868 uint32_t Mask) { 869 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 870 Val = Val | ConstVal; 871 } 872 873 void *getContext() const; 874 void setContext(void *); 875 876 template <typename T> void mapRequired(const char *Key, T &Val) { 877 EmptyContext Ctx; 878 this->processKey(Key, Val, true, Ctx); 879 } 880 881 template <typename T, typename Context> 882 void mapRequired(const char *Key, T &Val, Context &Ctx) { 883 this->processKey(Key, Val, true, Ctx); 884 } 885 886 template <typename T> void mapOptional(const char *Key, T &Val) { 887 EmptyContext Ctx; 888 mapOptionalWithContext(Key, Val, Ctx); 889 } 890 891 template <typename T, typename DefaultT> 892 void mapOptional(const char *Key, T &Val, const DefaultT &Default) { 893 EmptyContext Ctx; 894 mapOptionalWithContext(Key, Val, Default, Ctx); 895 } 896 897 template <typename T, typename Context> 898 std::enable_if_t<has_SequenceTraits<T>::value, void> 899 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { 900 // omit key/value instead of outputting empty sequence 901 if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) 902 return; 903 this->processKey(Key, Val, false, Ctx); 904 } 905 906 template <typename T, typename Context> 907 void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) { 908 this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false, 909 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, Optional<T> &Val, 930 const Optional<T> &DefaultValue, bool Required, 931 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 std::string Storage; 1002 raw_string_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, Optional<T> &Val, 1669 const Optional<T> &DefaultValue, bool Required, 1670 Context &Ctx) { 1671 assert(!DefaultValue && "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 Optional<X> key from a YAML description, we allow the 1681 // special "<none>" value, which can be used to specify that no value was 1682 // requested, i.e. the DefaultValue will be assigned. The DefaultValue is 1683 // usually None. 1684 bool IsNone = false; 1685 if (!outputting()) 1686 if (const auto *Node = dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode())) 1687 // We use rtrim to ignore possible white spaces that might exist when a 1688 // comment is present on the same line. 1689 IsNone = Node->getRawValue().rtrim(' ') == "<none>"; 1690 1691 if (IsNone) 1692 Val = DefaultValue; 1693 else 1694 yamlize(*this, *Val, Required, Ctx); 1695 this->postflightKey(SaveInfo); 1696 } else { 1697 if (UseDefault) 1698 Val = DefaultValue; 1699 } 1700 } 1701 1702 /// YAML I/O does conversion based on types. But often native data types 1703 /// are just a typedef of built in intergral types (e.g. int). But the C++ 1704 /// type matching system sees through the typedef and all the typedefed types 1705 /// look like a built in type. This will cause the generic YAML I/O conversion 1706 /// to be used. To provide better control over the YAML conversion, you can 1707 /// use this macro instead of typedef. It will create a class with one field 1708 /// and automatic conversion operators to and from the base type. 1709 /// Based on BOOST_STRONG_TYPEDEF 1710 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 1711 struct _type { \ 1712 _type() = default; \ 1713 _type(const _base v) : value(v) {} \ 1714 _type(const _type &v) = default; \ 1715 _type &operator=(const _type &rhs) = default; \ 1716 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 1717 operator const _base & () const { return value; } \ 1718 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 1719 bool operator==(const _base &rhs) const { return value == rhs; } \ 1720 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 1721 _base value; \ 1722 using BaseType = _base; \ 1723 }; 1724 1725 /// 1726 /// Use these types instead of uintXX_t in any mapping to have 1727 /// its yaml output formatted as hexadecimal. 1728 /// 1729 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1730 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1731 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1732 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1733 1734 template<> 1735 struct ScalarTraits<Hex8> { 1736 static void output(const Hex8 &, void *, raw_ostream &); 1737 static StringRef input(StringRef, void *, Hex8 &); 1738 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1739 }; 1740 1741 template<> 1742 struct ScalarTraits<Hex16> { 1743 static void output(const Hex16 &, void *, raw_ostream &); 1744 static StringRef input(StringRef, void *, Hex16 &); 1745 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1746 }; 1747 1748 template<> 1749 struct ScalarTraits<Hex32> { 1750 static void output(const Hex32 &, void *, raw_ostream &); 1751 static StringRef input(StringRef, void *, Hex32 &); 1752 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1753 }; 1754 1755 template<> 1756 struct ScalarTraits<Hex64> { 1757 static void output(const Hex64 &, void *, raw_ostream &); 1758 static StringRef input(StringRef, void *, Hex64 &); 1759 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1760 }; 1761 1762 template <> struct ScalarTraits<VersionTuple> { 1763 static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out); 1764 static StringRef input(StringRef, void *, VersionTuple &); 1765 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1766 }; 1767 1768 // Define non-member operator>> so that Input can stream in a document list. 1769 template <typename T> 1770 inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &> 1771 operator>>(Input &yin, T &docList) { 1772 int i = 0; 1773 EmptyContext Ctx; 1774 while ( yin.setCurrentDocument() ) { 1775 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); 1776 if ( yin.error() ) 1777 return yin; 1778 yin.nextDocument(); 1779 ++i; 1780 } 1781 return yin; 1782 } 1783 1784 // Define non-member operator>> so that Input can stream in a map as a document. 1785 template <typename T> 1786 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &> 1787 operator>>(Input &yin, T &docMap) { 1788 EmptyContext Ctx; 1789 yin.setCurrentDocument(); 1790 yamlize(yin, docMap, true, Ctx); 1791 return yin; 1792 } 1793 1794 // Define non-member operator>> so that Input can stream in a sequence as 1795 // a document. 1796 template <typename T> 1797 inline std::enable_if_t<has_SequenceTraits<T>::value, Input &> 1798 operator>>(Input &yin, T &docSeq) { 1799 EmptyContext Ctx; 1800 if (yin.setCurrentDocument()) 1801 yamlize(yin, docSeq, true, Ctx); 1802 return yin; 1803 } 1804 1805 // Define non-member operator>> so that Input can stream in a block scalar. 1806 template <typename T> 1807 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &> 1808 operator>>(Input &In, T &Val) { 1809 EmptyContext Ctx; 1810 if (In.setCurrentDocument()) 1811 yamlize(In, Val, true, Ctx); 1812 return In; 1813 } 1814 1815 // Define non-member operator>> so that Input can stream in a string map. 1816 template <typename T> 1817 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &> 1818 operator>>(Input &In, T &Val) { 1819 EmptyContext Ctx; 1820 if (In.setCurrentDocument()) 1821 yamlize(In, Val, true, Ctx); 1822 return In; 1823 } 1824 1825 // Define non-member operator>> so that Input can stream in a polymorphic type. 1826 template <typename T> 1827 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &> 1828 operator>>(Input &In, T &Val) { 1829 EmptyContext Ctx; 1830 if (In.setCurrentDocument()) 1831 yamlize(In, Val, true, Ctx); 1832 return In; 1833 } 1834 1835 // Provide better error message about types missing a trait specialization 1836 template <typename T> 1837 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &> 1838 operator>>(Input &yin, T &docSeq) { 1839 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1840 return yin; 1841 } 1842 1843 // Define non-member operator<< so that Output can stream out document list. 1844 template <typename T> 1845 inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &> 1846 operator<<(Output &yout, T &docList) { 1847 EmptyContext Ctx; 1848 yout.beginDocuments(); 1849 const size_t count = DocumentListTraits<T>::size(yout, docList); 1850 for(size_t i=0; i < count; ++i) { 1851 if ( yout.preflightDocument(i) ) { 1852 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, 1853 Ctx); 1854 yout.postflightDocument(); 1855 } 1856 } 1857 yout.endDocuments(); 1858 return yout; 1859 } 1860 1861 // Define non-member operator<< so that Output can stream out a map. 1862 template <typename T> 1863 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &> 1864 operator<<(Output &yout, T &map) { 1865 EmptyContext Ctx; 1866 yout.beginDocuments(); 1867 if ( yout.preflightDocument(0) ) { 1868 yamlize(yout, map, true, Ctx); 1869 yout.postflightDocument(); 1870 } 1871 yout.endDocuments(); 1872 return yout; 1873 } 1874 1875 // Define non-member operator<< so that Output can stream out a sequence. 1876 template <typename T> 1877 inline std::enable_if_t<has_SequenceTraits<T>::value, Output &> 1878 operator<<(Output &yout, T &seq) { 1879 EmptyContext Ctx; 1880 yout.beginDocuments(); 1881 if ( yout.preflightDocument(0) ) { 1882 yamlize(yout, seq, true, Ctx); 1883 yout.postflightDocument(); 1884 } 1885 yout.endDocuments(); 1886 return yout; 1887 } 1888 1889 // Define non-member operator<< so that Output can stream out a block scalar. 1890 template <typename T> 1891 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &> 1892 operator<<(Output &Out, T &Val) { 1893 EmptyContext Ctx; 1894 Out.beginDocuments(); 1895 if (Out.preflightDocument(0)) { 1896 yamlize(Out, Val, true, Ctx); 1897 Out.postflightDocument(); 1898 } 1899 Out.endDocuments(); 1900 return Out; 1901 } 1902 1903 // Define non-member operator<< so that Output can stream out a string map. 1904 template <typename T> 1905 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &> 1906 operator<<(Output &Out, T &Val) { 1907 EmptyContext Ctx; 1908 Out.beginDocuments(); 1909 if (Out.preflightDocument(0)) { 1910 yamlize(Out, Val, true, Ctx); 1911 Out.postflightDocument(); 1912 } 1913 Out.endDocuments(); 1914 return Out; 1915 } 1916 1917 // Define non-member operator<< so that Output can stream out a polymorphic 1918 // type. 1919 template <typename T> 1920 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &> 1921 operator<<(Output &Out, T &Val) { 1922 EmptyContext Ctx; 1923 Out.beginDocuments(); 1924 if (Out.preflightDocument(0)) { 1925 // FIXME: The parser does not support explicit documents terminated with a 1926 // plain scalar; the end-marker is included as part of the scalar token. 1927 assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported"); 1928 yamlize(Out, Val, true, Ctx); 1929 Out.postflightDocument(); 1930 } 1931 Out.endDocuments(); 1932 return Out; 1933 } 1934 1935 // Provide better error message about types missing a trait specialization 1936 template <typename T> 1937 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &> 1938 operator<<(Output &yout, T &seq) { 1939 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1940 return yout; 1941 } 1942 1943 template <bool B> struct IsFlowSequenceBase {}; 1944 template <> struct IsFlowSequenceBase<true> { static const bool flow = true; }; 1945 1946 template <typename T, bool Flow> 1947 struct SequenceTraitsImpl : IsFlowSequenceBase<Flow> { 1948 private: 1949 using type = typename T::value_type; 1950 1951 public: 1952 static size_t size(IO &io, T &seq) { return seq.size(); } 1953 1954 static type &element(IO &io, T &seq, size_t index) { 1955 if (index >= seq.size()) 1956 seq.resize(index + 1); 1957 return seq[index]; 1958 } 1959 }; 1960 1961 // Simple helper to check an expression can be used as a bool-valued template 1962 // argument. 1963 template <bool> struct CheckIsBool { static const bool value = true; }; 1964 1965 // If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have 1966 // SequenceTraits that do the obvious thing. 1967 template <typename T> 1968 struct SequenceTraits< 1969 std::vector<T>, 1970 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 1971 : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {}; 1972 template <typename T, unsigned N> 1973 struct SequenceTraits< 1974 SmallVector<T, N>, 1975 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 1976 : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {}; 1977 template <typename T> 1978 struct SequenceTraits< 1979 SmallVectorImpl<T>, 1980 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 1981 : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {}; 1982 1983 // Sequences of fundamental types use flow formatting. 1984 template <typename T> 1985 struct SequenceElementTraits<T, 1986 std::enable_if_t<std::is_fundamental<T>::value>> { 1987 static const bool flow = true; 1988 }; 1989 1990 // Sequences of strings use block formatting. 1991 template<> struct SequenceElementTraits<std::string> { 1992 static const bool flow = false; 1993 }; 1994 template<> struct SequenceElementTraits<StringRef> { 1995 static const bool flow = false; 1996 }; 1997 template<> struct SequenceElementTraits<std::pair<std::string, std::string>> { 1998 static const bool flow = false; 1999 }; 2000 2001 /// Implementation of CustomMappingTraits for std::map<std::string, T>. 2002 template <typename T> struct StdMapStringCustomMappingTraitsImpl { 2003 using map_type = std::map<std::string, T>; 2004 2005 static void inputOne(IO &io, StringRef key, map_type &v) { 2006 io.mapRequired(key.str().c_str(), v[std::string(key)]); 2007 } 2008 2009 static void output(IO &io, map_type &v) { 2010 for (auto &p : v) 2011 io.mapRequired(p.first.c_str(), p.second); 2012 } 2013 }; 2014 2015 } // end namespace yaml 2016 } // end namespace llvm 2017 2018 #define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW) \ 2019 namespace llvm { \ 2020 namespace yaml { \ 2021 static_assert( \ 2022 !std::is_fundamental<TYPE>::value && \ 2023 !std::is_same<TYPE, std::string>::value && \ 2024 !std::is_same<TYPE, llvm::StringRef>::value, \ 2025 "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \ 2026 template <> struct SequenceElementTraits<TYPE> { \ 2027 static const bool flow = FLOW; \ 2028 }; \ 2029 } \ 2030 } 2031 2032 /// Utility for declaring that a std::vector of a particular type 2033 /// should be considered a YAML sequence. 2034 #define LLVM_YAML_IS_SEQUENCE_VECTOR(type) \ 2035 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false) 2036 2037 /// Utility for declaring that a std::vector of a particular type 2038 /// should be considered a YAML flow sequence. 2039 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type) \ 2040 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true) 2041 2042 #define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \ 2043 namespace llvm { \ 2044 namespace yaml { \ 2045 template <> struct MappingTraits<Type> { \ 2046 static void mapping(IO &IO, Type &Obj); \ 2047 }; \ 2048 } \ 2049 } 2050 2051 #define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \ 2052 namespace llvm { \ 2053 namespace yaml { \ 2054 template <> struct ScalarEnumerationTraits<Type> { \ 2055 static void enumeration(IO &io, Type &Value); \ 2056 }; \ 2057 } \ 2058 } 2059 2060 #define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \ 2061 namespace llvm { \ 2062 namespace yaml { \ 2063 template <> struct ScalarBitSetTraits<Type> { \ 2064 static void bitset(IO &IO, Type &Options); \ 2065 }; \ 2066 } \ 2067 } 2068 2069 #define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \ 2070 namespace llvm { \ 2071 namespace yaml { \ 2072 template <> struct ScalarTraits<Type> { \ 2073 static void output(const Type &Value, void *ctx, raw_ostream &Out); \ 2074 static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ 2075 static QuotingType mustQuote(StringRef) { return MustQuote; } \ 2076 }; \ 2077 } \ 2078 } 2079 2080 /// Utility for declaring that a std::vector of a particular type 2081 /// should be considered a YAML document list. 2082 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 2083 namespace llvm { \ 2084 namespace yaml { \ 2085 template <unsigned N> \ 2086 struct DocumentListTraits<SmallVector<_type, N>> \ 2087 : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \ 2088 template <> \ 2089 struct DocumentListTraits<std::vector<_type>> \ 2090 : public SequenceTraitsImpl<std::vector<_type>, false> {}; \ 2091 } \ 2092 } 2093 2094 /// Utility for declaring that std::map<std::string, _type> should be considered 2095 /// a YAML map. 2096 #define LLVM_YAML_IS_STRING_MAP(_type) \ 2097 namespace llvm { \ 2098 namespace yaml { \ 2099 template <> \ 2100 struct CustomMappingTraits<std::map<std::string, _type>> \ 2101 : public StdMapStringCustomMappingTraitsImpl<_type> {}; \ 2102 } \ 2103 } 2104 2105 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64) 2106 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32) 2107 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16) 2108 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8) 2109 2110 #endif // LLVM_SUPPORT_YAMLTRAITS_H 2111