forked from OSchip/llvm-project
[YAMLIO] Add the ability to map with context.
mapping a yaml field to an object in code has always been a stateless operation. You could still pass state by using the `setContext` function of the YAMLIO object, but this represented global state for the entire yaml input. In order to have context-sensitive state, it is necessary to pass this state in at the granularity of an individual mapping. This patch adds support for this type of context-sensitive state. You simply pass an additional argument of type T to the `mapRequired` or `mapOptional` functions, and provided you have specialized a `MappingContextTraits<U, T>` class with the appropriate mapping function, you can pass this context into the mapping function. Reviewed By: chandlerc Differential Revision: https://reviews.llvm.org/D24162 llvm-svn: 280977
This commit is contained in:
parent
ba7c5cfbbb
commit
35377f88f5
|
@ -27,6 +27,8 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace yaml {
|
namespace yaml {
|
||||||
|
|
||||||
|
struct EmptyContext {};
|
||||||
|
|
||||||
/// This class should be specialized by any type that needs to be converted
|
/// This class should be specialized by any type that needs to be converted
|
||||||
/// to/from a YAML mapping. For example:
|
/// to/from a YAML mapping. For example:
|
||||||
///
|
///
|
||||||
|
@ -49,6 +51,28 @@ struct MappingTraits {
|
||||||
// static const bool flow = true;
|
// 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
|
/// 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
|
/// to/from a YAML scalar where there is a one-to-one mapping between
|
||||||
/// in-memory values and a string in YAML. For example:
|
/// in-memory values and a string in YAML. For example:
|
||||||
|
@ -258,11 +282,9 @@ public:
|
||||||
(sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
|
(sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test if MappingTraits<T> is defined on type T.
|
// Test if MappingContextTraits<T> is defined on type T.
|
||||||
template <class T>
|
template <class T, class Context> struct has_MappingTraits {
|
||||||
struct has_MappingTraits
|
typedef void (*Signature_mapping)(class IO &, T &, Context &);
|
||||||
{
|
|
||||||
typedef void (*Signature_mapping)(class IO&, T&);
|
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static char test(SameType<Signature_mapping, &U::mapping>*);
|
static char test(SameType<Signature_mapping, &U::mapping>*);
|
||||||
|
@ -271,14 +293,26 @@ struct has_MappingTraits
|
||||||
static double test(...);
|
static double test(...);
|
||||||
|
|
||||||
public:
|
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.
|
// Test if MappingTraits<T> is defined on type T.
|
||||||
template <class T>
|
template <class T> struct has_MappingTraits<T, EmptyContext> {
|
||||||
struct has_MappingValidateTraits
|
typedef void (*Signature_mapping)(class IO &, T &);
|
||||||
{
|
|
||||||
typedef StringRef (*Signature_validate)(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>
|
template <typename U>
|
||||||
static char test(SameType<Signature_validate, &U::validate>*);
|
static char test(SameType<Signature_validate, &U::validate>*);
|
||||||
|
@ -287,7 +321,21 @@ struct has_MappingValidateTraits
|
||||||
static double test(...);
|
static double test(...);
|
||||||
|
|
||||||
public:
|
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.
|
// Test if SequenceTraits<T> is defined on type T.
|
||||||
|
@ -432,25 +480,29 @@ inline bool needsQuotes(StringRef S) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T, typename Context>
|
||||||
struct missingTraits : public std::integral_constant<bool,
|
struct missingTraits
|
||||||
!has_ScalarEnumerationTraits<T>::value
|
: public std::integral_constant<bool,
|
||||||
&& !has_ScalarBitSetTraits<T>::value
|
!has_ScalarEnumerationTraits<T>::value &&
|
||||||
&& !has_ScalarTraits<T>::value
|
!has_ScalarBitSetTraits<T>::value &&
|
||||||
&& !has_BlockScalarTraits<T>::value
|
!has_ScalarTraits<T>::value &&
|
||||||
&& !has_MappingTraits<T>::value
|
!has_BlockScalarTraits<T>::value &&
|
||||||
&& !has_SequenceTraits<T>::value
|
!has_MappingTraits<T, Context>::value &&
|
||||||
&& !has_DocumentListTraits<T>::value > {};
|
!has_SequenceTraits<T>::value &&
|
||||||
|
!has_DocumentListTraits<T>::value> {};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T, typename Context>
|
||||||
struct validatedMappingTraits : public std::integral_constant<bool,
|
struct validatedMappingTraits
|
||||||
has_MappingTraits<T>::value
|
: public std::integral_constant<
|
||||||
&& has_MappingValidateTraits<T>::value> {};
|
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.
|
// Base class for Input and Output.
|
||||||
class IO {
|
class IO {
|
||||||
public:
|
public:
|
||||||
|
@ -512,9 +564,10 @@ public:
|
||||||
template <typename FBT, typename T>
|
template <typename FBT, typename T>
|
||||||
void enumFallback(T &Val) {
|
void enumFallback(T &Val) {
|
||||||
if (matchEnumFallback()) {
|
if (matchEnumFallback()) {
|
||||||
|
EmptyContext Context;
|
||||||
// FIXME: Force integral conversion to allow strong typedefs to convert.
|
// FIXME: Force integral conversion to allow strong typedefs to convert.
|
||||||
FBT Res = static_cast<typename FBT::BaseType>(Val);
|
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));
|
Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -550,40 +603,58 @@ public:
|
||||||
void *getContext();
|
void *getContext();
|
||||||
void setContext(void *);
|
void setContext(void *);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T> void mapRequired(const char *Key, T &Val) {
|
||||||
void mapRequired(const char* Key, T& Val) {
|
EmptyContext Ctx;
|
||||||
this->processKey(Key, Val, true);
|
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>
|
template <typename T>
|
||||||
typename std::enable_if<has_SequenceTraits<T>::value,void>::type
|
void mapOptional(const char *Key, T &Val, const T &Default) {
|
||||||
mapOptional(const char* Key, T& Val) {
|
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
|
// omit key/value instead of outputting empty sequence
|
||||||
if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) )
|
if (this->canElideEmptySequence() && !(Val.begin() != Val.end()))
|
||||||
return;
|
return;
|
||||||
this->processKey(Key, Val, false);
|
this->processKey(Key, Val, false, Ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename Context>
|
||||||
void mapOptional(const char* Key, Optional<T> &Val) {
|
void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) {
|
||||||
processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false);
|
this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false,
|
||||||
|
Ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename Context>
|
||||||
typename std::enable_if<!has_SequenceTraits<T>::value,void>::type
|
typename std::enable_if<!has_SequenceTraits<T>::value, void>::type
|
||||||
mapOptional(const char* Key, T& Val) {
|
mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
|
||||||
this->processKey(Key, Val, false);
|
this->processKey(Key, Val, false, Ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename Context>
|
||||||
void mapOptional(const char* Key, T& Val, const T& Default) {
|
void mapOptionalWithContext(const char *Key, T &Val, const T &Default,
|
||||||
this->processKeyWithDefault(Key, Val, Default, false);
|
Context &Ctx) {
|
||||||
|
this->processKeyWithDefault(Key, Val, Default, false, Ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T, typename Context>
|
||||||
void processKeyWithDefault(const char *Key, Optional<T> &Val,
|
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 &&
|
assert(DefaultValue.hasValue() == false &&
|
||||||
"Optional<T> shouldn't have a value!");
|
"Optional<T> shouldn't have a value!");
|
||||||
void *SaveInfo;
|
void *SaveInfo;
|
||||||
|
@ -593,7 +664,7 @@ private:
|
||||||
Val = T();
|
Val = T();
|
||||||
if (this->preflightKey(Key, Required, sameAsDefault, UseDefault,
|
if (this->preflightKey(Key, Required, sameAsDefault, UseDefault,
|
||||||
SaveInfo)) {
|
SaveInfo)) {
|
||||||
yamlize(*this, Val.getValue(), Required);
|
yamlize(*this, Val.getValue(), Required, Ctx);
|
||||||
this->postflightKey(SaveInfo);
|
this->postflightKey(SaveInfo);
|
||||||
} else {
|
} else {
|
||||||
if (UseDefault)
|
if (UseDefault)
|
||||||
|
@ -601,15 +672,15 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename Context>
|
||||||
void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue,
|
void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
|
||||||
bool Required) {
|
bool Required, Context &Ctx) {
|
||||||
void *SaveInfo;
|
void *SaveInfo;
|
||||||
bool UseDefault;
|
bool UseDefault;
|
||||||
const bool sameAsDefault = outputting() && Val == DefaultValue;
|
const bool sameAsDefault = outputting() && Val == DefaultValue;
|
||||||
if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
|
if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
|
||||||
SaveInfo) ) {
|
SaveInfo) ) {
|
||||||
yamlize(*this, Val, Required);
|
yamlize(*this, Val, Required, Ctx);
|
||||||
this->postflightKey(SaveInfo);
|
this->postflightKey(SaveInfo);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -618,12 +689,12 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename Context>
|
||||||
void processKey(const char *Key, T &Val, bool Required) {
|
void processKey(const char *Key, T &Val, bool Required, Context &Ctx) {
|
||||||
void *SaveInfo;
|
void *SaveInfo;
|
||||||
bool UseDefault;
|
bool UseDefault;
|
||||||
if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
|
if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
|
||||||
yamlize(*this, Val, Required);
|
yamlize(*this, Val, Required, Ctx);
|
||||||
this->postflightKey(SaveInfo);
|
this->postflightKey(SaveInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,17 +703,28 @@ private:
|
||||||
void *Ctxt;
|
void *Ctxt;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
namespace detail {
|
||||||
typename std::enable_if<has_ScalarEnumerationTraits<T>::value,void>::type
|
template <typename T, typename Context>
|
||||||
yamlize(IO &io, T &Val, bool) {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type
|
||||||
|
yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
|
||||||
io.beginEnumScalar();
|
io.beginEnumScalar();
|
||||||
ScalarEnumerationTraits<T>::enumeration(io, Val);
|
ScalarEnumerationTraits<T>::enumeration(io, Val);
|
||||||
io.endEnumScalar();
|
io.endEnumScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename std::enable_if<has_ScalarBitSetTraits<T>::value,void>::type
|
typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type
|
||||||
yamlize(IO &io, T &Val, bool) {
|
yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
|
||||||
bool DoClear;
|
bool DoClear;
|
||||||
if ( io.beginBitSetScalar(DoClear) ) {
|
if ( io.beginBitSetScalar(DoClear) ) {
|
||||||
if ( DoClear )
|
if ( DoClear )
|
||||||
|
@ -652,9 +734,9 @@ yamlize(IO &io, T &Val, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename std::enable_if<has_ScalarTraits<T>::value,void>::type
|
typename std::enable_if<has_ScalarTraits<T>::value, void>::type
|
||||||
yamlize(IO &io, T &Val, bool) {
|
yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
|
||||||
if ( io.outputting() ) {
|
if ( io.outputting() ) {
|
||||||
std::string Storage;
|
std::string Storage;
|
||||||
llvm::raw_string_ostream Buffer(Storage);
|
llvm::raw_string_ostream Buffer(Storage);
|
||||||
|
@ -674,7 +756,7 @@ yamlize(IO &io, T &Val, bool) {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type
|
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()) {
|
if (YamlIO.outputting()) {
|
||||||
std::string Storage;
|
std::string Storage;
|
||||||
llvm::raw_string_ostream Buffer(Storage);
|
llvm::raw_string_ostream Buffer(Storage);
|
||||||
|
@ -691,9 +773,9 @@ yamlize(IO &YamlIO, T &Val, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T, typename Context>
|
||||||
typename std::enable_if<validatedMappingTraits<T>::value, void>::type
|
typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type
|
||||||
yamlize(IO &io, T &Val, bool) {
|
yamlize(IO &io, T &Val, bool, Context &Ctx) {
|
||||||
if (has_FlowTraits<MappingTraits<T>>::value)
|
if (has_FlowTraits<MappingTraits<T>>::value)
|
||||||
io.beginFlowMapping();
|
io.beginFlowMapping();
|
||||||
else
|
else
|
||||||
|
@ -705,7 +787,7 @@ yamlize(IO &io, T &Val, bool) {
|
||||||
assert(Err.empty() && "invalid struct trying to be written as yaml");
|
assert(Err.empty() && "invalid struct trying to be written as yaml");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MappingTraits<T>::mapping(io, Val);
|
detail::doMapping(io, Val, Ctx);
|
||||||
if (!io.outputting()) {
|
if (!io.outputting()) {
|
||||||
StringRef Err = MappingTraits<T>::validate(io, Val);
|
StringRef Err = MappingTraits<T>::validate(io, Val);
|
||||||
if (!Err.empty())
|
if (!Err.empty())
|
||||||
|
@ -717,36 +799,36 @@ yamlize(IO &io, T &Val, bool) {
|
||||||
io.endMapping();
|
io.endMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T, typename Context>
|
||||||
typename std::enable_if<unvalidatedMappingTraits<T>::value, void>::type
|
typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type
|
||||||
yamlize(IO &io, T &Val, bool) {
|
yamlize(IO &io, T &Val, bool, Context &Ctx) {
|
||||||
if (has_FlowTraits<MappingTraits<T>>::value) {
|
if (has_FlowTraits<MappingTraits<T>>::value) {
|
||||||
io.beginFlowMapping();
|
io.beginFlowMapping();
|
||||||
MappingTraits<T>::mapping(io, Val);
|
detail::doMapping(io, Val, Ctx);
|
||||||
io.endFlowMapping();
|
io.endFlowMapping();
|
||||||
} else {
|
} else {
|
||||||
io.beginMapping();
|
io.beginMapping();
|
||||||
MappingTraits<T>::mapping(io, Val);
|
detail::doMapping(io, Val, Ctx);
|
||||||
io.endMapping();
|
io.endMapping();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename std::enable_if<missingTraits<T>::value, void>::type
|
typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type
|
||||||
yamlize(IO &io, T &Val, bool) {
|
yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
|
||||||
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
|
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T, typename Context>
|
||||||
typename std::enable_if<has_SequenceTraits<T>::value,void>::type
|
typename std::enable_if<has_SequenceTraits<T>::value, void>::type
|
||||||
yamlize(IO &io, T &Seq, bool) {
|
yamlize(IO &io, T &Seq, bool, Context &Ctx) {
|
||||||
if ( has_FlowTraits< SequenceTraits<T> >::value ) {
|
if ( has_FlowTraits< SequenceTraits<T> >::value ) {
|
||||||
unsigned incnt = io.beginFlowSequence();
|
unsigned incnt = io.beginFlowSequence();
|
||||||
unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
|
unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
|
||||||
for(unsigned i=0; i < count; ++i) {
|
for(unsigned i=0; i < count; ++i) {
|
||||||
void *SaveInfo;
|
void *SaveInfo;
|
||||||
if ( io.preflightFlowElement(i, 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);
|
io.postflightFlowElement(SaveInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -758,7 +840,7 @@ yamlize(IO &io, T &Seq, bool) {
|
||||||
for(unsigned i=0; i < count; ++i) {
|
for(unsigned i=0; i < count; ++i) {
|
||||||
void *SaveInfo;
|
void *SaveInfo;
|
||||||
if ( io.preflightElement(i, 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);
|
io.postflightElement(SaveInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1241,8 +1323,9 @@ inline
|
||||||
typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type
|
typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type
|
||||||
operator>>(Input &yin, T &docList) {
|
operator>>(Input &yin, T &docList) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
EmptyContext Ctx;
|
||||||
while ( yin.setCurrentDocument() ) {
|
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() )
|
if ( yin.error() )
|
||||||
return yin;
|
return yin;
|
||||||
yin.nextDocument();
|
yin.nextDocument();
|
||||||
|
@ -1253,11 +1336,12 @@ operator>>(Input &yin, T &docList) {
|
||||||
|
|
||||||
// Define non-member operator>> so that Input can stream in a map as a document.
|
// Define non-member operator>> so that Input can stream in a map as a document.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline
|
inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value,
|
||||||
typename std::enable_if<has_MappingTraits<T>::value, Input &>::type
|
Input &>::type
|
||||||
operator>>(Input &yin, T &docMap) {
|
operator>>(Input &yin, T &docMap) {
|
||||||
|
EmptyContext Ctx;
|
||||||
yin.setCurrentDocument();
|
yin.setCurrentDocument();
|
||||||
yamlize(yin, docMap, true);
|
yamlize(yin, docMap, true, Ctx);
|
||||||
return yin;
|
return yin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,8 +1351,9 @@ template <typename T>
|
||||||
inline
|
inline
|
||||||
typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type
|
typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type
|
||||||
operator>>(Input &yin, T &docSeq) {
|
operator>>(Input &yin, T &docSeq) {
|
||||||
|
EmptyContext Ctx;
|
||||||
if (yin.setCurrentDocument())
|
if (yin.setCurrentDocument())
|
||||||
yamlize(yin, docSeq, true);
|
yamlize(yin, docSeq, true, Ctx);
|
||||||
return yin;
|
return yin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1277,15 +1362,16 @@ template <typename T>
|
||||||
inline
|
inline
|
||||||
typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type
|
typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type
|
||||||
operator>>(Input &In, T &Val) {
|
operator>>(Input &In, T &Val) {
|
||||||
|
EmptyContext Ctx;
|
||||||
if (In.setCurrentDocument())
|
if (In.setCurrentDocument())
|
||||||
yamlize(In, Val, true);
|
yamlize(In, Val, true, Ctx);
|
||||||
return In;
|
return In;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide better error message about types missing a trait specialization
|
// Provide better error message about types missing a trait specialization
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline
|
inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
|
||||||
typename std::enable_if<missingTraits<T>::value, Input &>::type
|
Input &>::type
|
||||||
operator>>(Input &yin, T &docSeq) {
|
operator>>(Input &yin, T &docSeq) {
|
||||||
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
|
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
|
||||||
return yin;
|
return yin;
|
||||||
|
@ -1296,11 +1382,13 @@ template <typename T>
|
||||||
inline
|
inline
|
||||||
typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type
|
typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type
|
||||||
operator<<(Output &yout, T &docList) {
|
operator<<(Output &yout, T &docList) {
|
||||||
|
EmptyContext Ctx;
|
||||||
yout.beginDocuments();
|
yout.beginDocuments();
|
||||||
const size_t count = DocumentListTraits<T>::size(yout, docList);
|
const size_t count = DocumentListTraits<T>::size(yout, docList);
|
||||||
for(size_t i=0; i < count; ++i) {
|
for(size_t i=0; i < count; ++i) {
|
||||||
if ( yout.preflightDocument(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();
|
yout.postflightDocument();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1310,12 +1398,13 @@ operator<<(Output &yout, T &docList) {
|
||||||
|
|
||||||
// Define non-member operator<< so that Output can stream out a map.
|
// Define non-member operator<< so that Output can stream out a map.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline
|
inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value,
|
||||||
typename std::enable_if<has_MappingTraits<T>::value, Output &>::type
|
Output &>::type
|
||||||
operator<<(Output &yout, T &map) {
|
operator<<(Output &yout, T &map) {
|
||||||
|
EmptyContext Ctx;
|
||||||
yout.beginDocuments();
|
yout.beginDocuments();
|
||||||
if ( yout.preflightDocument(0) ) {
|
if ( yout.preflightDocument(0) ) {
|
||||||
yamlize(yout, map, true);
|
yamlize(yout, map, true, Ctx);
|
||||||
yout.postflightDocument();
|
yout.postflightDocument();
|
||||||
}
|
}
|
||||||
yout.endDocuments();
|
yout.endDocuments();
|
||||||
|
@ -1327,9 +1416,10 @@ template <typename T>
|
||||||
inline
|
inline
|
||||||
typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type
|
typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type
|
||||||
operator<<(Output &yout, T &seq) {
|
operator<<(Output &yout, T &seq) {
|
||||||
|
EmptyContext Ctx;
|
||||||
yout.beginDocuments();
|
yout.beginDocuments();
|
||||||
if ( yout.preflightDocument(0) ) {
|
if ( yout.preflightDocument(0) ) {
|
||||||
yamlize(yout, seq, true);
|
yamlize(yout, seq, true, Ctx);
|
||||||
yout.postflightDocument();
|
yout.postflightDocument();
|
||||||
}
|
}
|
||||||
yout.endDocuments();
|
yout.endDocuments();
|
||||||
|
@ -1341,9 +1431,10 @@ template <typename T>
|
||||||
inline
|
inline
|
||||||
typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type
|
typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type
|
||||||
operator<<(Output &Out, T &Val) {
|
operator<<(Output &Out, T &Val) {
|
||||||
|
EmptyContext Ctx;
|
||||||
Out.beginDocuments();
|
Out.beginDocuments();
|
||||||
if (Out.preflightDocument(0)) {
|
if (Out.preflightDocument(0)) {
|
||||||
yamlize(Out, Val, true);
|
yamlize(Out, Val, true, Ctx);
|
||||||
Out.postflightDocument();
|
Out.postflightDocument();
|
||||||
}
|
}
|
||||||
Out.endDocuments();
|
Out.endDocuments();
|
||||||
|
@ -1352,8 +1443,8 @@ operator<<(Output &Out, T &Val) {
|
||||||
|
|
||||||
// Provide better error message about types missing a trait specialization
|
// Provide better error message about types missing a trait specialization
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline
|
inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
|
||||||
typename std::enable_if<missingTraits<T>::value, Output &>::type
|
Output &>::type
|
||||||
operator<<(Output &yout, T &seq) {
|
operator<<(Output &yout, T &seq) {
|
||||||
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
|
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
|
||||||
return yout;
|
return yout;
|
||||||
|
|
|
@ -257,7 +257,8 @@ std::unique_ptr<Module> MIRParserImpl::parse() {
|
||||||
bool MIRParserImpl::parseMachineFunction(yaml::Input &In, Module &M,
|
bool MIRParserImpl::parseMachineFunction(yaml::Input &In, Module &M,
|
||||||
bool NoLLVMIR) {
|
bool NoLLVMIR) {
|
||||||
auto MF = llvm::make_unique<yaml::MachineFunction>();
|
auto MF = llvm::make_unique<yaml::MachineFunction>();
|
||||||
yaml::yamlize(In, *MF, false);
|
yaml::EmptyContext Ctx;
|
||||||
|
yaml::yamlize(In, *MF, false, Ctx);
|
||||||
if (In.error())
|
if (In.error())
|
||||||
return true;
|
return true;
|
||||||
auto FunctionName = MF->Name;
|
auto FunctionName = MF->Name;
|
||||||
|
|
|
@ -2299,3 +2299,72 @@ TEST(YAMLIO, TestWrapFlow) {
|
||||||
out.clear();
|
out.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MappingContext {
|
||||||
|
int A = 0;
|
||||||
|
};
|
||||||
|
struct SimpleMap {
|
||||||
|
int B = 0;
|
||||||
|
int C = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NestedMap {
|
||||||
|
NestedMap(MappingContext &Context) : Context(Context) {}
|
||||||
|
SimpleMap Simple;
|
||||||
|
MappingContext &Context;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace yaml {
|
||||||
|
template <> struct MappingContextTraits<SimpleMap, MappingContext> {
|
||||||
|
static void mapping(IO &io, SimpleMap &sm, MappingContext &Context) {
|
||||||
|
io.mapRequired("B", sm.B);
|
||||||
|
io.mapRequired("C", sm.C);
|
||||||
|
++Context.A;
|
||||||
|
io.mapRequired("Context", Context.A);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct MappingTraits<NestedMap> {
|
||||||
|
static void mapping(IO &io, NestedMap &nm) {
|
||||||
|
io.mapRequired("Simple", nm.Simple, nm.Context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(YAMLIO, TestMapWithContext) {
|
||||||
|
MappingContext Context;
|
||||||
|
NestedMap Nested(Context);
|
||||||
|
std::string out;
|
||||||
|
llvm::raw_string_ostream ostr(out);
|
||||||
|
|
||||||
|
Output yout(ostr, nullptr, 15);
|
||||||
|
|
||||||
|
yout << Nested;
|
||||||
|
ostr.flush();
|
||||||
|
EXPECT_EQ(1, Context.A);
|
||||||
|
EXPECT_EQ("---\n"
|
||||||
|
"Simple: \n"
|
||||||
|
" B: 0\n"
|
||||||
|
" C: 0\n"
|
||||||
|
" Context: 1\n"
|
||||||
|
"...\n",
|
||||||
|
out);
|
||||||
|
|
||||||
|
out.clear();
|
||||||
|
|
||||||
|
Nested.Simple.B = 2;
|
||||||
|
Nested.Simple.C = 3;
|
||||||
|
yout << Nested;
|
||||||
|
ostr.flush();
|
||||||
|
EXPECT_EQ(2, Context.A);
|
||||||
|
EXPECT_EQ("---\n"
|
||||||
|
"Simple: \n"
|
||||||
|
" B: 2\n"
|
||||||
|
" C: 3\n"
|
||||||
|
" Context: 2\n"
|
||||||
|
"...\n",
|
||||||
|
out);
|
||||||
|
out.clear();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue