diff options
Diffstat (limited to 'contrib/llvm/include/llvm/Support/YAMLTraits.h')
-rw-r--r-- | contrib/llvm/include/llvm/Support/YAMLTraits.h | 543 |
1 files changed, 372 insertions, 171 deletions
diff --git a/contrib/llvm/include/llvm/Support/YAMLTraits.h b/contrib/llvm/include/llvm/Support/YAMLTraits.h index bc3fa8a..cbba9c0 100644 --- a/contrib/llvm/include/llvm/Support/YAMLTraits.h +++ b/contrib/llvm/include/llvm/Support/YAMLTraits.h @@ -14,19 +14,30 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/Compiler.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cctype> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <new> +#include <string> #include <system_error> +#include <type_traits> +#include <vector> namespace llvm { namespace yaml { +struct EmptyContext {}; + /// This class should be specialized by any type that needs to be converted /// to/from a YAML mapping. For example: /// @@ -49,6 +60,28 @@ struct MappingTraits { // static const bool flow = true; }; +/// This class is similar to MappingTraits<T> but allows you to pass in +/// additional context for each map operation. For example: +/// +/// struct MappingContextTraits<MyStruct, MyContext> { +/// static void mapping(IO &io, MyStruct &s, MyContext &c) { +/// io.mapRequired("name", s.name); +/// io.mapRequired("size", s.size); +/// io.mapOptional("age", s.age); +/// ++c.TimesMapped; +/// } +/// }; +template <class T, class Context> struct MappingContextTraits { + // Must provide: + // static void mapping(IO &io, T &fields, Context &Ctx); + // Optionally may provide: + // static StringRef validate(IO &io, T &fields, Context &Ctx); + // + // The optional flow flag will cause generated YAML to use a flow mapping + // (e.g. { a: 0, b: 1 }): + // static const bool flow = true; +}; + /// This class should be specialized by any integral type that converts /// to/from a YAML scalar where there is a one-to-one mapping between /// in-memory values and a string in YAML. For example: @@ -114,7 +147,6 @@ struct ScalarTraits { //static bool mustQuote(StringRef); }; - /// This class should be specialized by type that requires custom conversion /// to/from a YAML literal block scalar. For example: /// @@ -147,7 +179,7 @@ struct BlockScalarTraits { /// to/from a YAML sequence. For example: /// /// template<> -/// struct SequenceTraits< std::vector<MyType> > { +/// struct SequenceTraits< std::vector<MyType>> { /// static size_t size(IO &io, std::vector<MyType> &seq) { /// return seq.size(); /// } @@ -177,9 +209,14 @@ struct DocumentListTraits { // static T::value_type& element(IO &io, T &seq, size_t index); }; -// Only used by compiler if both template types are the same -template <typename T, T> -struct SameType; +/// This class should be specialized by any type that needs to be converted +/// to/from a YAML mapping in the case where the names of the keys are not known +/// in advance, e.g. a string map. +template <typename T> +struct CustomMappingTraits { + // static void inputOne(IO &io, StringRef key, T &elem); + // static void output(IO &io, T &elem); +}; // Only used for better diagnostics of missing traits template <typename T> @@ -199,7 +236,7 @@ struct has_ScalarEnumerationTraits public: static bool const value = - (sizeof(test<ScalarEnumerationTraits<T> >(nullptr)) == 1); + (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); }; // Test if ScalarBitSetTraits<T> is defined on type T. @@ -215,7 +252,7 @@ struct has_ScalarBitSetTraits static double test(...); public: - static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(nullptr)) == 1); + static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); }; // Test if ScalarTraits<T> is defined on type T. @@ -258,11 +295,9 @@ public: (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1); }; -// Test if MappingTraits<T> is defined on type T. -template <class T> -struct has_MappingTraits -{ - typedef void (*Signature_mapping)(class IO&, T&); +// Test if MappingContextTraits<T> is defined on type T. +template <class T, class Context> struct has_MappingTraits { + typedef void (*Signature_mapping)(class IO &, T &, Context &); template <typename U> static char test(SameType<Signature_mapping, &U::mapping>*); @@ -271,14 +306,26 @@ struct has_MappingTraits static double test(...); public: - static bool const value = (sizeof(test<MappingTraits<T> >(nullptr)) == 1); + static bool const value = + (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); }; -// Test if MappingTraits<T>::validate() is defined on type T. -template <class T> -struct has_MappingValidateTraits -{ - typedef StringRef (*Signature_validate)(class IO&, T&); +// Test if MappingTraits<T> is defined on type T. +template <class T> struct has_MappingTraits<T, EmptyContext> { + typedef void (*Signature_mapping)(class IO &, T &); + + template <typename U> + static char test(SameType<Signature_mapping, &U::mapping> *); + + template <typename U> static double test(...); + +public: + static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); +}; + +// Test if MappingContextTraits<T>::validate() is defined on type T. +template <class T, class Context> struct has_MappingValidateTraits { + typedef StringRef (*Signature_validate)(class IO &, T &, Context &); template <typename U> static char test(SameType<Signature_validate, &U::validate>*); @@ -287,7 +334,21 @@ struct has_MappingValidateTraits static double test(...); public: - static bool const value = (sizeof(test<MappingTraits<T> >(nullptr)) == 1); + static bool const value = + (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); +}; + +// Test if MappingTraits<T>::validate() is defined on type T. +template <class T> struct has_MappingValidateTraits<T, EmptyContext> { + typedef StringRef (*Signature_validate)(class IO &, T &); + + template <typename U> + static char test(SameType<Signature_validate, &U::validate> *); + + template <typename U> static double test(...); + +public: + static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); }; // Test if SequenceTraits<T> is defined on type T. @@ -303,7 +364,24 @@ struct has_SequenceMethodTraits static double test(...); public: - static bool const value = (sizeof(test<SequenceTraits<T> >(nullptr)) == 1); + static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); +}; + +// Test if CustomMappingTraits<T> is defined on type T. +template <class T> +struct has_CustomMappingTraits +{ + typedef void (*Signature_input)(IO &io, StringRef key, T &v); + + template <typename U> + static char test(SameType<Signature_input, &U::inputOne>*); + + template <typename U> + static double test(...); + +public: + static bool const value = + (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1); }; // has_FlowTraits<int> will cause an error with some compilers because @@ -353,7 +431,7 @@ struct has_DocumentListTraits static double test(...); public: - static bool const value = (sizeof(test<DocumentListTraits<T> >(nullptr))==1); + static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); }; inline bool isNumber(StringRef S) { @@ -432,29 +510,33 @@ inline bool needsQuotes(StringRef S) { return false; } -template<typename T> -struct missingTraits : public std::integral_constant<bool, - !has_ScalarEnumerationTraits<T>::value - && !has_ScalarBitSetTraits<T>::value - && !has_ScalarTraits<T>::value - && !has_BlockScalarTraits<T>::value - && !has_MappingTraits<T>::value - && !has_SequenceTraits<T>::value - && !has_DocumentListTraits<T>::value > {}; - -template<typename T> -struct validatedMappingTraits : public std::integral_constant<bool, - has_MappingTraits<T>::value - && has_MappingValidateTraits<T>::value> {}; +template <typename T, typename Context> +struct missingTraits + : public std::integral_constant<bool, + !has_ScalarEnumerationTraits<T>::value && + !has_ScalarBitSetTraits<T>::value && + !has_ScalarTraits<T>::value && + !has_BlockScalarTraits<T>::value && + !has_MappingTraits<T, Context>::value && + !has_SequenceTraits<T>::value && + !has_CustomMappingTraits<T>::value && + !has_DocumentListTraits<T>::value> {}; + +template <typename T, typename Context> +struct validatedMappingTraits + : public std::integral_constant< + bool, has_MappingTraits<T, Context>::value && + has_MappingValidateTraits<T, Context>::value> {}; + +template <typename T, typename Context> +struct unvalidatedMappingTraits + : public std::integral_constant< + bool, has_MappingTraits<T, Context>::value && + !has_MappingValidateTraits<T, Context>::value> {}; -template<typename T> -struct unvalidatedMappingTraits : public std::integral_constant<bool, - has_MappingTraits<T>::value - && !has_MappingValidateTraits<T>::value> {}; // Base class for Input and Output. class IO { public: - IO(void *Ctxt=nullptr); virtual ~IO(); @@ -476,6 +558,7 @@ public: virtual void endMapping() = 0; virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; virtual void postflightKey(void*) = 0; + virtual std::vector<StringRef> keys() = 0; virtual void beginFlowMapping() = 0; virtual void endFlowMapping() = 0; @@ -512,9 +595,10 @@ public: template <typename FBT, typename T> void enumFallback(T &Val) { if (matchEnumFallback()) { + EmptyContext Context; // FIXME: Force integral conversion to allow strong typedefs to convert. FBT Res = static_cast<typename FBT::BaseType>(Val); - yamlize(*this, Res, true); + yamlize(*this, Res, true, Context); Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); } } @@ -550,40 +634,58 @@ public: void *getContext(); void setContext(void *); - template <typename T> - void mapRequired(const char* Key, T& Val) { - this->processKey(Key, Val, true); + template <typename T> void mapRequired(const char *Key, T &Val) { + EmptyContext Ctx; + this->processKey(Key, Val, true, Ctx); + } + template <typename T, typename Context> + void mapRequired(const char *Key, T &Val, Context &Ctx) { + this->processKey(Key, Val, true, Ctx); + } + + template <typename T> void mapOptional(const char *Key, T &Val) { + EmptyContext Ctx; + mapOptionalWithContext(Key, Val, Ctx); } template <typename T> - typename std::enable_if<has_SequenceTraits<T>::value,void>::type - mapOptional(const char* Key, T& Val) { + void mapOptional(const char *Key, T &Val, const T &Default) { + EmptyContext Ctx; + mapOptionalWithContext(Key, Val, Default, Ctx); + } + + template <typename T, typename Context> + typename std::enable_if<has_SequenceTraits<T>::value, void>::type + mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { // omit key/value instead of outputting empty sequence - if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) ) + if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) return; - this->processKey(Key, Val, false); + this->processKey(Key, Val, false, Ctx); } - template <typename T> - void mapOptional(const char* Key, Optional<T> &Val) { - processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false); + template <typename T, typename Context> + void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) { + this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false, + Ctx); } - template <typename T> - typename std::enable_if<!has_SequenceTraits<T>::value,void>::type - mapOptional(const char* Key, T& Val) { - this->processKey(Key, Val, false); + template <typename T, typename Context> + typename std::enable_if<!has_SequenceTraits<T>::value, void>::type + mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { + this->processKey(Key, Val, false, Ctx); } - template <typename T> - void mapOptional(const char* Key, T& Val, const T& Default) { - this->processKeyWithDefault(Key, Val, Default, false); + template <typename T, typename Context> + void mapOptionalWithContext(const char *Key, T &Val, const T &Default, + Context &Ctx) { + this->processKeyWithDefault(Key, Val, Default, false, Ctx); } private: - template <typename T> + template <typename T, typename Context> void processKeyWithDefault(const char *Key, Optional<T> &Val, - const Optional<T> &DefaultValue, bool Required) { + const Optional<T> &DefaultValue, bool Required, + Context &Ctx) { assert(DefaultValue.hasValue() == false && "Optional<T> shouldn't have a value!"); void *SaveInfo; @@ -593,7 +695,7 @@ private: Val = T(); if (this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) { - yamlize(*this, Val.getValue(), Required); + yamlize(*this, Val.getValue(), Required, Ctx); this->postflightKey(SaveInfo); } else { if (UseDefault) @@ -601,15 +703,15 @@ private: } } - template <typename T> - void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue, - bool Required) { + template <typename T, typename Context> + void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue, + bool Required, Context &Ctx) { void *SaveInfo; bool UseDefault; const bool sameAsDefault = outputting() && Val == DefaultValue; if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo) ) { - yamlize(*this, Val, Required); + yamlize(*this, Val, Required, Ctx); this->postflightKey(SaveInfo); } else { @@ -618,12 +720,12 @@ private: } } - template <typename T> - void processKey(const char *Key, T &Val, bool Required) { + template <typename T, typename Context> + void processKey(const char *Key, T &Val, bool Required, Context &Ctx) { void *SaveInfo; bool UseDefault; if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { - yamlize(*this, Val, Required); + yamlize(*this, Val, Required, Ctx); this->postflightKey(SaveInfo); } } @@ -632,17 +734,30 @@ private: void *Ctxt; }; -template<typename T> -typename std::enable_if<has_ScalarEnumerationTraits<T>::value,void>::type -yamlize(IO &io, T &Val, bool) { +namespace detail { + +template <typename T, typename Context> +void doMapping(IO &io, T &Val, Context &Ctx) { + MappingContextTraits<T, Context>::mapping(io, Val, Ctx); +} + +template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) { + MappingTraits<T>::mapping(io, Val); +} + +} // end namespace detail + +template <typename T> +typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { io.beginEnumScalar(); ScalarEnumerationTraits<T>::enumeration(io, Val); io.endEnumScalar(); } -template<typename T> -typename std::enable_if<has_ScalarBitSetTraits<T>::value,void>::type -yamlize(IO &io, T &Val, bool) { +template <typename T> +typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { bool DoClear; if ( io.beginBitSetScalar(DoClear) ) { if ( DoClear ) @@ -652,9 +767,9 @@ yamlize(IO &io, T &Val, bool) { } } -template<typename T> -typename std::enable_if<has_ScalarTraits<T>::value,void>::type -yamlize(IO &io, T &Val, bool) { +template <typename T> +typename std::enable_if<has_ScalarTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { if ( io.outputting() ) { std::string Storage; llvm::raw_string_ostream Buffer(Storage); @@ -674,7 +789,7 @@ yamlize(IO &io, T &Val, bool) { template <typename T> typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type -yamlize(IO &YamlIO, T &Val, bool) { +yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { if (YamlIO.outputting()) { std::string Storage; llvm::raw_string_ostream Buffer(Storage); @@ -691,9 +806,9 @@ yamlize(IO &YamlIO, T &Val, bool) { } } -template<typename T> -typename std::enable_if<validatedMappingTraits<T>::value, void>::type -yamlize(IO &io, T &Val, bool) { +template <typename T, typename Context> +typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type +yamlize(IO &io, T &Val, bool, Context &Ctx) { if (has_FlowTraits<MappingTraits<T>>::value) io.beginFlowMapping(); else @@ -705,7 +820,7 @@ yamlize(IO &io, T &Val, bool) { assert(Err.empty() && "invalid struct trying to be written as yaml"); } } - MappingTraits<T>::mapping(io, Val); + detail::doMapping(io, Val, Ctx); if (!io.outputting()) { StringRef Err = MappingTraits<T>::validate(io, Val); if (!Err.empty()) @@ -717,36 +832,51 @@ yamlize(IO &io, T &Val, bool) { io.endMapping(); } -template<typename T> -typename std::enable_if<unvalidatedMappingTraits<T>::value, void>::type -yamlize(IO &io, T &Val, bool) { +template <typename T, typename Context> +typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type +yamlize(IO &io, T &Val, bool, Context &Ctx) { if (has_FlowTraits<MappingTraits<T>>::value) { io.beginFlowMapping(); - MappingTraits<T>::mapping(io, Val); + detail::doMapping(io, Val, Ctx); io.endFlowMapping(); } else { io.beginMapping(); - MappingTraits<T>::mapping(io, Val); + detail::doMapping(io, Val, Ctx); io.endMapping(); } } -template<typename T> -typename std::enable_if<missingTraits<T>::value, void>::type -yamlize(IO &io, T &Val, bool) { +template <typename T> +typename std::enable_if<has_CustomMappingTraits<T>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { + if ( io.outputting() ) { + io.beginMapping(); + CustomMappingTraits<T>::output(io, Val); + io.endMapping(); + } else { + io.beginMapping(); + for (StringRef key : io.keys()) + CustomMappingTraits<T>::inputOne(io, key, Val); + io.endMapping(); + } +} + +template <typename T> +typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type +yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; } -template<typename T> -typename std::enable_if<has_SequenceTraits<T>::value,void>::type -yamlize(IO &io, T &Seq, bool) { +template <typename T, typename Context> +typename std::enable_if<has_SequenceTraits<T>::value, void>::type +yamlize(IO &io, T &Seq, bool, Context &Ctx) { if ( has_FlowTraits< SequenceTraits<T> >::value ) { unsigned incnt = io.beginFlowSequence(); unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; for(unsigned i=0; i < count; ++i) { void *SaveInfo; if ( io.preflightFlowElement(i, SaveInfo) ) { - yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); + yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); io.postflightFlowElement(SaveInfo); } } @@ -758,7 +888,7 @@ yamlize(IO &io, T &Seq, bool) { for(unsigned i=0; i < count; ++i) { void *SaveInfo; if ( io.preflightElement(i, SaveInfo) ) { - yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); + yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); io.postflightElement(SaveInfo); } } @@ -871,6 +1001,7 @@ struct ScalarTraits<support::detail::packed_endian_specific_integral< llvm::raw_ostream &Stream) { ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); } + static StringRef input(StringRef Str, void *Ctx, endian_type &E) { value_type V; auto R = ScalarTraits<value_type>::input(Str, Ctx, V); @@ -986,6 +1117,7 @@ private: void endMapping() override; bool preflightKey(const char *, bool, bool, bool &, void *&) override; void postflightKey(void *) override; + std::vector<StringRef> keys() override; void beginFlowMapping() override; void endFlowMapping() override; unsigned beginSequence() override; @@ -1010,9 +1142,11 @@ private: class HNode { virtual void anchor(); + public: HNode(Node *n) : _node(n) { } - virtual ~HNode() { } + virtual ~HNode() = default; + static inline bool classof(const HNode *) { return true; } Node *_node; @@ -1020,16 +1154,20 @@ private: class EmptyHNode : public HNode { void anchor() override; + public: EmptyHNode(Node *n) : HNode(n) { } + static inline bool classof(const HNode *n) { return NullNode::classof(n->_node); } + static inline bool classof(const EmptyHNode *) { return true; } }; class ScalarHNode : public HNode { void anchor() override; + public: ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } @@ -1039,7 +1177,9 @@ private: return ScalarNode::classof(n->_node) || BlockScalarNode::classof(n->_node); } + static inline bool classof(const ScalarHNode *) { return true; } + protected: StringRef _value; }; @@ -1053,14 +1193,13 @@ private: static inline bool classof(const HNode *n) { return MappingNode::classof(n->_node); } + static inline bool classof(const MapHNode *) { return true; } typedef llvm::StringMap<std::unique_ptr<HNode>> NameToNode; - bool isValidKey(StringRef key); - NameToNode Mapping; - llvm::SmallVector<const char*, 6> ValidKeys; + llvm::SmallVector<std::string, 6> ValidKeys; }; class SequenceHNode : public HNode { @@ -1072,6 +1211,7 @@ private: static inline bool classof(const HNode *n) { return SequenceNode::classof(n->_node); } + static inline bool classof(const SequenceHNode *) { return true; } std::vector<std::unique_ptr<HNode>> Entries; @@ -1117,6 +1257,7 @@ public: void endMapping() override; bool preflightKey(const char *key, bool, bool, bool &, void *&) override; void postflightKey(void *) override; + std::vector<StringRef> keys() override; void beginFlowMapping() override; void endFlowMapping() override; unsigned beginSequence() override; @@ -1138,7 +1279,7 @@ public: void blockScalarString(StringRef &) override; void setError(const Twine &message) override; bool canElideEmptySequence() override; -public: + // These are only used by operator<<. They could be private // if that templated operator could be made a friend. void beginDocuments(); @@ -1185,10 +1326,10 @@ private: /// Based on BOOST_STRONG_TYPEDEF #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ struct _type { \ - _type() { } \ - _type(const _base v) : value(v) { } \ - _type(const _type &v) : value(v.value) {} \ - _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\ + _type() = default; \ + _type(const _base v) : value(v) {} \ + _type(const _type &v) = default; \ + _type &operator=(const _type &rhs) = default; \ _type &operator=(const _base &rhs) { value = rhs; return *this; } \ operator const _base & () const { return value; } \ bool operator==(const _type &rhs) const { return value == rhs.value; } \ @@ -1241,8 +1382,9 @@ inline typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type operator>>(Input &yin, T &docList) { int i = 0; + EmptyContext Ctx; while ( yin.setCurrentDocument() ) { - yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true); + yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); if ( yin.error() ) return yin; yin.nextDocument(); @@ -1253,11 +1395,12 @@ operator>>(Input &yin, T &docList) { // Define non-member operator>> so that Input can stream in a map as a document. template <typename T> -inline -typename std::enable_if<has_MappingTraits<T>::value, Input &>::type +inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, + Input &>::type operator>>(Input &yin, T &docMap) { + EmptyContext Ctx; yin.setCurrentDocument(); - yamlize(yin, docMap, true); + yamlize(yin, docMap, true, Ctx); return yin; } @@ -1267,8 +1410,9 @@ template <typename T> inline typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type operator>>(Input &yin, T &docSeq) { + EmptyContext Ctx; if (yin.setCurrentDocument()) - yamlize(yin, docSeq, true); + yamlize(yin, docSeq, true, Ctx); return yin; } @@ -1277,15 +1421,27 @@ template <typename T> inline typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type operator>>(Input &In, T &Val) { + EmptyContext Ctx; if (In.setCurrentDocument()) - yamlize(In, Val, true); + yamlize(In, Val, true, Ctx); return In; } -// Provide better error message about types missing a trait specialization +// Define non-member operator>> so that Input can stream in a string map. template <typename T> inline -typename std::enable_if<missingTraits<T>::value, Input &>::type +typename std::enable_if<has_CustomMappingTraits<T>::value, Input &>::type +operator>>(Input &In, T &Val) { + EmptyContext Ctx; + if (In.setCurrentDocument()) + yamlize(In, Val, true, Ctx); + return In; +} + +// Provide better error message about types missing a trait specialization +template <typename T> +inline typename std::enable_if<missingTraits<T, EmptyContext>::value, + Input &>::type operator>>(Input &yin, T &docSeq) { char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; return yin; @@ -1296,11 +1452,13 @@ template <typename T> inline typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type operator<<(Output &yout, T &docList) { + EmptyContext Ctx; yout.beginDocuments(); const size_t count = DocumentListTraits<T>::size(yout, docList); for(size_t i=0; i < count; ++i) { if ( yout.preflightDocument(i) ) { - yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true); + yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, + Ctx); yout.postflightDocument(); } } @@ -1310,12 +1468,13 @@ operator<<(Output &yout, T &docList) { // Define non-member operator<< so that Output can stream out a map. template <typename T> -inline -typename std::enable_if<has_MappingTraits<T>::value, Output &>::type +inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value, + Output &>::type operator<<(Output &yout, T &map) { + EmptyContext Ctx; yout.beginDocuments(); if ( yout.preflightDocument(0) ) { - yamlize(yout, map, true); + yamlize(yout, map, true, Ctx); yout.postflightDocument(); } yout.endDocuments(); @@ -1327,9 +1486,10 @@ template <typename T> inline typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type operator<<(Output &yout, T &seq) { + EmptyContext Ctx; yout.beginDocuments(); if ( yout.preflightDocument(0) ) { - yamlize(yout, seq, true); + yamlize(yout, seq, true, Ctx); yout.postflightDocument(); } yout.endDocuments(); @@ -1341,84 +1501,125 @@ template <typename T> inline typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type operator<<(Output &Out, T &Val) { + EmptyContext Ctx; Out.beginDocuments(); if (Out.preflightDocument(0)) { - yamlize(Out, Val, true); + yamlize(Out, Val, true, Ctx); Out.postflightDocument(); } Out.endDocuments(); return Out; } -// Provide better error message about types missing a trait specialization +// Define non-member operator<< so that Output can stream out a string map. template <typename T> inline -typename std::enable_if<missingTraits<T>::value, Output &>::type +typename std::enable_if<has_CustomMappingTraits<T>::value, Output &>::type +operator<<(Output &Out, T &Val) { + EmptyContext Ctx; + Out.beginDocuments(); + if (Out.preflightDocument(0)) { + yamlize(Out, Val, true, Ctx); + Out.postflightDocument(); + } + Out.endDocuments(); + return Out; +} + +// Provide better error message about types missing a trait specialization +template <typename T> +inline typename std::enable_if<missingTraits<T, EmptyContext>::value, + Output &>::type operator<<(Output &yout, T &seq) { char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; return yout; } -} // namespace yaml -} // namespace llvm +template <typename T> struct SequenceTraitsImpl { + typedef typename T::value_type _type; + static size_t size(IO &io, T &seq) { return seq.size(); } + static _type &element(IO &io, T &seq, size_t index) { + if (index >= seq.size()) + seq.resize(index + 1); + return seq[index]; + } +}; + +/// Implementation of CustomMappingTraits for std::map<std::string, T>. +template <typename T> struct StdMapStringCustomMappingTraitsImpl { + typedef std::map<std::string, T> map_type; + static void inputOne(IO &io, StringRef key, map_type &v) { + io.mapRequired(key.str().c_str(), v[key]); + } + static void output(IO &io, map_type &v) { + for (auto &p : v) + io.mapRequired(p.first.c_str(), p.second); + } +}; + +} // end namespace yaml +} // end namespace llvm /// Utility for declaring that a std::vector of a particular type /// should be considered a YAML sequence. -#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ - namespace llvm { \ - namespace yaml { \ - template<> \ - struct SequenceTraits< std::vector<_type> > { \ - static size_t size(IO &io, std::vector<_type> &seq) { \ - return seq.size(); \ - } \ - static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ - if ( index >= seq.size() ) \ - seq.resize(index+1); \ - return seq[index]; \ - } \ - }; \ - } \ +#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ + namespace llvm { \ + namespace yaml { \ + template <> \ + struct SequenceTraits<std::vector<_type>> \ + : public SequenceTraitsImpl<std::vector<_type>> {}; \ + template <unsigned N> \ + struct SequenceTraits<SmallVector<_type, N>> \ + : public SequenceTraitsImpl<SmallVector<_type, N>> {}; \ + } \ } /// Utility for declaring that a std::vector of a particular type /// should be considered a YAML flow sequence. -#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ - namespace llvm { \ - namespace yaml { \ - template<> \ - struct SequenceTraits< std::vector<_type> > { \ - static size_t size(IO &io, std::vector<_type> &seq) { \ - return seq.size(); \ - } \ - static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ - (void)flow; /* Remove this workaround after PR17897 is fixed */ \ - if ( index >= seq.size() ) \ - seq.resize(index+1); \ - return seq[index]; \ - } \ - static const bool flow = true; \ - }; \ - } \ +/// We need to do a partial specialization on the vector version, not a full. +/// If this is a full specialization, the compiler is a bit too "smart" and +/// decides to warn on -Wunused-const-variable. This workaround can be +/// removed and we can do a full specialization on std::vector<T> once +/// PR28878 is fixed. +#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ + namespace llvm { \ + namespace yaml { \ + template <unsigned N> \ + struct SequenceTraits<SmallVector<_type, N>> \ + : public SequenceTraitsImpl<SmallVector<_type, N>> { \ + static const bool flow = true; \ + }; \ + template <typename Allocator> \ + struct SequenceTraits<std::vector<_type, Allocator>> \ + : public SequenceTraitsImpl<std::vector<_type, Allocator>> { \ + static const bool flow = true; \ + }; \ + } \ } /// Utility for declaring that a std::vector of a particular type /// should be considered a YAML document list. -#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ - namespace llvm { \ - namespace yaml { \ - template<> \ - struct DocumentListTraits< std::vector<_type> > { \ - static size_t size(IO &io, std::vector<_type> &seq) { \ - return seq.size(); \ - } \ - static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ - if ( index >= seq.size() ) \ - seq.resize(index+1); \ - return seq[index]; \ - } \ - }; \ - } \ +#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ + namespace llvm { \ + namespace yaml { \ + template <unsigned N> \ + struct DocumentListTraits<SmallVector<_type, N>> \ + : public SequenceTraitsImpl<SmallVector<_type, N>> {}; \ + template <> \ + struct DocumentListTraits<std::vector<_type>> \ + : public SequenceTraitsImpl<std::vector<_type>> {}; \ + } \ + } + +/// Utility for declaring that std::map<std::string, _type> should be considered +/// a YAML map. +#define LLVM_YAML_IS_STRING_MAP(_type) \ + namespace llvm { \ + namespace yaml { \ + template <> \ + struct CustomMappingTraits<std::map<std::string, _type>> \ + : public StdMapStringCustomMappingTraitsImpl<_type> {}; \ + } \ } #endif // LLVM_SUPPORT_YAMLTRAITS_H |