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