[llvm-commits] [llvm] r170019 - in /llvm/trunk: docs/YamlIO.rst docs/userguides.rst include/llvm/Support/YAMLTraits.h lib/Support/CMakeLists.txt lib/Support/YAMLTraits.cpp unittests/Support/CMakeLists.txt unittests/Support/YAMLIOTest.cpp

Chandler Carruth chandlerc at google.com
Sun Jan 6 16:40:48 PST 2013


Yea, it was missing for a long time. Nick Lewycky recently revived it.
Thanks!


On Sun, Jan 6, 2013 at 4:18 PM, Nick Kledzik <kledzik at apple.com> wrote:

> Thanks.  I'll take a look.  I did not even realize the testers had a leak
> mode!
>
> -Nick
>
> On Jan 5, 2013, at 1:29 AM, Chandler Carruth wrote:
>
> Hey Nick, I just wanted to mention that YamlIO seems to be leaking memory:
>
> http://lab.llvm.org:8011/builders/llvm-x86_64-linux-vg_leak/builds/140
>
> There are other (unrelated) failures on that bot, the yamlio ones look
> like actual leaks to me?
>
>
> On Wed, Dec 12, 2012 at 12:46 PM, Nick Kledzik <kledzik at apple.com> wrote:
>
>> Author: kledzik
>> Date: Wed Dec 12 14:46:15 2012
>> New Revision: 170019
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=170019&view=rev
>> Log:
>> Initial implementation of a utility for converting native data
>> structures to and from YAML using traits.  The first client will
>> be the test suite of lld.  The documentation will show up at:
>>
>>    http://llvm.org/docs/YamlIO.html
>>
>>
>>
>> Added:
>>     llvm/trunk/docs/YamlIO.rst
>>     llvm/trunk/include/llvm/Support/YAMLTraits.h
>>     llvm/trunk/lib/Support/YAMLTraits.cpp
>>     llvm/trunk/unittests/Support/YAMLIOTest.cpp
>> Modified:
>>     llvm/trunk/docs/userguides.rst
>>     llvm/trunk/lib/Support/CMakeLists.txt
>>     llvm/trunk/unittests/Support/CMakeLists.txt
>>
>> Added: llvm/trunk/docs/YamlIO.rst
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/YamlIO.rst?rev=170019&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/docs/YamlIO.rst (added)
>> +++ llvm/trunk/docs/YamlIO.rst Wed Dec 12 14:46:15 2012
>> @@ -0,0 +1,862 @@
>> +.. _yamlio:
>> +
>> +=====================
>> +YAML I/O
>> +=====================
>> +
>> +.. contents::
>> +   :local:
>> +
>> +Introduction to YAML
>> +====================
>> +
>> +YAML is a human readable data serialization language.  The full YAML
>> language
>> +spec can be read at `yaml.org
>> +<http://www.yaml.org/spec/1.2/spec.html#Introduction>`_.  The simplest
>> form of
>> +yaml is just "scalars", "mappings", and "sequences".  A scalar is any
>> number
>> +or string.  The pound/hash symbol (#) begins a comment line.   A mapping
>> is
>> +a set of key-value pairs where the key ends with a colon.  For example:
>> +
>> +.. code-block:: yaml
>> +
>> +     # a mapping
>> +     name:      Tom
>> +     hat-size:  7
>> +
>> +A sequence is a list of items where each item starts with a leading dash
>> ('-').
>> +For example:
>> +
>> +.. code-block:: yaml
>> +
>> +     # a sequence
>> +     - x86
>> +     - x86_64
>> +     - PowerPC
>> +
>> +You can combine mappings and sequences by indenting.  For example a
>> sequence
>> +of mappings in which one of the mapping values is itself a sequence:
>> +
>> +.. code-block:: yaml
>> +
>> +     # a sequence of mappings with one key's value being a sequence
>> +     - name:      Tom
>> +       cpus:
>> +        - x86
>> +        - x86_64
>> +     - name:      Bob
>> +       cpus:
>> +        - x86
>> +     - name:      Dan
>> +       cpus:
>> +        - PowerPC
>> +        - x86
>> +
>> +Sometime sequences are known to be short and the one entry per line is
>> too
>> +verbose, so YAML offers an alternate syntax for sequences called a "Flow
>> +Sequence" in which you put comma separated sequence elements into square
>> +brackets.  The above example could then be simplified to :
>> +
>> +
>> +.. code-block:: yaml
>> +
>> +     # a sequence of mappings with one key's value being a flow sequence
>> +     - name:      Tom
>> +       cpus:      [ x86, x86_64 ]
>> +     - name:      Bob
>> +       cpus:      [ x86 ]
>> +     - name:      Dan
>> +       cpus:      [ PowerPC, x86 ]
>> +
>> +
>> +Introduction to YAML I/O
>> +========================
>> +
>> +The use of indenting makes the YAML easy for a human to read and
>> understand,
>> +but having a program read and write YAML involves a lot of tedious
>> details.
>> +The YAML I/O library structures and simplifies reading and writing YAML
>> +documents.
>> +
>> +YAML I/O assumes you have some "native" data structures which you want
>> to be
>> +able to dump as YAML and recreate from YAML.  The first step is to try
>> +writing example YAML for your data structures. You may find after
>> looking at
>> +possible YAML representations that a direct mapping of your data
>> structures
>> +to YAML is not very readable.  Often the fields are not in the order that
>> +a human would find readable.  Or the same information is replicated in
>> multiple
>> +locations, making it hard for a human to write such YAML correctly.
>> +
>> +In relational database theory there is a design step called
>> normalization in
>> +which you reorganize fields and tables.  The same considerations need to
>> +go into the design of your YAML encoding.  But, you may not want to
>> change
>> +your exisiting native data structures.  Therefore, when writing out YAML
>> +there may be a normalization step, and when reading YAML there would be a
>> +corresponding denormalization step.
>> +
>> +YAML I/O uses a non-invasive, traits based design.  YAML I/O defines some
>> +abstract base templates.  You specialize those templates on your data
>> types.
>> +For instance, if you have an eumerated type FooBar you could specialize
>> +ScalarEnumerationTraits on that type and define the enumeration() method:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::ScalarEnumerationTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct ScalarEnumerationTraits<FooBar> {
>> +      static void enumeration(IO &io, FooBar &value) {
>> +      ...
>> +      }
>> +    };
>> +
>> +
>> +As with all YAML I/O template specializations, the
>> ScalarEnumerationTraits is used for
>> +both reading and writing YAML. That is, the mapping between in-memory
>> enum
>> +values and the YAML string representation is only in place.
>> +This assures that the code for writing and parsing of YAML stays in sync.
>> +
>> +To specify a YAML mappings, you define a specialization on
>> +llvm::yaml::MapppingTraits.
>> +If your native data structure happens to be a struct that is already
>> normalized,
>> +then the specialization is simple.  For example:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct MapppingTraits<Person> {
>> +      static void mapping(IO &io, Person &info) {
>> +        io.mapRequired("name",         info.name);
>> +        io.mapOptional("hat-size",     info.hatSize);
>> +      }
>> +    };
>> +
>> +
>> +A YAML sequence is automatically infered if you data type has
>> begin()/end()
>> +iterators and a push_back() method.  Therefore any of the STL containers
>> +(such as std::vector<>) will automatically translate to YAML sequences.
>> +
>> +Once you have defined specializations for your data types, you can
>> +programmatically use YAML I/O to write a YAML document:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::Output;
>> +
>> +    Person tom;
>> +    tom.name = "Tom";
>> +    tom.hatSize = 8;
>> +    Person dan;
>> +    dan.name = "Dan";
>> +    dan.hatSize = 7;
>> +    std::vector<Person> persons;
>> +    persons.push_back(tom);
>> +    persons.push_back(dan);
>> +
>> +    Output yout(llvm::outs());
>> +    yout << persons;
>> +
>> +This would write the following:
>> +
>> +.. code-block:: yaml
>> +
>> +     - name:      Tom
>> +       hat-size:  8
>> +     - name:      Dan
>> +       hat-size:  7
>> +
>> +And you can also read such YAML documents with the following code:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::Input;
>> +
>> +    typedef std::vector<Person> PersonList;
>> +    std::vector<PersonList> docs;
>> +
>> +    Input yin(document.getBuffer());
>> +    yin >> docs;
>> +
>> +    if ( yin.error() )
>> +      return;
>> +
>> +    // Process read document
>> +    for ( PersonList &pl : docs ) {
>> +      for ( Person &person : pl ) {
>> +        cout << "name=" << person.name;
>> +      }
>> +    }
>> +
>> +One other feature of YAML is the ability to define multiple documents in
>> a
>> +single file.  That is why reading YAML produces a vector of your
>> document type.
>> +
>> +
>> +
>> +Error Handling
>> +==============
>> +
>> +When parsing a YAML document, if the input does not match your schema (as
>> +expressed in your XxxTraits<> specializations).  YAML I/O
>> +will print out an error message and your Input object's error() method
>> will
>> +return true. For instance the following document:
>> +
>> +.. code-block:: yaml
>> +
>> +     - name:      Tom
>> +       shoe-size: 12
>> +     - name:      Dan
>> +       hat-size:  7
>> +
>> +Has a key (shoe-size) that is not defined in the schema.  YAML I/O will
>> +automatically generate this error:
>> +
>> +.. code-block:: yaml
>> +
>> +    YAML:2:2: error: unknown key 'shoe-size'
>> +      shoe-size:       12
>> +      ^~~~~~~~~
>> +
>> +Similar errors are produced for other input not conforming to the schema.
>> +
>> +
>> +Scalars
>> +=======
>> +
>> +YAML scalars are just strings (i.e. not a sequence or mapping).  The
>> YAML I/O
>> +library provides support for translating between YAML scalars and
>> specific
>> +C++ types.
>> +
>> +
>> +Built-in types
>> +--------------
>> +The following types have built-in support in YAML I/O:
>> +
>> +* bool
>> +* float
>> +* double
>> +* StringRef
>> +* int64_t
>> +* int32_t
>> +* int16_t
>> +* int8_t
>> +* uint64_t
>> +* uint32_t
>> +* uint16_t
>> +* uint8_t
>> +
>> +That is, you can use those types in fields of MapppingTraits or as
>> element type
>> +in sequence.  When reading, YAML I/O will validate that the string found
>> +is convertible to that type and error out if not.
>> +
>> +
>> +Unique types
>> +------------
>> +Given that YAML I/O is trait based, the selection of how to convert your
>> data
>> +to YAML is based on the type of your data.  But in C++ type matching,
>> typedefs
>> +do not generate unique type names.  That means if you have two typedefs
>> of
>> +unsigned int, to YAML I/O both types look exactly like unsigned int.  To
>> +facilitate make unique type names, YAML I/O provides a macro which is
>> used
>> +like a typedef on built-in types, but expands to create a class with
>> conversion
>> +operators to and from the base type.  For example:
>> +
>> +.. code-block:: c++
>> +
>> +    LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFooFlags)
>> +    LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyBarFlags)
>> +
>> +This generates two classes MyFooFlags and MyBarFlags which you can use
>> in your
>> +native data structures instead of uint32_t. They are implicitly
>> +converted to and from uint32_t.  The point of creating these unique types
>> +is that you can now specify traits on them to get different YAML
>> conversions.
>> +
>> +Hex types
>> +---------
>> +An example use of a unique type is that YAML I/O provides fixed sized
>> unsigned
>> +integers that are written with YAML I/O as hexadecimal instead of the
>> decimal
>> +format used by the built-in integer types:
>> +
>> +* Hex64
>> +* Hex32
>> +* Hex16
>> +* Hex8
>> +
>> +You can use llvm::yaml::Hex32 instead of uint32_t and the only different
>> will
>> +be that when YAML I/O writes out that type it will be formatted in
>> hexadecimal.
>> +
>> +
>> +ScalarEnumerationTraits
>> +-----------------------
>> +YAML I/O supports translating between in-memory enumerations and a set
>> of string
>> +values in YAML documents. This is done by specializing
>> ScalarEnumerationTraits<>
>> +on your enumeration type and define a enumeration() method.
>> +For instance, suppose you had an enumeration of CPUs and a struct with
>> it as
>> +a field:
>> +
>> +.. code-block:: c++
>> +
>> +    enum CPUs {
>> +      cpu_x86_64  = 5,
>> +      cpu_x86     = 7,
>> +      cpu_PowerPC = 8
>> +    };
>> +
>> +    struct Info {
>> +      CPUs      cpu;
>> +      uint32_t  flags;
>> +    };
>> +
>> +To support reading and writing of this enumeration, you can define a
>> +ScalarEnumerationTraits specialization on CPUs, which can then be used
>> +as a field type:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::ScalarEnumerationTraits;
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct ScalarEnumerationTraits<CPUs> {
>> +      static void enumeration(IO &io, CPUs &value) {
>> +        io.enumCase(value, "x86_64",  cpu_x86_64);
>> +        io.enumCase(value, "x86",     cpu_x86);
>> +        io.enumCase(value, "PowerPC", cpu_PowerPC);
>> +      }
>> +    };
>> +
>> +    template <>
>> +    struct MapppingTraits<Info> {
>> +      static void mapping(IO &io, Info &info) {
>> +        io.mapRequired("cpu",       info.cpu);
>> +        io.mapOptional("flags",     info.flags, 0);
>> +      }
>> +    };
>> +
>> +When reading YAML, if the string found does not match any of the the
>> strings
>> +specified by enumCase() methods, an error is automatically generated.
>> +When writing YAML, if the value being written does not match any of the
>> values
>> +specified by the enumCase() methods, a runtime assertion is triggered.
>> +
>> +
>> +BitValue
>> +--------
>> +Another common data structure in C++ is a field where each bit has a
>> unique
>> +meaning.  This is often used in a "flags" field.  YAML I/O has support
>> for
>> +converting such fields to a flow sequence.   For instance suppose you
>> +had the following bit flags defined:
>> +
>> +.. code-block:: c++
>> +
>> +    enum {
>> +      flagsPointy = 1
>> +      flagsHollow = 2
>> +      flagsFlat   = 4
>> +      flagsRound  = 8
>> +    };
>> +
>> +    LLVM_YAML_UNIQUE_TYPE(MyFlags, uint32_t)
>> +
>> +To support reading and writing of MyFlags, you specialize
>> ScalarBitSetTraits<>
>> +on MyFlags and provide the bit values and their names.
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::ScalarBitSetTraits;
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct ScalarBitSetTraits<MyFlags> {
>> +      static void bitset(IO &io, MyFlags &value) {
>> +        io.bitSetCase(value, "hollow",  flagHollow);
>> +        io.bitSetCase(value, "flat",    flagFlat);
>> +        io.bitSetCase(value, "round",   flagRound);
>> +        io.bitSetCase(value, "pointy",  flagPointy);
>> +      }
>> +    };
>> +
>> +    struct Info {
>> +      StringRef   name;
>> +      MyFlags     flags;
>> +    };
>> +
>> +    template <>
>> +    struct MapppingTraits<Info> {
>> +      static void mapping(IO &io, Info& info) {
>> +        io.mapRequired("name",  info.name);
>> +        io.mapRequired("flags", info.flags);
>> +       }
>> +    };
>> +
>> +With the above, YAML I/O (when writing) will test mask each value in the
>> +bitset trait against the flags field, and each that matches will
>> +cause the corresponding string to be added to the flow sequence.  The
>> opposite
>> +is done when reading and any unknown string values will result in a
>> error. With
>> +the above schema, a same valid YAML document is:
>> +
>> +.. code-block:: yaml
>> +
>> +    name:    Tom
>> +    flags:   [ pointy, flat ]
>> +
>> +
>> +Custom Scalar
>> +-------------
>> +Sometimes for readability a scalar needs to be formatted in a custom
>> way. For
>> +instance your internal data structure may use a integer for time
>> (seconds since
>> +some epoch), but in YAML it would be much nicer to express that integer
>> in
>> +some time format (e.g. 4-May-2012 10:30pm).  YAML I/O has a way to
>> support
>> +custom formatting and parsing of scalar types by specializing
>> ScalarTraits<> on
>> +your data type.  When writing, YAML I/O will provide the native type and
>> +your specialization must create a temporary llvm::StringRef.  When
>> reading,
>> +YAML I/O will provide a llvm::StringRef of scalar and your specialization
>> +must convert that to your native data type.  An outline of a custom
>> scalar type
>> +looks like:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::ScalarTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct ScalarTraits<MyCustomType> {
>> +      static void output(const T &value, llvm::raw_ostream &out) {
>> +        out << value;  // do custom formatting here
>> +      }
>> +      static StringRef input(StringRef scalar, T &value) {
>> +        // do custom parsing here.  Return the empty string on success,
>> +        // or an error message on failure.
>> +        return StringRef();
>> +      }
>> +    };
>> +
>> +
>> +Mappings
>> +========
>> +
>> +To be translated to or from a YAML mapping for your type T you must
>> specialize
>> +llvm::yaml::MapppingTraits on T and implement the "void mapping(IO &io,
>> T&)"
>> +method. If your native data structures use pointers to a class
>> everywhere,
>> +you can specialize on the class pointer.  Examples:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    // Example of struct Foo which is used by value
>> +    template <>
>> +    struct MapppingTraits<Foo> {
>> +      static void mapping(IO &io, Foo &foo) {
>> +        io.mapOptional("size",      foo.size);
>> +      ...
>> +      }
>> +    };
>> +
>> +    // Example of struct Bar which is natively always a pointer
>> +    template <>
>> +    struct MapppingTraits<Bar*> {
>> +      static void mapping(IO &io, Bar *&bar) {
>> +        io.mapOptional("size",    bar->size);
>> +      ...
>> +      }
>> +    };
>> +
>> +
>> +No Normalization
>> +----------------
>> +
>> +The mapping() method is responsible, if needed, for normalizing and
>> +denormalizing. In a simple case where the native data structure requires
>> no
>> +normalization, the mapping method just uses mapOptional() or
>> mapRequired() to
>> +bind the struct's fields to YAML key names.  For example:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct MapppingTraits<Person> {
>> +      static void mapping(IO &io, Person &info) {
>> +        io.mapRequired("name",         info.name);
>> +        io.mapOptional("hat-size",     info.hatSize);
>> +      }
>> +    };
>> +
>> +
>> +Normalization
>> +----------------
>> +
>> +When [de]normalization is required, the mapping() method needs a way to
>> access
>> +normalized values as fields. To help with this, there is
>> +a template MappingNormalization<> which you can then use to automatically
>> +do the normalization and denormalization.  The template is used to create
>> +a local variable in your mapping() method which contains the normalized
>> keys.
>> +
>> +Suppose you have native data type
>> +Polar which specifies a position in polar coordinates (distance, angle):
>> +
>> +.. code-block:: c++
>> +
>> +    struct Polar {
>> +      float distance;
>> +      float angle;
>> +    };
>> +
>> +but you've decided the normalized YAML for should be in x,y coordinates.
>> That
>> +is, you want the yaml to look like:
>> +
>> +.. code-block:: yaml
>> +
>> +    x:   10.3
>> +    y:   -4.7
>> +
>> +You can support this by defining a MapppingTraits that normalizes the
>> polar
>> +coordinates to x,y coordinates when writing YAML and denormalizes x,y
>> +coordindates into polar when reading YAML.
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    template <>
>> +    struct MapppingTraits<Polar> {
>> +
>> +      class NormalizedPolar {
>> +      public:
>> +        NormalizedPolar(IO &io)
>> +          : x(0.0), y(0.0) {
>> +        }
>> +        NormalizedPolar(IO &, Polar &polar)
>> +          : x(polar.distance * cos(polar.angle)),
>> +            y(polar.distance * sin(polar.angle)) {
>> +        }
>> +        Polar denormalize(IO &) {
>> +          return Polar(sqrt(x*x+y*y, arctan(x,y));
>> +        }
>> +
>> +        float        x;
>> +        float        y;
>> +      };
>> +
>> +      static void mapping(IO &io, Polar &polar) {
>> +        MappingNormalization<NormalizedPolar, Polar> keys(io, polar);
>> +
>> +        io.mapRequired("x",    keys->x);
>> +        io.mapRequired("y",    keys->y);
>> +      }
>> +    };
>> +
>> +When writing YAML, the local variable "keys" will be a stack allocated
>> +instance of NormalizedPolar, constructed from the suppled polar object
>> which
>> +initializes it x and y fields.  The mapRequired() methods then write out
>> the x
>> +and y values as key/value pairs.
>> +
>> +When reading YAML, the local variable "keys" will be a stack allocated
>> instance
>> +of NormalizedPolar, constructed by the empty constructor.  The
>> mapRequired
>> +methods will find the matching key in the YAML document and fill in the
>> x and y
>> +fields of the NormalizedPolar object keys. At the end of the mapping()
>> method
>> +when the local keys variable goes out of scope, the denormalize() method
>> will
>> +automatically be called to convert the read values back to polar
>> coordinates,
>> +and then assigned back to the second parameter to mapping().
>> +
>> +In some cases, the normalized class may be a subclass of the native type
>> and
>> +could be returned by the denormalize() method, except that the temporary
>> +normalized instance is stack allocated.  In these cases, the utility
>> template
>> +MappingNormalizationHeap<> can be used instead.  It just like
>> +MappingNormalization<> except that it heap allocates the normalized
>> object
>> +when reading YAML.  It never destroyes the normalized object.  The
>> denormalize()
>> +method can this return "this".
>> +
>> +
>> +Default values
>> +--------------
>> +Within a mapping() method, calls to io.mapRequired() mean that that key
>> is
>> +required to exist when parsing YAML documents, otherwise YAML I/O will
>> issue an
>> +error.
>> +
>> +On the other hand, keys registered with io.mapOptional() are allowed to
>> not
>> +exist in the YAML document being read.  So what value is put in the field
>> +for those optional keys?
>> +There are two steps to how those optional fields are filled in. First,
>> the
>> +second parameter to the mapping() method is a reference to a native
>> class.  That
>> +native class must have a default constructor.  Whatever value the default
>> +constructor initially sets for an optional field will be that field's
>> value.
>> +Second, the mapOptional() method has an optional third parameter.  If
>> provided
>> +it is the value that mapOptional() should set that field to if the YAML
>> document
>> +does not have that key.
>> +
>> +There is one important difference between those two ways (default
>> constructor
>> +and third parameter to mapOptional). When YAML I/O generates a YAML
>> document,
>> +if the mapOptional() third parameter is used, if the actual value being
>> written
>> +is the same as (using ==) the default value, then that key/value is not
>> written.
>> +
>> +
>> +Order of Keys
>> +--------------
>> +
>> +When writing out a YAML document, the keys are written in the order that
>> the
>> +calls to mapRequired()/mapOptional() are made in the mapping() method.
>> This
>> +gives you a chance to write the fields in an order that a human reader of
>> +the YAML document would find natural.  This may be different that the
>> order
>> +of the fields in the native class.
>> +
>> +When reading in a YAML document, the keys in the document can be in any
>> order,
>> +but they are processed in the order that the calls to
>> mapRequired()/mapOptional()
>> +are made in the mapping() method.  That enables some interesting
>> +functionality.  For instance, if the first field bound is the cpu and
>> the second
>> +field bound is flags, and the flags are cpu specific, you can
>> programmatically
>> +switch how the flags are converted to and from YAML based on the cpu.
>> +This works for both reading and writing. For example:
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::MapppingTraits;
>> +    using llvm::yaml::IO;
>> +
>> +    struct Info {
>> +      CPUs        cpu;
>> +      uint32_t    flags;
>> +    };
>> +
>> +    template <>
>> +    struct MapppingTraits<Info> {
>> +      static void mapping(IO &io, Info &info) {
>> +        io.mapRequired("cpu",       info.cpu);
>> +        // flags must come after cpu for this to work when reading yaml
>> +        if ( info.cpu == cpu_x86_64 )
>> +          io.mapRequired("flags",  *(My86_64Flags*)info.flags);
>> +        else
>> +          io.mapRequired("flags",  *(My86Flags*)info.flags);
>> +     }
>> +    };
>> +
>> +
>> +Sequence
>> +========
>> +
>> +To be translated to or from a YAML sequence for your type T you must
>> specialize
>> +llvm::yaml::SequenceTraits on T and implement two methods:
>> +“size_t size(IO &io, T&)† and “T::value_type& element(IO &io, T&,
>> size_t indx)†.
>> +For example:
>> +
>> +.. code-block:: c++
>> +
>> +  template <>
>> +  struct SequenceTraits<MySeq> {
>> +    static size_t size(IO &io, MySeq &list) { ... }
>> +    static MySeqEl element(IO &io, MySeq &list, size_t index) { ... }
>> +  };
>> +
>> +The size() method returns how many elements are currently in your
>> sequence.
>> +The element() method returns a reference to the i'th element in the
>> sequence.
>> +When parsing YAML, the element() method may be called with an index one
>> bigger
>> +than the current size.  Your element() method should allocate space for
>> one
>> +more element (using default constructor if element is a C++ object) and
>> returns
>> +a reference to that new allocated space.
>> +
>> +
>> +Flow Sequence
>> +-------------
>> +A YAML "flow sequence" is a sequence that when written to YAML it uses
>> the
>> +inline notation (e.g [ foo, bar ] ).  To specify that a sequence type
>> should
>> +be written in YAML as a flow sequence, your SequenceTraits
>> specialization should
>> +add "static const bool flow = true;".  For instance:
>> +
>> +.. code-block:: c++
>> +
>> +  template <>
>> +  struct SequenceTraits<MyList> {
>> +    static size_t size(IO &io, MyList &list) { ... }
>> +    static MyListEl element(IO &io, MyList &list, size_t index) { ... }
>> +
>> +    // The existence of this member causes YAML I/O to use a flow
>> sequence
>> +    static const bool flow = true;
>> +  };
>> +
>> +With the above, if you used MyList as the data type in your native data
>> +strucutures, then then when converted to YAML, a flow sequence of
>> integers
>> +will be used (e.g. [ 10, -3, 4 ]).
>> +
>> +
>> +Utility Macros
>> +--------------
>> +Since a common source of sequences is std::vector<>, YAML I/O provids
>> macros:
>> +LLVM_YAML_IS_SEQUENCE_VECTOR() and LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR()
>> which
>> +can be used to easily specify SequenceTraits<> on a std::vector type.
>>  YAML
>> +I/O does not partial specialize SequenceTraits on std::vector<> because
>> that
>> +would force all vectors to be sequences.  An example use of the macros:
>> +
>> +.. code-block:: c++
>> +
>> +  std::vector<MyType1>;
>> +  std::vector<MyType2>;
>> +  LLVM_YAML_IS_SEQUENCE_VECTOR(MyType1)
>> +  LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyType2)
>> +
>> +
>> +
>> +Document List
>> +=============
>> +
>> +YAML allows you to define multiple "documents" in a single YAML file.
>>  Each
>> +new document starts with a left aligned "---" token.  The end of all
>> documents
>> +is denoted with a left aligned "..." token.  Many users of YAML will
>> never
>> +have need for multiple documents.  The top level node in their YAML
>> schema
>> +will be a mapping or sequence. For those cases, the following is not
>> needed.
>> +But for cases where you do want multiple documents, you can specify a
>> +trait for you document list type.  The trait has the same methods as
>> +SequenceTraits but is named DocumentListTraits.  For example:
>> +
>> +.. code-block:: c++
>> +
>> +  template <>
>> +  struct DocumentListTraits<MyDocList> {
>> +    static size_t size(IO &io, MyDocList &list) { ... }
>> +    static MyDocType element(IO &io, MyDocList &list, size_t index) {
>> ... }
>> +  };
>> +
>> +
>> +User Context Data
>> +=================
>> +When an llvm::yaml::Input or llvm::yaml::Output object is created their
>> +constructors take an optional "context" parameter.  This is a pointer to
>> +whatever state information you might need.
>> +
>> +For instance, in a previous example we showed how the conversion type
>> for a
>> +flags field could be determined at runtime based on the value of another
>> field
>> +in the mapping. But what if an inner mapping needs to know some field
>> value
>> +of an outer mapping?  That is where the "context" parameter comes in. You
>> +can set values in the context in the outer map's mapping() method and
>> +retrieve those values in the inner map's mapping() method.
>> +
>> +The context value is just a void*.  All your traits which use the context
>> +and operate on your native data types, need to agree what the context
>> value
>> +actually is.  It could be a pointer to an object or struct which your
>> various
>> +traits use to shared context sensitive information.
>> +
>> +
>> +Output
>> +======
>> +
>> +The llvm::yaml::Output class is used to generate a YAML document from
>> your
>> +in-memory data structures, using traits defined on your data types.
>> +To instantiate an Output object you need an llvm::raw_ostream, and
>> optionally
>> +a context pointer:
>> +
>> +.. code-block:: c++
>> +
>> +      class Output : public IO {
>> +      public:
>> +        Output(llvm::raw_ostream &, void *context=NULL);
>> +
>> +Once you have an Output object, you can use the C++ stream operator on it
>> +to write your native data as YAML. One thing to recall is that a YAML
>> file
>> +can contain multiple "documents".  If the top level data structure you
>> are
>> +streaming as YAML is a mapping, scalar, or sequence, then Output assumes
>> you
>> +are generating one document and wraps the mapping output
>> +with  "``---``" and trailing "``...``".
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::Output;
>> +
>> +    void dumpMyMapDoc(const MyMapType &info) {
>> +      Output yout(llvm::outs());
>> +      yout << info;
>> +    }
>> +
>> +The above could produce output like:
>> +
>> +.. code-block:: yaml
>> +
>> +     ---
>> +     name:      Tom
>> +     hat-size:  7
>> +     ...
>> +
>> +On the other hand, if the top level data structure you are streaming as
>> YAML
>> +has a DocumentListTraits specialization, then Output walks through each
>> element
>> +of your DocumentList and generates a "---" before the start of each
>> element
>> +and ends with a "...".
>> +
>> +.. code-block:: c++
>> +
>> +    using llvm::yaml::Output;
>> +
>> +    void dumpMyMapDoc(const MyDocListType &docList) {
>> +      Output yout(llvm::outs());
>> +      yout << docList;
>> +    }
>> +
>> +The above could produce output like:
>> +
>> +.. code-block:: yaml
>> +
>> +     ---
>> +     name:      Tom
>> +     hat-size:  7
>> +     ---
>> +     name:      Tom
>> +     shoe-size:  11
>> +     ...
>> +
>> +Input
>> +=====
>> +
>> +The llvm::yaml::Input class is used to parse YAML document(s) into your
>> native
>> +data structures. To instantiate an Input
>> +object you need a StringRef to the entire YAML file, and optionally a
>> context
>> +pointer:
>> +
>> +.. code-block:: c++
>> +
>> +      class Input : public IO {
>> +      public:
>> +        Input(StringRef inputContent, void *context=NULL);
>> +
>> +Once you have an Input object, you can use the C++ stream operator to
>> read
>> +the document(s).  If you expect there might be multiple YAML documents in
>> +one file, you'll need to specialize DocumentListTraits on a list of your
>> +document type and stream in that document list type.  Otherwise you can
>> +just stream in the document type.  Also, you can check if there was
>> +any syntax errors in the YAML be calling the error() method on the Input
>> +object.  For example:
>> +
>> +.. code-block:: c++
>> +
>> +     // Reading a single document
>> +     using llvm::yaml::Input;
>> +
>> +     Input yin(mb.getBuffer());
>> +
>> +     // Parse the YAML file
>> +     MyDocType theDoc;
>> +     yin >> theDoc;
>> +
>> +     // Check for error
>> +     if ( yin.error() )
>> +       return;
>> +
>> +
>> +.. code-block:: c++
>> +
>> +     // Reading multiple documents in one file
>> +     using llvm::yaml::Input;
>> +
>> +     LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(std::vector<MyDocType>)
>> +
>> +     Input yin(mb.getBuffer());
>> +
>> +     // Parse the YAML file
>> +     std::vector<MyDocType> theDocList;
>> +     yin >> theDocList;
>> +
>> +     // Check for error
>> +     if ( yin.error() )
>> +       return;
>> +
>> +
>>
>> Modified: llvm/trunk/docs/userguides.rst
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/userguides.rst?rev=170019&r1=170018&r2=170019&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/docs/userguides.rst (original)
>> +++ llvm/trunk/docs/userguides.rst Wed Dec 12 14:46:15 2012
>> @@ -24,6 +24,7 @@
>>     tutorial/index
>>     ReleaseNotes
>>     Passes
>> +   YamlIO
>>
>>  * :ref:`getting_started`
>>
>> @@ -100,6 +101,10 @@
>>
>>     Instructions for adding new builder to LLVM buildbot master.
>>
>> +* :ref:`yamlio`
>> +
>> +   A reference guide for using LLVM's YAML I/O library.
>> +
>>  * **IRC** -- You can probably find help on the unofficial LLVM IRC.
>>
>>     We often are on irc.oftc.net in the #llvm channel.  If you are using
>> the
>>
>> Added: llvm/trunk/include/llvm/Support/YAMLTraits.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/YAMLTraits.h?rev=170019&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Support/YAMLTraits.h (added)
>> +++ llvm/trunk/include/llvm/Support/YAMLTraits.h Wed Dec 12 14:46:15 2012
>> @@ -0,0 +1,1114 @@
>> +//===- llvm/Supporrt/YAMLTraits.h -------------------------------*- C++
>> -*-===//
>> +//
>> +//                             The LLVM Linker
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_YAML_TRAITS_H_
>> +#define LLVM_YAML_TRAITS_H_
>> +
>> +
>> +#include "llvm/ADT/DenseMap.h"
>> +#include "llvm/ADT/DenseMapInfo.h"
>> +#include "llvm/ADT/SmallVector.h"
>> +#include "llvm/ADT/StringExtras.h"
>> +#include "llvm/ADT/StringRef.h"
>> +#include "llvm/ADT/StringSwitch.h"
>> +#include "llvm/ADT/Twine.h"
>> +#include "llvm/Support/Compiler.h"
>> +#include "llvm/Support/SourceMgr.h"
>> +#include "llvm/Support/system_error.h"
>> +#include "llvm/Support/type_traits.h"
>> +#include "llvm/Support/YAMLParser.h"
>> +#include "llvm/Support/raw_ostream.h"
>> +
>> +
>> +namespace llvm {
>> +namespace yaml {
>> +
>> +
>> +/// This class should be specialized by any type that needs to be
>> converted
>> +/// to/from a YAML mapping.  For example:
>> +///
>> +///     struct ScalarBitSetTraits<MyStruct> {
>> +///       static void mapping(IO &io, MyStruct &s) {
>> +///         io.mapRequired("name", s.name);
>> +///         io.mapRequired("size", s.size);
>> +///         io.mapOptional("age",  s.age);
>> +///       }
>> +///     };
>> +template<class T>
>> +struct MappingTraits {
>> +  // Must provide:
>> +  // static void mapping(IO &io, T &fields);
>> +};
>> +
>> +
>> +/// This class should be specialized by any integral type that converts
>> +/// to/from a YAML scalar where there is a one-to-one mapping between
>> +/// in-memory values and a string in YAML.  For example:
>> +///
>> +///     struct ScalarEnumerationTraits<Colors> {
>> +///         static void enumeration(IO &io, Colors &value) {
>> +///           io.enumCase(value, "red",   cRed);
>> +///           io.enumCase(value, "blue",  cBlue);
>> +///           io.enumCase(value, "green", cGreen);
>> +///         }
>> +///       };
>> +template<typename T>
>> +struct ScalarEnumerationTraits {
>> +  // Must provide:
>> +  // static void enumeration(IO &io, T &value);
>> +};
>> +
>> +
>> +/// This class should be specialized by any integer type that is a union
>> +/// of bit values and the YAML representation is a flow sequence of
>> +/// strings.  For example:
>> +///
>> +///      struct ScalarBitSetTraits<MyFlags> {
>> +///        static void bitset(IO &io, MyFlags &value) {
>> +///          io.bitSetCase(value, "big",   flagBig);
>> +///          io.bitSetCase(value, "flat",  flagFlat);
>> +///          io.bitSetCase(value, "round", flagRound);
>> +///        }
>> +///      };
>> +template<typename T>
>> +struct ScalarBitSetTraits {
>> +  // Must provide:
>> +  // static void bitset(IO &io, T &value);
>> +};
>> +
>> +
>> +/// This class should be specialized by type that requires custom
>> conversion
>> +/// to/from a yaml scalar.  For example:
>> +///
>> +///    template<>
>> +///    struct ScalarTraits<MyType> {
>> +///      static void output(const MyType &val, void*, llvm::raw_ostream
>> &out) {
>> +///        // stream out custom formatting
>> +///        out << llvm::format("%x", val);
>> +///      }
>> +///      static StringRef input(StringRef scalar, void*, MyType &value) {
>> +///        // parse scalar and set `value`
>> +///        // return empty string on success, or error string
>> +///        return StringRef();
>> +///      }
>> +///    };
>> +template<typename T>
>> +struct ScalarTraits {
>> +  // Must provide:
>> +  //
>> +  // Function to write the value as a string:
>> +  //static void output(const T &value, void *ctxt, llvm::raw_ostream
>> &out);
>> +  //
>> +  // Function to convert a string to a value.  Returns the empty
>> +  // StringRef on success or an error string if string is malformed:
>> +  //static StringRef input(StringRef scalar, void *ctxt, T &value);
>> +};
>> +
>> +
>> +/// This class should be specialized by any type that needs to be
>> converted
>> +/// to/from a YAML sequence.  For example:
>> +///
>> +///    template<>
>> +///    struct SequenceTraits< std::vector<MyType> > {
>> +///      static size_t size(IO &io, std::vector<MyType> &seq) {
>> +///        return seq.size();
>> +///      }
>> +///      static MyType& element(IO &, std::vector<MyType> &seq, size_t
>> index) {
>> +///        if ( index >= seq.size() )
>> +///          seq.resize(index+1);
>> +///        return seq[index];
>> +///      }
>> +///    };
>> +template<typename T>
>> +struct SequenceTraits {
>> +  // Must provide:
>> +  // static size_t size(IO &io, T &seq);
>> +  // static T::value_type& element(IO &io, T &seq, size_t index);
>> +  //
>> +  // The following is option and will cause generated YAML to use
>> +  // a flow sequence (e.g. [a,b,c]).
>> +  // static const bool flow = true;
>> +};
>> +
>> +
>> +/// This class should be specialized by any type that needs to be
>> converted
>> +/// to/from a list of YAML documents.
>> +template<typename T>
>> +struct DocumentListTraits {
>> +  // Must provide:
>> +  // static size_t size(IO &io, T &seq);
>> +  // static T::value_type& element(IO &io, T &seq, size_t index);
>> +};
>> +
>> +
>> +// Only used by compiler if both template types are the same
>> +template <typename T, T>
>> +struct SameType;
>> +
>> +// Only used for better diagnostics of missing traits
>> +template <typename T>
>> +struct MissingTrait;
>> +
>> +
>> +
>> +// Test if ScalarEnumerationTraits<T> is defined on type T.
>> +template <class T>
>> +struct has_ScalarEnumerationTraits
>> +{
>> +  typedef void (*Signature_enumeration)(class IO&, T&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_enumeration, &U::enumeration>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +public:
>> +  static bool const value = (sizeof(test<ScalarEnumerationTraits<T>
>> >(0)) == 1);
>> +};
>> +
>> +
>> +// Test if ScalarBitSetTraits<T> is defined on type T.
>> +template <class T>
>> +struct has_ScalarBitSetTraits
>> +{
>> +  typedef void (*Signature_bitset)(class IO&, T&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_bitset, &U::bitset>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +public:
>> +  static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(0)) ==
>> 1);
>> +};
>> +
>> +
>> +// Test if ScalarTraits<T> is defined on type T.
>> +template <class T>
>> +struct has_ScalarTraits
>> +{
>> +  typedef llvm::StringRef (*Signature_input)(llvm::StringRef, void*, T&);
>> +  typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_input, &U::input>*,
>> +                   SameType<Signature_output, &U::output>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +public:
>> +  static bool const value = (sizeof(test<ScalarTraits<T> >(0,0)) == 1);
>> +};
>> +
>> +
>> +// Test if MappingTraits<T> is defined on type T.
>> +template <class T>
>> +struct has_MappingTraits
>> +{
>> +  typedef void (*Signature_mapping)(class IO&, T&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_mapping, &U::mapping>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +public:
>> +  static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
>> +};
>> +
>> +
>> +// Test if SequenceTraits<T> is defined on type T
>> +// and SequenceTraits<T>::flow is *not* defined.
>> +template <class T>
>> +struct has_SequenceTraits
>> +{
>> +  typedef size_t (*Signature_size)(class IO&, T&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_size, &U::size>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +  template <typename U> static
>> +  char flowtest( char[sizeof(&U::flow)] ) ;
>> +
>> +  template <typename U>
>> +  static double flowtest(...);
>> +
>> +public:
>> +  static bool const value =  (sizeof(test<SequenceTraits<T> >(0)) == 1)
>> +                          && (sizeof(flowtest<T>(0)) != 1);
>> +};
>> +
>> +
>> +// Test if SequenceTraits<T> is defined on type T
>> +// and SequenceTraits<T>::flow is defined.
>> +template <class T>
>> +struct has_FlowSequenceTraits
>> +{
>> +  typedef size_t (*Signature_size)(class IO&, T&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_size, &U::size>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +  template <typename U> static
>> +  char flowtest( char[sizeof(&U::flow)] ) ;
>> +
>> +  template <typename U>
>> +  static double flowtest(...);
>> +
>> +public:
>> +  static bool const value =  (sizeof(test<SequenceTraits<T> >(0)) == 1)
>> +                          && (sizeof(flowtest<T>(0)) == 1);
>> +};
>> +
>> +
>> +// Test if DocumentListTraits<T> is defined on type T
>> +template <class T>
>> +struct has_DocumentListTraits
>> +{
>> +  typedef size_t (*Signature_size)(class IO&, T&);
>> +
>> +  template <typename U>
>> +  static char test(SameType<Signature_size, &U::size>*);
>> +
>> +  template <typename U>
>> +  static double test(...);
>> +
>> +public:
>> +  static bool const value =  (sizeof(test<DocumentListTraits<T> >(0)) ==
>> 1);
>> +};
>> +
>> +
>> +
>> +
>> +template<typename T>
>> +struct missingTraits : public  llvm::integral_constant<bool,
>> +
>> !has_ScalarEnumerationTraits<T>::value
>> +                                      &&
>> !has_ScalarBitSetTraits<T>::value
>> +                                      && !has_ScalarTraits<T>::value
>> +                                      && !has_MappingTraits<T>::value
>> +                                      && !has_SequenceTraits<T>::value
>> +                                      &&
>> !has_FlowSequenceTraits<T>::value
>> +                                      &&
>> !has_DocumentListTraits<T>::value >  {};
>> +
>> +
>> +// Base class for Input and Output.
>> +class IO {
>> +public:
>> +
>> +  IO(void *Ctxt=NULL);
>> +  virtual ~IO();
>> +
>> +  virtual bool outputting() = 0;
>> +
>> +  virtual unsigned beginSequence() = 0;
>> +  virtual bool preflightElement(unsigned, void *&) = 0;
>> +  virtual void postflightElement(void*) = 0;
>> +  virtual void endSequence() = 0;
>> +
>> +  virtual unsigned beginFlowSequence() = 0;
>> +  virtual bool preflightFlowElement(unsigned, void *&) = 0;
>> +  virtual void postflightFlowElement(void*) = 0;
>> +  virtual void endFlowSequence() = 0;
>> +
>> +  virtual void beginMapping() = 0;
>> +  virtual void endMapping() = 0;
>> +  virtual bool preflightKey(const char*, bool, bool, bool &, void *&) =
>> 0;
>> +  virtual void postflightKey(void*) = 0;
>> +
>> +  virtual void beginEnumScalar() = 0;
>> +  virtual bool matchEnumScalar(const char*, bool) = 0;
>> +  virtual void endEnumScalar() = 0;
>> +
>> +  virtual bool beginBitSetScalar(bool &) = 0;
>> +  virtual bool bitSetMatch(const char*, bool) = 0;
>> +  virtual void endBitSetScalar() = 0;
>> +
>> +  virtual void scalarString(StringRef &) = 0;
>> +
>> +  virtual void setError(const Twine &) = 0;
>> +
>> +  template <typename T>
>> +  void enumCase(T &Val, const char* Str, const T ConstVal) {
>> +    if ( matchEnumScalar(Str, (Val == ConstVal)) ) {
>> +      Val = ConstVal;
>> +    }
>> +  }
>> +
>> +  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
>> +  template <typename T>
>> +  void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
>> +    if ( matchEnumScalar(Str, (Val == static_cast<T>(ConstVal))) ) {
>> +      Val = ConstVal;
>> +    }
>> +  }
>> +
>> +  template <typename T>
>> +  void bitSetCase(T &Val, const char* Str, const T ConstVal) {
>> +    if ( bitSetMatch(Str, ((Val & ConstVal) == ConstVal)) ) {
>> +      Val = Val | ConstVal;
>> +    }
>> +  }
>> +
>> +  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
>> +  template <typename T>
>> +  void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
>> +    if ( bitSetMatch(Str, ((Val & ConstVal) == ConstVal)) ) {
>> +      Val = Val | ConstVal;
>> +    }
>> +  }
>> +
>> +  void *getContext();
>> +  void setContext(void *);
>> +
>> +  template <typename T>
>> +  void mapRequired(const char* Key, T& Val) {
>> +    this->processKey(Key, Val, true);
>> +  }
>> +
>> +  template <typename T>
>> +  typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type
>> +  mapOptional(const char* Key, T& Val) {
>> +    // omit key/value instead of outputting empty sequence
>> +    if ( this->outputting() && !(Val.begin() != Val.end()) )
>> +      return;
>> +    this->processKey(Key, Val, false);
>> +  }
>> +
>> +  template <typename T>
>> +  typename llvm::enable_if_c<!has_SequenceTraits<T>::value,void>::type
>> +  mapOptional(const char* Key, T& Val) {
>> +    this->processKey(Key, Val, false);
>> +  }
>> +
>> +  template <typename T>
>> +  void mapOptional(const char* Key, T& Val, const T& Default) {
>> +    this->processKeyWithDefault(Key, Val, Default, false);
>> +  }
>> +
>> +
>> +private:
>> +  template <typename T>
>> +  void processKeyWithDefault(const char *Key, T &Val, const T&
>> DefaultValue,
>> +                                                                bool
>> Required) {
>> +    void *SaveInfo;
>> +    bool UseDefault;
>> +    const bool sameAsDefault = (Val == DefaultValue);
>> +    if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
>> +
>>  SaveInfo) ) {
>> +      yamlize(*this, Val, Required);
>> +      this->postflightKey(SaveInfo);
>> +    }
>> +    else {
>> +      if ( UseDefault )
>> +        Val = DefaultValue;
>> +    }
>> +  }
>> +
>> +  template <typename T>
>> +  void processKey(const char *Key, T &Val, bool Required) {
>> +    void *SaveInfo;
>> +    bool UseDefault;
>> +    if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo)
>> ) {
>> +      yamlize(*this, Val, Required);
>> +      this->postflightKey(SaveInfo);
>> +    }
>> +  }
>> +
>> +private:
>> +  void  *Ctxt;
>> +};
>> +
>> +
>> +
>> +template<typename T>
>> +typename
>> llvm::enable_if_c<has_ScalarEnumerationTraits<T>::value,void>::type
>> +yamlize(IO &io, T &Val, bool) {
>> +  io.beginEnumScalar();
>> +  ScalarEnumerationTraits<T>::enumeration(io, Val);
>> +  io.endEnumScalar();
>> +}
>> +
>> +template<typename T>
>> +typename llvm::enable_if_c<has_ScalarBitSetTraits<T>::value,void>::type
>> +yamlize(IO &io, T &Val, bool) {
>> +  bool DoClear;
>> +  if ( io.beginBitSetScalar(DoClear) ) {
>> +    if ( DoClear )
>> +      Val = static_cast<T>(0);
>> +    ScalarBitSetTraits<T>::bitset(io, Val);
>> +    io.endBitSetScalar();
>> +  }
>> +}
>> +
>> +
>> +template<typename T>
>> +typename llvm::enable_if_c<has_ScalarTraits<T>::value,void>::type
>> +yamlize(IO &io, T &Val, bool) {
>> +  if ( io.outputting() ) {
>> +    std::string Storage;
>> +    llvm::raw_string_ostream Buffer(Storage);
>> +    ScalarTraits<T>::output(Val, io.getContext(), Buffer);
>> +    StringRef Str = Buffer.str();
>> +    io.scalarString(Str);
>> +  }
>> +  else {
>> +    StringRef Str;
>> +    io.scalarString(Str);
>> +    StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
>> +    if ( !Result.empty() ) {
>> +      io.setError(llvm::Twine(Result));
>> +    }
>> +  }
>> +}
>> +
>> +
>> +template<typename T>
>> +typename llvm::enable_if_c<has_MappingTraits<T>::value, void>::type
>> +yamlize(IO &io, T &Val, bool) {
>> +  io.beginMapping();
>> +  MappingTraits<T>::mapping(io, Val);
>> +  io.endMapping();
>> +}
>> +
>> +#ifndef BUILDING_YAMLIO
>> +template<typename T>
>> +typename llvm::enable_if_c<missingTraits<T>::value, void>::type
>> +yamlize(IO &io, T &Val, bool) {
>> +  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
>> +}
>> +#endif
>> +
>> +template<typename T>
>> +typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type
>> +yamlize(IO &io, T &Seq, bool) {
>> +  unsigned incount = io.beginSequence();
>> +  unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) :
>> incount;
>> +  for(unsigned i=0; i < count; ++i) {
>> +    void *SaveInfo;
>> +    if ( io.preflightElement(i, SaveInfo) ) {
>> +      yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
>> +      io.postflightElement(SaveInfo);
>> +    }
>> +  }
>> +  io.endSequence();
>> +}
>> +
>> +template<typename T>
>> +typename llvm::enable_if_c<has_FlowSequenceTraits<T>::value,void>::type
>> +yamlize(IO &io, T &Seq, bool) {
>> +  unsigned incount = io.beginFlowSequence();
>> +  unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) :
>> incount;
>> +  for(unsigned i=0; i < count; ++i) {
>> +    void *SaveInfo;
>> +    if ( io.preflightFlowElement(i, SaveInfo) ) {
>> +      yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
>> +      io.postflightFlowElement(SaveInfo);
>> +    }
>> +  }
>> +  io.endFlowSequence();
>> +}
>> +
>> +
>> +
>> +// Clients of YAML I/O only see declaration of the traits for built-in
>> +// types.  The implementation is in the LLVM Support library.  Without
>> +// this #ifdef, every client would get a copy of the implementation of
>> +// these traits.
>> +#ifndef BUILDING_YAMLIO
>> +template<>
>> +struct ScalarTraits<bool> {
>> +  static void output(const bool &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, bool &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<StringRef> {
>> +  static void output(const StringRef &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, StringRef &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<uint8_t> {
>> +  static void output(const uint8_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, uint8_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<uint16_t> {
>> +  static void output(const uint16_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, uint16_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<uint32_t> {
>> +  static void output(const uint32_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, uint32_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<uint64_t> {
>> +  static void output(const uint64_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, uint64_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<int8_t> {
>> +  static void output(const int8_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, int8_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<int16_t> {
>> +  static void output(const int16_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, int16_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<int32_t> {
>> +  static void output(const int32_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, int32_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<int64_t> {
>> +  static void output(const int64_t &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, int64_t &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<float> {
>> +  static void output(const float &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, float &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<double> {
>> +  static void output(const double &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, double &);
>> +};
>> +#endif
>> +
>> +
>> +
>> +// Utility for use within MappingTraits<>::mapping() method
>> +// to [de]normalize an object for use with YAML conversion.
>> +template <typename TNorm, typename TFinal>
>> +struct MappingNormalization {
>> +  MappingNormalization(IO &i_o, TFinal &Obj)
>> +      : io(i_o), BufPtr(NULL), Result(Obj) {
>> +    if ( io.outputting() ) {
>> +      BufPtr = new (&Buffer) TNorm(io, Obj);
>> +    }
>> +    else {
>> +      BufPtr = new (&Buffer) TNorm(io);
>> +    }
>> +  }
>> +
>> +  ~MappingNormalization() {
>> +    if ( ! io.outputting() ) {
>> +      Result = BufPtr->denormalize(io);
>> +    }
>> +    BufPtr->~TNorm();
>> +  }
>> +
>> +  TNorm* operator->() { return BufPtr; }
>> +
>> +private:
>> +  typedef typename llvm::AlignedCharArrayUnion<TNorm> Storage;
>> +
>> +  Storage       Buffer;
>> +  IO           &io;
>> +  TNorm        *BufPtr;
>> +  TFinal       &Result;
>> +};
>> +
>> +
>> +
>> +// Utility for use within MappingTraits<>::mapping() method
>> +// to [de]normalize an object for use with YAML conversion.
>> +template <typename TNorm, typename TFinal>
>> +struct MappingNormalizationHeap {
>> +  MappingNormalizationHeap(IO &i_o, TFinal &Obj)
>> +    : io(i_o), BufPtr(NULL), Result(Obj) {
>> +    if ( io.outputting() ) {
>> +      BufPtr = new (&Buffer) TNorm(io, Obj);
>> +    }
>> +    else {
>> +      BufPtr = new TNorm(io);
>> +    }
>> +  }
>> +
>> +  ~MappingNormalizationHeap() {
>> +    if ( io.outputting() ) {
>> +      BufPtr->~TNorm();
>> +    }
>> +    else {
>> +      Result = BufPtr->denormalize(io);
>> +    }
>> +  }
>> +
>> +  TNorm* operator->() { return BufPtr; }
>> +
>> +private:
>> +  typedef typename llvm::AlignedCharArrayUnion<TNorm> Storage;
>> +
>> +  Storage       Buffer;
>> +  IO           &io;
>> +  TNorm        *BufPtr;
>> +  TFinal       &Result;
>> +};
>> +
>> +
>> +
>> +///
>> +/// The Input class is used to parse a yaml document into in-memory
>> structs
>> +/// and vectors.
>> +///
>> +/// It works by using YAMLParser to do a syntax parse of the entire yaml
>> +/// document, then the Input class builds a graph of HNodes which wraps
>> +/// each yaml Node.  The extra layer is buffering.  The low level yaml
>> +/// parser only lets you look at each node once.  The buffering layer
>> lets
>> +/// you search and interate multiple times.  This is necessary because
>> +/// the mapRequired() method calls may not be in the same order
>> +/// as the keys in the document.
>> +///
>> +class Input : public IO {
>> +public:
>> +  // Construct a yaml Input object from a StringRef and optional
>> user-data.
>> +  Input(StringRef InputContent, void *Ctxt=NULL);
>> +
>> +  // Check if there was an syntax or semantic error during parsing.
>> +  llvm::error_code error();
>> +
>> +  // To set alternate error reporting.
>> +  void setDiagHandler(llvm::SourceMgr::DiagHandlerTy Handler, void *Ctxt
>> = 0);
>> +
>> +private:
>> +  virtual bool outputting();
>> +  virtual void beginMapping();
>> +  virtual void endMapping();
>> +  virtual bool preflightKey(const char *, bool, bool, bool &, void *&);
>> +  virtual void postflightKey(void *);
>> +  virtual unsigned beginSequence();
>> +  virtual void endSequence();
>> +  virtual bool preflightElement(unsigned index, void *&);
>> +  virtual void postflightElement(void *);
>> +  virtual unsigned beginFlowSequence();
>> +  virtual bool preflightFlowElement(unsigned , void *&);
>> +  virtual void postflightFlowElement(void *);
>> +  virtual void endFlowSequence();
>> +  virtual void beginEnumScalar();
>> +  virtual bool matchEnumScalar(const char*, bool);
>> +  virtual void endEnumScalar();
>> +  virtual bool beginBitSetScalar(bool &);
>> +  virtual bool bitSetMatch(const char *, bool );
>> +  virtual void endBitSetScalar();
>> +  virtual void scalarString(StringRef &);
>> +  virtual void setError(const Twine &message);
>> +
>> +  class HNode {
>> +  public:
>> +    HNode(Node *n) : _node(n) { }
>> +    static inline bool classof(const HNode *) { return true; }
>> +
>> +    Node *_node;
>> +  };
>> +
>> +  class EmptyHNode : public HNode {
>> +  public:
>> +    EmptyHNode(Node *n) : HNode(n) { }
>> +    static inline bool classof(const HNode *n) {
>> +      return NullNode::classof(n->_node);
>> +    }
>> +    static inline bool classof(const EmptyHNode *) { return true; }
>> +  };
>> +
>> +  class ScalarHNode : public HNode {
>> +  public:
>> +    ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
>> +
>> +    StringRef value() const { return _value; }
>> +
>> +    static inline bool classof(const HNode *n) {
>> +      return ScalarNode::classof(n->_node);
>> +    }
>> +    static inline bool classof(const ScalarHNode *) { return true; }
>> +  protected:
>> +    StringRef _value;
>> +  };
>> +
>> +  class MapHNode : public HNode {
>> +  public:
>> +    MapHNode(Node *n) : HNode(n) { }
>> +
>> +    static inline bool classof(const HNode *n) {
>> +      return MappingNode::classof(n->_node);
>> +    }
>> +    static inline bool classof(const MapHNode *) { return true; }
>> +
>> +    struct StrMappingInfo {
>> +      static StringRef getEmptyKey() { return StringRef(); }
>> +      static StringRef getTombstoneKey() { return StringRef(" ", 0); }
>> +      static unsigned getHashValue(StringRef const val) {
>> +                                                return
>> llvm::HashString(val); }
>> +      static bool isEqual(StringRef const lhs,
>> +                          StringRef const rhs) { return lhs.equals(rhs);
>> }
>> +    };
>> +    typedef llvm::DenseMap<StringRef, HNode*, StrMappingInfo> NameToNode;
>> +
>> +    bool isValidKey(StringRef key);
>> +
>> +    NameToNode                        Mapping;
>> +    llvm::SmallVector<const char*, 6> ValidKeys;
>> +  };
>> +
>> +  class SequenceHNode : public HNode {
>> +  public:
>> +    SequenceHNode(Node *n) : HNode(n) { }
>> +
>> +    static inline bool classof(const HNode *n) {
>> +      return SequenceNode::classof(n->_node);
>> +    }
>> +    static inline bool classof(const SequenceHNode *) { return true; }
>> +
>> +    std::vector<HNode*> Entries;
>> +  };
>> +
>> +  Input::HNode *createHNodes(Node *node);
>> +  void setError(HNode *hnode, const Twine &message);
>> +  void setError(Node *node, const Twine &message);
>> +
>> +
>> +public:
>> +  // These are only used by operator>>. They could be private
>> +  // if those templated things could be made friends.
>> +  bool setCurrentDocument();
>> +  void nextDocument();
>> +
>> +private:
>> +  llvm::yaml::Stream              *Strm;
>> +  llvm::SourceMgr                  SrcMgr;
>> +  llvm::error_code                 EC;
>> +  llvm::BumpPtrAllocator           Allocator;
>> +  llvm::yaml::document_iterator    DocIterator;
>> +  std::vector<bool>                BitValuesUsed;
>> +  HNode                           *CurrentNode;
>> +  bool                             ScalarMatchFound;
>> +};
>> +
>> +
>> +
>> +
>> +///
>> +/// The Output class is used to generate a yaml document from in-memory
>> structs
>> +/// and vectors.
>> +///
>> +class Output : public IO {
>> +public:
>> +  Output(llvm::raw_ostream &, void *Ctxt=NULL);
>> +  virtual ~Output();
>> +
>> +  virtual bool outputting();
>> +  virtual void beginMapping();
>> +  virtual void endMapping();
>> +  virtual bool preflightKey(const char *key, bool, bool, bool &, void
>> *&);
>> +  virtual void postflightKey(void *);
>> +  virtual unsigned beginSequence();
>> +  virtual void endSequence();
>> +  virtual bool preflightElement(unsigned, void *&);
>> +  virtual void postflightElement(void *);
>> +  virtual unsigned beginFlowSequence();
>> +  virtual bool preflightFlowElement(unsigned, void *&);
>> +  virtual void postflightFlowElement(void *);
>> +  virtual void endFlowSequence();
>> +  virtual void beginEnumScalar();
>> +  virtual bool matchEnumScalar(const char*, bool);
>> +  virtual void endEnumScalar();
>> +  virtual bool beginBitSetScalar(bool &);
>> +  virtual bool bitSetMatch(const char *, bool );
>> +  virtual void endBitSetScalar();
>> +  virtual void scalarString(StringRef &);
>> +  virtual void setError(const Twine &message);
>> +
>> +public:
>> +  // These are only used by operator<<. They could be private
>> +  // if that templated operator could be made a friend.
>> +  void beginDocuments();
>> +  bool preflightDocument(unsigned);
>> +  void postflightDocument();
>> +  void endDocuments();
>> +
>> +private:
>> +  void output(StringRef s);
>> +  void outputUpToEndOfLine(StringRef s);
>> +  void newLineCheck();
>> +  void outputNewLine();
>> +  void paddedKey(StringRef key);
>> +
>> +  enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey };
>> +
>> +  llvm::raw_ostream       &Out;
>> +  SmallVector<InState, 8>  StateStack;
>> +  int                      Column;
>> +  int                      ColumnAtFlowStart;
>> +  bool                     NeedBitValueComma;
>> +  bool                     NeedFlowSequenceComma;
>> +  bool                     EnumerationMatchFound;
>> +  bool                     NeedsNewLine;
>> +};
>> +
>> +
>> +
>> +
>> +/// YAML I/O does conversion based on types. But often native data types
>> +/// are just a typedef of built in intergral types (e.g. int).  But the
>> C++
>> +/// type matching system sees through the typedef and all the typedefed
>> types
>> +/// look like a built in type. This will cause the generic YAML I/O
>> conversion
>> +/// to be used. To provide better control over the YAML conversion, you
>> can
>> +/// use this macro instead of typedef.  It will create a class with one
>> field
>> +/// and automatic conversion operators to and from the base type.
>> +/// Based on BOOST_STRONG_TYPEDEF
>> +#define LLVM_YAML_STRONG_TYPEDEF(_base, _type)
>>       \
>> +    struct _type {
>>       \
>> +        _type() { }
>>        \
>> +        _type(const _base v) : value(v) { }
>>        \
>> +        _type(const _type &v) : value(v.value) {}
>>        \
>> +        _type &operator=(const _type &rhs) { value = rhs.value; return
>> *this; }\
>> +        _type &operator=(const _base &rhs) { value = rhs; return *this;
>> }      \
>> +        operator const _base & () const { return value; }
>>        \
>> +        bool operator==(const _type &rhs) const { return value ==
>> rhs.value; } \
>> +        bool operator==(const _base &rhs) const { return value == rhs; }
>>       \
>> +        bool operator<(const _type &rhs) const { return value <
>> rhs.value; }   \
>> +        _base value;
>>       \
>> +    };
>> +
>> +
>> +
>> +///
>> +/// Use these types instead of uintXX_t in any mapping to have
>> +/// its yaml output formatted as hexadecimal.
>> +///
>> +LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
>> +LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
>> +LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
>> +LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
>> +
>> +
>> +// Clients of YAML I/O only see declaration of the traits for Hex*
>> +// types.  The implementation is in the LLVM Support library.  Without
>> +// this #ifdef, every client would get a copy of the implementation of
>> +// these traits.
>> +#ifndef BUILDING_YAMLIO
>> +template<>
>> +struct ScalarTraits<Hex8> {
>> +  static void output(const Hex8 &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, Hex8 &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<Hex16> {
>> +  static void output(const Hex16 &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, Hex16 &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<Hex32> {
>> +  static void output(const Hex32 &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, Hex32 &);
>> +};
>> +
>> +template<>
>> +struct ScalarTraits<Hex64> {
>> +  static void output(const Hex64 &, void*, llvm::raw_ostream &);
>> +  static llvm::StringRef input(llvm::StringRef , void*, Hex64 &);
>> +};
>> +#endif
>> +
>> +
>> +// Define non-member operator>> so that Input can stream in a document
>> list.
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Input
>> &>::type
>> +operator>>(Input &yin, T &docList) {
>> +  int i = 0;
>> +  while ( yin.setCurrentDocument() ) {
>> +    yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true);
>> +    if ( yin.error() )
>> +      return yin;
>> +    yin.nextDocument();
>> +    ++i;
>> +  }
>> +  return yin;
>> +}
>> +
>> +// Define non-member operator>> so that Input can stream in a map as a
>> document.
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<has_MappingTraits<T>::value,Input &>::type
>> +operator>>(Input &yin, T &docMap) {
>> +  yin.setCurrentDocument();
>> +  yamlize(yin, docMap, true);
>> +  return yin;
>> +}
>> +
>> +// Define non-member operator>> so that Input can stream in a sequence as
>> +// a document.
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<has_SequenceTraits<T>::value,Input &>::type
>> +operator>>(Input &yin, T &docSeq) {
>> +  yin.setCurrentDocument();
>> +  yamlize(yin, docSeq, true);
>> +  return yin;
>> +}
>> +
>> +#ifndef BUILDING_YAMLIO
>> +// Provide better error message about types missing a trait
>> specialization
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<missingTraits<T>::value,Input &>::type
>> +operator>>(Input &yin, T &docSeq) {
>> +  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
>> +  return yin;
>> +}
>> +#endif
>> +
>> +
>> +// Define non-member operator<< so that Output can stream out document
>> list.
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Output
>> &>::type
>> +operator<<(Output &yout, T &docList) {
>> +  yout.beginDocuments();
>> +  const size_t count = DocumentListTraits<T>::size(yout, docList);
>> +  for(size_t i=0; i < count; ++i) {
>> +    if ( yout.preflightDocument(i) ) {
>> +      yamlize(yout, DocumentListTraits<T>::element(yout, docList, i),
>> true);
>> +      yout.postflightDocument();
>> +    }
>> +  }
>> +  yout.endDocuments();
>> +  return yout;
>> +}
>> +
>> +// Define non-member operator<< so that Output can stream out a map.
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<has_MappingTraits<T>::value,Output &>::type
>> +operator<<(Output &yout, T &map) {
>> +  yout.beginDocuments();
>> +  if ( yout.preflightDocument(0) ) {
>> +    yamlize(yout, map, true);
>> +    yout.postflightDocument();
>> +  }
>> +  yout.endDocuments();
>> +  return yout;
>> +}
>> +
>> +// Define non-member operator<< so that Output can stream out a sequence.
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<has_SequenceTraits<T>::value,Output &>::type
>> +operator<<(Output &yout, T &seq) {
>> +  yout.beginDocuments();
>> +  if ( yout.preflightDocument(0) ) {
>> +    yamlize(yout, seq, true);
>> +    yout.postflightDocument();
>> +  }
>> +  yout.endDocuments();
>> +  return yout;
>> +}
>> +
>> +#ifndef BUILDING_YAMLIO
>> +// Provide better error message about types missing a trait
>> specialization
>> +template <typename T>
>> +inline
>> +typename llvm::enable_if_c<missingTraits<T>::value,Output &>::type
>> +operator<<(Output &yout, T &seq) {
>> +  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
>> +  return yout;
>> +}
>> +#endif
>> +
>> +
>> +} // namespace yaml
>> +} // namespace llvm
>> +
>> +
>> +/// Utility for declaring that a std::vector of a particular type
>> +/// should be considered a YAML sequence.
>> +#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type)
>>     \
>> +  namespace llvm {
>>    \
>> +  namespace yaml {
>>    \
>> +    template<>
>>    \
>> +    struct SequenceTraits< std::vector<_type> > {
>>     \
>> +      static size_t size(IO &io, std::vector<_type> &seq) {
>>     \
>> +        return seq.size();
>>    \
>> +      }
>>     \
>> +      static _type& element(IO &io, std::vector<_type> &seq, size_t
>> index) {\
>> +        if ( index >= seq.size() )
>>    \
>> +          seq.resize(index+1);
>>    \
>> +        return seq[index];
>>    \
>> +      }
>>     \
>> +    };
>>    \
>> +  }
>>     \
>> +  }
>> +
>> +/// Utility for declaring that a std::vector of a particular type
>> +/// should be considered a YAML flow sequence.
>> +#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type)
>>    \
>> +  namespace llvm {
>>    \
>> +  namespace yaml {
>>    \
>> +    template<>
>>    \
>> +    struct SequenceTraits< std::vector<_type> > {
>>     \
>> +      static size_t size(IO &io, std::vector<_type> &seq) {
>>     \
>> +        return seq.size();
>>    \
>> +      }
>>     \
>> +      static _type& element(IO &io, std::vector<_type> &seq, size_t
>> index) {\
>> +        if ( index >= seq.size() )
>>    \
>> +          seq.resize(index+1);
>>    \
>> +        return seq[index];
>>    \
>> +      }
>>     \
>> +      static const bool flow = true;
>>    \
>> +    };
>>    \
>> +  }
>>     \
>> +  }
>> +
>> +/// Utility for declaring that a std::vector of a particular type
>> +/// should be considered a YAML document list.
>> +#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type)
>>    \
>> +  namespace llvm {
>>    \
>> +  namespace yaml {
>>    \
>> +    template<>
>>    \
>> +    struct DocumentListTraits< std::vector<_type> > {
>>     \
>> +      static size_t size(IO &io, std::vector<_type> &seq) {
>>     \
>> +        return seq.size();
>>    \
>> +      }
>>     \
>> +      static _type& element(IO &io, std::vector<_type> &seq, size_t
>> index) {\
>> +        if ( index >= seq.size() )
>>    \
>> +          seq.resize(index+1);
>>    \
>> +        return seq[index];
>>    \
>> +      }
>>     \
>> +    };
>>    \
>> +  }
>>     \
>> +  }
>> +
>> +
>> +
>> +#endif // LLVM_YAML_TRAITS_H_
>>
>> Modified: llvm/trunk/lib/Support/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CMakeLists.txt?rev=170019&r1=170018&r2=170019&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Support/CMakeLists.txt (original)
>> +++ llvm/trunk/lib/Support/CMakeLists.txt Wed Dec 12 14:46:15 2012
>> @@ -50,6 +50,7 @@
>>    Triple.cpp
>>    Twine.cpp
>>    YAMLParser.cpp
>> +  YAMLTraits.cpp
>>    raw_os_ostream.cpp
>>    raw_ostream.cpp
>>    regcomp.c
>>
>> Added: llvm/trunk/lib/Support/YAMLTraits.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/YAMLTraits.cpp?rev=170019&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Support/YAMLTraits.cpp (added)
>> +++ llvm/trunk/lib/Support/YAMLTraits.cpp Wed Dec 12 14:46:15 2012
>> @@ -0,0 +1,881 @@
>> +//===- lib/Support/YAMLTraits.cpp
>> -----------------------------------------===//
>> +//
>> +//                             The LLVM Linker
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#define BUILDING_YAMLIO
>> +#include "llvm/Support/YAMLTraits.h"
>> +
>> +#include "llvm/ADT/Twine.h"
>> +#include "llvm/Support/Casting.h"
>> +#include "llvm/Support/ErrorHandling.h"
>> +#in
>
> ...
>
> [Message clipped]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130106/908175c0/attachment.html>


More information about the llvm-commits mailing list