1 //===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_SUPPORT_YAMLTRAITS_H
11 #define LLVM_SUPPORT_YAMLTRAITS_H
14 #include "llvm/ADT/DenseMap.h"
15 #include "llvm/ADT/DenseMapInfo.h"
16 #include "llvm/ADT/Optional.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/ADT/Twine.h"
22 #include "llvm/Support/Compiler.h"
23 #include "llvm/Support/Regex.h"
24 #include "llvm/Support/SourceMgr.h"
25 #include "llvm/Support/YAMLParser.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <system_error>
33 /// This class should be specialized by any type that needs to be converted
34 /// to/from a YAML mapping. For example:
36 /// struct MappingTraits<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);
44 struct MappingTraits
{
46 // static void mapping(IO &io, T &fields);
47 // Optionally may provide:
48 // static StringRef validate(IO &io, T &fields);
52 /// This class should be specialized by any integral type that converts
53 /// to/from a YAML scalar where there is a one-to-one mapping between
54 /// in-memory values and a string in YAML. For example:
56 /// struct ScalarEnumerationTraits<Colors> {
57 /// static void enumeration(IO &io, Colors &value) {
58 /// io.enumCase(value, "red", cRed);
59 /// io.enumCase(value, "blue", cBlue);
60 /// io.enumCase(value, "green", cGreen);
64 struct ScalarEnumerationTraits
{
66 // static void enumeration(IO &io, T &value);
70 /// This class should be specialized by any integer type that is a union
71 /// of bit values and the YAML representation is a flow sequence of
72 /// strings. For example:
74 /// struct ScalarBitSetTraits<MyFlags> {
75 /// static void bitset(IO &io, MyFlags &value) {
76 /// io.bitSetCase(value, "big", flagBig);
77 /// io.bitSetCase(value, "flat", flagFlat);
78 /// io.bitSetCase(value, "round", flagRound);
82 struct ScalarBitSetTraits
{
84 // static void bitset(IO &io, T &value);
88 /// This class should be specialized by type that requires custom conversion
89 /// to/from a yaml scalar. For example:
92 /// struct ScalarTraits<MyType> {
93 /// static void output(const MyType &val, void*, llvm::raw_ostream &out) {
94 /// // stream out custom formatting
95 /// out << llvm::format("%x", val);
97 /// static StringRef input(StringRef scalar, void*, MyType &value) {
98 /// // parse scalar and set `value`
99 /// // return empty string on success, or error string
100 /// return StringRef();
102 /// static bool mustQuote(StringRef) { return true; }
105 struct ScalarTraits
{
108 // Function to write the value as a string:
109 //static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
111 // Function to convert a string to a value. Returns the empty
112 // StringRef on success or an error string if string is malformed:
113 //static StringRef input(StringRef scalar, void *ctxt, T &value);
115 // Function to determine if the value should be quoted.
116 //static bool mustQuote(StringRef);
120 /// This class should be specialized by any type that needs to be converted
121 /// to/from a YAML sequence. For example:
124 /// struct SequenceTraits< std::vector<MyType> > {
125 /// static size_t size(IO &io, std::vector<MyType> &seq) {
126 /// return seq.size();
128 /// static MyType& element(IO &, std::vector<MyType> &seq, size_t index) {
129 /// if ( index >= seq.size() )
130 /// seq.resize(index+1);
131 /// return seq[index];
135 struct SequenceTraits
{
137 // static size_t size(IO &io, T &seq);
138 // static T::value_type& element(IO &io, T &seq, size_t index);
140 // The following is option and will cause generated YAML to use
141 // a flow sequence (e.g. [a,b,c]).
142 // static const bool flow = true;
146 /// This class should be specialized by any type that needs to be converted
147 /// to/from a list of YAML documents.
149 struct DocumentListTraits
{
151 // static size_t size(IO &io, T &seq);
152 // static T::value_type& element(IO &io, T &seq, size_t index);
156 // Only used by compiler if both template types are the same
157 template <typename T
, T
>
160 // Only used for better diagnostics of missing traits
161 template <typename T
>
166 // Test if ScalarEnumerationTraits<T> is defined on type T.
168 struct has_ScalarEnumerationTraits
170 typedef void (*Signature_enumeration
)(class IO
&, T
&);
172 template <typename U
>
173 static char test(SameType
<Signature_enumeration
, &U::enumeration
>*);
175 template <typename U
>
176 static double test(...);
179 static bool const value
=
180 (sizeof(test
<ScalarEnumerationTraits
<T
> >(nullptr)) == 1);
184 // Test if ScalarBitSetTraits<T> is defined on type T.
186 struct has_ScalarBitSetTraits
188 typedef void (*Signature_bitset
)(class IO
&, T
&);
190 template <typename U
>
191 static char test(SameType
<Signature_bitset
, &U::bitset
>*);
193 template <typename U
>
194 static double test(...);
197 static bool const value
= (sizeof(test
<ScalarBitSetTraits
<T
> >(nullptr)) == 1);
201 // Test if ScalarTraits<T> is defined on type T.
203 struct has_ScalarTraits
205 typedef StringRef (*Signature_input
)(StringRef
, void*, T
&);
206 typedef void (*Signature_output
)(const T
&, void*, llvm::raw_ostream
&);
207 typedef bool (*Signature_mustQuote
)(StringRef
);
209 template <typename U
>
210 static char test(SameType
<Signature_input
, &U::input
> *,
211 SameType
<Signature_output
, &U::output
> *,
212 SameType
<Signature_mustQuote
, &U::mustQuote
> *);
214 template <typename U
>
215 static double test(...);
218 static bool const value
=
219 (sizeof(test
<ScalarTraits
<T
>>(nullptr, nullptr, nullptr)) == 1);
223 // Test if MappingTraits<T> is defined on type T.
225 struct has_MappingTraits
227 typedef void (*Signature_mapping
)(class IO
&, T
&);
229 template <typename U
>
230 static char test(SameType
<Signature_mapping
, &U::mapping
>*);
232 template <typename U
>
233 static double test(...);
236 static bool const value
= (sizeof(test
<MappingTraits
<T
> >(nullptr)) == 1);
239 // Test if MappingTraits<T>::validate() is defined on type T.
241 struct has_MappingValidateTraits
243 typedef StringRef (*Signature_validate
)(class IO
&, T
&);
245 template <typename U
>
246 static char test(SameType
<Signature_validate
, &U::validate
>*);
248 template <typename U
>
249 static double test(...);
252 static bool const value
= (sizeof(test
<MappingTraits
<T
> >(nullptr)) == 1);
257 // Test if SequenceTraits<T> is defined on type T.
259 struct has_SequenceMethodTraits
261 typedef size_t (*Signature_size
)(class IO
&, T
&);
263 template <typename U
>
264 static char test(SameType
<Signature_size
, &U::size
>*);
266 template <typename U
>
267 static double test(...);
270 static bool const value
= (sizeof(test
<SequenceTraits
<T
> >(nullptr)) == 1);
274 // has_FlowTraits<int> will cause an error with some compilers because
275 // it subclasses int. Using this wrapper only instantiates the
276 // real has_FlowTraits only if the template type is a class.
277 template <typename T
, bool Enabled
= std::is_class
<T
>::value
>
281 static const bool value
= false;
284 // Some older gcc compilers don't support straight forward tests
285 // for members, so test for ambiguity cause by the base and derived
286 // classes both defining the member.
288 struct has_FlowTraits
<T
, true>
290 struct Fallback
{ bool flow
; };
291 struct Derived
: T
, Fallback
{ };
294 static char (&f(SameType
<bool Fallback::*, &C::flow
>*))[1];
297 static char (&f(...))[2];
300 static bool const value
= sizeof(f
<Derived
>(nullptr)) == 2;
305 // Test if SequenceTraits<T> is defined on type T
307 struct has_SequenceTraits
: public std::integral_constant
<bool,
308 has_SequenceMethodTraits
<T
>::value
> { };
311 // Test if DocumentListTraits<T> is defined on type T
313 struct has_DocumentListTraits
315 typedef size_t (*Signature_size
)(class IO
&, T
&);
317 template <typename U
>
318 static char test(SameType
<Signature_size
, &U::size
>*);
320 template <typename U
>
321 static double test(...);
324 static bool const value
= (sizeof(test
<DocumentListTraits
<T
> >(nullptr))==1);
327 inline bool isNumber(StringRef S
) {
328 static const char OctalChars
[] = "01234567";
329 if (S
.startswith("0") &&
330 S
.drop_front().find_first_not_of(OctalChars
) == StringRef::npos
)
333 if (S
.startswith("0o") &&
334 S
.drop_front(2).find_first_not_of(OctalChars
) == StringRef::npos
)
337 static const char HexChars
[] = "0123456789abcdefABCDEF";
338 if (S
.startswith("0x") &&
339 S
.drop_front(2).find_first_not_of(HexChars
) == StringRef::npos
)
342 static const char DecChars
[] = "0123456789";
343 if (S
.find_first_not_of(DecChars
) == StringRef::npos
)
346 if (S
.equals(".inf") || S
.equals(".Inf") || S
.equals(".INF"))
349 Regex
FloatMatcher("^(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$");
350 if (FloatMatcher
.match(S
))
356 inline bool isNumeric(StringRef S
) {
357 if ((S
.front() == '-' || S
.front() == '+') && isNumber(S
.drop_front()))
363 if (S
.equals(".nan") || S
.equals(".NaN") || S
.equals(".NAN"))
369 inline bool isNull(StringRef S
) {
370 return S
.equals("null") || S
.equals("Null") || S
.equals("NULL") ||
374 inline bool isBool(StringRef S
) {
375 return S
.equals("true") || S
.equals("True") || S
.equals("TRUE") ||
376 S
.equals("false") || S
.equals("False") || S
.equals("FALSE");
379 inline bool needsQuotes(StringRef S
) {
382 if (isspace(S
.front()) || isspace(S
.back()))
384 if (S
.front() == ',')
387 static const char ScalarSafeChars
[] =
388 "abcdefghijklmnopqrstuvwxyz"
389 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t";
390 if (S
.find_first_not_of(ScalarSafeChars
) != StringRef::npos
)
405 struct missingTraits
: public std::integral_constant
<bool,
406 !has_ScalarEnumerationTraits
<T
>::value
407 && !has_ScalarBitSetTraits
<T
>::value
408 && !has_ScalarTraits
<T
>::value
409 && !has_MappingTraits
<T
>::value
410 && !has_SequenceTraits
<T
>::value
411 && !has_DocumentListTraits
<T
>::value
> {};
414 struct validatedMappingTraits
: public std::integral_constant
<bool,
415 has_MappingTraits
<T
>::value
416 && has_MappingValidateTraits
<T
>::value
> {};
419 struct unvalidatedMappingTraits
: public std::integral_constant
<bool,
420 has_MappingTraits
<T
>::value
421 && !has_MappingValidateTraits
<T
>::value
> {};
422 // Base class for Input and Output.
426 IO(void *Ctxt
=nullptr);
429 virtual bool outputting() = 0;
431 virtual unsigned beginSequence() = 0;
432 virtual bool preflightElement(unsigned, void *&) = 0;
433 virtual void postflightElement(void*) = 0;
434 virtual void endSequence() = 0;
435 virtual bool canElideEmptySequence() = 0;
437 virtual unsigned beginFlowSequence() = 0;
438 virtual bool preflightFlowElement(unsigned, void *&) = 0;
439 virtual void postflightFlowElement(void*) = 0;
440 virtual void endFlowSequence() = 0;
442 virtual bool mapTag(StringRef Tag
, bool Default
=false) = 0;
443 virtual void beginMapping() = 0;
444 virtual void endMapping() = 0;
445 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
446 virtual void postflightKey(void*) = 0;
448 virtual void beginEnumScalar() = 0;
449 virtual bool matchEnumScalar(const char*, bool) = 0;
450 virtual void endEnumScalar() = 0;
452 virtual bool beginBitSetScalar(bool &) = 0;
453 virtual bool bitSetMatch(const char*, bool) = 0;
454 virtual void endBitSetScalar() = 0;
456 virtual void scalarString(StringRef
&, bool) = 0;
458 virtual void setError(const Twine
&) = 0;
460 template <typename T
>
461 void enumCase(T
&Val
, const char* Str
, const T ConstVal
) {
462 if ( matchEnumScalar(Str
, outputting() && Val
== ConstVal
) ) {
467 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
468 template <typename T
>
469 void enumCase(T
&Val
, const char* Str
, const uint32_t ConstVal
) {
470 if ( matchEnumScalar(Str
, outputting() && Val
== static_cast<T
>(ConstVal
)) ) {
475 template <typename T
>
476 void bitSetCase(T
&Val
, const char* Str
, const T ConstVal
) {
477 if ( bitSetMatch(Str
, outputting() && (Val
& ConstVal
) == ConstVal
) ) {
478 Val
= Val
| ConstVal
;
482 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
483 template <typename T
>
484 void bitSetCase(T
&Val
, const char* Str
, const uint32_t ConstVal
) {
485 if ( bitSetMatch(Str
, outputting() && (Val
& ConstVal
) == ConstVal
) ) {
486 Val
= Val
| ConstVal
;
490 template <typename T
>
491 void maskedBitSetCase(T
&Val
, const char *Str
, T ConstVal
, T Mask
) {
492 if (bitSetMatch(Str
, outputting() && (Val
& Mask
) == ConstVal
))
493 Val
= Val
| ConstVal
;
496 template <typename T
>
497 void maskedBitSetCase(T
&Val
, const char *Str
, uint32_t ConstVal
,
499 if (bitSetMatch(Str
, outputting() && (Val
& Mask
) == ConstVal
))
500 Val
= Val
| ConstVal
;
504 void setContext(void *);
506 template <typename T
>
507 void mapRequired(const char* Key
, T
& Val
) {
508 this->processKey(Key
, Val
, true);
511 template <typename T
>
512 typename
std::enable_if
<has_SequenceTraits
<T
>::value
,void>::type
513 mapOptional(const char* Key
, T
& Val
) {
514 // omit key/value instead of outputting empty sequence
515 if ( this->canElideEmptySequence() && !(Val
.begin() != Val
.end()) )
517 this->processKey(Key
, Val
, false);
520 template <typename T
>
521 void mapOptional(const char* Key
, Optional
<T
> &Val
) {
522 processKeyWithDefault(Key
, Val
, Optional
<T
>(), /*Required=*/false);
525 template <typename T
>
526 typename
std::enable_if
<!has_SequenceTraits
<T
>::value
,void>::type
527 mapOptional(const char* Key
, T
& Val
) {
528 this->processKey(Key
, Val
, false);
531 template <typename T
>
532 void mapOptional(const char* Key
, T
& Val
, const T
& Default
) {
533 this->processKeyWithDefault(Key
, Val
, Default
, false);
537 template <typename T
>
538 void processKeyWithDefault(const char *Key
, Optional
<T
> &Val
,
539 const Optional
<T
> &DefaultValue
, bool Required
) {
540 assert(DefaultValue
.hasValue() == false &&
541 "Optional<T> shouldn't have a value!");
544 const bool sameAsDefault
= outputting() && !Val
.hasValue();
545 if (!outputting() && !Val
.hasValue())
547 if (this->preflightKey(Key
, Required
, sameAsDefault
, UseDefault
,
549 yamlize(*this, Val
.getValue(), Required
);
550 this->postflightKey(SaveInfo
);
557 template <typename T
>
558 void processKeyWithDefault(const char *Key
, T
&Val
, const T
& DefaultValue
,
562 const bool sameAsDefault
= outputting() && Val
== DefaultValue
;
563 if ( this->preflightKey(Key
, Required
, sameAsDefault
, UseDefault
,
565 yamlize(*this, Val
, Required
);
566 this->postflightKey(SaveInfo
);
574 template <typename T
>
575 void processKey(const char *Key
, T
&Val
, bool Required
) {
578 if ( this->preflightKey(Key
, Required
, false, UseDefault
, SaveInfo
) ) {
579 yamlize(*this, Val
, Required
);
580 this->postflightKey(SaveInfo
);
591 typename
std::enable_if
<has_ScalarEnumerationTraits
<T
>::value
,void>::type
592 yamlize(IO
&io
, T
&Val
, bool) {
593 io
.beginEnumScalar();
594 ScalarEnumerationTraits
<T
>::enumeration(io
, Val
);
599 typename
std::enable_if
<has_ScalarBitSetTraits
<T
>::value
,void>::type
600 yamlize(IO
&io
, T
&Val
, bool) {
602 if ( io
.beginBitSetScalar(DoClear
) ) {
604 Val
= static_cast<T
>(0);
605 ScalarBitSetTraits
<T
>::bitset(io
, Val
);
606 io
.endBitSetScalar();
612 typename
std::enable_if
<has_ScalarTraits
<T
>::value
,void>::type
613 yamlize(IO
&io
, T
&Val
, bool) {
614 if ( io
.outputting() ) {
616 llvm::raw_string_ostream
Buffer(Storage
);
617 ScalarTraits
<T
>::output(Val
, io
.getContext(), Buffer
);
618 StringRef Str
= Buffer
.str();
619 io
.scalarString(Str
, ScalarTraits
<T
>::mustQuote(Str
));
623 io
.scalarString(Str
, ScalarTraits
<T
>::mustQuote(Str
));
624 StringRef Result
= ScalarTraits
<T
>::input(Str
, io
.getContext(), Val
);
625 if ( !Result
.empty() ) {
626 io
.setError(llvm::Twine(Result
));
633 typename
std::enable_if
<validatedMappingTraits
<T
>::value
, void>::type
634 yamlize(IO
&io
, T
&Val
, bool) {
636 if (io
.outputting()) {
637 StringRef Err
= MappingTraits
<T
>::validate(io
, Val
);
639 llvm::errs() << Err
<< "\n";
640 assert(Err
.empty() && "invalid struct trying to be written as yaml");
643 MappingTraits
<T
>::mapping(io
, Val
);
644 if (!io
.outputting()) {
645 StringRef Err
= MappingTraits
<T
>::validate(io
, Val
);
653 typename
std::enable_if
<unvalidatedMappingTraits
<T
>::value
, void>::type
654 yamlize(IO
&io
, T
&Val
, bool) {
656 MappingTraits
<T
>::mapping(io
, Val
);
661 typename
std::enable_if
<missingTraits
<T
>::value
, void>::type
662 yamlize(IO
&io
, T
&Val
, bool) {
663 char missing_yaml_trait_for_type
[sizeof(MissingTrait
<T
>)];
667 typename
std::enable_if
<has_SequenceTraits
<T
>::value
,void>::type
668 yamlize(IO
&io
, T
&Seq
, bool) {
669 if ( has_FlowTraits
< SequenceTraits
<T
> >::value
) {
670 unsigned incnt
= io
.beginFlowSequence();
671 unsigned count
= io
.outputting() ? SequenceTraits
<T
>::size(io
, Seq
) : incnt
;
672 for(unsigned i
=0; i
< count
; ++i
) {
674 if ( io
.preflightFlowElement(i
, SaveInfo
) ) {
675 yamlize(io
, SequenceTraits
<T
>::element(io
, Seq
, i
), true);
676 io
.postflightFlowElement(SaveInfo
);
679 io
.endFlowSequence();
682 unsigned incnt
= io
.beginSequence();
683 unsigned count
= io
.outputting() ? SequenceTraits
<T
>::size(io
, Seq
) : incnt
;
684 for(unsigned i
=0; i
< count
; ++i
) {
686 if ( io
.preflightElement(i
, SaveInfo
) ) {
687 yamlize(io
, SequenceTraits
<T
>::element(io
, Seq
, i
), true);
688 io
.postflightElement(SaveInfo
);
697 struct ScalarTraits
<bool> {
698 static void output(const bool &, void*, llvm::raw_ostream
&);
699 static StringRef
input(StringRef
, void*, bool &);
700 static bool mustQuote(StringRef
) { return false; }
704 struct ScalarTraits
<StringRef
> {
705 static void output(const StringRef
&, void*, llvm::raw_ostream
&);
706 static StringRef
input(StringRef
, void*, StringRef
&);
707 static bool mustQuote(StringRef S
) { return needsQuotes(S
); }
711 struct ScalarTraits
<std::string
> {
712 static void output(const std::string
&, void*, llvm::raw_ostream
&);
713 static StringRef
input(StringRef
, void*, std::string
&);
714 static bool mustQuote(StringRef S
) { return needsQuotes(S
); }
718 struct ScalarTraits
<uint8_t> {
719 static void output(const uint8_t &, void*, llvm::raw_ostream
&);
720 static StringRef
input(StringRef
, void*, uint8_t &);
721 static bool mustQuote(StringRef
) { return false; }
725 struct ScalarTraits
<uint16_t> {
726 static void output(const uint16_t &, void*, llvm::raw_ostream
&);
727 static StringRef
input(StringRef
, void*, uint16_t &);
728 static bool mustQuote(StringRef
) { return false; }
732 struct ScalarTraits
<uint32_t> {
733 static void output(const uint32_t &, void*, llvm::raw_ostream
&);
734 static StringRef
input(StringRef
, void*, uint32_t &);
735 static bool mustQuote(StringRef
) { return false; }
739 struct ScalarTraits
<uint64_t> {
740 static void output(const uint64_t &, void*, llvm::raw_ostream
&);
741 static StringRef
input(StringRef
, void*, uint64_t &);
742 static bool mustQuote(StringRef
) { return false; }
746 struct ScalarTraits
<int8_t> {
747 static void output(const int8_t &, void*, llvm::raw_ostream
&);
748 static StringRef
input(StringRef
, void*, int8_t &);
749 static bool mustQuote(StringRef
) { return false; }
753 struct ScalarTraits
<int16_t> {
754 static void output(const int16_t &, void*, llvm::raw_ostream
&);
755 static StringRef
input(StringRef
, void*, int16_t &);
756 static bool mustQuote(StringRef
) { return false; }
760 struct ScalarTraits
<int32_t> {
761 static void output(const int32_t &, void*, llvm::raw_ostream
&);
762 static StringRef
input(StringRef
, void*, int32_t &);
763 static bool mustQuote(StringRef
) { return false; }
767 struct ScalarTraits
<int64_t> {
768 static void output(const int64_t &, void*, llvm::raw_ostream
&);
769 static StringRef
input(StringRef
, void*, int64_t &);
770 static bool mustQuote(StringRef
) { return false; }
774 struct ScalarTraits
<float> {
775 static void output(const float &, void*, llvm::raw_ostream
&);
776 static StringRef
input(StringRef
, void*, float &);
777 static bool mustQuote(StringRef
) { return false; }
781 struct ScalarTraits
<double> {
782 static void output(const double &, void*, llvm::raw_ostream
&);
783 static StringRef
input(StringRef
, void*, double &);
784 static bool mustQuote(StringRef
) { return false; }
789 // Utility for use within MappingTraits<>::mapping() method
790 // to [de]normalize an object for use with YAML conversion.
791 template <typename TNorm
, typename TFinal
>
792 struct MappingNormalization
{
793 MappingNormalization(IO
&i_o
, TFinal
&Obj
)
794 : io(i_o
), BufPtr(nullptr), Result(Obj
) {
795 if ( io
.outputting() ) {
796 BufPtr
= new (&Buffer
) TNorm(io
, Obj
);
799 BufPtr
= new (&Buffer
) TNorm(io
);
803 ~MappingNormalization() {
804 if ( ! io
.outputting() ) {
805 Result
= BufPtr
->denormalize(io
);
810 TNorm
* operator->() { return BufPtr
; }
813 typedef llvm::AlignedCharArrayUnion
<TNorm
> Storage
;
823 // Utility for use within MappingTraits<>::mapping() method
824 // to [de]normalize an object for use with YAML conversion.
825 template <typename TNorm
, typename TFinal
>
826 struct MappingNormalizationHeap
{
827 MappingNormalizationHeap(IO
&i_o
, TFinal
&Obj
)
828 : io(i_o
), BufPtr(NULL
), Result(Obj
) {
829 if ( io
.outputting() ) {
830 BufPtr
= new (&Buffer
) TNorm(io
, Obj
);
833 BufPtr
= new TNorm(io
);
837 ~MappingNormalizationHeap() {
838 if ( io
.outputting() ) {
842 Result
= BufPtr
->denormalize(io
);
846 TNorm
* operator->() { return BufPtr
; }
849 typedef llvm::AlignedCharArrayUnion
<TNorm
> Storage
;
860 /// The Input class is used to parse a yaml document into in-memory structs
863 /// It works by using YAMLParser to do a syntax parse of the entire yaml
864 /// document, then the Input class builds a graph of HNodes which wraps
865 /// each yaml Node. The extra layer is buffering. The low level yaml
866 /// parser only lets you look at each node once. The buffering layer lets
867 /// you search and interate multiple times. This is necessary because
868 /// the mapRequired() method calls may not be in the same order
869 /// as the keys in the document.
871 class Input
: public IO
{
873 // Construct a yaml Input object from a StringRef and optional
874 // user-data. The DiagHandler can be specified to provide
875 // alternative error reporting.
876 Input(StringRef InputContent
,
877 void *Ctxt
= nullptr,
878 SourceMgr::DiagHandlerTy DiagHandler
= nullptr,
879 void *DiagHandlerCtxt
= nullptr);
882 // Check if there was an syntax or semantic error during parsing.
883 std::error_code
error();
886 bool outputting() override
;
887 bool mapTag(StringRef
, bool) override
;
888 void beginMapping() override
;
889 void endMapping() override
;
890 bool preflightKey(const char *, bool, bool, bool &, void *&) override
;
891 void postflightKey(void *) override
;
892 unsigned beginSequence() override
;
893 void endSequence() override
;
894 bool preflightElement(unsigned index
, void *&) override
;
895 void postflightElement(void *) override
;
896 unsigned beginFlowSequence() override
;
897 bool preflightFlowElement(unsigned , void *&) override
;
898 void postflightFlowElement(void *) override
;
899 void endFlowSequence() override
;
900 void beginEnumScalar() override
;
901 bool matchEnumScalar(const char*, bool) override
;
902 void endEnumScalar() override
;
903 bool beginBitSetScalar(bool &) override
;
904 bool bitSetMatch(const char *, bool ) override
;
905 void endBitSetScalar() override
;
906 void scalarString(StringRef
&, bool) override
;
907 void setError(const Twine
&message
) override
;
908 bool canElideEmptySequence() override
;
911 virtual void anchor();
913 HNode(Node
*n
) : _node(n
) { }
915 static inline bool classof(const HNode
*) { return true; }
920 class EmptyHNode
: public HNode
{
921 void anchor() override
;
923 EmptyHNode(Node
*n
) : HNode(n
) { }
924 static inline bool classof(const HNode
*n
) {
925 return NullNode::classof(n
->_node
);
927 static inline bool classof(const EmptyHNode
*) { return true; }
930 class ScalarHNode
: public HNode
{
931 void anchor() override
;
933 ScalarHNode(Node
*n
, StringRef s
) : HNode(n
), _value(s
) { }
935 StringRef
value() const { return _value
; }
937 static inline bool classof(const HNode
*n
) {
938 return ScalarNode::classof(n
->_node
);
940 static inline bool classof(const ScalarHNode
*) { return true; }
945 class MapHNode
: public HNode
{
946 virtual void anchor();
949 MapHNode(Node
*n
) : HNode(n
) { }
951 static inline bool classof(const HNode
*n
) {
952 return MappingNode::classof(n
->_node
);
954 static inline bool classof(const MapHNode
*) { return true; }
956 typedef llvm::StringMap
<std::unique_ptr
<HNode
>> NameToNode
;
958 bool isValidKey(StringRef key
);
961 llvm::SmallVector
<const char*, 6> ValidKeys
;
964 class SequenceHNode
: public HNode
{
965 virtual void anchor();
968 SequenceHNode(Node
*n
) : HNode(n
) { }
970 static inline bool classof(const HNode
*n
) {
971 return SequenceNode::classof(n
->_node
);
973 static inline bool classof(const SequenceHNode
*) { return true; }
975 std::vector
<std::unique_ptr
<HNode
>> Entries
;
978 std::unique_ptr
<Input::HNode
> createHNodes(Node
*node
);
979 void setError(HNode
*hnode
, const Twine
&message
);
980 void setError(Node
*node
, const Twine
&message
);
984 // These are only used by operator>>. They could be private
985 // if those templated things could be made friends.
986 bool setCurrentDocument();
990 llvm::SourceMgr SrcMgr
; // must be before Strm
991 std::unique_ptr
<llvm::yaml::Stream
> Strm
;
992 std::unique_ptr
<HNode
> TopNode
;
994 llvm::BumpPtrAllocator StringAllocator
;
995 llvm::yaml::document_iterator DocIterator
;
996 std::vector
<bool> BitValuesUsed
;
998 bool ScalarMatchFound
;
1005 /// The Output class is used to generate a yaml document from in-memory structs
1008 class Output
: public IO
{
1010 Output(llvm::raw_ostream
&, void *Ctxt
=nullptr);
1013 bool outputting() override
;
1014 bool mapTag(StringRef
, bool) override
;
1015 void beginMapping() override
;
1016 void endMapping() override
;
1017 bool preflightKey(const char *key
, bool, bool, bool &, void *&) override
;
1018 void postflightKey(void *) override
;
1019 unsigned beginSequence() override
;
1020 void endSequence() override
;
1021 bool preflightElement(unsigned, void *&) override
;
1022 void postflightElement(void *) override
;
1023 unsigned beginFlowSequence() override
;
1024 bool preflightFlowElement(unsigned, void *&) override
;
1025 void postflightFlowElement(void *) override
;
1026 void endFlowSequence() override
;
1027 void beginEnumScalar() override
;
1028 bool matchEnumScalar(const char*, bool) override
;
1029 void endEnumScalar() override
;
1030 bool beginBitSetScalar(bool &) override
;
1031 bool bitSetMatch(const char *, bool ) override
;
1032 void endBitSetScalar() override
;
1033 void scalarString(StringRef
&, bool) override
;
1034 void setError(const Twine
&message
) override
;
1035 bool canElideEmptySequence() override
;
1037 // These are only used by operator<<. They could be private
1038 // if that templated operator could be made a friend.
1039 void beginDocuments();
1040 bool preflightDocument(unsigned);
1041 void postflightDocument();
1042 void endDocuments();
1045 void output(StringRef s
);
1046 void outputUpToEndOfLine(StringRef s
);
1047 void newLineCheck();
1048 void outputNewLine();
1049 void paddedKey(StringRef key
);
1051 enum InState
{ inSeq
, inFlowSeq
, inMapFirstKey
, inMapOtherKey
};
1053 llvm::raw_ostream
&Out
;
1054 SmallVector
<InState
, 8> StateStack
;
1056 int ColumnAtFlowStart
;
1057 bool NeedBitValueComma
;
1058 bool NeedFlowSequenceComma
;
1059 bool EnumerationMatchFound
;
1066 /// YAML I/O does conversion based on types. But often native data types
1067 /// are just a typedef of built in intergral types (e.g. int). But the C++
1068 /// type matching system sees through the typedef and all the typedefed types
1069 /// look like a built in type. This will cause the generic YAML I/O conversion
1070 /// to be used. To provide better control over the YAML conversion, you can
1071 /// use this macro instead of typedef. It will create a class with one field
1072 /// and automatic conversion operators to and from the base type.
1073 /// Based on BOOST_STRONG_TYPEDEF
1074 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \
1077 _type(const _base v) : value(v) { } \
1078 _type(const _type &v) : value(v.value) {} \
1079 _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\
1080 _type &operator=(const _base &rhs) { value = rhs; return *this; } \
1081 operator const _base & () const { return value; } \
1082 bool operator==(const _type &rhs) const { return value == rhs.value; } \
1083 bool operator==(const _base &rhs) const { return value == rhs; } \
1084 bool operator<(const _type &rhs) const { return value < rhs.value; } \
1091 /// Use these types instead of uintXX_t in any mapping to have
1092 /// its yaml output formatted as hexadecimal.
1094 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8
)
1095 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16
)
1096 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32
)
1097 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64
)
1101 struct ScalarTraits
<Hex8
> {
1102 static void output(const Hex8
&, void*, llvm::raw_ostream
&);
1103 static StringRef
input(StringRef
, void*, Hex8
&);
1104 static bool mustQuote(StringRef
) { return false; }
1108 struct ScalarTraits
<Hex16
> {
1109 static void output(const Hex16
&, void*, llvm::raw_ostream
&);
1110 static StringRef
input(StringRef
, void*, Hex16
&);
1111 static bool mustQuote(StringRef
) { return false; }
1115 struct ScalarTraits
<Hex32
> {
1116 static void output(const Hex32
&, void*, llvm::raw_ostream
&);
1117 static StringRef
input(StringRef
, void*, Hex32
&);
1118 static bool mustQuote(StringRef
) { return false; }
1122 struct ScalarTraits
<Hex64
> {
1123 static void output(const Hex64
&, void*, llvm::raw_ostream
&);
1124 static StringRef
input(StringRef
, void*, Hex64
&);
1125 static bool mustQuote(StringRef
) { return false; }
1129 // Define non-member operator>> so that Input can stream in a document list.
1130 template <typename T
>
1132 typename
std::enable_if
<has_DocumentListTraits
<T
>::value
, Input
&>::type
1133 operator>>(Input
&yin
, T
&docList
) {
1135 while ( yin
.setCurrentDocument() ) {
1136 yamlize(yin
, DocumentListTraits
<T
>::element(yin
, docList
, i
), true);
1145 // Define non-member operator>> so that Input can stream in a map as a document.
1146 template <typename T
>
1148 typename
std::enable_if
<has_MappingTraits
<T
>::value
, Input
&>::type
1149 operator>>(Input
&yin
, T
&docMap
) {
1150 yin
.setCurrentDocument();
1151 yamlize(yin
, docMap
, true);
1155 // Define non-member operator>> so that Input can stream in a sequence as
1157 template <typename T
>
1159 typename
std::enable_if
<has_SequenceTraits
<T
>::value
, Input
&>::type
1160 operator>>(Input
&yin
, T
&docSeq
) {
1161 if (yin
.setCurrentDocument())
1162 yamlize(yin
, docSeq
, true);
1166 // Provide better error message about types missing a trait specialization
1167 template <typename T
>
1169 typename
std::enable_if
<missingTraits
<T
>::value
, Input
&>::type
1170 operator>>(Input
&yin
, T
&docSeq
) {
1171 char missing_yaml_trait_for_type
[sizeof(MissingTrait
<T
>)];
1176 // Define non-member operator<< so that Output can stream out document list.
1177 template <typename T
>
1179 typename
std::enable_if
<has_DocumentListTraits
<T
>::value
, Output
&>::type
1180 operator<<(Output
&yout
, T
&docList
) {
1181 yout
.beginDocuments();
1182 const size_t count
= DocumentListTraits
<T
>::size(yout
, docList
);
1183 for(size_t i
=0; i
< count
; ++i
) {
1184 if ( yout
.preflightDocument(i
) ) {
1185 yamlize(yout
, DocumentListTraits
<T
>::element(yout
, docList
, i
), true);
1186 yout
.postflightDocument();
1189 yout
.endDocuments();
1193 // Define non-member operator<< so that Output can stream out a map.
1194 template <typename T
>
1196 typename
std::enable_if
<has_MappingTraits
<T
>::value
, Output
&>::type
1197 operator<<(Output
&yout
, T
&map
) {
1198 yout
.beginDocuments();
1199 if ( yout
.preflightDocument(0) ) {
1200 yamlize(yout
, map
, true);
1201 yout
.postflightDocument();
1203 yout
.endDocuments();
1207 // Define non-member operator<< so that Output can stream out a sequence.
1208 template <typename T
>
1210 typename
std::enable_if
<has_SequenceTraits
<T
>::value
, Output
&>::type
1211 operator<<(Output
&yout
, T
&seq
) {
1212 yout
.beginDocuments();
1213 if ( yout
.preflightDocument(0) ) {
1214 yamlize(yout
, seq
, true);
1215 yout
.postflightDocument();
1217 yout
.endDocuments();
1221 // Provide better error message about types missing a trait specialization
1222 template <typename T
>
1224 typename
std::enable_if
<missingTraits
<T
>::value
, Output
&>::type
1225 operator<<(Output
&yout
, T
&seq
) {
1226 char missing_yaml_trait_for_type
[sizeof(MissingTrait
<T
>)];
1235 /// Utility for declaring that a std::vector of a particular type
1236 /// should be considered a YAML sequence.
1237 #define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \
1241 struct SequenceTraits< std::vector<_type> > { \
1242 static size_t size(IO &io, std::vector<_type> &seq) { \
1243 return seq.size(); \
1245 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1246 if ( index >= seq.size() ) \
1247 seq.resize(index+1); \
1248 return seq[index]; \
1254 /// Utility for declaring that a std::vector of a particular type
1255 /// should be considered a YAML flow sequence.
1256 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \
1260 struct SequenceTraits< std::vector<_type> > { \
1261 static size_t size(IO &io, std::vector<_type> &seq) { \
1262 return seq.size(); \
1264 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1265 (void)flow; /* Remove this workaround after PR17897 is fixed */ \
1266 if ( index >= seq.size() ) \
1267 seq.resize(index+1); \
1268 return seq[index]; \
1270 static const bool flow = true; \
1275 /// Utility for declaring that a std::vector of a particular type
1276 /// should be considered a YAML document list.
1277 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \
1281 struct DocumentListTraits< std::vector<_type> > { \
1282 static size_t size(IO &io, std::vector<_type> &seq) { \
1283 return seq.size(); \
1285 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1286 if ( index >= seq.size() ) \
1287 seq.resize(index+1); \
1288 return seq[index]; \
1296 #endif // LLVM_SUPPORT_YAMLTRAITS_H