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