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