- //===-- MsgPackDocument.h - MsgPack Document --------------------*- C++ -*-===// 
- // 
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 
- // See https://llvm.org/LICENSE.txt for license information. 
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 
- // 
- //===----------------------------------------------------------------------===// 
- /// \file 
- /// This file declares a class that exposes a simple in-memory representation 
- /// of a document of MsgPack objects, that can be read from MsgPack, written to 
- /// MsgPack, and inspected and modified in memory. This is intended to be a 
- /// lighter-weight (in terms of memory allocations) replacement for 
- /// MsgPackTypes. 
- /// 
- //===----------------------------------------------------------------------===// 
-   
- #ifndef LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H 
- #define LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H 
-   
- #include "llvm/BinaryFormat/MsgPackReader.h" 
- #include <map> 
-   
- namespace llvm { 
- namespace msgpack { 
-   
- class ArrayDocNode; 
- class Document; 
- class MapDocNode; 
-   
- /// The kind of a DocNode and its owning Document. 
- struct KindAndDocument { 
-   Document *Doc; 
-   Type Kind; 
- }; 
-   
- /// A node in a MsgPack Document. This is a simple copyable and 
- /// passable-by-value type that does not own any memory. 
- class DocNode { 
-   friend Document; 
-   
- public: 
-   typedef std::map<DocNode, DocNode> MapTy; 
-   typedef std::vector<DocNode> ArrayTy; 
-   
- private: 
-   // Using KindAndDocument allows us to squeeze Kind and a pointer to the 
-   // owning Document into the same word. Having a pointer to the owning 
-   // Document makes the API of DocNode more convenient, and allows its use in 
-   // YAMLIO. 
-   const KindAndDocument *KindAndDoc; 
-   
- protected: 
-   // The union of different values. 
-   union { 
-     int64_t Int; 
-     uint64_t UInt; 
-     bool Bool; 
-     double Float; 
-     StringRef Raw; 
-     ArrayTy *Array; 
-     MapTy *Map; 
-   }; 
-   
- public: 
-   // Default constructor gives an empty node with no associated Document. All 
-   // you can do with it is "isEmpty()". 
-   DocNode() : KindAndDoc(nullptr) {} 
-   
-   // Type methods 
-   bool isMap() const { return getKind() == Type::Map; } 
-   bool isArray() const { return getKind() == Type::Array; } 
-   bool isScalar() const { return !isMap() && !isArray(); } 
-   bool isString() const { return getKind() == Type::String; } 
-   
-   // Accessors. isEmpty() returns true for both a default-constructed DocNode 
-   // that has no associated Document, and the result of getEmptyNode(), which 
-   // does have an associated document. 
-   bool isEmpty() const { return !KindAndDoc || getKind() == Type::Empty; } 
-   Type getKind() const { return KindAndDoc->Kind; } 
-   Document *getDocument() const { return KindAndDoc->Doc; } 
-   
-   int64_t &getInt() { 
-     assert(getKind() == Type::Int); 
-     return Int; 
-   } 
-   
-   uint64_t &getUInt() { 
-     assert(getKind() == Type::UInt); 
-     return UInt; 
-   } 
-   
-   bool &getBool() { 
-     assert(getKind() == Type::Boolean); 
-     return Bool; 
-   } 
-   
-   double &getFloat() { 
-     assert(getKind() == Type::Float); 
-     return Float; 
-   } 
-   
-   int64_t getInt() const { 
-     assert(getKind() == Type::Int); 
-     return Int; 
-   } 
-   
-   uint64_t getUInt() const { 
-     assert(getKind() == Type::UInt); 
-     return UInt; 
-   } 
-   
-   bool getBool() const { 
-     assert(getKind() == Type::Boolean); 
-     return Bool; 
-   } 
-   
-   double getFloat() const { 
-     assert(getKind() == Type::Float); 
-     return Float; 
-   } 
-   
-   StringRef getString() const { 
-     assert(getKind() == Type::String); 
-     return Raw; 
-   } 
-   
-   /// Get an ArrayDocNode for an array node. If Convert, convert the node to an 
-   /// array node if necessary. 
-   ArrayDocNode &getArray(bool Convert = false) { 
-     if (getKind() != Type::Array) { 
-       assert(Convert); 
-       convertToArray(); 
-     } 
-     // This could be a static_cast, except ArrayDocNode is a forward reference. 
-     return *reinterpret_cast<ArrayDocNode *>(this); 
-   } 
-   
-   /// Get a MapDocNode for a map node. If Convert, convert the node to a map 
-   /// node if necessary. 
-   MapDocNode &getMap(bool Convert = false) { 
-     if (getKind() != Type::Map) { 
-       assert(Convert); 
-       convertToMap(); 
-     } 
-     // This could be a static_cast, except MapDocNode is a forward reference. 
-     return *reinterpret_cast<MapDocNode *>(this); 
-   } 
-   
-   /// Comparison operator, used for map keys. 
-   friend bool operator<(const DocNode &Lhs, const DocNode &Rhs) { 
-     // This has to cope with one or both of the nodes being default-constructed, 
-     // such that KindAndDoc is not set. 
-     if (Rhs.isEmpty()) 
-       return false; 
-     if (Lhs.KindAndDoc != Rhs.KindAndDoc) { 
-       if (Lhs.isEmpty()) 
-         return true; 
-       return (unsigned)Lhs.getKind() < (unsigned)Rhs.getKind(); 
-     } 
-     switch (Lhs.getKind()) { 
-     case Type::Int: 
-       return Lhs.Int < Rhs.Int; 
-     case Type::UInt: 
-       return Lhs.UInt < Rhs.UInt; 
-     case Type::Nil: 
-       return false; 
-     case Type::Boolean: 
-       return Lhs.Bool < Rhs.Bool; 
-     case Type::Float: 
-       return Lhs.Float < Rhs.Float; 
-     case Type::String: 
-     case Type::Binary: 
-       return Lhs.Raw < Rhs.Raw; 
-     default: 
-       llvm_unreachable("bad map key type"); 
-     } 
-   } 
-   
-   /// Equality operator 
-   friend bool operator==(const DocNode &Lhs, const DocNode &Rhs) { 
-     return !(Lhs < Rhs) && !(Rhs < Lhs); 
-   } 
-   
-   /// Inequality operator 
-   friend bool operator!=(const DocNode &Lhs, const DocNode &Rhs) { 
-     return !(Lhs == Rhs); 
-   } 
-   
-   /// Convert this node to a string, assuming it is scalar. 
-   std::string toString() const; 
-   
-   /// Convert the StringRef and use it to set this DocNode (assuming scalar). If 
-   /// it is a string, copy the string into the Document's strings list so we do 
-   /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag. 
-   StringRef fromString(StringRef S, StringRef Tag = ""); 
-   
-   /// Convenience assignment operators. This only works if the destination 
-   /// DocNode has an associated Document, i.e. it was not constructed using the 
-   /// default constructor. The string one does not copy, so the string must 
-   /// remain valid for the lifetime of the Document. Use fromString to avoid 
-   /// that restriction. 
-   DocNode &operator=(const char *Val) { return *this = StringRef(Val); } 
-   DocNode &operator=(StringRef Val); 
-   DocNode &operator=(bool Val); 
-   DocNode &operator=(int Val); 
-   DocNode &operator=(unsigned Val); 
-   DocNode &operator=(int64_t Val); 
-   DocNode &operator=(uint64_t Val); 
-   
- private: 
-   // Private constructor setting KindAndDoc, used by methods in Document. 
-   DocNode(const KindAndDocument *KindAndDoc) : KindAndDoc(KindAndDoc) {} 
-   
-   void convertToArray(); 
-   void convertToMap(); 
- }; 
-   
- /// A DocNode that is a map. 
- class MapDocNode : public DocNode { 
- public: 
-   MapDocNode() = default; 
-   MapDocNode(DocNode &N) : DocNode(N) { assert(getKind() == Type::Map); } 
-   
-   // Map access methods. 
-   size_t size() const { return Map->size(); } 
-   bool empty() const { return !size(); } 
-   MapTy::iterator begin() { return Map->begin(); } 
-   MapTy::iterator end() { return Map->end(); } 
-   MapTy::iterator find(DocNode Key) { return Map->find(Key); } 
-   MapTy::iterator find(StringRef Key); 
-   MapTy::iterator erase(MapTy::const_iterator I) { return Map->erase(I); } 
-   size_t erase(DocNode Key) { return Map->erase(Key); } 
-   MapTy::iterator erase(MapTy::const_iterator First, 
-                         MapTy::const_iterator Second) { 
-     return Map->erase(First, Second); 
-   } 
-   /// Member access. The string data must remain valid for the lifetime of the 
-   /// Document. 
-   DocNode &operator[](StringRef S); 
-   /// Member access, with convenience versions for an integer key. 
-   DocNode &operator[](DocNode Key); 
-   DocNode &operator[](int Key); 
-   DocNode &operator[](unsigned Key); 
-   DocNode &operator[](int64_t Key); 
-   DocNode &operator[](uint64_t Key); 
- }; 
-   
- /// A DocNode that is an array. 
- class ArrayDocNode : public DocNode { 
- public: 
-   ArrayDocNode() = default; 
-   ArrayDocNode(DocNode &N) : DocNode(N) { assert(getKind() == Type::Array); } 
-   
-   // Array access methods. 
-   size_t size() const { return Array->size(); } 
-   bool empty() const { return !size(); } 
-   DocNode &back() const { return Array->back(); } 
-   ArrayTy::iterator begin() { return Array->begin(); } 
-   ArrayTy::iterator end() { return Array->end(); } 
-   void push_back(DocNode N) { 
-     assert(N.isEmpty() || N.getDocument() == getDocument()); 
-     Array->push_back(N); 
-   } 
-   
-   /// Element access. This extends the array if necessary, with empty nodes. 
-   DocNode &operator[](size_t Index); 
- }; 
-   
- /// Simple in-memory representation of a document of msgpack objects with 
- /// ability to find and create array and map elements.  Does not currently cope 
- /// with any extension types. 
- class Document { 
-   // Maps, arrays and strings used by nodes in the document. No attempt is made 
-   // to free unused ones. 
-   std::vector<std::unique_ptr<DocNode::MapTy>> Maps; 
-   std::vector<std::unique_ptr<DocNode::ArrayTy>> Arrays; 
-   std::vector<std::unique_ptr<char[]>> Strings; 
-   
-   // The root node of the document. 
-   DocNode Root; 
-   
-   // The KindAndDocument structs pointed to by nodes in the document. 
-   KindAndDocument KindAndDocs[size_t(Type::Empty) + 1]; 
-   
-   // Whether YAML output uses hex for UInt. 
-   bool HexMode = false; 
-   
- public: 
-   Document() { 
-     clear(); 
-     for (unsigned T = 0; T != unsigned(Type::Empty) + 1; ++T) 
-       KindAndDocs[T] = {this, Type(T)}; 
-   } 
-   
-   /// Get ref to the document's root element. 
-   DocNode &getRoot() { return Root; } 
-   
-   /// Restore the Document to an empty state. 
-   void clear() { getRoot() = getEmptyNode(); } 
-   
-   /// Create an empty node associated with this Document. 
-   DocNode getEmptyNode() { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Empty)]); 
-     return N; 
-   } 
-   
-   /// Create a nil node associated with this Document. 
-   DocNode getNode() { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Nil)]); 
-     return N; 
-   } 
-   
-   /// Create an Int node associated with this Document. 
-   DocNode getNode(int64_t V) { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Int)]); 
-     N.Int = V; 
-     return N; 
-   } 
-   
-   /// Create an Int node associated with this Document. 
-   DocNode getNode(int V) { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Int)]); 
-     N.Int = V; 
-     return N; 
-   } 
-   
-   /// Create a UInt node associated with this Document. 
-   DocNode getNode(uint64_t V) { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::UInt)]); 
-     N.UInt = V; 
-     return N; 
-   } 
-   
-   /// Create a UInt node associated with this Document. 
-   DocNode getNode(unsigned V) { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::UInt)]); 
-     N.UInt = V; 
-     return N; 
-   } 
-   
-   /// Create a Boolean node associated with this Document. 
-   DocNode getNode(bool V) { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Boolean)]); 
-     N.Bool = V; 
-     return N; 
-   } 
-   
-   /// Create a Float node associated with this Document. 
-   DocNode getNode(double V) { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Float)]); 
-     N.Float = V; 
-     return N; 
-   } 
-   
-   /// Create a String node associated with this Document. If !Copy, the passed 
-   /// string must remain valid for the lifetime of the Document. 
-   DocNode getNode(StringRef V, bool Copy = false) { 
-     if (Copy) 
-       V = addString(V); 
-     auto N = DocNode(&KindAndDocs[size_t(Type::String)]); 
-     N.Raw = V; 
-     return N; 
-   } 
-   
-   /// Create a String node associated with this Document. If !Copy, the passed 
-   /// string must remain valid for the lifetime of the Document. 
-   DocNode getNode(const char *V, bool Copy = false) { 
-     return getNode(StringRef(V), Copy); 
-   } 
-   
-   /// Create an empty Map node associated with this Document. 
-   MapDocNode getMapNode() { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Map)]); 
-     Maps.push_back(std::unique_ptr<DocNode::MapTy>(new DocNode::MapTy)); 
-     N.Map = Maps.back().get(); 
-     return N.getMap(); 
-   } 
-   
-   /// Create an empty Array node associated with this Document. 
-   ArrayDocNode getArrayNode() { 
-     auto N = DocNode(&KindAndDocs[size_t(Type::Array)]); 
-     Arrays.push_back(std::unique_ptr<DocNode::ArrayTy>(new DocNode::ArrayTy)); 
-     N.Array = Arrays.back().get(); 
-     return N.getArray(); 
-   } 
-   
-   /// Read a document from a binary msgpack blob, merging into anything already 
-   /// in the Document. The blob data must remain valid for the lifetime of this 
-   /// Document (because a string object in the document contains a StringRef 
-   /// into the original blob). If Multi, then this sets root to an array and 
-   /// adds top-level objects to it. If !Multi, then it only reads a single 
-   /// top-level object, even if there are more, and sets root to that. Returns 
-   /// false if failed due to illegal format or merge error. 
-   /// 
-   /// The Merger arg is a callback function that is called when the merge has a 
-   /// conflict, that is, it is trying to set an item that is already set. If the 
-   /// conflict cannot be resolved, the callback function returns -1. If the 
-   /// conflict can be resolved, the callback returns a non-negative number and 
-   /// sets *DestNode to the resolved node. The returned non-negative number is 
-   /// significant only for an array node; it is then the array index to start 
-   /// populating at. That allows Merger to choose whether to merge array 
-   /// elements (returns 0) or append new elements (returns existing size). 
-   /// 
-   /// If SrcNode is an array or map, the resolution must be that *DestNode is an 
-   /// array or map respectively, although it could be the array or map 
-   /// (respectively) that was already there. MapKey is the key if *DestNode is a 
-   /// map entry, a nil node otherwise. 
-   /// 
-   /// The default for Merger is to disallow any conflict. 
-   bool readFromBlob( 
-       StringRef Blob, bool Multi, 
-       function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)> 
-           Merger = [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { 
-             return -1; 
-           }); 
-   
-   /// Write a MsgPack document to a binary MsgPack blob. 
-   void writeToBlob(std::string &Blob); 
-   
-   /// Copy a string into the Document's strings list, and return the copy that 
-   /// is owned by the Document. 
-   StringRef addString(StringRef S) { 
-     Strings.push_back(std::unique_ptr<char[]>(new char[S.size()])); 
-     memcpy(&Strings.back()[0], S.data(), S.size()); 
-     return StringRef(&Strings.back()[0], S.size()); 
-   } 
-   
-   /// Set whether YAML output uses hex for UInt. Default off. 
-   void setHexMode(bool Val = true) { HexMode = Val; } 
-   
-   /// Get Hexmode flag. 
-   bool getHexMode() const { return HexMode; } 
-   
-   /// Convert MsgPack Document to YAML text. 
-   void toYAML(raw_ostream &OS); 
-   
-   /// Read YAML text into the MsgPack document. Returns false on failure. 
-   bool fromYAML(StringRef S); 
- }; 
-   
- } // namespace msgpack 
- } // namespace llvm 
-   
- #endif // LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H 
-