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