1249259Sdim//===- llvm/Supporrt/YAMLTraits.h -------------------------------*- C++ -*-===//
2249259Sdim//
3249259Sdim//                             The LLVM Linker
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim
10249259Sdim#ifndef LLVM_SUPPORT_YAMLTRAITS_H
11249259Sdim#define LLVM_SUPPORT_YAMLTRAITS_H
12249259Sdim
13249259Sdim
14249259Sdim#include "llvm/ADT/DenseMap.h"
15249259Sdim#include "llvm/ADT/DenseMapInfo.h"
16249259Sdim#include "llvm/ADT/SmallVector.h"
17263509Sdim#include "llvm/ADT/StringMap.h"
18249259Sdim#include "llvm/ADT/StringRef.h"
19249259Sdim#include "llvm/ADT/StringSwitch.h"
20249259Sdim#include "llvm/ADT/Twine.h"
21263509Sdim#include "llvm/Support/Casting.h"
22249259Sdim#include "llvm/Support/Compiler.h"
23249259Sdim#include "llvm/Support/SourceMgr.h"
24249259Sdim#include "llvm/Support/YAMLParser.h"
25249259Sdim#include "llvm/Support/raw_ostream.h"
26249259Sdim#include "llvm/Support/system_error.h"
27249259Sdim#include "llvm/Support/type_traits.h"
28249259Sdim
29249259Sdim
30249259Sdimnamespace llvm {
31249259Sdimnamespace yaml {
32249259Sdim
33249259Sdim
34249259Sdim/// This class should be specialized by any type that needs to be converted
35249259Sdim/// to/from a YAML mapping.  For example:
36249259Sdim///
37249259Sdim///     struct ScalarBitSetTraits<MyStruct> {
38249259Sdim///       static void mapping(IO &io, MyStruct &s) {
39249259Sdim///         io.mapRequired("name", s.name);
40249259Sdim///         io.mapRequired("size", s.size);
41249259Sdim///         io.mapOptional("age",  s.age);
42249259Sdim///       }
43249259Sdim///     };
44249259Sdimtemplate<class T>
45249259Sdimstruct MappingTraits {
46249259Sdim  // Must provide:
47249259Sdim  // static void mapping(IO &io, T &fields);
48249259Sdim};
49249259Sdim
50249259Sdim
51249259Sdim/// This class should be specialized by any integral type that converts
52249259Sdim/// to/from a YAML scalar where there is a one-to-one mapping between
53249259Sdim/// in-memory values and a string in YAML.  For example:
54249259Sdim///
55249259Sdim///     struct ScalarEnumerationTraits<Colors> {
56249259Sdim///         static void enumeration(IO &io, Colors &value) {
57249259Sdim///           io.enumCase(value, "red",   cRed);
58249259Sdim///           io.enumCase(value, "blue",  cBlue);
59249259Sdim///           io.enumCase(value, "green", cGreen);
60249259Sdim///         }
61249259Sdim///       };
62249259Sdimtemplate<typename T>
63249259Sdimstruct ScalarEnumerationTraits {
64249259Sdim  // Must provide:
65249259Sdim  // static void enumeration(IO &io, T &value);
66249259Sdim};
67249259Sdim
68249259Sdim
69249259Sdim/// This class should be specialized by any integer type that is a union
70249259Sdim/// of bit values and the YAML representation is a flow sequence of
71249259Sdim/// strings.  For example:
72249259Sdim///
73249259Sdim///      struct ScalarBitSetTraits<MyFlags> {
74249259Sdim///        static void bitset(IO &io, MyFlags &value) {
75249259Sdim///          io.bitSetCase(value, "big",   flagBig);
76249259Sdim///          io.bitSetCase(value, "flat",  flagFlat);
77249259Sdim///          io.bitSetCase(value, "round", flagRound);
78249259Sdim///        }
79249259Sdim///      };
80249259Sdimtemplate<typename T>
81249259Sdimstruct ScalarBitSetTraits {
82249259Sdim  // Must provide:
83249259Sdim  // static void bitset(IO &io, T &value);
84249259Sdim};
85249259Sdim
86249259Sdim
87249259Sdim/// This class should be specialized by type that requires custom conversion
88249259Sdim/// to/from a yaml scalar.  For example:
89249259Sdim///
90249259Sdim///    template<>
91249259Sdim///    struct ScalarTraits<MyType> {
92249259Sdim///      static void output(const MyType &val, void*, llvm::raw_ostream &out) {
93249259Sdim///        // stream out custom formatting
94249259Sdim///        out << llvm::format("%x", val);
95249259Sdim///      }
96249259Sdim///      static StringRef input(StringRef scalar, void*, MyType &value) {
97249259Sdim///        // parse scalar and set `value`
98249259Sdim///        // return empty string on success, or error string
99249259Sdim///        return StringRef();
100249259Sdim///      }
101249259Sdim///    };
102249259Sdimtemplate<typename T>
103249259Sdimstruct ScalarTraits {
104249259Sdim  // Must provide:
105249259Sdim  //
106249259Sdim  // Function to write the value as a string:
107249259Sdim  //static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
108249259Sdim  //
109249259Sdim  // Function to convert a string to a value.  Returns the empty
110249259Sdim  // StringRef on success or an error string if string is malformed:
111249259Sdim  //static StringRef input(StringRef scalar, void *ctxt, T &value);
112249259Sdim};
113249259Sdim
114249259Sdim
115249259Sdim/// This class should be specialized by any type that needs to be converted
116249259Sdim/// to/from a YAML sequence.  For example:
117249259Sdim///
118249259Sdim///    template<>
119249259Sdim///    struct SequenceTraits< std::vector<MyType> > {
120249259Sdim///      static size_t size(IO &io, std::vector<MyType> &seq) {
121249259Sdim///        return seq.size();
122249259Sdim///      }
123249259Sdim///      static MyType& element(IO &, std::vector<MyType> &seq, size_t index) {
124249259Sdim///        if ( index >= seq.size() )
125249259Sdim///          seq.resize(index+1);
126249259Sdim///        return seq[index];
127249259Sdim///      }
128249259Sdim///    };
129249259Sdimtemplate<typename T>
130249259Sdimstruct SequenceTraits {
131249259Sdim  // Must provide:
132249259Sdim  // static size_t size(IO &io, T &seq);
133249259Sdim  // static T::value_type& element(IO &io, T &seq, size_t index);
134249259Sdim  //
135249259Sdim  // The following is option and will cause generated YAML to use
136249259Sdim  // a flow sequence (e.g. [a,b,c]).
137249259Sdim  // static const bool flow = true;
138249259Sdim};
139249259Sdim
140249259Sdim
141249259Sdim/// This class should be specialized by any type that needs to be converted
142249259Sdim/// to/from a list of YAML documents.
143249259Sdimtemplate<typename T>
144249259Sdimstruct DocumentListTraits {
145249259Sdim  // Must provide:
146249259Sdim  // static size_t size(IO &io, T &seq);
147249259Sdim  // static T::value_type& element(IO &io, T &seq, size_t index);
148249259Sdim};
149249259Sdim
150249259Sdim
151249259Sdim// Only used by compiler if both template types are the same
152249259Sdimtemplate <typename T, T>
153249259Sdimstruct SameType;
154249259Sdim
155249259Sdim// Only used for better diagnostics of missing traits
156249259Sdimtemplate <typename T>
157249259Sdimstruct MissingTrait;
158249259Sdim
159249259Sdim
160249259Sdim
161249259Sdim// Test if ScalarEnumerationTraits<T> is defined on type T.
162249259Sdimtemplate <class T>
163249259Sdimstruct has_ScalarEnumerationTraits
164249259Sdim{
165249259Sdim  typedef void (*Signature_enumeration)(class IO&, T&);
166249259Sdim
167249259Sdim  template <typename U>
168249259Sdim  static char test(SameType<Signature_enumeration, &U::enumeration>*);
169249259Sdim
170249259Sdim  template <typename U>
171249259Sdim  static double test(...);
172249259Sdim
173249259Sdimpublic:
174249259Sdim  static bool const value = (sizeof(test<ScalarEnumerationTraits<T> >(0)) == 1);
175249259Sdim};
176249259Sdim
177249259Sdim
178249259Sdim// Test if ScalarBitSetTraits<T> is defined on type T.
179249259Sdimtemplate <class T>
180249259Sdimstruct has_ScalarBitSetTraits
181249259Sdim{
182249259Sdim  typedef void (*Signature_bitset)(class IO&, T&);
183249259Sdim
184249259Sdim  template <typename U>
185249259Sdim  static char test(SameType<Signature_bitset, &U::bitset>*);
186249259Sdim
187249259Sdim  template <typename U>
188249259Sdim  static double test(...);
189249259Sdim
190249259Sdimpublic:
191249259Sdim  static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(0)) == 1);
192249259Sdim};
193249259Sdim
194249259Sdim
195249259Sdim// Test if ScalarTraits<T> is defined on type T.
196249259Sdimtemplate <class T>
197249259Sdimstruct has_ScalarTraits
198249259Sdim{
199249259Sdim  typedef StringRef (*Signature_input)(StringRef, void*, T&);
200249259Sdim  typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&);
201249259Sdim
202249259Sdim  template <typename U>
203249259Sdim  static char test(SameType<Signature_input, &U::input>*,
204249259Sdim                   SameType<Signature_output, &U::output>*);
205249259Sdim
206249259Sdim  template <typename U>
207249259Sdim  static double test(...);
208249259Sdim
209249259Sdimpublic:
210249259Sdim  static bool const value = (sizeof(test<ScalarTraits<T> >(0,0)) == 1);
211249259Sdim};
212249259Sdim
213249259Sdim
214249259Sdim// Test if MappingTraits<T> is defined on type T.
215249259Sdimtemplate <class T>
216249259Sdimstruct has_MappingTraits
217249259Sdim{
218249259Sdim  typedef void (*Signature_mapping)(class IO&, T&);
219249259Sdim
220249259Sdim  template <typename U>
221249259Sdim  static char test(SameType<Signature_mapping, &U::mapping>*);
222249259Sdim
223249259Sdim  template <typename U>
224249259Sdim  static double test(...);
225249259Sdim
226249259Sdimpublic:
227249259Sdim  static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
228249259Sdim};
229249259Sdim
230249259Sdim
231249259Sdim// Test if SequenceTraits<T> is defined on type T.
232249259Sdimtemplate <class T>
233249259Sdimstruct has_SequenceMethodTraits
234249259Sdim{
235249259Sdim  typedef size_t (*Signature_size)(class IO&, T&);
236249259Sdim
237249259Sdim  template <typename U>
238249259Sdim  static char test(SameType<Signature_size, &U::size>*);
239249259Sdim
240249259Sdim  template <typename U>
241249259Sdim  static double test(...);
242249259Sdim
243249259Sdimpublic:
244249259Sdim  static bool const value =  (sizeof(test<SequenceTraits<T> >(0)) == 1);
245249259Sdim};
246249259Sdim
247249259Sdim
248249259Sdim// has_FlowTraits<int> will cause an error with some compilers because
249249259Sdim// it subclasses int.  Using this wrapper only instantiates the
250249259Sdim// real has_FlowTraits only if the template type is a class.
251249259Sdimtemplate <typename T, bool Enabled = llvm::is_class<T>::value>
252249259Sdimclass has_FlowTraits
253249259Sdim{
254249259Sdimpublic:
255249259Sdim   static const bool value = false;
256249259Sdim};
257249259Sdim
258249259Sdim// Some older gcc compilers don't support straight forward tests
259249259Sdim// for members, so test for ambiguity cause by the base and derived
260249259Sdim// classes both defining the member.
261249259Sdimtemplate <class T>
262249259Sdimstruct has_FlowTraits<T, true>
263249259Sdim{
264249259Sdim  struct Fallback { bool flow; };
265249259Sdim  struct Derived : T, Fallback { };
266249259Sdim
267249259Sdim  template<typename C>
268249259Sdim  static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
269249259Sdim
270249259Sdim  template<typename C>
271249259Sdim  static char (&f(...))[2];
272249259Sdim
273249259Sdimpublic:
274249259Sdim  static bool const value = sizeof(f<Derived>(0)) == 2;
275249259Sdim};
276249259Sdim
277249259Sdim
278249259Sdim
279249259Sdim// Test if SequenceTraits<T> is defined on type T
280249259Sdimtemplate<typename T>
281249259Sdimstruct has_SequenceTraits : public  llvm::integral_constant<bool,
282249259Sdim                                      has_SequenceMethodTraits<T>::value > { };
283249259Sdim
284249259Sdim
285249259Sdim// Test if DocumentListTraits<T> is defined on type T
286249259Sdimtemplate <class T>
287249259Sdimstruct has_DocumentListTraits
288249259Sdim{
289249259Sdim  typedef size_t (*Signature_size)(class IO&, T&);
290249259Sdim
291249259Sdim  template <typename U>
292249259Sdim  static char test(SameType<Signature_size, &U::size>*);
293249259Sdim
294249259Sdim  template <typename U>
295249259Sdim  static double test(...);
296249259Sdim
297249259Sdimpublic:
298249259Sdim  static bool const value =  (sizeof(test<DocumentListTraits<T> >(0)) == 1);
299249259Sdim};
300249259Sdim
301249259Sdim
302249259Sdim
303249259Sdim
304249259Sdimtemplate<typename T>
305249259Sdimstruct missingTraits : public  llvm::integral_constant<bool,
306249259Sdim                                         !has_ScalarEnumerationTraits<T>::value
307249259Sdim                                      && !has_ScalarBitSetTraits<T>::value
308249259Sdim                                      && !has_ScalarTraits<T>::value
309249259Sdim                                      && !has_MappingTraits<T>::value
310249259Sdim                                      && !has_SequenceTraits<T>::value
311249259Sdim                                      && !has_DocumentListTraits<T>::value >  {};
312249259Sdim
313249259Sdim
314249259Sdim// Base class for Input and Output.
315249259Sdimclass IO {
316249259Sdimpublic:
317249259Sdim
318249259Sdim  IO(void *Ctxt=NULL);
319249259Sdim  virtual ~IO();
320249259Sdim
321263509Sdim  virtual bool outputting() const = 0;
322249259Sdim
323249259Sdim  virtual unsigned beginSequence() = 0;
324249259Sdim  virtual bool preflightElement(unsigned, void *&) = 0;
325249259Sdim  virtual void postflightElement(void*) = 0;
326249259Sdim  virtual void endSequence() = 0;
327263509Sdim  virtual bool canElideEmptySequence() = 0;
328249259Sdim
329249259Sdim  virtual unsigned beginFlowSequence() = 0;
330249259Sdim  virtual bool preflightFlowElement(unsigned, void *&) = 0;
331249259Sdim  virtual void postflightFlowElement(void*) = 0;
332249259Sdim  virtual void endFlowSequence() = 0;
333249259Sdim
334263509Sdim  virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
335249259Sdim  virtual void beginMapping() = 0;
336249259Sdim  virtual void endMapping() = 0;
337249259Sdim  virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
338249259Sdim  virtual void postflightKey(void*) = 0;
339249259Sdim
340249259Sdim  virtual void beginEnumScalar() = 0;
341249259Sdim  virtual bool matchEnumScalar(const char*, bool) = 0;
342249259Sdim  virtual void endEnumScalar() = 0;
343249259Sdim
344249259Sdim  virtual bool beginBitSetScalar(bool &) = 0;
345249259Sdim  virtual bool bitSetMatch(const char*, bool) = 0;
346249259Sdim  virtual void endBitSetScalar() = 0;
347249259Sdim
348249259Sdim  virtual void scalarString(StringRef &) = 0;
349249259Sdim
350249259Sdim  virtual void setError(const Twine &) = 0;
351249259Sdim
352249259Sdim  template <typename T>
353249259Sdim  void enumCase(T &Val, const char* Str, const T ConstVal) {
354249259Sdim    if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
355249259Sdim      Val = ConstVal;
356249259Sdim    }
357249259Sdim  }
358249259Sdim
359249259Sdim  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
360249259Sdim  template <typename T>
361249259Sdim  void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
362249259Sdim    if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
363249259Sdim      Val = ConstVal;
364249259Sdim    }
365249259Sdim  }
366249259Sdim
367249259Sdim  template <typename T>
368249259Sdim  void bitSetCase(T &Val, const char* Str, const T ConstVal) {
369249259Sdim    if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
370249259Sdim      Val = Val | ConstVal;
371249259Sdim    }
372249259Sdim  }
373249259Sdim
374249259Sdim  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
375249259Sdim  template <typename T>
376249259Sdim  void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
377249259Sdim    if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
378249259Sdim      Val = Val | ConstVal;
379249259Sdim    }
380249259Sdim  }
381249259Sdim
382249259Sdim  void *getContext();
383249259Sdim  void setContext(void *);
384249259Sdim
385249259Sdim  template <typename T>
386249259Sdim  void mapRequired(const char* Key, T& Val) {
387249259Sdim    this->processKey(Key, Val, true);
388249259Sdim  }
389249259Sdim
390249259Sdim  template <typename T>
391249259Sdim  typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type
392249259Sdim  mapOptional(const char* Key, T& Val) {
393249259Sdim    // omit key/value instead of outputting empty sequence
394263509Sdim    if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) )
395249259Sdim      return;
396249259Sdim    this->processKey(Key, Val, false);
397249259Sdim  }
398249259Sdim
399249259Sdim  template <typename T>
400249259Sdim  typename llvm::enable_if_c<!has_SequenceTraits<T>::value,void>::type
401249259Sdim  mapOptional(const char* Key, T& Val) {
402249259Sdim    this->processKey(Key, Val, false);
403249259Sdim  }
404249259Sdim
405249259Sdim  template <typename T>
406249259Sdim  void mapOptional(const char* Key, T& Val, const T& Default) {
407249259Sdim    this->processKeyWithDefault(Key, Val, Default, false);
408249259Sdim  }
409263509Sdim
410249259Sdimprivate:
411249259Sdim  template <typename T>
412249259Sdim  void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue,
413249259Sdim                                                                bool Required) {
414249259Sdim    void *SaveInfo;
415249259Sdim    bool UseDefault;
416249259Sdim    const bool sameAsDefault = outputting() && Val == DefaultValue;
417249259Sdim    if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
418249259Sdim                                                                  SaveInfo) ) {
419249259Sdim      yamlize(*this, Val, Required);
420249259Sdim      this->postflightKey(SaveInfo);
421249259Sdim    }
422249259Sdim    else {
423249259Sdim      if ( UseDefault )
424249259Sdim        Val = DefaultValue;
425249259Sdim    }
426249259Sdim  }
427249259Sdim
428249259Sdim  template <typename T>
429249259Sdim  void processKey(const char *Key, T &Val, bool Required) {
430249259Sdim    void *SaveInfo;
431249259Sdim    bool UseDefault;
432249259Sdim    if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
433249259Sdim      yamlize(*this, Val, Required);
434249259Sdim      this->postflightKey(SaveInfo);
435249259Sdim    }
436249259Sdim  }
437249259Sdim
438249259Sdimprivate:
439249259Sdim  void  *Ctxt;
440249259Sdim};
441249259Sdim
442249259Sdim
443249259Sdim
444249259Sdimtemplate<typename T>
445249259Sdimtypename llvm::enable_if_c<has_ScalarEnumerationTraits<T>::value,void>::type
446249259Sdimyamlize(IO &io, T &Val, bool) {
447249259Sdim  io.beginEnumScalar();
448249259Sdim  ScalarEnumerationTraits<T>::enumeration(io, Val);
449249259Sdim  io.endEnumScalar();
450249259Sdim}
451249259Sdim
452249259Sdimtemplate<typename T>
453249259Sdimtypename llvm::enable_if_c<has_ScalarBitSetTraits<T>::value,void>::type
454249259Sdimyamlize(IO &io, T &Val, bool) {
455249259Sdim  bool DoClear;
456249259Sdim  if ( io.beginBitSetScalar(DoClear) ) {
457249259Sdim    if ( DoClear )
458249259Sdim      Val = static_cast<T>(0);
459249259Sdim    ScalarBitSetTraits<T>::bitset(io, Val);
460249259Sdim    io.endBitSetScalar();
461249259Sdim  }
462249259Sdim}
463249259Sdim
464249259Sdim
465249259Sdimtemplate<typename T>
466249259Sdimtypename llvm::enable_if_c<has_ScalarTraits<T>::value,void>::type
467249259Sdimyamlize(IO &io, T &Val, bool) {
468249259Sdim  if ( io.outputting() ) {
469249259Sdim    std::string Storage;
470249259Sdim    llvm::raw_string_ostream Buffer(Storage);
471249259Sdim    ScalarTraits<T>::output(Val, io.getContext(), Buffer);
472249259Sdim    StringRef Str = Buffer.str();
473249259Sdim    io.scalarString(Str);
474249259Sdim  }
475249259Sdim  else {
476249259Sdim    StringRef Str;
477249259Sdim    io.scalarString(Str);
478249259Sdim    StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
479249259Sdim    if ( !Result.empty() ) {
480249259Sdim      io.setError(llvm::Twine(Result));
481249259Sdim    }
482249259Sdim  }
483249259Sdim}
484249259Sdim
485249259Sdim
486249259Sdimtemplate<typename T>
487249259Sdimtypename llvm::enable_if_c<has_MappingTraits<T>::value, void>::type
488249259Sdimyamlize(IO &io, T &Val, bool) {
489249259Sdim  io.beginMapping();
490249259Sdim  MappingTraits<T>::mapping(io, Val);
491249259Sdim  io.endMapping();
492249259Sdim}
493249259Sdim
494249259Sdimtemplate<typename T>
495249259Sdimtypename llvm::enable_if_c<missingTraits<T>::value, void>::type
496249259Sdimyamlize(IO &io, T &Val, bool) {
497249259Sdim  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
498249259Sdim}
499249259Sdim
500249259Sdimtemplate<typename T>
501249259Sdimtypename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type
502249259Sdimyamlize(IO &io, T &Seq, bool) {
503249259Sdim  if ( has_FlowTraits< SequenceTraits<T> >::value ) {
504249259Sdim    unsigned incnt = io.beginFlowSequence();
505249259Sdim    unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
506249259Sdim    for(unsigned i=0; i < count; ++i) {
507249259Sdim      void *SaveInfo;
508249259Sdim      if ( io.preflightFlowElement(i, SaveInfo) ) {
509249259Sdim        yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
510249259Sdim        io.postflightFlowElement(SaveInfo);
511249259Sdim      }
512249259Sdim    }
513249259Sdim    io.endFlowSequence();
514249259Sdim  }
515249259Sdim  else {
516249259Sdim    unsigned incnt = io.beginSequence();
517249259Sdim    unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
518249259Sdim    for(unsigned i=0; i < count; ++i) {
519249259Sdim      void *SaveInfo;
520249259Sdim      if ( io.preflightElement(i, SaveInfo) ) {
521249259Sdim        yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
522249259Sdim        io.postflightElement(SaveInfo);
523249259Sdim      }
524249259Sdim    }
525249259Sdim    io.endSequence();
526249259Sdim  }
527249259Sdim}
528249259Sdim
529249259Sdim
530249259Sdimtemplate<>
531249259Sdimstruct ScalarTraits<bool> {
532249259Sdim  static void output(const bool &, void*, llvm::raw_ostream &);
533249259Sdim  static StringRef input(StringRef, void*, bool &);
534249259Sdim};
535249259Sdim
536249259Sdimtemplate<>
537249259Sdimstruct ScalarTraits<StringRef> {
538249259Sdim  static void output(const StringRef &, void*, llvm::raw_ostream &);
539249259Sdim  static StringRef input(StringRef, void*, StringRef &);
540249259Sdim};
541249259Sdim
542249259Sdimtemplate<>
543249259Sdimstruct ScalarTraits<uint8_t> {
544249259Sdim  static void output(const uint8_t &, void*, llvm::raw_ostream &);
545249259Sdim  static StringRef input(StringRef, void*, uint8_t &);
546249259Sdim};
547249259Sdim
548249259Sdimtemplate<>
549249259Sdimstruct ScalarTraits<uint16_t> {
550249259Sdim  static void output(const uint16_t &, void*, llvm::raw_ostream &);
551249259Sdim  static StringRef input(StringRef, void*, uint16_t &);
552249259Sdim};
553249259Sdim
554249259Sdimtemplate<>
555249259Sdimstruct ScalarTraits<uint32_t> {
556249259Sdim  static void output(const uint32_t &, void*, llvm::raw_ostream &);
557249259Sdim  static StringRef input(StringRef, void*, uint32_t &);
558249259Sdim};
559249259Sdim
560249259Sdimtemplate<>
561249259Sdimstruct ScalarTraits<uint64_t> {
562249259Sdim  static void output(const uint64_t &, void*, llvm::raw_ostream &);
563249259Sdim  static StringRef input(StringRef, void*, uint64_t &);
564249259Sdim};
565249259Sdim
566249259Sdimtemplate<>
567249259Sdimstruct ScalarTraits<int8_t> {
568249259Sdim  static void output(const int8_t &, void*, llvm::raw_ostream &);
569249259Sdim  static StringRef input(StringRef, void*, int8_t &);
570249259Sdim};
571249259Sdim
572249259Sdimtemplate<>
573249259Sdimstruct ScalarTraits<int16_t> {
574249259Sdim  static void output(const int16_t &, void*, llvm::raw_ostream &);
575249259Sdim  static StringRef input(StringRef, void*, int16_t &);
576249259Sdim};
577249259Sdim
578249259Sdimtemplate<>
579249259Sdimstruct ScalarTraits<int32_t> {
580249259Sdim  static void output(const int32_t &, void*, llvm::raw_ostream &);
581249259Sdim  static StringRef input(StringRef, void*, int32_t &);
582249259Sdim};
583249259Sdim
584249259Sdimtemplate<>
585249259Sdimstruct ScalarTraits<int64_t> {
586249259Sdim  static void output(const int64_t &, void*, llvm::raw_ostream &);
587249259Sdim  static StringRef input(StringRef, void*, int64_t &);
588249259Sdim};
589249259Sdim
590249259Sdimtemplate<>
591249259Sdimstruct ScalarTraits<float> {
592249259Sdim  static void output(const float &, void*, llvm::raw_ostream &);
593249259Sdim  static StringRef input(StringRef, void*, float &);
594249259Sdim};
595249259Sdim
596249259Sdimtemplate<>
597249259Sdimstruct ScalarTraits<double> {
598249259Sdim  static void output(const double &, void*, llvm::raw_ostream &);
599249259Sdim  static StringRef input(StringRef, void*, double &);
600249259Sdim};
601249259Sdim
602249259Sdim
603249259Sdim
604249259Sdim// Utility for use within MappingTraits<>::mapping() method
605249259Sdim// to [de]normalize an object for use with YAML conversion.
606249259Sdimtemplate <typename TNorm, typename TFinal>
607249259Sdimstruct MappingNormalization {
608249259Sdim  MappingNormalization(IO &i_o, TFinal &Obj)
609249259Sdim      : io(i_o), BufPtr(NULL), Result(Obj) {
610249259Sdim    if ( io.outputting() ) {
611249259Sdim      BufPtr = new (&Buffer) TNorm(io, Obj);
612249259Sdim    }
613249259Sdim    else {
614249259Sdim      BufPtr = new (&Buffer) TNorm(io);
615249259Sdim    }
616249259Sdim  }
617249259Sdim
618249259Sdim  ~MappingNormalization() {
619249259Sdim    if ( ! io.outputting() ) {
620249259Sdim      Result = BufPtr->denormalize(io);
621249259Sdim    }
622249259Sdim    BufPtr->~TNorm();
623249259Sdim  }
624249259Sdim
625249259Sdim  TNorm* operator->() { return BufPtr; }
626249259Sdim
627249259Sdimprivate:
628249259Sdim  typedef llvm::AlignedCharArrayUnion<TNorm> Storage;
629249259Sdim
630249259Sdim  Storage       Buffer;
631249259Sdim  IO           &io;
632249259Sdim  TNorm        *BufPtr;
633249259Sdim  TFinal       &Result;
634249259Sdim};
635249259Sdim
636249259Sdim
637249259Sdim
638249259Sdim// Utility for use within MappingTraits<>::mapping() method
639249259Sdim// to [de]normalize an object for use with YAML conversion.
640249259Sdimtemplate <typename TNorm, typename TFinal>
641249259Sdimstruct MappingNormalizationHeap {
642249259Sdim  MappingNormalizationHeap(IO &i_o, TFinal &Obj)
643249259Sdim    : io(i_o), BufPtr(NULL), Result(Obj) {
644249259Sdim    if ( io.outputting() ) {
645249259Sdim      BufPtr = new (&Buffer) TNorm(io, Obj);
646249259Sdim    }
647249259Sdim    else {
648249259Sdim      BufPtr = new TNorm(io);
649249259Sdim    }
650249259Sdim  }
651249259Sdim
652249259Sdim  ~MappingNormalizationHeap() {
653249259Sdim    if ( io.outputting() ) {
654249259Sdim      BufPtr->~TNorm();
655249259Sdim    }
656249259Sdim    else {
657249259Sdim      Result = BufPtr->denormalize(io);
658249259Sdim    }
659249259Sdim  }
660249259Sdim
661249259Sdim  TNorm* operator->() { return BufPtr; }
662249259Sdim
663249259Sdimprivate:
664249259Sdim  typedef llvm::AlignedCharArrayUnion<TNorm> Storage;
665249259Sdim
666249259Sdim  Storage       Buffer;
667249259Sdim  IO           &io;
668249259Sdim  TNorm        *BufPtr;
669249259Sdim  TFinal       &Result;
670249259Sdim};
671249259Sdim
672249259Sdim
673249259Sdim
674249259Sdim///
675249259Sdim/// The Input class is used to parse a yaml document into in-memory structs
676249259Sdim/// and vectors.
677249259Sdim///
678249259Sdim/// It works by using YAMLParser to do a syntax parse of the entire yaml
679249259Sdim/// document, then the Input class builds a graph of HNodes which wraps
680249259Sdim/// each yaml Node.  The extra layer is buffering.  The low level yaml
681249259Sdim/// parser only lets you look at each node once.  The buffering layer lets
682249259Sdim/// you search and interate multiple times.  This is necessary because
683249259Sdim/// the mapRequired() method calls may not be in the same order
684249259Sdim/// as the keys in the document.
685249259Sdim///
686249259Sdimclass Input : public IO {
687249259Sdimpublic:
688263509Sdim  // Construct a yaml Input object from a StringRef and optional
689263509Sdim  // user-data. The DiagHandler can be specified to provide
690263509Sdim  // alternative error reporting.
691263509Sdim  Input(StringRef InputContent,
692263509Sdim        void *Ctxt = NULL,
693263509Sdim        SourceMgr::DiagHandlerTy DiagHandler = NULL,
694263509Sdim        void *DiagHandlerCtxt = NULL);
695249259Sdim  ~Input();
696263509Sdim
697249259Sdim  // Check if there was an syntax or semantic error during parsing.
698249259Sdim  llvm::error_code error();
699249259Sdim
700263509Sdim  static bool classof(const IO *io) { return !io->outputting(); }
701249259Sdim
702249259Sdimprivate:
703263509Sdim  virtual bool outputting() const;
704263509Sdim  virtual bool mapTag(StringRef, bool);
705249259Sdim  virtual void beginMapping();
706249259Sdim  virtual void endMapping();
707249259Sdim  virtual bool preflightKey(const char *, bool, bool, bool &, void *&);
708249259Sdim  virtual void postflightKey(void *);
709249259Sdim  virtual unsigned beginSequence();
710249259Sdim  virtual void endSequence();
711249259Sdim  virtual bool preflightElement(unsigned index, void *&);
712249259Sdim  virtual void postflightElement(void *);
713249259Sdim  virtual unsigned beginFlowSequence();
714249259Sdim  virtual bool preflightFlowElement(unsigned , void *&);
715249259Sdim  virtual void postflightFlowElement(void *);
716249259Sdim  virtual void endFlowSequence();
717249259Sdim  virtual void beginEnumScalar();
718249259Sdim  virtual bool matchEnumScalar(const char*, bool);
719249259Sdim  virtual void endEnumScalar();
720249259Sdim  virtual bool beginBitSetScalar(bool &);
721249259Sdim  virtual bool bitSetMatch(const char *, bool );
722249259Sdim  virtual void endBitSetScalar();
723249259Sdim  virtual void scalarString(StringRef &);
724249259Sdim  virtual void setError(const Twine &message);
725263509Sdim  virtual bool canElideEmptySequence();
726249259Sdim
727249259Sdim  class HNode {
728263509Sdim    virtual void anchor();
729249259Sdim  public:
730249259Sdim    HNode(Node *n) : _node(n) { }
731249259Sdim    virtual ~HNode() { }
732249259Sdim    static inline bool classof(const HNode *) { return true; }
733249259Sdim
734249259Sdim    Node *_node;
735249259Sdim  };
736249259Sdim
737249259Sdim  class EmptyHNode : public HNode {
738263509Sdim    virtual void anchor();
739249259Sdim  public:
740249259Sdim    EmptyHNode(Node *n) : HNode(n) { }
741249259Sdim    static inline bool classof(const HNode *n) {
742249259Sdim      return NullNode::classof(n->_node);
743249259Sdim    }
744249259Sdim    static inline bool classof(const EmptyHNode *) { return true; }
745249259Sdim  };
746249259Sdim
747249259Sdim  class ScalarHNode : public HNode {
748263509Sdim    virtual void anchor();
749249259Sdim  public:
750249259Sdim    ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
751249259Sdim
752249259Sdim    StringRef value() const { return _value; }
753249259Sdim
754249259Sdim    static inline bool classof(const HNode *n) {
755249259Sdim      return ScalarNode::classof(n->_node);
756249259Sdim    }
757249259Sdim    static inline bool classof(const ScalarHNode *) { return true; }
758249259Sdim  protected:
759249259Sdim    StringRef _value;
760249259Sdim  };
761249259Sdim
762249259Sdim  class MapHNode : public HNode {
763249259Sdim  public:
764249259Sdim    MapHNode(Node *n) : HNode(n) { }
765249259Sdim    virtual ~MapHNode();
766249259Sdim
767249259Sdim    static inline bool classof(const HNode *n) {
768249259Sdim      return MappingNode::classof(n->_node);
769249259Sdim    }
770249259Sdim    static inline bool classof(const MapHNode *) { return true; }
771249259Sdim
772263509Sdim    typedef llvm::StringMap<HNode*> NameToNode;
773249259Sdim
774249259Sdim    bool isValidKey(StringRef key);
775249259Sdim
776249259Sdim    NameToNode                        Mapping;
777249259Sdim    llvm::SmallVector<const char*, 6> ValidKeys;
778249259Sdim  };
779249259Sdim
780249259Sdim  class SequenceHNode : public HNode {
781249259Sdim  public:
782249259Sdim    SequenceHNode(Node *n) : HNode(n) { }
783249259Sdim    virtual ~SequenceHNode();
784249259Sdim
785249259Sdim    static inline bool classof(const HNode *n) {
786249259Sdim      return SequenceNode::classof(n->_node);
787249259Sdim    }
788249259Sdim    static inline bool classof(const SequenceHNode *) { return true; }
789249259Sdim
790249259Sdim    std::vector<HNode*> Entries;
791249259Sdim  };
792249259Sdim
793249259Sdim  Input::HNode *createHNodes(Node *node);
794249259Sdim  void setError(HNode *hnode, const Twine &message);
795249259Sdim  void setError(Node *node, const Twine &message);
796249259Sdim
797249259Sdim
798249259Sdimpublic:
799249259Sdim  // These are only used by operator>>. They could be private
800249259Sdim  // if those templated things could be made friends.
801249259Sdim  bool setCurrentDocument();
802249259Sdim  void nextDocument();
803249259Sdim
804249259Sdimprivate:
805249259Sdim  llvm::SourceMgr                  SrcMgr; // must be before Strm
806249259Sdim  OwningPtr<llvm::yaml::Stream>    Strm;
807249259Sdim  OwningPtr<HNode>                 TopNode;
808249259Sdim  llvm::error_code                 EC;
809249259Sdim  llvm::BumpPtrAllocator           StringAllocator;
810249259Sdim  llvm::yaml::document_iterator    DocIterator;
811249259Sdim  std::vector<bool>                BitValuesUsed;
812249259Sdim  HNode                           *CurrentNode;
813249259Sdim  bool                             ScalarMatchFound;
814249259Sdim};
815249259Sdim
816249259Sdim
817249259Sdim
818249259Sdim
819249259Sdim///
820249259Sdim/// The Output class is used to generate a yaml document from in-memory structs
821249259Sdim/// and vectors.
822249259Sdim///
823249259Sdimclass Output : public IO {
824249259Sdimpublic:
825249259Sdim  Output(llvm::raw_ostream &, void *Ctxt=NULL);
826249259Sdim  virtual ~Output();
827249259Sdim
828263509Sdim  static bool classof(const IO *io) { return io->outputting(); }
829263509Sdim
830263509Sdim  virtual bool outputting() const;
831263509Sdim  virtual bool mapTag(StringRef, bool);
832249259Sdim  virtual void beginMapping();
833249259Sdim  virtual void endMapping();
834249259Sdim  virtual bool preflightKey(const char *key, bool, bool, bool &, void *&);
835249259Sdim  virtual void postflightKey(void *);
836249259Sdim  virtual unsigned beginSequence();
837249259Sdim  virtual void endSequence();
838249259Sdim  virtual bool preflightElement(unsigned, void *&);
839249259Sdim  virtual void postflightElement(void *);
840249259Sdim  virtual unsigned beginFlowSequence();
841249259Sdim  virtual bool preflightFlowElement(unsigned, void *&);
842249259Sdim  virtual void postflightFlowElement(void *);
843249259Sdim  virtual void endFlowSequence();
844249259Sdim  virtual void beginEnumScalar();
845249259Sdim  virtual bool matchEnumScalar(const char*, bool);
846249259Sdim  virtual void endEnumScalar();
847249259Sdim  virtual bool beginBitSetScalar(bool &);
848249259Sdim  virtual bool bitSetMatch(const char *, bool );
849249259Sdim  virtual void endBitSetScalar();
850249259Sdim  virtual void scalarString(StringRef &);
851249259Sdim  virtual void setError(const Twine &message);
852263509Sdim  virtual bool canElideEmptySequence();
853249259Sdimpublic:
854249259Sdim  // These are only used by operator<<. They could be private
855249259Sdim  // if that templated operator could be made a friend.
856249259Sdim  void beginDocuments();
857249259Sdim  bool preflightDocument(unsigned);
858249259Sdim  void postflightDocument();
859249259Sdim  void endDocuments();
860249259Sdim
861249259Sdimprivate:
862249259Sdim  void output(StringRef s);
863249259Sdim  void outputUpToEndOfLine(StringRef s);
864249259Sdim  void newLineCheck();
865249259Sdim  void outputNewLine();
866249259Sdim  void paddedKey(StringRef key);
867249259Sdim
868249259Sdim  enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey };
869249259Sdim
870249259Sdim  llvm::raw_ostream       &Out;
871249259Sdim  SmallVector<InState, 8>  StateStack;
872249259Sdim  int                      Column;
873249259Sdim  int                      ColumnAtFlowStart;
874249259Sdim  bool                     NeedBitValueComma;
875249259Sdim  bool                     NeedFlowSequenceComma;
876249259Sdim  bool                     EnumerationMatchFound;
877249259Sdim  bool                     NeedsNewLine;
878249259Sdim};
879249259Sdim
880249259Sdim
881249259Sdim
882249259Sdim
883249259Sdim/// YAML I/O does conversion based on types. But often native data types
884249259Sdim/// are just a typedef of built in intergral types (e.g. int).  But the C++
885249259Sdim/// type matching system sees through the typedef and all the typedefed types
886249259Sdim/// look like a built in type. This will cause the generic YAML I/O conversion
887249259Sdim/// to be used. To provide better control over the YAML conversion, you can
888249259Sdim/// use this macro instead of typedef.  It will create a class with one field
889249259Sdim/// and automatic conversion operators to and from the base type.
890249259Sdim/// Based on BOOST_STRONG_TYPEDEF
891249259Sdim#define LLVM_YAML_STRONG_TYPEDEF(_base, _type)                                 \
892249259Sdim    struct _type {                                                             \
893249259Sdim        _type() { }                                                            \
894249259Sdim        _type(const _base v) : value(v) { }                                    \
895249259Sdim        _type(const _type &v) : value(v.value) {}                              \
896249259Sdim        _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\
897249259Sdim        _type &operator=(const _base &rhs) { value = rhs; return *this; }      \
898249259Sdim        operator const _base & () const { return value; }                      \
899249259Sdim        bool operator==(const _type &rhs) const { return value == rhs.value; } \
900249259Sdim        bool operator==(const _base &rhs) const { return value == rhs; }       \
901249259Sdim        bool operator<(const _type &rhs) const { return value < rhs.value; }   \
902249259Sdim        _base value;                                                           \
903249259Sdim    };
904249259Sdim
905249259Sdim
906249259Sdim
907249259Sdim///
908249259Sdim/// Use these types instead of uintXX_t in any mapping to have
909249259Sdim/// its yaml output formatted as hexadecimal.
910249259Sdim///
911249259SdimLLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
912249259SdimLLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
913249259SdimLLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
914249259SdimLLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
915249259Sdim
916249259Sdim
917249259Sdimtemplate<>
918249259Sdimstruct ScalarTraits<Hex8> {
919249259Sdim  static void output(const Hex8 &, void*, llvm::raw_ostream &);
920249259Sdim  static StringRef input(StringRef, void*, Hex8 &);
921249259Sdim};
922249259Sdim
923249259Sdimtemplate<>
924249259Sdimstruct ScalarTraits<Hex16> {
925249259Sdim  static void output(const Hex16 &, void*, llvm::raw_ostream &);
926249259Sdim  static StringRef input(StringRef, void*, Hex16 &);
927249259Sdim};
928249259Sdim
929249259Sdimtemplate<>
930249259Sdimstruct ScalarTraits<Hex32> {
931249259Sdim  static void output(const Hex32 &, void*, llvm::raw_ostream &);
932249259Sdim  static StringRef input(StringRef, void*, Hex32 &);
933249259Sdim};
934249259Sdim
935249259Sdimtemplate<>
936249259Sdimstruct ScalarTraits<Hex64> {
937249259Sdim  static void output(const Hex64 &, void*, llvm::raw_ostream &);
938249259Sdim  static StringRef input(StringRef, void*, Hex64 &);
939249259Sdim};
940249259Sdim
941249259Sdim
942249259Sdim// Define non-member operator>> so that Input can stream in a document list.
943249259Sdimtemplate <typename T>
944249259Sdiminline
945249259Sdimtypename llvm::enable_if_c<has_DocumentListTraits<T>::value,Input &>::type
946249259Sdimoperator>>(Input &yin, T &docList) {
947249259Sdim  int i = 0;
948249259Sdim  while ( yin.setCurrentDocument() ) {
949249259Sdim    yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true);
950249259Sdim    if ( yin.error() )
951249259Sdim      return yin;
952249259Sdim    yin.nextDocument();
953249259Sdim    ++i;
954249259Sdim  }
955249259Sdim  return yin;
956249259Sdim}
957249259Sdim
958249259Sdim// Define non-member operator>> so that Input can stream in a map as a document.
959249259Sdimtemplate <typename T>
960249259Sdiminline
961249259Sdimtypename llvm::enable_if_c<has_MappingTraits<T>::value,Input &>::type
962249259Sdimoperator>>(Input &yin, T &docMap) {
963249259Sdim  yin.setCurrentDocument();
964249259Sdim  yamlize(yin, docMap, true);
965249259Sdim  return yin;
966249259Sdim}
967249259Sdim
968249259Sdim// Define non-member operator>> so that Input can stream in a sequence as
969249259Sdim// a document.
970249259Sdimtemplate <typename T>
971249259Sdiminline
972249259Sdimtypename llvm::enable_if_c<has_SequenceTraits<T>::value,Input &>::type
973249259Sdimoperator>>(Input &yin, T &docSeq) {
974263509Sdim  if (yin.setCurrentDocument())
975263509Sdim    yamlize(yin, docSeq, true);
976249259Sdim  return yin;
977249259Sdim}
978249259Sdim
979249259Sdim// Provide better error message about types missing a trait specialization
980249259Sdimtemplate <typename T>
981249259Sdiminline
982249259Sdimtypename llvm::enable_if_c<missingTraits<T>::value,Input &>::type
983249259Sdimoperator>>(Input &yin, T &docSeq) {
984249259Sdim  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
985249259Sdim  return yin;
986249259Sdim}
987249259Sdim
988249259Sdim
989249259Sdim// Define non-member operator<< so that Output can stream out document list.
990249259Sdimtemplate <typename T>
991249259Sdiminline
992249259Sdimtypename llvm::enable_if_c<has_DocumentListTraits<T>::value,Output &>::type
993249259Sdimoperator<<(Output &yout, T &docList) {
994249259Sdim  yout.beginDocuments();
995249259Sdim  const size_t count = DocumentListTraits<T>::size(yout, docList);
996249259Sdim  for(size_t i=0; i < count; ++i) {
997249259Sdim    if ( yout.preflightDocument(i) ) {
998249259Sdim      yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true);
999249259Sdim      yout.postflightDocument();
1000249259Sdim    }
1001249259Sdim  }
1002249259Sdim  yout.endDocuments();
1003249259Sdim  return yout;
1004249259Sdim}
1005249259Sdim
1006249259Sdim// Define non-member operator<< so that Output can stream out a map.
1007249259Sdimtemplate <typename T>
1008249259Sdiminline
1009249259Sdimtypename llvm::enable_if_c<has_MappingTraits<T>::value,Output &>::type
1010249259Sdimoperator<<(Output &yout, T &map) {
1011249259Sdim  yout.beginDocuments();
1012249259Sdim  if ( yout.preflightDocument(0) ) {
1013249259Sdim    yamlize(yout, map, true);
1014249259Sdim    yout.postflightDocument();
1015249259Sdim  }
1016249259Sdim  yout.endDocuments();
1017249259Sdim  return yout;
1018249259Sdim}
1019249259Sdim
1020249259Sdim// Define non-member operator<< so that Output can stream out a sequence.
1021249259Sdimtemplate <typename T>
1022249259Sdiminline
1023249259Sdimtypename llvm::enable_if_c<has_SequenceTraits<T>::value,Output &>::type
1024249259Sdimoperator<<(Output &yout, T &seq) {
1025249259Sdim  yout.beginDocuments();
1026249259Sdim  if ( yout.preflightDocument(0) ) {
1027249259Sdim    yamlize(yout, seq, true);
1028249259Sdim    yout.postflightDocument();
1029249259Sdim  }
1030249259Sdim  yout.endDocuments();
1031249259Sdim  return yout;
1032249259Sdim}
1033249259Sdim
1034249259Sdim// Provide better error message about types missing a trait specialization
1035249259Sdimtemplate <typename T>
1036249259Sdiminline
1037249259Sdimtypename llvm::enable_if_c<missingTraits<T>::value,Output &>::type
1038249259Sdimoperator<<(Output &yout, T &seq) {
1039249259Sdim  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1040249259Sdim  return yout;
1041249259Sdim}
1042249259Sdim
1043249259Sdim
1044249259Sdim} // namespace yaml
1045249259Sdim} // namespace llvm
1046249259Sdim
1047249259Sdim
1048249259Sdim/// Utility for declaring that a std::vector of a particular type
1049249259Sdim/// should be considered a YAML sequence.
1050249259Sdim#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type)                                 \
1051249259Sdim  namespace llvm {                                                          \
1052249259Sdim  namespace yaml {                                                          \
1053249259Sdim    template<>                                                              \
1054249259Sdim    struct SequenceTraits< std::vector<_type> > {                           \
1055249259Sdim      static size_t size(IO &io, std::vector<_type> &seq) {                 \
1056249259Sdim        return seq.size();                                                  \
1057249259Sdim      }                                                                     \
1058249259Sdim      static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1059249259Sdim        if ( index >= seq.size() )                                          \
1060249259Sdim          seq.resize(index+1);                                              \
1061249259Sdim        return seq[index];                                                  \
1062249259Sdim      }                                                                     \
1063249259Sdim    };                                                                      \
1064249259Sdim  }                                                                         \
1065249259Sdim  }
1066249259Sdim
1067249259Sdim/// Utility for declaring that a std::vector of a particular type
1068249259Sdim/// should be considered a YAML flow sequence.
1069249259Sdim#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type)                            \
1070249259Sdim  namespace llvm {                                                          \
1071249259Sdim  namespace yaml {                                                          \
1072249259Sdim    template<>                                                              \
1073249259Sdim    struct SequenceTraits< std::vector<_type> > {                           \
1074249259Sdim      static size_t size(IO &io, std::vector<_type> &seq) {                 \
1075249259Sdim        return seq.size();                                                  \
1076249259Sdim      }                                                                     \
1077249259Sdim      static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1078249259Sdim        if ( index >= seq.size() )                                          \
1079249259Sdim          seq.resize(index+1);                                              \
1080249259Sdim        return seq[index];                                                  \
1081249259Sdim      }                                                                     \
1082249259Sdim      static const bool flow = true;                                        \
1083249259Sdim    };                                                                      \
1084249259Sdim  }                                                                         \
1085249259Sdim  }
1086249259Sdim
1087249259Sdim/// Utility for declaring that a std::vector of a particular type
1088249259Sdim/// should be considered a YAML document list.
1089249259Sdim#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type)                            \
1090249259Sdim  namespace llvm {                                                          \
1091249259Sdim  namespace yaml {                                                          \
1092249259Sdim    template<>                                                              \
1093249259Sdim    struct DocumentListTraits< std::vector<_type> > {                       \
1094249259Sdim      static size_t size(IO &io, std::vector<_type> &seq) {                 \
1095249259Sdim        return seq.size();                                                  \
1096249259Sdim      }                                                                     \
1097249259Sdim      static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1098249259Sdim        if ( index >= seq.size() )                                          \
1099249259Sdim          seq.resize(index+1);                                              \
1100249259Sdim        return seq[index];                                                  \
1101249259Sdim      }                                                                     \
1102249259Sdim    };                                                                      \
1103249259Sdim  }                                                                         \
1104249259Sdim  }
1105249259Sdim
1106249259Sdim
1107249259Sdim
1108249259Sdim#endif // LLVM_SUPPORT_YAMLTRAITS_H
1109