Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:22

0001 //===-- MsgPackDocument.h - MsgPack Document --------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 /// This file declares a class that exposes a simple in-memory representation
0010 /// of a document of MsgPack objects, that can be read from MsgPack, written to
0011 /// MsgPack, and inspected and modified in memory. This is intended to be a
0012 /// lighter-weight (in terms of memory allocations) replacement for
0013 /// MsgPackTypes.
0014 ///
0015 //===----------------------------------------------------------------------===//
0016 
0017 #ifndef LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
0018 #define LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
0019 
0020 #include "llvm/BinaryFormat/MsgPackReader.h"
0021 #include <map>
0022 
0023 namespace llvm {
0024 namespace msgpack {
0025 
0026 class ArrayDocNode;
0027 class Document;
0028 class MapDocNode;
0029 
0030 /// The kind of a DocNode and its owning Document.
0031 struct KindAndDocument {
0032   Document *Doc;
0033   Type Kind;
0034 };
0035 
0036 /// A node in a MsgPack Document. This is a simple copyable and
0037 /// passable-by-value type that does not own any memory.
0038 class DocNode {
0039   friend Document;
0040 
0041 public:
0042   typedef std::map<DocNode, DocNode> MapTy;
0043   typedef std::vector<DocNode> ArrayTy;
0044 
0045 private:
0046   // Using KindAndDocument allows us to squeeze Kind and a pointer to the
0047   // owning Document into the same word. Having a pointer to the owning
0048   // Document makes the API of DocNode more convenient, and allows its use in
0049   // YAMLIO.
0050   const KindAndDocument *KindAndDoc;
0051 
0052 protected:
0053   // The union of different values.
0054   union {
0055     int64_t Int;
0056     uint64_t UInt;
0057     bool Bool;
0058     double Float;
0059     StringRef Raw;
0060     ArrayTy *Array;
0061     MapTy *Map;
0062   };
0063 
0064 public:
0065   // Default constructor gives an empty node with no associated Document. All
0066   // you can do with it is "isEmpty()".
0067   DocNode() : KindAndDoc(nullptr) {}
0068 
0069   // Type methods
0070   bool isMap() const { return getKind() == Type::Map; }
0071   bool isArray() const { return getKind() == Type::Array; }
0072   bool isScalar() const { return !isMap() && !isArray(); }
0073   bool isString() const { return getKind() == Type::String; }
0074 
0075   // Accessors. isEmpty() returns true for both a default-constructed DocNode
0076   // that has no associated Document, and the result of getEmptyNode(), which
0077   // does have an associated document.
0078   bool isEmpty() const { return !KindAndDoc || getKind() == Type::Empty; }
0079   Type getKind() const { return KindAndDoc->Kind; }
0080   Document *getDocument() const { return KindAndDoc->Doc; }
0081 
0082   int64_t &getInt() {
0083     assert(getKind() == Type::Int);
0084     return Int;
0085   }
0086 
0087   uint64_t &getUInt() {
0088     assert(getKind() == Type::UInt);
0089     return UInt;
0090   }
0091 
0092   bool &getBool() {
0093     assert(getKind() == Type::Boolean);
0094     return Bool;
0095   }
0096 
0097   double &getFloat() {
0098     assert(getKind() == Type::Float);
0099     return Float;
0100   }
0101 
0102   int64_t getInt() const {
0103     assert(getKind() == Type::Int);
0104     return Int;
0105   }
0106 
0107   uint64_t getUInt() const {
0108     assert(getKind() == Type::UInt);
0109     return UInt;
0110   }
0111 
0112   bool getBool() const {
0113     assert(getKind() == Type::Boolean);
0114     return Bool;
0115   }
0116 
0117   double getFloat() const {
0118     assert(getKind() == Type::Float);
0119     return Float;
0120   }
0121 
0122   StringRef getString() const {
0123     assert(getKind() == Type::String);
0124     return Raw;
0125   }
0126 
0127   MemoryBufferRef getBinary() const {
0128     assert(getKind() == Type::Binary);
0129     return MemoryBufferRef(Raw, "");
0130   }
0131 
0132   /// Get an ArrayDocNode for an array node. If Convert, convert the node to an
0133   /// array node if necessary.
0134   ArrayDocNode &getArray(bool Convert = false) {
0135     if (getKind() != Type::Array) {
0136       assert(Convert);
0137       convertToArray();
0138     }
0139     // This could be a static_cast, except ArrayDocNode is a forward reference.
0140     return *reinterpret_cast<ArrayDocNode *>(this);
0141   }
0142 
0143   /// Get a MapDocNode for a map node. If Convert, convert the node to a map
0144   /// node if necessary.
0145   MapDocNode &getMap(bool Convert = false) {
0146     if (getKind() != Type::Map) {
0147       assert(Convert);
0148       convertToMap();
0149     }
0150     // This could be a static_cast, except MapDocNode is a forward reference.
0151     return *reinterpret_cast<MapDocNode *>(this);
0152   }
0153 
0154   /// Comparison operator, used for map keys.
0155   friend bool operator<(const DocNode &Lhs, const DocNode &Rhs) {
0156     // This has to cope with one or both of the nodes being default-constructed,
0157     // such that KindAndDoc is not set.
0158     if (Rhs.isEmpty())
0159       return false;
0160     if (Lhs.KindAndDoc != Rhs.KindAndDoc) {
0161       if (Lhs.isEmpty())
0162         return true;
0163       return (unsigned)Lhs.getKind() < (unsigned)Rhs.getKind();
0164     }
0165     switch (Lhs.getKind()) {
0166     case Type::Int:
0167       return Lhs.Int < Rhs.Int;
0168     case Type::UInt:
0169       return Lhs.UInt < Rhs.UInt;
0170     case Type::Nil:
0171       return false;
0172     case Type::Boolean:
0173       return Lhs.Bool < Rhs.Bool;
0174     case Type::Float:
0175       return Lhs.Float < Rhs.Float;
0176     case Type::String:
0177     case Type::Binary:
0178       return Lhs.Raw < Rhs.Raw;
0179     default:
0180       llvm_unreachable("bad map key type");
0181     }
0182   }
0183 
0184   /// Equality operator
0185   friend bool operator==(const DocNode &Lhs, const DocNode &Rhs) {
0186     return !(Lhs < Rhs) && !(Rhs < Lhs);
0187   }
0188 
0189   /// Inequality operator
0190   friend bool operator!=(const DocNode &Lhs, const DocNode &Rhs) {
0191     return !(Lhs == Rhs);
0192   }
0193 
0194   /// Convert this node to a string, assuming it is scalar.
0195   std::string toString() const;
0196 
0197   /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
0198   /// it is a string, copy the string into the Document's strings list so we do
0199   /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
0200   StringRef fromString(StringRef S, StringRef Tag = "");
0201 
0202   /// Convenience assignment operators. This only works if the destination
0203   /// DocNode has an associated Document, i.e. it was not constructed using the
0204   /// default constructor. The string one does not copy, so the string must
0205   /// remain valid for the lifetime of the Document. Use fromString to avoid
0206   /// that restriction.
0207   DocNode &operator=(const char *Val) { return *this = StringRef(Val); }
0208   DocNode &operator=(StringRef Val);
0209   DocNode &operator=(MemoryBufferRef Val);
0210   DocNode &operator=(bool Val);
0211   DocNode &operator=(int Val);
0212   DocNode &operator=(unsigned Val);
0213   DocNode &operator=(int64_t Val);
0214   DocNode &operator=(uint64_t Val);
0215 
0216 private:
0217   // Private constructor setting KindAndDoc, used by methods in Document.
0218   DocNode(const KindAndDocument *KindAndDoc) : KindAndDoc(KindAndDoc) {}
0219 
0220   void convertToArray();
0221   void convertToMap();
0222 };
0223 
0224 /// A DocNode that is a map.
0225 class MapDocNode : public DocNode {
0226 public:
0227   MapDocNode() = default;
0228   MapDocNode(DocNode &N) : DocNode(N) { assert(getKind() == Type::Map); }
0229 
0230   // Map access methods.
0231   size_t size() const { return Map->size(); }
0232   bool empty() const { return !size(); }
0233   MapTy::iterator begin() { return Map->begin(); }
0234   MapTy::iterator end() { return Map->end(); }
0235   MapTy::iterator find(DocNode Key) { return Map->find(Key); }
0236   MapTy::iterator find(StringRef Key);
0237   MapTy::iterator erase(MapTy::const_iterator I) { return Map->erase(I); }
0238   size_t erase(DocNode Key) { return Map->erase(Key); }
0239   MapTy::iterator erase(MapTy::const_iterator First,
0240                         MapTy::const_iterator Second) {
0241     return Map->erase(First, Second);
0242   }
0243   /// Member access. The string data must remain valid for the lifetime of the
0244   /// Document.
0245   DocNode &operator[](StringRef S);
0246   /// Member access, with convenience versions for an integer key.
0247   DocNode &operator[](DocNode Key);
0248   DocNode &operator[](int Key);
0249   DocNode &operator[](unsigned Key);
0250   DocNode &operator[](int64_t Key);
0251   DocNode &operator[](uint64_t Key);
0252 };
0253 
0254 /// A DocNode that is an array.
0255 class ArrayDocNode : public DocNode {
0256 public:
0257   ArrayDocNode() = default;
0258   ArrayDocNode(DocNode &N) : DocNode(N) { assert(getKind() == Type::Array); }
0259 
0260   // Array access methods.
0261   size_t size() const { return Array->size(); }
0262   bool empty() const { return !size(); }
0263   DocNode &back() const { return Array->back(); }
0264   ArrayTy::iterator begin() { return Array->begin(); }
0265   ArrayTy::iterator end() { return Array->end(); }
0266   void push_back(DocNode N) {
0267     assert(N.isEmpty() || N.getDocument() == getDocument());
0268     Array->push_back(N);
0269   }
0270 
0271   /// Element access. This extends the array if necessary, with empty nodes.
0272   DocNode &operator[](size_t Index);
0273 };
0274 
0275 /// Simple in-memory representation of a document of msgpack objects with
0276 /// ability to find and create array and map elements.  Does not currently cope
0277 /// with any extension types.
0278 class Document {
0279   // Maps, arrays and strings used by nodes in the document. No attempt is made
0280   // to free unused ones.
0281   std::vector<std::unique_ptr<DocNode::MapTy>> Maps;
0282   std::vector<std::unique_ptr<DocNode::ArrayTy>> Arrays;
0283   std::vector<std::unique_ptr<char[]>> Strings;
0284 
0285   // The root node of the document.
0286   DocNode Root;
0287 
0288   // The KindAndDocument structs pointed to by nodes in the document.
0289   KindAndDocument KindAndDocs[size_t(Type::Empty) + 1];
0290 
0291   // Whether YAML output uses hex for UInt.
0292   bool HexMode = false;
0293 
0294 public:
0295   Document() {
0296     clear();
0297     for (unsigned T = 0; T != unsigned(Type::Empty) + 1; ++T)
0298       KindAndDocs[T] = {this, Type(T)};
0299   }
0300 
0301   /// Get ref to the document's root element.
0302   DocNode &getRoot() { return Root; }
0303 
0304   /// Restore the Document to an empty state.
0305   void clear() { getRoot() = getEmptyNode(); }
0306 
0307   /// Create an empty node associated with this Document.
0308   DocNode getEmptyNode() {
0309     auto N = DocNode(&KindAndDocs[size_t(Type::Empty)]);
0310     return N;
0311   }
0312 
0313   /// Create a nil node associated with this Document.
0314   DocNode getNode() {
0315     auto N = DocNode(&KindAndDocs[size_t(Type::Nil)]);
0316     return N;
0317   }
0318 
0319   /// Create an Int node associated with this Document.
0320   DocNode getNode(int64_t V) {
0321     auto N = DocNode(&KindAndDocs[size_t(Type::Int)]);
0322     N.Int = V;
0323     return N;
0324   }
0325 
0326   /// Create an Int node associated with this Document.
0327   DocNode getNode(int V) {
0328     auto N = DocNode(&KindAndDocs[size_t(Type::Int)]);
0329     N.Int = V;
0330     return N;
0331   }
0332 
0333   /// Create a UInt node associated with this Document.
0334   DocNode getNode(uint64_t V) {
0335     auto N = DocNode(&KindAndDocs[size_t(Type::UInt)]);
0336     N.UInt = V;
0337     return N;
0338   }
0339 
0340   /// Create a UInt node associated with this Document.
0341   DocNode getNode(unsigned V) {
0342     auto N = DocNode(&KindAndDocs[size_t(Type::UInt)]);
0343     N.UInt = V;
0344     return N;
0345   }
0346 
0347   /// Create a Boolean node associated with this Document.
0348   DocNode getNode(bool V) {
0349     auto N = DocNode(&KindAndDocs[size_t(Type::Boolean)]);
0350     N.Bool = V;
0351     return N;
0352   }
0353 
0354   /// Create a Float node associated with this Document.
0355   DocNode getNode(double V) {
0356     auto N = DocNode(&KindAndDocs[size_t(Type::Float)]);
0357     N.Float = V;
0358     return N;
0359   }
0360 
0361   /// Create a String node associated with this Document. If !Copy, the passed
0362   /// string must remain valid for the lifetime of the Document.
0363   DocNode getNode(StringRef V, bool Copy = false) {
0364     if (Copy)
0365       V = addString(V);
0366     auto N = DocNode(&KindAndDocs[size_t(Type::String)]);
0367     N.Raw = V;
0368     return N;
0369   }
0370 
0371   /// Create a String node associated with this Document. If !Copy, the passed
0372   /// string must remain valid for the lifetime of the Document.
0373   DocNode getNode(const char *V, bool Copy = false) {
0374     return getNode(StringRef(V), Copy);
0375   }
0376 
0377   /// Create a Binary node associated with this Document. If !Copy, the passed
0378   /// buffer must remain valid for the lifetime of the Document.
0379   DocNode getNode(MemoryBufferRef V, bool Copy = false) {
0380     auto Raw = V.getBuffer();
0381     if (Copy)
0382       Raw = addString(Raw);
0383     auto N = DocNode(&KindAndDocs[size_t(Type::Binary)]);
0384     N.Raw = Raw;
0385     return N;
0386   }
0387 
0388   /// Create an empty Map node associated with this Document.
0389   MapDocNode getMapNode() {
0390     auto N = DocNode(&KindAndDocs[size_t(Type::Map)]);
0391     Maps.push_back(std::make_unique<DocNode::MapTy>());
0392     N.Map = Maps.back().get();
0393     return N.getMap();
0394   }
0395 
0396   /// Create an empty Array node associated with this Document.
0397   ArrayDocNode getArrayNode() {
0398     auto N = DocNode(&KindAndDocs[size_t(Type::Array)]);
0399     Arrays.push_back(std::make_unique<DocNode::ArrayTy>());
0400     N.Array = Arrays.back().get();
0401     return N.getArray();
0402   }
0403 
0404   /// Read a document from a binary msgpack blob, merging into anything already
0405   /// in the Document. The blob data must remain valid for the lifetime of this
0406   /// Document (because a string object in the document contains a StringRef
0407   /// into the original blob). If Multi, then this sets root to an array and
0408   /// adds top-level objects to it. If !Multi, then it only reads a single
0409   /// top-level object, even if there are more, and sets root to that. Returns
0410   /// false if failed due to illegal format or merge error.
0411   ///
0412   /// The Merger arg is a callback function that is called when the merge has a
0413   /// conflict, that is, it is trying to set an item that is already set. If the
0414   /// conflict cannot be resolved, the callback function returns -1. If the
0415   /// conflict can be resolved, the callback returns a non-negative number and
0416   /// sets *DestNode to the resolved node. The returned non-negative number is
0417   /// significant only for an array node; it is then the array index to start
0418   /// populating at. That allows Merger to choose whether to merge array
0419   /// elements (returns 0) or append new elements (returns existing size).
0420   ///
0421   /// If SrcNode is an array or map, the resolution must be that *DestNode is an
0422   /// array or map respectively, although it could be the array or map
0423   /// (respectively) that was already there. MapKey is the key if *DestNode is a
0424   /// map entry, a nil node otherwise.
0425   ///
0426   /// The default for Merger is to disallow any conflict.
0427   bool readFromBlob(
0428       StringRef Blob, bool Multi,
0429       function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)>
0430           Merger = [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {
0431             return -1;
0432           });
0433 
0434   /// Write a MsgPack document to a binary MsgPack blob.
0435   void writeToBlob(std::string &Blob);
0436 
0437   /// Copy a string into the Document's strings list, and return the copy that
0438   /// is owned by the Document.
0439   StringRef addString(StringRef S) {
0440     Strings.push_back(std::unique_ptr<char[]>(new char[S.size()]));
0441     memcpy(&Strings.back()[0], S.data(), S.size());
0442     return StringRef(&Strings.back()[0], S.size());
0443   }
0444 
0445   /// Set whether YAML output uses hex for UInt. Default off.
0446   void setHexMode(bool Val = true) { HexMode = Val; }
0447 
0448   /// Get Hexmode flag.
0449   bool getHexMode() const { return HexMode; }
0450 
0451   /// Convert MsgPack Document to YAML text.
0452   void toYAML(raw_ostream &OS);
0453 
0454   /// Read YAML text into the MsgPack document. Returns false on failure.
0455   bool fromYAML(StringRef S);
0456 };
0457 
0458 } // namespace msgpack
0459 } // namespace llvm
0460 
0461 #endif // LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H