YAMLTraits.h revision 263508
1//===- llvm/Supporrt/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/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/Casting.h" 22#include "llvm/Support/Compiler.h" 23#include "llvm/Support/SourceMgr.h" 24#include "llvm/Support/YAMLParser.h" 25#include "llvm/Support/raw_ostream.h" 26#include "llvm/Support/system_error.h" 27#include "llvm/Support/type_traits.h" 28 29 30namespace llvm { 31namespace yaml { 32 33 34/// This class should be specialized by any type that needs to be converted 35/// to/from a YAML mapping. For example: 36/// 37/// struct ScalarBitSetTraits<MyStruct> { 38/// static void mapping(IO &io, MyStruct &s) { 39/// io.mapRequired("name", s.name); 40/// io.mapRequired("size", s.size); 41/// io.mapOptional("age", s.age); 42/// } 43/// }; 44template<class T> 45struct MappingTraits { 46 // Must provide: 47 // static void mapping(IO &io, T &fields); 48}; 49 50 51/// This class should be specialized by any integral type that converts 52/// to/from a YAML scalar where there is a one-to-one mapping between 53/// in-memory values and a string in YAML. For example: 54/// 55/// struct ScalarEnumerationTraits<Colors> { 56/// static void enumeration(IO &io, Colors &value) { 57/// io.enumCase(value, "red", cRed); 58/// io.enumCase(value, "blue", cBlue); 59/// io.enumCase(value, "green", cGreen); 60/// } 61/// }; 62template<typename T> 63struct ScalarEnumerationTraits { 64 // Must provide: 65 // static void enumeration(IO &io, T &value); 66}; 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/// }; 80template<typename T> 81struct ScalarBitSetTraits { 82 // Must provide: 83 // static void bitset(IO &io, T &value); 84}; 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/// }; 102template<typename T> 103struct 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 114 115/// This class should be specialized by any type that needs to be converted 116/// to/from a YAML sequence. For example: 117/// 118/// template<> 119/// struct SequenceTraits< std::vector<MyType> > { 120/// static size_t size(IO &io, std::vector<MyType> &seq) { 121/// return seq.size(); 122/// } 123/// static MyType& element(IO &, std::vector<MyType> &seq, size_t index) { 124/// if ( index >= seq.size() ) 125/// seq.resize(index+1); 126/// return seq[index]; 127/// } 128/// }; 129template<typename T> 130struct SequenceTraits { 131 // Must provide: 132 // static size_t size(IO &io, T &seq); 133 // static T::value_type& element(IO &io, T &seq, size_t index); 134 // 135 // The following is option and will cause generated YAML to use 136 // a flow sequence (e.g. [a,b,c]). 137 // static const bool flow = true; 138}; 139 140 141/// This class should be specialized by any type that needs to be converted 142/// to/from a list of YAML documents. 143template<typename T> 144struct DocumentListTraits { 145 // Must provide: 146 // static size_t size(IO &io, T &seq); 147 // static T::value_type& element(IO &io, T &seq, size_t index); 148}; 149 150 151// Only used by compiler if both template types are the same 152template <typename T, T> 153struct SameType; 154 155// Only used for better diagnostics of missing traits 156template <typename T> 157struct MissingTrait; 158 159 160 161// Test if ScalarEnumerationTraits<T> is defined on type T. 162template <class T> 163struct has_ScalarEnumerationTraits 164{ 165 typedef void (*Signature_enumeration)(class IO&, T&); 166 167 template <typename U> 168 static char test(SameType<Signature_enumeration, &U::enumeration>*); 169 170 template <typename U> 171 static double test(...); 172 173public: 174 static bool const value = (sizeof(test<ScalarEnumerationTraits<T> >(0)) == 1); 175}; 176 177 178// Test if ScalarBitSetTraits<T> is defined on type T. 179template <class T> 180struct has_ScalarBitSetTraits 181{ 182 typedef void (*Signature_bitset)(class IO&, T&); 183 184 template <typename U> 185 static char test(SameType<Signature_bitset, &U::bitset>*); 186 187 template <typename U> 188 static double test(...); 189 190public: 191 static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(0)) == 1); 192}; 193 194 195// Test if ScalarTraits<T> is defined on type T. 196template <class T> 197struct has_ScalarTraits 198{ 199 typedef StringRef (*Signature_input)(StringRef, void*, T&); 200 typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&); 201 202 template <typename U> 203 static char test(SameType<Signature_input, &U::input>*, 204 SameType<Signature_output, &U::output>*); 205 206 template <typename U> 207 static double test(...); 208 209public: 210 static bool const value = (sizeof(test<ScalarTraits<T> >(0,0)) == 1); 211}; 212 213 214// Test if MappingTraits<T> is defined on type T. 215template <class T> 216struct has_MappingTraits 217{ 218 typedef void (*Signature_mapping)(class IO&, T&); 219 220 template <typename U> 221 static char test(SameType<Signature_mapping, &U::mapping>*); 222 223 template <typename U> 224 static double test(...); 225 226public: 227 static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1); 228}; 229 230 231// Test if SequenceTraits<T> is defined on type T. 232template <class T> 233struct has_SequenceMethodTraits 234{ 235 typedef size_t (*Signature_size)(class IO&, T&); 236 237 template <typename U> 238 static char test(SameType<Signature_size, &U::size>*); 239 240 template <typename U> 241 static double test(...); 242 243public: 244 static bool const value = (sizeof(test<SequenceTraits<T> >(0)) == 1); 245}; 246 247 248// has_FlowTraits<int> will cause an error with some compilers because 249// it subclasses int. Using this wrapper only instantiates the 250// real has_FlowTraits only if the template type is a class. 251template <typename T, bool Enabled = llvm::is_class<T>::value> 252class has_FlowTraits 253{ 254public: 255 static const bool value = false; 256}; 257 258// Some older gcc compilers don't support straight forward tests 259// for members, so test for ambiguity cause by the base and derived 260// classes both defining the member. 261template <class T> 262struct has_FlowTraits<T, true> 263{ 264 struct Fallback { bool flow; }; 265 struct Derived : T, Fallback { }; 266 267 template<typename C> 268 static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; 269 270 template<typename C> 271 static char (&f(...))[2]; 272 273public: 274 static bool const value = sizeof(f<Derived>(0)) == 2; 275}; 276 277 278 279// Test if SequenceTraits<T> is defined on type T 280template<typename T> 281struct has_SequenceTraits : public llvm::integral_constant<bool, 282 has_SequenceMethodTraits<T>::value > { }; 283 284 285// Test if DocumentListTraits<T> is defined on type T 286template <class T> 287struct has_DocumentListTraits 288{ 289 typedef size_t (*Signature_size)(class IO&, T&); 290 291 template <typename U> 292 static char test(SameType<Signature_size, &U::size>*); 293 294 template <typename U> 295 static double test(...); 296 297public: 298 static bool const value = (sizeof(test<DocumentListTraits<T> >(0)) == 1); 299}; 300 301 302 303 304template<typename T> 305struct missingTraits : public llvm::integral_constant<bool, 306 !has_ScalarEnumerationTraits<T>::value 307 && !has_ScalarBitSetTraits<T>::value 308 && !has_ScalarTraits<T>::value 309 && !has_MappingTraits<T>::value 310 && !has_SequenceTraits<T>::value 311 && !has_DocumentListTraits<T>::value > {}; 312 313 314// Base class for Input and Output. 315class IO { 316public: 317 318 IO(void *Ctxt=NULL); 319 virtual ~IO(); 320 321 virtual bool outputting() const = 0; 322 323 virtual unsigned beginSequence() = 0; 324 virtual bool preflightElement(unsigned, void *&) = 0; 325 virtual void postflightElement(void*) = 0; 326 virtual void endSequence() = 0; 327 virtual bool canElideEmptySequence() = 0; 328 329 virtual unsigned beginFlowSequence() = 0; 330 virtual bool preflightFlowElement(unsigned, void *&) = 0; 331 virtual void postflightFlowElement(void*) = 0; 332 virtual void endFlowSequence() = 0; 333 334 virtual bool mapTag(StringRef Tag, bool Default=false) = 0; 335 virtual void beginMapping() = 0; 336 virtual void endMapping() = 0; 337 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; 338 virtual void postflightKey(void*) = 0; 339 340 virtual void beginEnumScalar() = 0; 341 virtual bool matchEnumScalar(const char*, bool) = 0; 342 virtual void endEnumScalar() = 0; 343 344 virtual bool beginBitSetScalar(bool &) = 0; 345 virtual bool bitSetMatch(const char*, bool) = 0; 346 virtual void endBitSetScalar() = 0; 347 348 virtual void scalarString(StringRef &) = 0; 349 350 virtual void setError(const Twine &) = 0; 351 352 template <typename T> 353 void enumCase(T &Val, const char* Str, const T ConstVal) { 354 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { 355 Val = ConstVal; 356 } 357 } 358 359 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 360 template <typename T> 361 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { 362 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { 363 Val = ConstVal; 364 } 365 } 366 367 template <typename T> 368 void bitSetCase(T &Val, const char* Str, const T ConstVal) { 369 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 370 Val = Val | ConstVal; 371 } 372 } 373 374 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 375 template <typename T> 376 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { 377 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 378 Val = Val | ConstVal; 379 } 380 } 381 382 void *getContext(); 383 void setContext(void *); 384 385 template <typename T> 386 void mapRequired(const char* Key, T& Val) { 387 this->processKey(Key, Val, true); 388 } 389 390 template <typename T> 391 typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type 392 mapOptional(const char* Key, T& Val) { 393 // omit key/value instead of outputting empty sequence 394 if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) ) 395 return; 396 this->processKey(Key, Val, false); 397 } 398 399 template <typename T> 400 typename llvm::enable_if_c<!has_SequenceTraits<T>::value,void>::type 401 mapOptional(const char* Key, T& Val) { 402 this->processKey(Key, Val, false); 403 } 404 405 template <typename T> 406 void mapOptional(const char* Key, T& Val, const T& Default) { 407 this->processKeyWithDefault(Key, Val, Default, false); 408 } 409 410private: 411 template <typename T> 412 void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue, 413 bool Required) { 414 void *SaveInfo; 415 bool UseDefault; 416 const bool sameAsDefault = outputting() && Val == DefaultValue; 417 if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, 418 SaveInfo) ) { 419 yamlize(*this, Val, Required); 420 this->postflightKey(SaveInfo); 421 } 422 else { 423 if ( UseDefault ) 424 Val = DefaultValue; 425 } 426 } 427 428 template <typename T> 429 void processKey(const char *Key, T &Val, bool Required) { 430 void *SaveInfo; 431 bool UseDefault; 432 if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { 433 yamlize(*this, Val, Required); 434 this->postflightKey(SaveInfo); 435 } 436 } 437 438private: 439 void *Ctxt; 440}; 441 442 443 444template<typename T> 445typename llvm::enable_if_c<has_ScalarEnumerationTraits<T>::value,void>::type 446yamlize(IO &io, T &Val, bool) { 447 io.beginEnumScalar(); 448 ScalarEnumerationTraits<T>::enumeration(io, Val); 449 io.endEnumScalar(); 450} 451 452template<typename T> 453typename llvm::enable_if_c<has_ScalarBitSetTraits<T>::value,void>::type 454yamlize(IO &io, T &Val, bool) { 455 bool DoClear; 456 if ( io.beginBitSetScalar(DoClear) ) { 457 if ( DoClear ) 458 Val = static_cast<T>(0); 459 ScalarBitSetTraits<T>::bitset(io, Val); 460 io.endBitSetScalar(); 461 } 462} 463 464 465template<typename T> 466typename llvm::enable_if_c<has_ScalarTraits<T>::value,void>::type 467yamlize(IO &io, T &Val, bool) { 468 if ( io.outputting() ) { 469 std::string Storage; 470 llvm::raw_string_ostream Buffer(Storage); 471 ScalarTraits<T>::output(Val, io.getContext(), Buffer); 472 StringRef Str = Buffer.str(); 473 io.scalarString(Str); 474 } 475 else { 476 StringRef Str; 477 io.scalarString(Str); 478 StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); 479 if ( !Result.empty() ) { 480 io.setError(llvm::Twine(Result)); 481 } 482 } 483} 484 485 486template<typename T> 487typename llvm::enable_if_c<has_MappingTraits<T>::value, void>::type 488yamlize(IO &io, T &Val, bool) { 489 io.beginMapping(); 490 MappingTraits<T>::mapping(io, Val); 491 io.endMapping(); 492} 493 494template<typename T> 495typename llvm::enable_if_c<missingTraits<T>::value, void>::type 496yamlize(IO &io, T &Val, bool) { 497 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 498} 499 500template<typename T> 501typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type 502yamlize(IO &io, T &Seq, bool) { 503 if ( has_FlowTraits< SequenceTraits<T> >::value ) { 504 unsigned incnt = io.beginFlowSequence(); 505 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 506 for(unsigned i=0; i < count; ++i) { 507 void *SaveInfo; 508 if ( io.preflightFlowElement(i, SaveInfo) ) { 509 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); 510 io.postflightFlowElement(SaveInfo); 511 } 512 } 513 io.endFlowSequence(); 514 } 515 else { 516 unsigned incnt = io.beginSequence(); 517 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 518 for(unsigned i=0; i < count; ++i) { 519 void *SaveInfo; 520 if ( io.preflightElement(i, SaveInfo) ) { 521 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); 522 io.postflightElement(SaveInfo); 523 } 524 } 525 io.endSequence(); 526 } 527} 528 529 530template<> 531struct ScalarTraits<bool> { 532 static void output(const bool &, void*, llvm::raw_ostream &); 533 static StringRef input(StringRef, void*, bool &); 534}; 535 536template<> 537struct ScalarTraits<StringRef> { 538 static void output(const StringRef &, void*, llvm::raw_ostream &); 539 static StringRef input(StringRef, void*, StringRef &); 540}; 541 542template<> 543struct ScalarTraits<uint8_t> { 544 static void output(const uint8_t &, void*, llvm::raw_ostream &); 545 static StringRef input(StringRef, void*, uint8_t &); 546}; 547 548template<> 549struct ScalarTraits<uint16_t> { 550 static void output(const uint16_t &, void*, llvm::raw_ostream &); 551 static StringRef input(StringRef, void*, uint16_t &); 552}; 553 554template<> 555struct ScalarTraits<uint32_t> { 556 static void output(const uint32_t &, void*, llvm::raw_ostream &); 557 static StringRef input(StringRef, void*, uint32_t &); 558}; 559 560template<> 561struct ScalarTraits<uint64_t> { 562 static void output(const uint64_t &, void*, llvm::raw_ostream &); 563 static StringRef input(StringRef, void*, uint64_t &); 564}; 565 566template<> 567struct ScalarTraits<int8_t> { 568 static void output(const int8_t &, void*, llvm::raw_ostream &); 569 static StringRef input(StringRef, void*, int8_t &); 570}; 571 572template<> 573struct ScalarTraits<int16_t> { 574 static void output(const int16_t &, void*, llvm::raw_ostream &); 575 static StringRef input(StringRef, void*, int16_t &); 576}; 577 578template<> 579struct ScalarTraits<int32_t> { 580 static void output(const int32_t &, void*, llvm::raw_ostream &); 581 static StringRef input(StringRef, void*, int32_t &); 582}; 583 584template<> 585struct ScalarTraits<int64_t> { 586 static void output(const int64_t &, void*, llvm::raw_ostream &); 587 static StringRef input(StringRef, void*, int64_t &); 588}; 589 590template<> 591struct ScalarTraits<float> { 592 static void output(const float &, void*, llvm::raw_ostream &); 593 static StringRef input(StringRef, void*, float &); 594}; 595 596template<> 597struct ScalarTraits<double> { 598 static void output(const double &, void*, llvm::raw_ostream &); 599 static StringRef input(StringRef, void*, double &); 600}; 601 602 603 604// Utility for use within MappingTraits<>::mapping() method 605// to [de]normalize an object for use with YAML conversion. 606template <typename TNorm, typename TFinal> 607struct MappingNormalization { 608 MappingNormalization(IO &i_o, TFinal &Obj) 609 : io(i_o), BufPtr(NULL), Result(Obj) { 610 if ( io.outputting() ) { 611 BufPtr = new (&Buffer) TNorm(io, Obj); 612 } 613 else { 614 BufPtr = new (&Buffer) TNorm(io); 615 } 616 } 617 618 ~MappingNormalization() { 619 if ( ! io.outputting() ) { 620 Result = BufPtr->denormalize(io); 621 } 622 BufPtr->~TNorm(); 623 } 624 625 TNorm* operator->() { return BufPtr; } 626 627private: 628 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 629 630 Storage Buffer; 631 IO &io; 632 TNorm *BufPtr; 633 TFinal &Result; 634}; 635 636 637 638// Utility for use within MappingTraits<>::mapping() method 639// to [de]normalize an object for use with YAML conversion. 640template <typename TNorm, typename TFinal> 641struct MappingNormalizationHeap { 642 MappingNormalizationHeap(IO &i_o, TFinal &Obj) 643 : io(i_o), BufPtr(NULL), Result(Obj) { 644 if ( io.outputting() ) { 645 BufPtr = new (&Buffer) TNorm(io, Obj); 646 } 647 else { 648 BufPtr = new TNorm(io); 649 } 650 } 651 652 ~MappingNormalizationHeap() { 653 if ( io.outputting() ) { 654 BufPtr->~TNorm(); 655 } 656 else { 657 Result = BufPtr->denormalize(io); 658 } 659 } 660 661 TNorm* operator->() { return BufPtr; } 662 663private: 664 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 665 666 Storage Buffer; 667 IO &io; 668 TNorm *BufPtr; 669 TFinal &Result; 670}; 671 672 673 674/// 675/// The Input class is used to parse a yaml document into in-memory structs 676/// and vectors. 677/// 678/// It works by using YAMLParser to do a syntax parse of the entire yaml 679/// document, then the Input class builds a graph of HNodes which wraps 680/// each yaml Node. The extra layer is buffering. The low level yaml 681/// parser only lets you look at each node once. The buffering layer lets 682/// you search and interate multiple times. This is necessary because 683/// the mapRequired() method calls may not be in the same order 684/// as the keys in the document. 685/// 686class Input : public IO { 687public: 688 // Construct a yaml Input object from a StringRef and optional 689 // user-data. The DiagHandler can be specified to provide 690 // alternative error reporting. 691 Input(StringRef InputContent, 692 void *Ctxt = NULL, 693 SourceMgr::DiagHandlerTy DiagHandler = NULL, 694 void *DiagHandlerCtxt = NULL); 695 ~Input(); 696 697 // Check if there was an syntax or semantic error during parsing. 698 llvm::error_code error(); 699 700 static bool classof(const IO *io) { return !io->outputting(); } 701 702private: 703 virtual bool outputting() const; 704 virtual bool mapTag(StringRef, bool); 705 virtual void beginMapping(); 706 virtual void endMapping(); 707 virtual bool preflightKey(const char *, bool, bool, bool &, void *&); 708 virtual void postflightKey(void *); 709 virtual unsigned beginSequence(); 710 virtual void endSequence(); 711 virtual bool preflightElement(unsigned index, void *&); 712 virtual void postflightElement(void *); 713 virtual unsigned beginFlowSequence(); 714 virtual bool preflightFlowElement(unsigned , void *&); 715 virtual void postflightFlowElement(void *); 716 virtual void endFlowSequence(); 717 virtual void beginEnumScalar(); 718 virtual bool matchEnumScalar(const char*, bool); 719 virtual void endEnumScalar(); 720 virtual bool beginBitSetScalar(bool &); 721 virtual bool bitSetMatch(const char *, bool ); 722 virtual void endBitSetScalar(); 723 virtual void scalarString(StringRef &); 724 virtual void setError(const Twine &message); 725 virtual bool canElideEmptySequence(); 726 727 class HNode { 728 virtual void anchor(); 729 public: 730 HNode(Node *n) : _node(n) { } 731 virtual ~HNode() { } 732 static inline bool classof(const HNode *) { return true; } 733 734 Node *_node; 735 }; 736 737 class EmptyHNode : public HNode { 738 virtual void anchor(); 739 public: 740 EmptyHNode(Node *n) : HNode(n) { } 741 static inline bool classof(const HNode *n) { 742 return NullNode::classof(n->_node); 743 } 744 static inline bool classof(const EmptyHNode *) { return true; } 745 }; 746 747 class ScalarHNode : public HNode { 748 virtual void anchor(); 749 public: 750 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } 751 752 StringRef value() const { return _value; } 753 754 static inline bool classof(const HNode *n) { 755 return ScalarNode::classof(n->_node); 756 } 757 static inline bool classof(const ScalarHNode *) { return true; } 758 protected: 759 StringRef _value; 760 }; 761 762 class MapHNode : public HNode { 763 public: 764 MapHNode(Node *n) : HNode(n) { } 765 virtual ~MapHNode(); 766 767 static inline bool classof(const HNode *n) { 768 return MappingNode::classof(n->_node); 769 } 770 static inline bool classof(const MapHNode *) { return true; } 771 772 typedef llvm::StringMap<HNode*> NameToNode; 773 774 bool isValidKey(StringRef key); 775 776 NameToNode Mapping; 777 llvm::SmallVector<const char*, 6> ValidKeys; 778 }; 779 780 class SequenceHNode : public HNode { 781 public: 782 SequenceHNode(Node *n) : HNode(n) { } 783 virtual ~SequenceHNode(); 784 785 static inline bool classof(const HNode *n) { 786 return SequenceNode::classof(n->_node); 787 } 788 static inline bool classof(const SequenceHNode *) { return true; } 789 790 std::vector<HNode*> Entries; 791 }; 792 793 Input::HNode *createHNodes(Node *node); 794 void setError(HNode *hnode, const Twine &message); 795 void setError(Node *node, const Twine &message); 796 797 798public: 799 // These are only used by operator>>. They could be private 800 // if those templated things could be made friends. 801 bool setCurrentDocument(); 802 void nextDocument(); 803 804private: 805 llvm::SourceMgr SrcMgr; // must be before Strm 806 OwningPtr<llvm::yaml::Stream> Strm; 807 OwningPtr<HNode> TopNode; 808 llvm::error_code EC; 809 llvm::BumpPtrAllocator StringAllocator; 810 llvm::yaml::document_iterator DocIterator; 811 std::vector<bool> BitValuesUsed; 812 HNode *CurrentNode; 813 bool ScalarMatchFound; 814}; 815 816 817 818 819/// 820/// The Output class is used to generate a yaml document from in-memory structs 821/// and vectors. 822/// 823class Output : public IO { 824public: 825 Output(llvm::raw_ostream &, void *Ctxt=NULL); 826 virtual ~Output(); 827 828 static bool classof(const IO *io) { return io->outputting(); } 829 830 virtual bool outputting() const; 831 virtual bool mapTag(StringRef, bool); 832 virtual void beginMapping(); 833 virtual void endMapping(); 834 virtual bool preflightKey(const char *key, bool, bool, bool &, void *&); 835 virtual void postflightKey(void *); 836 virtual unsigned beginSequence(); 837 virtual void endSequence(); 838 virtual bool preflightElement(unsigned, void *&); 839 virtual void postflightElement(void *); 840 virtual unsigned beginFlowSequence(); 841 virtual bool preflightFlowElement(unsigned, void *&); 842 virtual void postflightFlowElement(void *); 843 virtual void endFlowSequence(); 844 virtual void beginEnumScalar(); 845 virtual bool matchEnumScalar(const char*, bool); 846 virtual void endEnumScalar(); 847 virtual bool beginBitSetScalar(bool &); 848 virtual bool bitSetMatch(const char *, bool ); 849 virtual void endBitSetScalar(); 850 virtual void scalarString(StringRef &); 851 virtual void setError(const Twine &message); 852 virtual bool canElideEmptySequence(); 853public: 854 // These are only used by operator<<. They could be private 855 // if that templated operator could be made a friend. 856 void beginDocuments(); 857 bool preflightDocument(unsigned); 858 void postflightDocument(); 859 void endDocuments(); 860 861private: 862 void output(StringRef s); 863 void outputUpToEndOfLine(StringRef s); 864 void newLineCheck(); 865 void outputNewLine(); 866 void paddedKey(StringRef key); 867 868 enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey }; 869 870 llvm::raw_ostream &Out; 871 SmallVector<InState, 8> StateStack; 872 int Column; 873 int ColumnAtFlowStart; 874 bool NeedBitValueComma; 875 bool NeedFlowSequenceComma; 876 bool EnumerationMatchFound; 877 bool NeedsNewLine; 878}; 879 880 881 882 883/// YAML I/O does conversion based on types. But often native data types 884/// are just a typedef of built in intergral types (e.g. int). But the C++ 885/// type matching system sees through the typedef and all the typedefed types 886/// look like a built in type. This will cause the generic YAML I/O conversion 887/// to be used. To provide better control over the YAML conversion, you can 888/// use this macro instead of typedef. It will create a class with one field 889/// and automatic conversion operators to and from the base type. 890/// Based on BOOST_STRONG_TYPEDEF 891#define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 892 struct _type { \ 893 _type() { } \ 894 _type(const _base v) : value(v) { } \ 895 _type(const _type &v) : value(v.value) {} \ 896 _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\ 897 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 898 operator const _base & () const { return value; } \ 899 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 900 bool operator==(const _base &rhs) const { return value == rhs; } \ 901 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 902 _base value; \ 903 }; 904 905 906 907/// 908/// Use these types instead of uintXX_t in any mapping to have 909/// its yaml output formatted as hexadecimal. 910/// 911LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 912LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 913LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 914LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 915 916 917template<> 918struct ScalarTraits<Hex8> { 919 static void output(const Hex8 &, void*, llvm::raw_ostream &); 920 static StringRef input(StringRef, void*, Hex8 &); 921}; 922 923template<> 924struct ScalarTraits<Hex16> { 925 static void output(const Hex16 &, void*, llvm::raw_ostream &); 926 static StringRef input(StringRef, void*, Hex16 &); 927}; 928 929template<> 930struct ScalarTraits<Hex32> { 931 static void output(const Hex32 &, void*, llvm::raw_ostream &); 932 static StringRef input(StringRef, void*, Hex32 &); 933}; 934 935template<> 936struct ScalarTraits<Hex64> { 937 static void output(const Hex64 &, void*, llvm::raw_ostream &); 938 static StringRef input(StringRef, void*, Hex64 &); 939}; 940 941 942// Define non-member operator>> so that Input can stream in a document list. 943template <typename T> 944inline 945typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Input &>::type 946operator>>(Input &yin, T &docList) { 947 int i = 0; 948 while ( yin.setCurrentDocument() ) { 949 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true); 950 if ( yin.error() ) 951 return yin; 952 yin.nextDocument(); 953 ++i; 954 } 955 return yin; 956} 957 958// Define non-member operator>> so that Input can stream in a map as a document. 959template <typename T> 960inline 961typename llvm::enable_if_c<has_MappingTraits<T>::value,Input &>::type 962operator>>(Input &yin, T &docMap) { 963 yin.setCurrentDocument(); 964 yamlize(yin, docMap, true); 965 return yin; 966} 967 968// Define non-member operator>> so that Input can stream in a sequence as 969// a document. 970template <typename T> 971inline 972typename llvm::enable_if_c<has_SequenceTraits<T>::value,Input &>::type 973operator>>(Input &yin, T &docSeq) { 974 if (yin.setCurrentDocument()) 975 yamlize(yin, docSeq, true); 976 return yin; 977} 978 979// Provide better error message about types missing a trait specialization 980template <typename T> 981inline 982typename llvm::enable_if_c<missingTraits<T>::value,Input &>::type 983operator>>(Input &yin, T &docSeq) { 984 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 985 return yin; 986} 987 988 989// Define non-member operator<< so that Output can stream out document list. 990template <typename T> 991inline 992typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Output &>::type 993operator<<(Output &yout, T &docList) { 994 yout.beginDocuments(); 995 const size_t count = DocumentListTraits<T>::size(yout, docList); 996 for(size_t i=0; i < count; ++i) { 997 if ( yout.preflightDocument(i) ) { 998 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true); 999 yout.postflightDocument(); 1000 } 1001 } 1002 yout.endDocuments(); 1003 return yout; 1004} 1005 1006// Define non-member operator<< so that Output can stream out a map. 1007template <typename T> 1008inline 1009typename llvm::enable_if_c<has_MappingTraits<T>::value,Output &>::type 1010operator<<(Output &yout, T &map) { 1011 yout.beginDocuments(); 1012 if ( yout.preflightDocument(0) ) { 1013 yamlize(yout, map, true); 1014 yout.postflightDocument(); 1015 } 1016 yout.endDocuments(); 1017 return yout; 1018} 1019 1020// Define non-member operator<< so that Output can stream out a sequence. 1021template <typename T> 1022inline 1023typename llvm::enable_if_c<has_SequenceTraits<T>::value,Output &>::type 1024operator<<(Output &yout, T &seq) { 1025 yout.beginDocuments(); 1026 if ( yout.preflightDocument(0) ) { 1027 yamlize(yout, seq, true); 1028 yout.postflightDocument(); 1029 } 1030 yout.endDocuments(); 1031 return yout; 1032} 1033 1034// Provide better error message about types missing a trait specialization 1035template <typename T> 1036inline 1037typename llvm::enable_if_c<missingTraits<T>::value,Output &>::type 1038operator<<(Output &yout, T &seq) { 1039 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1040 return yout; 1041} 1042 1043 1044} // namespace yaml 1045} // namespace llvm 1046 1047 1048/// Utility for declaring that a std::vector of a particular type 1049/// should be considered a YAML sequence. 1050#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ 1051 namespace llvm { \ 1052 namespace yaml { \ 1053 template<> \ 1054 struct SequenceTraits< std::vector<_type> > { \ 1055 static size_t size(IO &io, std::vector<_type> &seq) { \ 1056 return seq.size(); \ 1057 } \ 1058 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1059 if ( index >= seq.size() ) \ 1060 seq.resize(index+1); \ 1061 return seq[index]; \ 1062 } \ 1063 }; \ 1064 } \ 1065 } 1066 1067/// Utility for declaring that a std::vector of a particular type 1068/// should be considered a YAML flow sequence. 1069#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ 1070 namespace llvm { \ 1071 namespace yaml { \ 1072 template<> \ 1073 struct SequenceTraits< std::vector<_type> > { \ 1074 static size_t size(IO &io, std::vector<_type> &seq) { \ 1075 return seq.size(); \ 1076 } \ 1077 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1078 if ( index >= seq.size() ) \ 1079 seq.resize(index+1); \ 1080 return seq[index]; \ 1081 } \ 1082 static const bool flow = true; \ 1083 }; \ 1084 } \ 1085 } 1086 1087/// Utility for declaring that a std::vector of a particular type 1088/// should be considered a YAML document list. 1089#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 1090 namespace llvm { \ 1091 namespace yaml { \ 1092 template<> \ 1093 struct DocumentListTraits< std::vector<_type> > { \ 1094 static size_t size(IO &io, std::vector<_type> &seq) { \ 1095 return seq.size(); \ 1096 } \ 1097 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1098 if ( index >= seq.size() ) \ 1099 seq.resize(index+1); \ 1100 return seq[index]; \ 1101 } \ 1102 }; \ 1103 } \ 1104 } 1105 1106 1107 1108#endif // LLVM_SUPPORT_YAMLTRAITS_H 1109