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