1 //===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_SUPPORT_YAMLTRAITS_H 11 #define LLVM_SUPPORT_YAMLTRAITS_H 12 13 #include "llvm/ADT/Optional.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/ADT/StringMap.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/ADT/Twine.h" 18 #include "llvm/Support/AlignOf.h" 19 #include "llvm/Support/Allocator.h" 20 #include "llvm/Support/Endian.h" 21 #include "llvm/Support/Regex.h" 22 #include "llvm/Support/SourceMgr.h" 23 #include "llvm/Support/YAMLParser.h" 24 #include "llvm/Support/raw_ostream.h" 25 #include <cassert> 26 #include <cctype> 27 #include <cstddef> 28 #include <cstdint> 29 #include <memory> 30 #include <new> 31 #include <string> 32 #include <system_error> 33 #include <type_traits> 34 #include <vector> 35 36 namespace llvm { 37 namespace yaml { 38 39 struct EmptyContext {}; 40 41 /// This class should be specialized by any type that needs to be converted 42 /// to/from a YAML mapping. For example: 43 /// 44 /// struct MappingTraits<MyStruct> { 45 /// static void mapping(IO &io, MyStruct &s) { 46 /// io.mapRequired("name", s.name); 47 /// io.mapRequired("size", s.size); 48 /// io.mapOptional("age", s.age); 49 /// } 50 /// }; 51 template<class T> 52 struct MappingTraits { 53 // Must provide: 54 // static void mapping(IO &io, T &fields); 55 // Optionally may provide: 56 // static StringRef validate(IO &io, T &fields); 57 // 58 // The optional flow flag will cause generated YAML to use a flow mapping 59 // (e.g. { a: 0, b: 1 }): 60 // static const bool flow = true; 61 }; 62 63 /// This class is similar to MappingTraits<T> but allows you to pass in 64 /// additional context for each map operation. For example: 65 /// 66 /// struct MappingContextTraits<MyStruct, MyContext> { 67 /// static void mapping(IO &io, MyStruct &s, MyContext &c) { 68 /// io.mapRequired("name", s.name); 69 /// io.mapRequired("size", s.size); 70 /// io.mapOptional("age", s.age); 71 /// ++c.TimesMapped; 72 /// } 73 /// }; 74 template <class T, class Context> struct MappingContextTraits { 75 // Must provide: 76 // static void mapping(IO &io, T &fields, Context &Ctx); 77 // Optionally may provide: 78 // static StringRef validate(IO &io, T &fields, Context &Ctx); 79 // 80 // The optional flow flag will cause generated YAML to use a flow mapping 81 // (e.g. { a: 0, b: 1 }): 82 // static const bool flow = true; 83 }; 84 85 /// This class should be specialized by any integral type that converts 86 /// to/from a YAML scalar where there is a one-to-one mapping between 87 /// in-memory values and a string in YAML. For example: 88 /// 89 /// struct ScalarEnumerationTraits<Colors> { 90 /// static void enumeration(IO &io, Colors &value) { 91 /// io.enumCase(value, "red", cRed); 92 /// io.enumCase(value, "blue", cBlue); 93 /// io.enumCase(value, "green", cGreen); 94 /// } 95 /// }; 96 template<typename T> 97 struct ScalarEnumerationTraits { 98 // Must provide: 99 // static void enumeration(IO &io, T &value); 100 }; 101 102 /// This class should be specialized by any integer type that is a union 103 /// of bit values and the YAML representation is a flow sequence of 104 /// strings. For example: 105 /// 106 /// struct ScalarBitSetTraits<MyFlags> { 107 /// static void bitset(IO &io, MyFlags &value) { 108 /// io.bitSetCase(value, "big", flagBig); 109 /// io.bitSetCase(value, "flat", flagFlat); 110 /// io.bitSetCase(value, "round", flagRound); 111 /// } 112 /// }; 113 template<typename T> 114 struct ScalarBitSetTraits { 115 // Must provide: 116 // static void bitset(IO &io, T &value); 117 }; 118 119 /// This class should be specialized by type that requires custom conversion 120 /// to/from a yaml scalar. For example: 121 /// 122 /// template<> 123 /// struct ScalarTraits<MyType> { 124 /// static void output(const MyType &val, void*, llvm::raw_ostream &out) { 125 /// // stream out custom formatting 126 /// out << llvm::format("%x", val); 127 /// } 128 /// static StringRef input(StringRef scalar, void*, MyType &value) { 129 /// // parse scalar and set `value` 130 /// // return empty string on success, or error string 131 /// return StringRef(); 132 /// } 133 /// static bool mustQuote(StringRef) { return true; } 134 /// }; 135 template<typename T> 136 struct ScalarTraits { 137 // Must provide: 138 // 139 // Function to write the value as a string: 140 //static void output(const T &value, void *ctxt, llvm::raw_ostream &out); 141 // 142 // Function to convert a string to a value. Returns the empty 143 // StringRef on success or an error string if string is malformed: 144 //static StringRef input(StringRef scalar, void *ctxt, T &value); 145 // 146 // Function to determine if the value should be quoted. 147 //static bool mustQuote(StringRef); 148 }; 149 150 /// This class should be specialized by type that requires custom conversion 151 /// to/from a YAML literal block scalar. For example: 152 /// 153 /// template <> 154 /// struct BlockScalarTraits<MyType> { 155 /// static void output(const MyType &Value, void*, llvm::raw_ostream &Out) 156 /// { 157 /// // stream out custom formatting 158 /// Out << Val; 159 /// } 160 /// static StringRef input(StringRef Scalar, void*, MyType &Value) { 161 /// // parse scalar and set `value` 162 /// // return empty string on success, or error string 163 /// return StringRef(); 164 /// } 165 /// }; 166 template <typename T> 167 struct BlockScalarTraits { 168 // Must provide: 169 // 170 // Function to write the value as a string: 171 // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out); 172 // 173 // Function to convert a string to a value. Returns the empty 174 // StringRef on success or an error string if string is malformed: 175 // static StringRef input(StringRef Scalar, void *ctxt, T &Value); 176 }; 177 178 /// This class should be specialized by any type that needs to be converted 179 /// to/from a YAML sequence. For example: 180 /// 181 /// template<> 182 /// struct SequenceTraits< std::vector<MyType>> { 183 /// static size_t size(IO &io, std::vector<MyType> &seq) { 184 /// return seq.size(); 185 /// } 186 /// static MyType& element(IO &, std::vector<MyType> &seq, size_t index) { 187 /// if ( index >= seq.size() ) 188 /// seq.resize(index+1); 189 /// return seq[index]; 190 /// } 191 /// }; 192 template<typename T> 193 struct SequenceTraits { 194 // Must provide: 195 // static size_t size(IO &io, T &seq); 196 // static T::value_type& element(IO &io, T &seq, size_t index); 197 // 198 // The following is option and will cause generated YAML to use 199 // a flow sequence (e.g. [a,b,c]). 200 // static const bool flow = true; 201 }; 202 203 /// This class should be specialized by any type that needs to be converted 204 /// to/from a list of YAML documents. 205 template<typename T> 206 struct DocumentListTraits { 207 // Must provide: 208 // static size_t size(IO &io, T &seq); 209 // static T::value_type& element(IO &io, T &seq, size_t index); 210 }; 211 212 // Only used for better diagnostics of missing traits 213 template <typename T> 214 struct MissingTrait; 215 216 // Test if ScalarEnumerationTraits<T> is defined on type T. 217 template <class T> 218 struct has_ScalarEnumerationTraits 219 { 220 typedef void (*Signature_enumeration)(class IO&, T&); 221 222 template <typename U> 223 static char test(SameType<Signature_enumeration, &U::enumeration>*); 224 225 template <typename U> 226 static double test(...); 227 228 public: 229 static bool const value = 230 (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); 231 }; 232 233 // Test if ScalarBitSetTraits<T> is defined on type T. 234 template <class T> 235 struct has_ScalarBitSetTraits 236 { 237 typedef void (*Signature_bitset)(class IO&, T&); 238 239 template <typename U> 240 static char test(SameType<Signature_bitset, &U::bitset>*); 241 242 template <typename U> 243 static double test(...); 244 245 public: 246 static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); 247 }; 248 249 // Test if ScalarTraits<T> is defined on type T. 250 template <class T> 251 struct has_ScalarTraits 252 { 253 typedef StringRef (*Signature_input)(StringRef, void*, T&); 254 typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&); 255 typedef bool (*Signature_mustQuote)(StringRef); 256 257 template <typename U> 258 static char test(SameType<Signature_input, &U::input> *, 259 SameType<Signature_output, &U::output> *, 260 SameType<Signature_mustQuote, &U::mustQuote> *); 261 262 template <typename U> 263 static double test(...); 264 265 public: 266 static bool const value = 267 (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); 268 }; 269 270 // Test if BlockScalarTraits<T> is defined on type T. 271 template <class T> 272 struct has_BlockScalarTraits 273 { 274 typedef StringRef (*Signature_input)(StringRef, void *, T &); 275 typedef void (*Signature_output)(const T &, void *, llvm::raw_ostream &); 276 277 template <typename U> 278 static char test(SameType<Signature_input, &U::input> *, 279 SameType<Signature_output, &U::output> *); 280 281 template <typename U> 282 static double test(...); 283 284 public: 285 static bool const value = 286 (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1); 287 }; 288 289 // Test if MappingContextTraits<T> is defined on type T. 290 template <class T, class Context> struct has_MappingTraits { 291 typedef void (*Signature_mapping)(class IO &, T &, Context &); 292 293 template <typename U> 294 static char test(SameType<Signature_mapping, &U::mapping>*); 295 296 template <typename U> 297 static double test(...); 298 299 public: 300 static bool const value = 301 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 302 }; 303 304 // Test if MappingTraits<T> is defined on type T. 305 template <class T> struct has_MappingTraits<T, EmptyContext> { 306 typedef void (*Signature_mapping)(class IO &, T &); 307 308 template <typename U> 309 static char test(SameType<Signature_mapping, &U::mapping> *); 310 311 template <typename U> static double test(...); 312 313 public: 314 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 315 }; 316 317 // Test if MappingContextTraits<T>::validate() is defined on type T. 318 template <class T, class Context> struct has_MappingValidateTraits { 319 typedef StringRef (*Signature_validate)(class IO &, T &, Context &); 320 321 template <typename U> 322 static char test(SameType<Signature_validate, &U::validate>*); 323 324 template <typename U> 325 static double test(...); 326 327 public: 328 static bool const value = 329 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 330 }; 331 332 // Test if MappingTraits<T>::validate() is defined on type T. 333 template <class T> struct has_MappingValidateTraits<T, EmptyContext> { 334 typedef StringRef (*Signature_validate)(class IO &, T &); 335 336 template <typename U> 337 static char test(SameType<Signature_validate, &U::validate> *); 338 339 template <typename U> static double test(...); 340 341 public: 342 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 343 }; 344 345 // Test if SequenceTraits<T> is defined on type T. 346 template <class T> 347 struct has_SequenceMethodTraits 348 { 349 typedef size_t (*Signature_size)(class IO&, T&); 350 351 template <typename U> 352 static char test(SameType<Signature_size, &U::size>*); 353 354 template <typename U> 355 static double test(...); 356 357 public: 358 static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); 359 }; 360 361 // has_FlowTraits<int> will cause an error with some compilers because 362 // it subclasses int. Using this wrapper only instantiates the 363 // real has_FlowTraits only if the template type is a class. 364 template <typename T, bool Enabled = std::is_class<T>::value> 365 class has_FlowTraits 366 { 367 public: 368 static const bool value = false; 369 }; 370 371 // Some older gcc compilers don't support straight forward tests 372 // for members, so test for ambiguity cause by the base and derived 373 // classes both defining the member. 374 template <class T> 375 struct has_FlowTraits<T, true> 376 { 377 struct Fallback { bool flow; }; 378 struct Derived : T, Fallback { }; 379 380 template<typename C> 381 static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; 382 383 template<typename C> 384 static char (&f(...))[2]; 385 386 public: 387 static bool const value = sizeof(f<Derived>(nullptr)) == 2; 388 }; 389 390 // Test if SequenceTraits<T> is defined on type T 391 template<typename T> 392 struct has_SequenceTraits : public std::integral_constant<bool, 393 has_SequenceMethodTraits<T>::value > { }; 394 395 // Test if DocumentListTraits<T> is defined on type T 396 template <class T> 397 struct has_DocumentListTraits 398 { 399 typedef size_t (*Signature_size)(class IO&, T&); 400 401 template <typename U> 402 static char test(SameType<Signature_size, &U::size>*); 403 404 template <typename U> 405 static double test(...); 406 407 public: 408 static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); 409 }; 410 411 inline bool isNumber(StringRef S) { 412 static const char OctalChars[] = "01234567"; 413 if (S.startswith("0") && 414 S.drop_front().find_first_not_of(OctalChars) == StringRef::npos) 415 return true; 416 417 if (S.startswith("0o") && 418 S.drop_front(2).find_first_not_of(OctalChars) == StringRef::npos) 419 return true; 420 421 static const char HexChars[] = "0123456789abcdefABCDEF"; 422 if (S.startswith("0x") && 423 S.drop_front(2).find_first_not_of(HexChars) == StringRef::npos) 424 return true; 425 426 static const char DecChars[] = "0123456789"; 427 if (S.find_first_not_of(DecChars) == StringRef::npos) 428 return true; 429 430 if (S.equals(".inf") || S.equals(".Inf") || S.equals(".INF")) 431 return true; 432 433 Regex FloatMatcher("^(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$"); 434 if (FloatMatcher.match(S)) 435 return true; 436 437 return false; 438 } 439 440 inline bool isNumeric(StringRef S) { 441 if ((S.front() == '-' || S.front() == '+') && isNumber(S.drop_front())) 442 return true; 443 444 if (isNumber(S)) 445 return true; 446 447 if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) 448 return true; 449 450 return false; 451 } 452 453 inline bool isNull(StringRef S) { 454 return S.equals("null") || S.equals("Null") || S.equals("NULL") || 455 S.equals("~"); 456 } 457 458 inline bool isBool(StringRef S) { 459 return S.equals("true") || S.equals("True") || S.equals("TRUE") || 460 S.equals("false") || S.equals("False") || S.equals("FALSE"); 461 } 462 463 inline bool needsQuotes(StringRef S) { 464 if (S.empty()) 465 return true; 466 if (isspace(S.front()) || isspace(S.back())) 467 return true; 468 if (S.front() == ',') 469 return true; 470 471 static const char ScalarSafeChars[] = 472 "abcdefghijklmnopqrstuvwxyz" 473 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; 474 if (S.find_first_not_of(ScalarSafeChars) != StringRef::npos) 475 return true; 476 477 if (isNull(S)) 478 return true; 479 if (isBool(S)) 480 return true; 481 if (isNumeric(S)) 482 return true; 483 484 return false; 485 } 486 487 template <typename T, typename Context> 488 struct missingTraits 489 : public std::integral_constant<bool, 490 !has_ScalarEnumerationTraits<T>::value && 491 !has_ScalarBitSetTraits<T>::value && 492 !has_ScalarTraits<T>::value && 493 !has_BlockScalarTraits<T>::value && 494 !has_MappingTraits<T, Context>::value && 495 !has_SequenceTraits<T>::value && 496 !has_DocumentListTraits<T>::value> {}; 497 498 template <typename T, typename Context> 499 struct validatedMappingTraits 500 : public std::integral_constant< 501 bool, has_MappingTraits<T, Context>::value && 502 has_MappingValidateTraits<T, Context>::value> {}; 503 504 template <typename T, typename Context> 505 struct unvalidatedMappingTraits 506 : public std::integral_constant< 507 bool, has_MappingTraits<T, Context>::value && 508 !has_MappingValidateTraits<T, Context>::value> {}; 509 510 // Base class for Input and Output. 511 class IO { 512 public: 513 IO(void *Ctxt=nullptr); 514 virtual ~IO(); 515 516 virtual bool outputting() = 0; 517 518 virtual unsigned beginSequence() = 0; 519 virtual bool preflightElement(unsigned, void *&) = 0; 520 virtual void postflightElement(void*) = 0; 521 virtual void endSequence() = 0; 522 virtual bool canElideEmptySequence() = 0; 523 524 virtual unsigned beginFlowSequence() = 0; 525 virtual bool preflightFlowElement(unsigned, void *&) = 0; 526 virtual void postflightFlowElement(void*) = 0; 527 virtual void endFlowSequence() = 0; 528 529 virtual bool mapTag(StringRef Tag, bool Default=false) = 0; 530 virtual void beginMapping() = 0; 531 virtual void endMapping() = 0; 532 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; 533 virtual void postflightKey(void*) = 0; 534 535 virtual void beginFlowMapping() = 0; 536 virtual void endFlowMapping() = 0; 537 538 virtual void beginEnumScalar() = 0; 539 virtual bool matchEnumScalar(const char*, bool) = 0; 540 virtual bool matchEnumFallback() = 0; 541 virtual void endEnumScalar() = 0; 542 543 virtual bool beginBitSetScalar(bool &) = 0; 544 virtual bool bitSetMatch(const char*, bool) = 0; 545 virtual void endBitSetScalar() = 0; 546 547 virtual void scalarString(StringRef &, bool) = 0; 548 virtual void blockScalarString(StringRef &) = 0; 549 550 virtual void setError(const Twine &) = 0; 551 552 template <typename T> 553 void enumCase(T &Val, const char* Str, const T ConstVal) { 554 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { 555 Val = ConstVal; 556 } 557 } 558 559 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 560 template <typename T> 561 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { 562 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { 563 Val = ConstVal; 564 } 565 } 566 567 template <typename FBT, typename T> 568 void enumFallback(T &Val) { 569 if (matchEnumFallback()) { 570 EmptyContext Context; 571 // FIXME: Force integral conversion to allow strong typedefs to convert. 572 FBT Res = static_cast<typename FBT::BaseType>(Val); 573 yamlize(*this, Res, true, Context); 574 Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); 575 } 576 } 577 578 template <typename T> 579 void bitSetCase(T &Val, const char* Str, const T ConstVal) { 580 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 581 Val = Val | ConstVal; 582 } 583 } 584 585 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 586 template <typename T> 587 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { 588 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 589 Val = Val | ConstVal; 590 } 591 } 592 593 template <typename T> 594 void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { 595 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 596 Val = Val | ConstVal; 597 } 598 599 template <typename T> 600 void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, 601 uint32_t Mask) { 602 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 603 Val = Val | ConstVal; 604 } 605 606 void *getContext(); 607 void setContext(void *); 608 609 template <typename T> void mapRequired(const char *Key, T &Val) { 610 EmptyContext Ctx; 611 this->processKey(Key, Val, true, Ctx); 612 } 613 template <typename T, typename Context> 614 void mapRequired(const char *Key, T &Val, Context &Ctx) { 615 this->processKey(Key, Val, true, Ctx); 616 } 617 618 template <typename T> void mapOptional(const char *Key, T &Val) { 619 EmptyContext Ctx; 620 mapOptionalWithContext(Key, Val, Ctx); 621 } 622 623 template <typename T> 624 void mapOptional(const char *Key, T &Val, const T &Default) { 625 EmptyContext Ctx; 626 mapOptionalWithContext(Key, Val, Default, Ctx); 627 } 628 629 template <typename T, typename Context> 630 typename std::enable_if<has_SequenceTraits<T>::value, void>::type 631 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { 632 // omit key/value instead of outputting empty sequence 633 if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) 634 return; 635 this->processKey(Key, Val, false, Ctx); 636 } 637 638 template <typename T, typename Context> 639 void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) { 640 this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false, 641 Ctx); 642 } 643 644 template <typename T, typename Context> 645 typename std::enable_if<!has_SequenceTraits<T>::value, void>::type 646 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { 647 this->processKey(Key, Val, false, Ctx); 648 } 649 650 template <typename T, typename Context> 651 void mapOptionalWithContext(const char *Key, T &Val, const T &Default, 652 Context &Ctx) { 653 this->processKeyWithDefault(Key, Val, Default, false, Ctx); 654 } 655 656 private: 657 template <typename T, typename Context> 658 void processKeyWithDefault(const char *Key, Optional<T> &Val, 659 const Optional<T> &DefaultValue, bool Required, 660 Context &Ctx) { 661 assert(DefaultValue.hasValue() == false && 662 "Optional<T> shouldn't have a value!"); 663 void *SaveInfo; 664 bool UseDefault; 665 const bool sameAsDefault = outputting() && !Val.hasValue(); 666 if (!outputting() && !Val.hasValue()) 667 Val = T(); 668 if (this->preflightKey(Key, Required, sameAsDefault, UseDefault, 669 SaveInfo)) { 670 yamlize(*this, Val.getValue(), Required, Ctx); 671 this->postflightKey(SaveInfo); 672 } else { 673 if (UseDefault) 674 Val = DefaultValue; 675 } 676 } 677 678 template <typename T, typename Context> 679 void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue, 680 bool Required, Context &Ctx) { 681 void *SaveInfo; 682 bool UseDefault; 683 const bool sameAsDefault = outputting() && Val == DefaultValue; 684 if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, 685 SaveInfo) ) { 686 yamlize(*this, Val, Required, Ctx); 687 this->postflightKey(SaveInfo); 688 } 689 else { 690 if ( UseDefault ) 691 Val = DefaultValue; 692 } 693 } 694 695 template <typename T, typename Context> 696 void processKey(const char *Key, T &Val, bool Required, Context &Ctx) { 697 void *SaveInfo; 698 bool UseDefault; 699 if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { 700 yamlize(*this, Val, Required, Ctx); 701 this->postflightKey(SaveInfo); 702 } 703 } 704 705 private: 706 void *Ctxt; 707 }; 708 709 namespace detail { 710 711 template <typename T, typename Context> 712 void doMapping(IO &io, T &Val, Context &Ctx) { 713 MappingContextTraits<T, Context>::mapping(io, Val, Ctx); 714 } 715 716 template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) { 717 MappingTraits<T>::mapping(io, Val); 718 } 719 720 } // end namespace detail 721 722 template <typename T> 723 typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type 724 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 725 io.beginEnumScalar(); 726 ScalarEnumerationTraits<T>::enumeration(io, Val); 727 io.endEnumScalar(); 728 } 729 730 template <typename T> 731 typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type 732 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 733 bool DoClear; 734 if ( io.beginBitSetScalar(DoClear) ) { 735 if ( DoClear ) 736 Val = static_cast<T>(0); 737 ScalarBitSetTraits<T>::bitset(io, Val); 738 io.endBitSetScalar(); 739 } 740 } 741 742 template <typename T> 743 typename std::enable_if<has_ScalarTraits<T>::value, void>::type 744 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 745 if ( io.outputting() ) { 746 std::string Storage; 747 llvm::raw_string_ostream Buffer(Storage); 748 ScalarTraits<T>::output(Val, io.getContext(), Buffer); 749 StringRef Str = Buffer.str(); 750 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 751 } 752 else { 753 StringRef Str; 754 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 755 StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); 756 if ( !Result.empty() ) { 757 io.setError(llvm::Twine(Result)); 758 } 759 } 760 } 761 762 template <typename T> 763 typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type 764 yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { 765 if (YamlIO.outputting()) { 766 std::string Storage; 767 llvm::raw_string_ostream Buffer(Storage); 768 BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer); 769 StringRef Str = Buffer.str(); 770 YamlIO.blockScalarString(Str); 771 } else { 772 StringRef Str; 773 YamlIO.blockScalarString(Str); 774 StringRef Result = 775 BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val); 776 if (!Result.empty()) 777 YamlIO.setError(llvm::Twine(Result)); 778 } 779 } 780 781 template <typename T, typename Context> 782 typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type 783 yamlize(IO &io, T &Val, bool, Context &Ctx) { 784 if (has_FlowTraits<MappingTraits<T>>::value) 785 io.beginFlowMapping(); 786 else 787 io.beginMapping(); 788 if (io.outputting()) { 789 StringRef Err = MappingTraits<T>::validate(io, Val); 790 if (!Err.empty()) { 791 llvm::errs() << Err << "\n"; 792 assert(Err.empty() && "invalid struct trying to be written as yaml"); 793 } 794 } 795 detail::doMapping(io, Val, Ctx); 796 if (!io.outputting()) { 797 StringRef Err = MappingTraits<T>::validate(io, Val); 798 if (!Err.empty()) 799 io.setError(Err); 800 } 801 if (has_FlowTraits<MappingTraits<T>>::value) 802 io.endFlowMapping(); 803 else 804 io.endMapping(); 805 } 806 807 template <typename T, typename Context> 808 typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type 809 yamlize(IO &io, T &Val, bool, Context &Ctx) { 810 if (has_FlowTraits<MappingTraits<T>>::value) { 811 io.beginFlowMapping(); 812 detail::doMapping(io, Val, Ctx); 813 io.endFlowMapping(); 814 } else { 815 io.beginMapping(); 816 detail::doMapping(io, Val, Ctx); 817 io.endMapping(); 818 } 819 } 820 821 template <typename T> 822 typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type 823 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 824 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 825 } 826 827 template <typename T, typename Context> 828 typename std::enable_if<has_SequenceTraits<T>::value, void>::type 829 yamlize(IO &io, T &Seq, bool, Context &Ctx) { 830 if ( has_FlowTraits< SequenceTraits<T> >::value ) { 831 unsigned incnt = io.beginFlowSequence(); 832 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 833 for(unsigned i=0; i < count; ++i) { 834 void *SaveInfo; 835 if ( io.preflightFlowElement(i, SaveInfo) ) { 836 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); 837 io.postflightFlowElement(SaveInfo); 838 } 839 } 840 io.endFlowSequence(); 841 } 842 else { 843 unsigned incnt = io.beginSequence(); 844 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 845 for(unsigned i=0; i < count; ++i) { 846 void *SaveInfo; 847 if ( io.preflightElement(i, SaveInfo) ) { 848 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); 849 io.postflightElement(SaveInfo); 850 } 851 } 852 io.endSequence(); 853 } 854 } 855 856 template<> 857 struct ScalarTraits<bool> { 858 static void output(const bool &, void*, llvm::raw_ostream &); 859 static StringRef input(StringRef, void*, bool &); 860 static bool mustQuote(StringRef) { return false; } 861 }; 862 863 template<> 864 struct ScalarTraits<StringRef> { 865 static void output(const StringRef &, void*, llvm::raw_ostream &); 866 static StringRef input(StringRef, void*, StringRef &); 867 static bool mustQuote(StringRef S) { return needsQuotes(S); } 868 }; 869 870 template<> 871 struct ScalarTraits<std::string> { 872 static void output(const std::string &, void*, llvm::raw_ostream &); 873 static StringRef input(StringRef, void*, std::string &); 874 static bool mustQuote(StringRef S) { return needsQuotes(S); } 875 }; 876 877 template<> 878 struct ScalarTraits<uint8_t> { 879 static void output(const uint8_t &, void*, llvm::raw_ostream &); 880 static StringRef input(StringRef, void*, uint8_t &); 881 static bool mustQuote(StringRef) { return false; } 882 }; 883 884 template<> 885 struct ScalarTraits<uint16_t> { 886 static void output(const uint16_t &, void*, llvm::raw_ostream &); 887 static StringRef input(StringRef, void*, uint16_t &); 888 static bool mustQuote(StringRef) { return false; } 889 }; 890 891 template<> 892 struct ScalarTraits<uint32_t> { 893 static void output(const uint32_t &, void*, llvm::raw_ostream &); 894 static StringRef input(StringRef, void*, uint32_t &); 895 static bool mustQuote(StringRef) { return false; } 896 }; 897 898 template<> 899 struct ScalarTraits<uint64_t> { 900 static void output(const uint64_t &, void*, llvm::raw_ostream &); 901 static StringRef input(StringRef, void*, uint64_t &); 902 static bool mustQuote(StringRef) { return false; } 903 }; 904 905 template<> 906 struct ScalarTraits<int8_t> { 907 static void output(const int8_t &, void*, llvm::raw_ostream &); 908 static StringRef input(StringRef, void*, int8_t &); 909 static bool mustQuote(StringRef) { return false; } 910 }; 911 912 template<> 913 struct ScalarTraits<int16_t> { 914 static void output(const int16_t &, void*, llvm::raw_ostream &); 915 static StringRef input(StringRef, void*, int16_t &); 916 static bool mustQuote(StringRef) { return false; } 917 }; 918 919 template<> 920 struct ScalarTraits<int32_t> { 921 static void output(const int32_t &, void*, llvm::raw_ostream &); 922 static StringRef input(StringRef, void*, int32_t &); 923 static bool mustQuote(StringRef) { return false; } 924 }; 925 926 template<> 927 struct ScalarTraits<int64_t> { 928 static void output(const int64_t &, void*, llvm::raw_ostream &); 929 static StringRef input(StringRef, void*, int64_t &); 930 static bool mustQuote(StringRef) { return false; } 931 }; 932 933 template<> 934 struct ScalarTraits<float> { 935 static void output(const float &, void*, llvm::raw_ostream &); 936 static StringRef input(StringRef, void*, float &); 937 static bool mustQuote(StringRef) { return false; } 938 }; 939 940 template<> 941 struct ScalarTraits<double> { 942 static void output(const double &, void*, llvm::raw_ostream &); 943 static StringRef input(StringRef, void*, double &); 944 static bool mustQuote(StringRef) { return false; } 945 }; 946 947 // For endian types, we just use the existing ScalarTraits for the underlying 948 // type. This way endian aware types are supported whenever a ScalarTraits 949 // is defined for the underlying type. 950 template <typename value_type, support::endianness endian, size_t alignment> 951 struct ScalarTraits<support::detail::packed_endian_specific_integral< 952 value_type, endian, alignment>> { 953 typedef support::detail::packed_endian_specific_integral<value_type, endian, 954 alignment> 955 endian_type; 956 957 static void output(const endian_type &E, void *Ctx, 958 llvm::raw_ostream &Stream) { 959 ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); 960 } 961 962 static StringRef input(StringRef Str, void *Ctx, endian_type &E) { 963 value_type V; 964 auto R = ScalarTraits<value_type>::input(Str, Ctx, V); 965 E = static_cast<endian_type>(V); 966 return R; 967 } 968 969 static bool mustQuote(StringRef Str) { 970 return ScalarTraits<value_type>::mustQuote(Str); 971 } 972 }; 973 974 // Utility for use within MappingTraits<>::mapping() method 975 // to [de]normalize an object for use with YAML conversion. 976 template <typename TNorm, typename TFinal> 977 struct MappingNormalization { 978 MappingNormalization(IO &i_o, TFinal &Obj) 979 : io(i_o), BufPtr(nullptr), Result(Obj) { 980 if ( io.outputting() ) { 981 BufPtr = new (&Buffer) TNorm(io, Obj); 982 } 983 else { 984 BufPtr = new (&Buffer) TNorm(io); 985 } 986 } 987 988 ~MappingNormalization() { 989 if ( ! io.outputting() ) { 990 Result = BufPtr->denormalize(io); 991 } 992 BufPtr->~TNorm(); 993 } 994 995 TNorm* operator->() { return BufPtr; } 996 997 private: 998 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 999 1000 Storage Buffer; 1001 IO &io; 1002 TNorm *BufPtr; 1003 TFinal &Result; 1004 }; 1005 1006 // Utility for use within MappingTraits<>::mapping() method 1007 // to [de]normalize an object for use with YAML conversion. 1008 template <typename TNorm, typename TFinal> 1009 struct MappingNormalizationHeap { 1010 MappingNormalizationHeap(IO &i_o, TFinal &Obj, 1011 llvm::BumpPtrAllocator *allocator) 1012 : io(i_o), BufPtr(nullptr), Result(Obj) { 1013 if ( io.outputting() ) { 1014 BufPtr = new (&Buffer) TNorm(io, Obj); 1015 } 1016 else if (allocator) { 1017 BufPtr = allocator->Allocate<TNorm>(); 1018 new (BufPtr) TNorm(io); 1019 } else { 1020 BufPtr = new TNorm(io); 1021 } 1022 } 1023 1024 ~MappingNormalizationHeap() { 1025 if ( io.outputting() ) { 1026 BufPtr->~TNorm(); 1027 } 1028 else { 1029 Result = BufPtr->denormalize(io); 1030 } 1031 } 1032 1033 TNorm* operator->() { return BufPtr; } 1034 1035 private: 1036 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 1037 1038 Storage Buffer; 1039 IO &io; 1040 TNorm *BufPtr; 1041 TFinal &Result; 1042 }; 1043 1044 /// 1045 /// The Input class is used to parse a yaml document into in-memory structs 1046 /// and vectors. 1047 /// 1048 /// It works by using YAMLParser to do a syntax parse of the entire yaml 1049 /// document, then the Input class builds a graph of HNodes which wraps 1050 /// each yaml Node. The extra layer is buffering. The low level yaml 1051 /// parser only lets you look at each node once. The buffering layer lets 1052 /// you search and interate multiple times. This is necessary because 1053 /// the mapRequired() method calls may not be in the same order 1054 /// as the keys in the document. 1055 /// 1056 class Input : public IO { 1057 public: 1058 // Construct a yaml Input object from a StringRef and optional 1059 // user-data. The DiagHandler can be specified to provide 1060 // alternative error reporting. 1061 Input(StringRef InputContent, 1062 void *Ctxt = nullptr, 1063 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 1064 void *DiagHandlerCtxt = nullptr); 1065 ~Input() override; 1066 1067 // Check if there was an syntax or semantic error during parsing. 1068 std::error_code error(); 1069 1070 private: 1071 bool outputting() override; 1072 bool mapTag(StringRef, bool) override; 1073 void beginMapping() override; 1074 void endMapping() override; 1075 bool preflightKey(const char *, bool, bool, bool &, void *&) override; 1076 void postflightKey(void *) override; 1077 void beginFlowMapping() override; 1078 void endFlowMapping() override; 1079 unsigned beginSequence() override; 1080 void endSequence() override; 1081 bool preflightElement(unsigned index, void *&) override; 1082 void postflightElement(void *) override; 1083 unsigned beginFlowSequence() override; 1084 bool preflightFlowElement(unsigned , void *&) override; 1085 void postflightFlowElement(void *) override; 1086 void endFlowSequence() override; 1087 void beginEnumScalar() override; 1088 bool matchEnumScalar(const char*, bool) override; 1089 bool matchEnumFallback() override; 1090 void endEnumScalar() override; 1091 bool beginBitSetScalar(bool &) override; 1092 bool bitSetMatch(const char *, bool ) override; 1093 void endBitSetScalar() override; 1094 void scalarString(StringRef &, bool) override; 1095 void blockScalarString(StringRef &) override; 1096 void setError(const Twine &message) override; 1097 bool canElideEmptySequence() override; 1098 1099 class HNode { 1100 virtual void anchor(); 1101 1102 public: 1103 HNode(Node *n) : _node(n) { } 1104 virtual ~HNode() = default; 1105 1106 static inline bool classof(const HNode *) { return true; } 1107 1108 Node *_node; 1109 }; 1110 1111 class EmptyHNode : public HNode { 1112 void anchor() override; 1113 1114 public: 1115 EmptyHNode(Node *n) : HNode(n) { } 1116 1117 static inline bool classof(const HNode *n) { 1118 return NullNode::classof(n->_node); 1119 } 1120 1121 static inline bool classof(const EmptyHNode *) { return true; } 1122 }; 1123 1124 class ScalarHNode : public HNode { 1125 void anchor() override; 1126 1127 public: 1128 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } 1129 1130 StringRef value() const { return _value; } 1131 1132 static inline bool classof(const HNode *n) { 1133 return ScalarNode::classof(n->_node) || 1134 BlockScalarNode::classof(n->_node); 1135 } 1136 1137 static inline bool classof(const ScalarHNode *) { return true; } 1138 1139 protected: 1140 StringRef _value; 1141 }; 1142 1143 class MapHNode : public HNode { 1144 void anchor() override; 1145 1146 public: 1147 MapHNode(Node *n) : HNode(n) { } 1148 1149 static inline bool classof(const HNode *n) { 1150 return MappingNode::classof(n->_node); 1151 } 1152 1153 static inline bool classof(const MapHNode *) { return true; } 1154 1155 typedef llvm::StringMap<std::unique_ptr<HNode>> NameToNode; 1156 1157 bool isValidKey(StringRef key); 1158 1159 NameToNode Mapping; 1160 llvm::SmallVector<const char*, 6> ValidKeys; 1161 }; 1162 1163 class SequenceHNode : public HNode { 1164 void anchor() override; 1165 1166 public: 1167 SequenceHNode(Node *n) : HNode(n) { } 1168 1169 static inline bool classof(const HNode *n) { 1170 return SequenceNode::classof(n->_node); 1171 } 1172 1173 static inline bool classof(const SequenceHNode *) { return true; } 1174 1175 std::vector<std::unique_ptr<HNode>> Entries; 1176 }; 1177 1178 std::unique_ptr<Input::HNode> createHNodes(Node *node); 1179 void setError(HNode *hnode, const Twine &message); 1180 void setError(Node *node, const Twine &message); 1181 1182 public: 1183 // These are only used by operator>>. They could be private 1184 // if those templated things could be made friends. 1185 bool setCurrentDocument(); 1186 bool nextDocument(); 1187 1188 /// Returns the current node that's being parsed by the YAML Parser. 1189 const Node *getCurrentNode() const; 1190 1191 private: 1192 llvm::SourceMgr SrcMgr; // must be before Strm 1193 std::unique_ptr<llvm::yaml::Stream> Strm; 1194 std::unique_ptr<HNode> TopNode; 1195 std::error_code EC; 1196 llvm::BumpPtrAllocator StringAllocator; 1197 llvm::yaml::document_iterator DocIterator; 1198 std::vector<bool> BitValuesUsed; 1199 HNode *CurrentNode; 1200 bool ScalarMatchFound; 1201 }; 1202 1203 /// 1204 /// The Output class is used to generate a yaml document from in-memory structs 1205 /// and vectors. 1206 /// 1207 class Output : public IO { 1208 public: 1209 Output(llvm::raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); 1210 ~Output() override; 1211 1212 bool outputting() override; 1213 bool mapTag(StringRef, bool) override; 1214 void beginMapping() override; 1215 void endMapping() override; 1216 bool preflightKey(const char *key, bool, bool, bool &, void *&) override; 1217 void postflightKey(void *) override; 1218 void beginFlowMapping() override; 1219 void endFlowMapping() override; 1220 unsigned beginSequence() override; 1221 void endSequence() override; 1222 bool preflightElement(unsigned, void *&) override; 1223 void postflightElement(void *) override; 1224 unsigned beginFlowSequence() override; 1225 bool preflightFlowElement(unsigned, void *&) override; 1226 void postflightFlowElement(void *) override; 1227 void endFlowSequence() override; 1228 void beginEnumScalar() override; 1229 bool matchEnumScalar(const char*, bool) override; 1230 bool matchEnumFallback() override; 1231 void endEnumScalar() override; 1232 bool beginBitSetScalar(bool &) override; 1233 bool bitSetMatch(const char *, bool ) override; 1234 void endBitSetScalar() override; 1235 void scalarString(StringRef &, bool) override; 1236 void blockScalarString(StringRef &) override; 1237 void setError(const Twine &message) override; 1238 bool canElideEmptySequence() override; 1239 1240 // These are only used by operator<<. They could be private 1241 // if that templated operator could be made a friend. 1242 void beginDocuments(); 1243 bool preflightDocument(unsigned); 1244 void postflightDocument(); 1245 void endDocuments(); 1246 1247 private: 1248 void output(StringRef s); 1249 void outputUpToEndOfLine(StringRef s); 1250 void newLineCheck(); 1251 void outputNewLine(); 1252 void paddedKey(StringRef key); 1253 void flowKey(StringRef Key); 1254 1255 enum InState { 1256 inSeq, 1257 inFlowSeq, 1258 inMapFirstKey, 1259 inMapOtherKey, 1260 inFlowMapFirstKey, 1261 inFlowMapOtherKey 1262 }; 1263 1264 llvm::raw_ostream &Out; 1265 int WrapColumn; 1266 SmallVector<InState, 8> StateStack; 1267 int Column; 1268 int ColumnAtFlowStart; 1269 int ColumnAtMapFlowStart; 1270 bool NeedBitValueComma; 1271 bool NeedFlowSequenceComma; 1272 bool EnumerationMatchFound; 1273 bool NeedsNewLine; 1274 }; 1275 1276 /// YAML I/O does conversion based on types. But often native data types 1277 /// are just a typedef of built in intergral types (e.g. int). But the C++ 1278 /// type matching system sees through the typedef and all the typedefed types 1279 /// look like a built in type. This will cause the generic YAML I/O conversion 1280 /// to be used. To provide better control over the YAML conversion, you can 1281 /// use this macro instead of typedef. It will create a class with one field 1282 /// and automatic conversion operators to and from the base type. 1283 /// Based on BOOST_STRONG_TYPEDEF 1284 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 1285 struct _type { \ 1286 _type() = default; \ 1287 _type(const _base v) : value(v) {} \ 1288 _type(const _type &v) = default; \ 1289 _type &operator=(const _type &rhs) = default; \ 1290 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 1291 operator const _base & () const { return value; } \ 1292 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 1293 bool operator==(const _base &rhs) const { return value == rhs; } \ 1294 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 1295 _base value; \ 1296 typedef _base BaseType; \ 1297 }; 1298 1299 /// 1300 /// Use these types instead of uintXX_t in any mapping to have 1301 /// its yaml output formatted as hexadecimal. 1302 /// 1303 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1304 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1305 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1306 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1307 1308 template<> 1309 struct ScalarTraits<Hex8> { 1310 static void output(const Hex8 &, void*, llvm::raw_ostream &); 1311 static StringRef input(StringRef, void*, Hex8 &); 1312 static bool mustQuote(StringRef) { return false; } 1313 }; 1314 1315 template<> 1316 struct ScalarTraits<Hex16> { 1317 static void output(const Hex16 &, void*, llvm::raw_ostream &); 1318 static StringRef input(StringRef, void*, Hex16 &); 1319 static bool mustQuote(StringRef) { return false; } 1320 }; 1321 1322 template<> 1323 struct ScalarTraits<Hex32> { 1324 static void output(const Hex32 &, void*, llvm::raw_ostream &); 1325 static StringRef input(StringRef, void*, Hex32 &); 1326 static bool mustQuote(StringRef) { return false; } 1327 }; 1328 1329 template<> 1330 struct ScalarTraits<Hex64> { 1331 static void output(const Hex64 &, void*, llvm::raw_ostream &); 1332 static StringRef input(StringRef, void*, Hex64 &); 1333 static bool mustQuote(StringRef) { return false; } 1334 }; 1335 1336 // Define non-member operator>> so that Input can stream in a document list. 1337 template <typename T> 1338 inline 1339 typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type 1340 operator>>(Input &yin, T &docList) { 1341 int i = 0; 1342 EmptyContext Ctx; 1343 while ( yin.setCurrentDocument() ) { 1344 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); 1345 if ( yin.error() ) 1346 return yin; 1347 yin.nextDocument(); 1348 ++i; 1349 } 1350 return yin; 1351 } 1352 1353 // Define non-member operator>> so that Input can stream in a map as a document. 1354 template <typename T> 1355 inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, 1356 Input &>::type 1357 operator>>(Input &yin, T &docMap) { 1358 EmptyContext Ctx; 1359 yin.setCurrentDocument(); 1360 yamlize(yin, docMap, true, Ctx); 1361 return yin; 1362 } 1363 1364 // Define non-member operator>> so that Input can stream in a sequence as 1365 // a document. 1366 template <typename T> 1367 inline 1368 typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type 1369 operator>>(Input &yin, T &docSeq) { 1370 EmptyContext Ctx; 1371 if (yin.setCurrentDocument()) 1372 yamlize(yin, docSeq, true, Ctx); 1373 return yin; 1374 } 1375 1376 // Define non-member operator>> so that Input can stream in a block scalar. 1377 template <typename T> 1378 inline 1379 typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type 1380 operator>>(Input &In, T &Val) { 1381 EmptyContext Ctx; 1382 if (In.setCurrentDocument()) 1383 yamlize(In, Val, true, Ctx); 1384 return In; 1385 } 1386 1387 // Provide better error message about types missing a trait specialization 1388 template <typename T> 1389 inline typename std::enable_if<missingTraits<T, EmptyContext>::value, 1390 Input &>::type 1391 operator>>(Input &yin, T &docSeq) { 1392 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1393 return yin; 1394 } 1395 1396 // Define non-member operator<< so that Output can stream out document list. 1397 template <typename T> 1398 inline 1399 typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type 1400 operator<<(Output &yout, T &docList) { 1401 EmptyContext Ctx; 1402 yout.beginDocuments(); 1403 const size_t count = DocumentListTraits<T>::size(yout, docList); 1404 for(size_t i=0; i < count; ++i) { 1405 if ( yout.preflightDocument(i) ) { 1406 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, 1407 Ctx); 1408 yout.postflightDocument(); 1409 } 1410 } 1411 yout.endDocuments(); 1412 return yout; 1413 } 1414 1415 // Define non-member operator<< so that Output can stream out a map. 1416 template <typename T> 1417 inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, 1418 Output &>::type 1419 operator<<(Output &yout, T &map) { 1420 EmptyContext Ctx; 1421 yout.beginDocuments(); 1422 if ( yout.preflightDocument(0) ) { 1423 yamlize(yout, map, true, Ctx); 1424 yout.postflightDocument(); 1425 } 1426 yout.endDocuments(); 1427 return yout; 1428 } 1429 1430 // Define non-member operator<< so that Output can stream out a sequence. 1431 template <typename T> 1432 inline 1433 typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type 1434 operator<<(Output &yout, T &seq) { 1435 EmptyContext Ctx; 1436 yout.beginDocuments(); 1437 if ( yout.preflightDocument(0) ) { 1438 yamlize(yout, seq, true, Ctx); 1439 yout.postflightDocument(); 1440 } 1441 yout.endDocuments(); 1442 return yout; 1443 } 1444 1445 // Define non-member operator<< so that Output can stream out a block scalar. 1446 template <typename T> 1447 inline 1448 typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type 1449 operator<<(Output &Out, T &Val) { 1450 EmptyContext Ctx; 1451 Out.beginDocuments(); 1452 if (Out.preflightDocument(0)) { 1453 yamlize(Out, Val, true, Ctx); 1454 Out.postflightDocument(); 1455 } 1456 Out.endDocuments(); 1457 return Out; 1458 } 1459 1460 // Provide better error message about types missing a trait specialization 1461 template <typename T> 1462 inline typename std::enable_if<missingTraits<T, EmptyContext>::value, 1463 Output &>::type 1464 operator<<(Output &yout, T &seq) { 1465 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1466 return yout; 1467 } 1468 1469 template <typename T> struct SequenceTraitsImpl { 1470 typedef typename T::value_type _type; 1471 static size_t size(IO &io, T &seq) { return seq.size(); } 1472 static _type &element(IO &io, T &seq, size_t index) { 1473 if (index >= seq.size()) 1474 seq.resize(index + 1); 1475 return seq[index]; 1476 } 1477 }; 1478 1479 } // end namespace yaml 1480 } // end namespace llvm 1481 1482 /// Utility for declaring that a std::vector of a particular type 1483 /// should be considered a YAML sequence. 1484 #define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ 1485 namespace llvm { \ 1486 namespace yaml { \ 1487 template <> \ 1488 struct SequenceTraits<std::vector<_type>> \ 1489 : public SequenceTraitsImpl<std::vector<_type>> {}; \ 1490 template <unsigned N> \ 1491 struct SequenceTraits<SmallVector<_type, N>> \ 1492 : public SequenceTraitsImpl<SmallVector<_type, N>> {}; \ 1493 } \ 1494 } 1495 1496 /// Utility for declaring that a std::vector of a particular type 1497 /// should be considered a YAML flow sequence. 1498 /// We need to do a partial specialization on the vector version, not a full. 1499 /// If this is a full specialization, the compiler is a bit too "smart" and 1500 /// decides to warn on -Wunused-const-variable. This workaround can be 1501 /// removed and we can do a full specialization on std::vector<T> once 1502 /// PR28878 is fixed. 1503 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ 1504 namespace llvm { \ 1505 namespace yaml { \ 1506 template <unsigned N> \ 1507 struct SequenceTraits<SmallVector<_type, N>> \ 1508 : public SequenceTraitsImpl<SmallVector<_type, N>> { \ 1509 static const bool flow = true; \ 1510 }; \ 1511 template <typename Allocator> \ 1512 struct SequenceTraits<std::vector<_type, Allocator>> \ 1513 : public SequenceTraitsImpl<std::vector<_type, Allocator>> { \ 1514 static const bool flow = true; \ 1515 }; \ 1516 } \ 1517 } 1518 1519 /// Utility for declaring that a std::vector of a particular type 1520 /// should be considered a YAML document list. 1521 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 1522 namespace llvm { \ 1523 namespace yaml { \ 1524 template <unsigned N> \ 1525 struct DocumentListTraits<SmallVector<_type, N>> \ 1526 : public SequenceTraitsImpl<SmallVector<_type, N>> {}; \ 1527 template <> \ 1528 struct DocumentListTraits<std::vector<_type>> \ 1529 : public SequenceTraitsImpl<std::vector<_type>> {}; \ 1530 } \ 1531 } 1532 1533 #endif // LLVM_SUPPORT_YAMLTRAITS_H 1534