MsgPackDocument.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- MsgPackDocument.h - MsgPack Document --------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. /// \file
  14. /// This file declares a class that exposes a simple in-memory representation
  15. /// of a document of MsgPack objects, that can be read from MsgPack, written to
  16. /// MsgPack, and inspected and modified in memory. This is intended to be a
  17. /// lighter-weight (in terms of memory allocations) replacement for
  18. /// MsgPackTypes.
  19. ///
  20. //===----------------------------------------------------------------------===//
  21. #ifndef LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
  22. #define LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
  23. #include "llvm/BinaryFormat/MsgPackReader.h"
  24. #include <map>
  25. namespace llvm {
  26. namespace msgpack {
  27. class ArrayDocNode;
  28. class Document;
  29. class MapDocNode;
  30. /// The kind of a DocNode and its owning Document.
  31. struct KindAndDocument {
  32. Document *Doc;
  33. Type Kind;
  34. };
  35. /// A node in a MsgPack Document. This is a simple copyable and
  36. /// passable-by-value type that does not own any memory.
  37. class DocNode {
  38. friend Document;
  39. public:
  40. typedef std::map<DocNode, DocNode> MapTy;
  41. typedef std::vector<DocNode> ArrayTy;
  42. private:
  43. // Using KindAndDocument allows us to squeeze Kind and a pointer to the
  44. // owning Document into the same word. Having a pointer to the owning
  45. // Document makes the API of DocNode more convenient, and allows its use in
  46. // YAMLIO.
  47. const KindAndDocument *KindAndDoc;
  48. protected:
  49. // The union of different values.
  50. union {
  51. int64_t Int;
  52. uint64_t UInt;
  53. bool Bool;
  54. double Float;
  55. StringRef Raw;
  56. ArrayTy *Array;
  57. MapTy *Map;
  58. };
  59. public:
  60. // Default constructor gives an empty node with no associated Document. All
  61. // you can do with it is "isEmpty()".
  62. DocNode() : KindAndDoc(nullptr) {}
  63. // Type methods
  64. bool isMap() const { return getKind() == Type::Map; }
  65. bool isArray() const { return getKind() == Type::Array; }
  66. bool isScalar() const { return !isMap() && !isArray(); }
  67. bool isString() const { return getKind() == Type::String; }
  68. // Accessors. isEmpty() returns true for both a default-constructed DocNode
  69. // that has no associated Document, and the result of getEmptyNode(), which
  70. // does have an associated document.
  71. bool isEmpty() const { return !KindAndDoc || getKind() == Type::Empty; }
  72. Type getKind() const { return KindAndDoc->Kind; }
  73. Document *getDocument() const { return KindAndDoc->Doc; }
  74. int64_t &getInt() {
  75. assert(getKind() == Type::Int);
  76. return Int;
  77. }
  78. uint64_t &getUInt() {
  79. assert(getKind() == Type::UInt);
  80. return UInt;
  81. }
  82. bool &getBool() {
  83. assert(getKind() == Type::Boolean);
  84. return Bool;
  85. }
  86. double &getFloat() {
  87. assert(getKind() == Type::Float);
  88. return Float;
  89. }
  90. int64_t getInt() const {
  91. assert(getKind() == Type::Int);
  92. return Int;
  93. }
  94. uint64_t getUInt() const {
  95. assert(getKind() == Type::UInt);
  96. return UInt;
  97. }
  98. bool getBool() const {
  99. assert(getKind() == Type::Boolean);
  100. return Bool;
  101. }
  102. double getFloat() const {
  103. assert(getKind() == Type::Float);
  104. return Float;
  105. }
  106. StringRef getString() const {
  107. assert(getKind() == Type::String);
  108. return Raw;
  109. }
  110. /// Get an ArrayDocNode for an array node. If Convert, convert the node to an
  111. /// array node if necessary.
  112. ArrayDocNode &getArray(bool Convert = false) {
  113. if (getKind() != Type::Array) {
  114. assert(Convert);
  115. convertToArray();
  116. }
  117. // This could be a static_cast, except ArrayDocNode is a forward reference.
  118. return *reinterpret_cast<ArrayDocNode *>(this);
  119. }
  120. /// Get a MapDocNode for a map node. If Convert, convert the node to a map
  121. /// node if necessary.
  122. MapDocNode &getMap(bool Convert = false) {
  123. if (getKind() != Type::Map) {
  124. assert(Convert);
  125. convertToMap();
  126. }
  127. // This could be a static_cast, except MapDocNode is a forward reference.
  128. return *reinterpret_cast<MapDocNode *>(this);
  129. }
  130. /// Comparison operator, used for map keys.
  131. friend bool operator<(const DocNode &Lhs, const DocNode &Rhs) {
  132. // This has to cope with one or both of the nodes being default-constructed,
  133. // such that KindAndDoc is not set.
  134. if (Rhs.isEmpty())
  135. return false;
  136. if (Lhs.KindAndDoc != Rhs.KindAndDoc) {
  137. if (Lhs.isEmpty())
  138. return true;
  139. return (unsigned)Lhs.getKind() < (unsigned)Rhs.getKind();
  140. }
  141. switch (Lhs.getKind()) {
  142. case Type::Int:
  143. return Lhs.Int < Rhs.Int;
  144. case Type::UInt:
  145. return Lhs.UInt < Rhs.UInt;
  146. case Type::Nil:
  147. return false;
  148. case Type::Boolean:
  149. return Lhs.Bool < Rhs.Bool;
  150. case Type::Float:
  151. return Lhs.Float < Rhs.Float;
  152. case Type::String:
  153. case Type::Binary:
  154. return Lhs.Raw < Rhs.Raw;
  155. default:
  156. llvm_unreachable("bad map key type");
  157. }
  158. }
  159. /// Equality operator
  160. friend bool operator==(const DocNode &Lhs, const DocNode &Rhs) {
  161. return !(Lhs < Rhs) && !(Rhs < Lhs);
  162. }
  163. /// Inequality operator
  164. friend bool operator!=(const DocNode &Lhs, const DocNode &Rhs) {
  165. return !(Lhs == Rhs);
  166. }
  167. /// Convert this node to a string, assuming it is scalar.
  168. std::string toString() const;
  169. /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
  170. /// it is a string, copy the string into the Document's strings list so we do
  171. /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
  172. StringRef fromString(StringRef S, StringRef Tag = "");
  173. /// Convenience assignment operators. This only works if the destination
  174. /// DocNode has an associated Document, i.e. it was not constructed using the
  175. /// default constructor. The string one does not copy, so the string must
  176. /// remain valid for the lifetime of the Document. Use fromString to avoid
  177. /// that restriction.
  178. DocNode &operator=(const char *Val) { return *this = StringRef(Val); }
  179. DocNode &operator=(StringRef Val);
  180. DocNode &operator=(bool Val);
  181. DocNode &operator=(int Val);
  182. DocNode &operator=(unsigned Val);
  183. DocNode &operator=(int64_t Val);
  184. DocNode &operator=(uint64_t Val);
  185. private:
  186. // Private constructor setting KindAndDoc, used by methods in Document.
  187. DocNode(const KindAndDocument *KindAndDoc) : KindAndDoc(KindAndDoc) {}
  188. void convertToArray();
  189. void convertToMap();
  190. };
  191. /// A DocNode that is a map.
  192. class MapDocNode : public DocNode {
  193. public:
  194. MapDocNode() = default;
  195. MapDocNode(DocNode &N) : DocNode(N) { assert(getKind() == Type::Map); }
  196. // Map access methods.
  197. size_t size() const { return Map->size(); }
  198. bool empty() const { return !size(); }
  199. MapTy::iterator begin() { return Map->begin(); }
  200. MapTy::iterator end() { return Map->end(); }
  201. MapTy::iterator find(DocNode Key) { return Map->find(Key); }
  202. MapTy::iterator find(StringRef Key);
  203. MapTy::iterator erase(MapTy::const_iterator I) { return Map->erase(I); }
  204. size_t erase(DocNode Key) { return Map->erase(Key); }
  205. MapTy::iterator erase(MapTy::const_iterator First,
  206. MapTy::const_iterator Second) {
  207. return Map->erase(First, Second);
  208. }
  209. /// Member access. The string data must remain valid for the lifetime of the
  210. /// Document.
  211. DocNode &operator[](StringRef S);
  212. /// Member access, with convenience versions for an integer key.
  213. DocNode &operator[](DocNode Key);
  214. DocNode &operator[](int Key);
  215. DocNode &operator[](unsigned Key);
  216. DocNode &operator[](int64_t Key);
  217. DocNode &operator[](uint64_t Key);
  218. };
  219. /// A DocNode that is an array.
  220. class ArrayDocNode : public DocNode {
  221. public:
  222. ArrayDocNode() = default;
  223. ArrayDocNode(DocNode &N) : DocNode(N) { assert(getKind() == Type::Array); }
  224. // Array access methods.
  225. size_t size() const { return Array->size(); }
  226. bool empty() const { return !size(); }
  227. DocNode &back() const { return Array->back(); }
  228. ArrayTy::iterator begin() { return Array->begin(); }
  229. ArrayTy::iterator end() { return Array->end(); }
  230. void push_back(DocNode N) {
  231. assert(N.isEmpty() || N.getDocument() == getDocument());
  232. Array->push_back(N);
  233. }
  234. /// Element access. This extends the array if necessary, with empty nodes.
  235. DocNode &operator[](size_t Index);
  236. };
  237. /// Simple in-memory representation of a document of msgpack objects with
  238. /// ability to find and create array and map elements. Does not currently cope
  239. /// with any extension types.
  240. class Document {
  241. // Maps, arrays and strings used by nodes in the document. No attempt is made
  242. // to free unused ones.
  243. std::vector<std::unique_ptr<DocNode::MapTy>> Maps;
  244. std::vector<std::unique_ptr<DocNode::ArrayTy>> Arrays;
  245. std::vector<std::unique_ptr<char[]>> Strings;
  246. // The root node of the document.
  247. DocNode Root;
  248. // The KindAndDocument structs pointed to by nodes in the document.
  249. KindAndDocument KindAndDocs[size_t(Type::Empty) + 1];
  250. // Whether YAML output uses hex for UInt.
  251. bool HexMode = false;
  252. public:
  253. Document() {
  254. clear();
  255. for (unsigned T = 0; T != unsigned(Type::Empty) + 1; ++T)
  256. KindAndDocs[T] = {this, Type(T)};
  257. }
  258. /// Get ref to the document's root element.
  259. DocNode &getRoot() { return Root; }
  260. /// Restore the Document to an empty state.
  261. void clear() { getRoot() = getEmptyNode(); }
  262. /// Create an empty node associated with this Document.
  263. DocNode getEmptyNode() {
  264. auto N = DocNode(&KindAndDocs[size_t(Type::Empty)]);
  265. return N;
  266. }
  267. /// Create a nil node associated with this Document.
  268. DocNode getNode() {
  269. auto N = DocNode(&KindAndDocs[size_t(Type::Nil)]);
  270. return N;
  271. }
  272. /// Create an Int node associated with this Document.
  273. DocNode getNode(int64_t V) {
  274. auto N = DocNode(&KindAndDocs[size_t(Type::Int)]);
  275. N.Int = V;
  276. return N;
  277. }
  278. /// Create an Int node associated with this Document.
  279. DocNode getNode(int V) {
  280. auto N = DocNode(&KindAndDocs[size_t(Type::Int)]);
  281. N.Int = V;
  282. return N;
  283. }
  284. /// Create a UInt node associated with this Document.
  285. DocNode getNode(uint64_t V) {
  286. auto N = DocNode(&KindAndDocs[size_t(Type::UInt)]);
  287. N.UInt = V;
  288. return N;
  289. }
  290. /// Create a UInt node associated with this Document.
  291. DocNode getNode(unsigned V) {
  292. auto N = DocNode(&KindAndDocs[size_t(Type::UInt)]);
  293. N.UInt = V;
  294. return N;
  295. }
  296. /// Create a Boolean node associated with this Document.
  297. DocNode getNode(bool V) {
  298. auto N = DocNode(&KindAndDocs[size_t(Type::Boolean)]);
  299. N.Bool = V;
  300. return N;
  301. }
  302. /// Create a Float node associated with this Document.
  303. DocNode getNode(double V) {
  304. auto N = DocNode(&KindAndDocs[size_t(Type::Float)]);
  305. N.Float = V;
  306. return N;
  307. }
  308. /// Create a String node associated with this Document. If !Copy, the passed
  309. /// string must remain valid for the lifetime of the Document.
  310. DocNode getNode(StringRef V, bool Copy = false) {
  311. if (Copy)
  312. V = addString(V);
  313. auto N = DocNode(&KindAndDocs[size_t(Type::String)]);
  314. N.Raw = V;
  315. return N;
  316. }
  317. /// Create a String node associated with this Document. If !Copy, the passed
  318. /// string must remain valid for the lifetime of the Document.
  319. DocNode getNode(const char *V, bool Copy = false) {
  320. return getNode(StringRef(V), Copy);
  321. }
  322. /// Create an empty Map node associated with this Document.
  323. MapDocNode getMapNode() {
  324. auto N = DocNode(&KindAndDocs[size_t(Type::Map)]);
  325. Maps.push_back(std::unique_ptr<DocNode::MapTy>(new DocNode::MapTy));
  326. N.Map = Maps.back().get();
  327. return N.getMap();
  328. }
  329. /// Create an empty Array node associated with this Document.
  330. ArrayDocNode getArrayNode() {
  331. auto N = DocNode(&KindAndDocs[size_t(Type::Array)]);
  332. Arrays.push_back(std::unique_ptr<DocNode::ArrayTy>(new DocNode::ArrayTy));
  333. N.Array = Arrays.back().get();
  334. return N.getArray();
  335. }
  336. /// Read a document from a binary msgpack blob, merging into anything already
  337. /// in the Document. The blob data must remain valid for the lifetime of this
  338. /// Document (because a string object in the document contains a StringRef
  339. /// into the original blob). If Multi, then this sets root to an array and
  340. /// adds top-level objects to it. If !Multi, then it only reads a single
  341. /// top-level object, even if there are more, and sets root to that. Returns
  342. /// false if failed due to illegal format or merge error.
  343. ///
  344. /// The Merger arg is a callback function that is called when the merge has a
  345. /// conflict, that is, it is trying to set an item that is already set. If the
  346. /// conflict cannot be resolved, the callback function returns -1. If the
  347. /// conflict can be resolved, the callback returns a non-negative number and
  348. /// sets *DestNode to the resolved node. The returned non-negative number is
  349. /// significant only for an array node; it is then the array index to start
  350. /// populating at. That allows Merger to choose whether to merge array
  351. /// elements (returns 0) or append new elements (returns existing size).
  352. ///
  353. /// If SrcNode is an array or map, the resolution must be that *DestNode is an
  354. /// array or map respectively, although it could be the array or map
  355. /// (respectively) that was already there. MapKey is the key if *DestNode is a
  356. /// map entry, a nil node otherwise.
  357. ///
  358. /// The default for Merger is to disallow any conflict.
  359. bool readFromBlob(
  360. StringRef Blob, bool Multi,
  361. function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)>
  362. Merger = [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {
  363. return -1;
  364. });
  365. /// Write a MsgPack document to a binary MsgPack blob.
  366. void writeToBlob(std::string &Blob);
  367. /// Copy a string into the Document's strings list, and return the copy that
  368. /// is owned by the Document.
  369. StringRef addString(StringRef S) {
  370. Strings.push_back(std::unique_ptr<char[]>(new char[S.size()]));
  371. memcpy(&Strings.back()[0], S.data(), S.size());
  372. return StringRef(&Strings.back()[0], S.size());
  373. }
  374. /// Set whether YAML output uses hex for UInt. Default off.
  375. void setHexMode(bool Val = true) { HexMode = Val; }
  376. /// Get Hexmode flag.
  377. bool getHexMode() const { return HexMode; }
  378. /// Convert MsgPack Document to YAML text.
  379. void toYAML(raw_ostream &OS);
  380. /// Read YAML text into the MsgPack document. Returns false on failure.
  381. bool fromYAML(StringRef S);
  382. };
  383. } // namespace msgpack
  384. } // namespace llvm
  385. #endif // LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
  386. #ifdef __GNUC__
  387. #pragma GCC diagnostic pop
  388. #endif