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