1 //===-- MsgPackDocument.h - MsgPack Document --------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
15 //===----------------------------------------------------------------------===//
17 #ifndef LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
18 #define LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H
20 #include "llvm/BinaryFormat/MsgPackReader.h"
30 /// The kind of a DocNode and its owning Document.
31 struct KindAndDocument
{
36 /// A node in a MsgPack Document. This is a simple copyable and
37 /// passable-by-value type that does not own any memory.
42 typedef std::map
<DocNode
, DocNode
> MapTy
;
43 typedef std::vector
<DocNode
> ArrayTy
;
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
50 const KindAndDocument
*KindAndDoc
;
53 // The union of different values.
65 DocNode() : KindAndDoc(nullptr) {}
68 bool isMap() const { return getKind() == Type::Map
; }
69 bool isArray() const { return getKind() == Type::Array
; }
70 bool isScalar() const { return !isMap() && !isArray(); }
71 bool isString() const { return getKind() == Type::String
; }
74 bool isEmpty() const { return !KindAndDoc
; }
75 Type
getKind() const { return KindAndDoc
->Kind
; }
76 Document
*getDocument() const { return KindAndDoc
->Doc
; }
79 assert(getKind() == Type::Int
);
84 assert(getKind() == Type::UInt
);
89 assert(getKind() == Type::Boolean
);
94 assert(getKind() == Type::Float
);
98 int64_t getInt() const {
99 assert(getKind() == Type::Int
);
103 uint64_t getUInt() const {
104 assert(getKind() == Type::UInt
);
108 bool getBool() const {
109 assert(getKind() == Type::Boolean
);
113 double getFloat() const {
114 assert(getKind() == Type::Float
);
118 StringRef
getString() const {
119 assert(getKind() == Type::String
);
123 /// Get an ArrayDocNode for an array node. If Convert, convert the node to an
124 /// array node if necessary.
125 ArrayDocNode
&getArray(bool Convert
= false) {
126 if (getKind() != Type::Array
) {
130 // This could be a static_cast, except ArrayDocNode is a forward reference.
131 return *reinterpret_cast<ArrayDocNode
*>(this);
134 /// Get a MapDocNode for a map node. If Convert, convert the node to a map
135 /// node if necessary.
136 MapDocNode
&getMap(bool Convert
= false) {
137 if (getKind() != Type::Map
) {
141 // This could be a static_cast, except MapDocNode is a forward reference.
142 return *reinterpret_cast<MapDocNode
*>(this);
145 /// Comparison operator, used for map keys.
146 friend bool operator<(const DocNode
&Lhs
, const DocNode
&Rhs
) {
147 // This has to cope with one or both of the nodes being default-constructed,
148 // such that KindAndDoc is not set.
149 if (Lhs
.KindAndDoc
!= Rhs
.KindAndDoc
) {
154 return (unsigned)Lhs
.getKind() < (unsigned)Rhs
.getKind();
156 switch (Lhs
.getKind()) {
158 return Lhs
.Int
< Rhs
.Int
;
160 return Lhs
.UInt
< Rhs
.UInt
;
164 return Lhs
.Bool
< Rhs
.Bool
;
166 return Lhs
.Float
< Rhs
.Float
;
169 return Lhs
.Raw
< Rhs
.Raw
;
171 llvm_unreachable("bad map key type");
175 /// Equality operator
176 friend bool operator==(const DocNode
&Lhs
, const DocNode
&Rhs
) {
177 return !(Lhs
< Rhs
) && !(Rhs
< Lhs
);
180 /// Convert this node to a string, assuming it is scalar.
181 std::string
toString() const;
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
= "");
189 // Private constructor setting KindAndDoc, used by methods in Document.
190 DocNode(const KindAndDocument
*KindAndDoc
) : KindAndDoc(KindAndDoc
) {}
192 void convertToArray();
196 /// A DocNode that is a map.
197 class MapDocNode
: public DocNode
{
200 MapDocNode(DocNode
&N
) : DocNode(N
) { assert(getKind() == Type::Map
); }
202 // Map access methods.
203 size_t size() const { return Map
->size(); }
204 bool empty() const { return !size(); }
205 MapTy::iterator
begin() { return Map
->begin(); }
206 MapTy::iterator
end() { return Map
->end(); }
207 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
211 DocNode
&operator[](StringRef S
);
213 DocNode
&operator[](DocNode Key
);
216 /// A DocNode that is an array.
217 class ArrayDocNode
: public DocNode
{
220 ArrayDocNode(DocNode
&N
) : DocNode(N
) { assert(getKind() == Type::Array
); }
222 // Array access methods.
223 size_t size() const { return Array
->size(); }
224 bool empty() const { return !size(); }
225 ArrayTy::iterator
begin() { return Array
->begin(); }
226 ArrayTy::iterator
end() { return Array
->end(); }
227 void push_back(DocNode N
) {
228 assert(N
.getDocument() == getDocument());
232 /// Element access. This extends the array if necessary.
233 DocNode
&operator[](size_t Index
);
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.
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
;
246 // The root node of the document.
249 // The KindAndDocument structs pointed to by nodes in the document.
250 KindAndDocument KindAndDocs
[size_t(Type::Extension
) + 1];
252 // Whether YAML output uses hex for UInt.
253 bool HexMode
= false;
258 for (unsigned T
= 0; T
!= size_t(Type::Extension
) + 1; ++T
)
259 KindAndDocs
[T
] = {this, Type(T
)};
262 /// Get ref to the document's root element.
263 DocNode
&getRoot() { return Root
; }
265 /// Restore the Document to an empty state.
266 void clear() { getRoot() = getNode(); }
268 /// Create a nil node associated with this Document.
270 auto N
= DocNode(&KindAndDocs
[size_t(Type::Nil
)]);
274 /// Create an Int node associated with this Document.
275 DocNode
getNode(int64_t V
) {
276 auto N
= DocNode(&KindAndDocs
[size_t(Type::Int
)]);
281 /// Create an Int node associated with this Document.
282 DocNode
getNode(int V
) {
283 auto N
= DocNode(&KindAndDocs
[size_t(Type::Int
)]);
288 /// Create a UInt node associated with this Document.
289 DocNode
getNode(uint64_t V
) {
290 auto N
= DocNode(&KindAndDocs
[size_t(Type::UInt
)]);
295 /// Create a UInt node associated with this Document.
296 DocNode
getNode(unsigned V
) {
297 auto N
= DocNode(&KindAndDocs
[size_t(Type::UInt
)]);
302 /// Create a Boolean node associated with this Document.
303 DocNode
getNode(bool V
) {
304 auto N
= DocNode(&KindAndDocs
[size_t(Type::Boolean
)]);
309 /// Create a Float node associated with this Document.
310 DocNode
getNode(double V
) {
311 auto N
= DocNode(&KindAndDocs
[size_t(Type::Float
)]);
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 DocNode
getNode(StringRef V
, bool Copy
= false) {
321 auto N
= DocNode(&KindAndDocs
[size_t(Type::String
)]);
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 DocNode
getNode(const char *V
, bool Copy
= false) {
329 return getNode(StringRef(V
), Copy
);
332 /// Create an empty Map node associated with this Document.
333 MapDocNode
getMapNode() {
334 auto N
= DocNode(&KindAndDocs
[size_t(Type::Map
)]);
335 Maps
.push_back(std::unique_ptr
<DocNode::MapTy
>(new DocNode::MapTy
));
336 N
.Map
= Maps
.back().get();
340 /// Create an empty Array node associated with this Document.
341 ArrayDocNode
getArrayNode() {
342 auto N
= DocNode(&KindAndDocs
[size_t(Type::Array
)]);
343 Arrays
.push_back(std::unique_ptr
<DocNode::ArrayTy
>(new DocNode::ArrayTy
));
344 N
.Array
= Arrays
.back().get();
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
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
);
358 /// Write a MsgPack document to a binary MsgPack blob.
359 void writeToBlob(std::string
&Blob
);
361 /// Copy a string into the Document's strings list, and return the copy that
362 /// is owned by the Document.
363 StringRef
addString(StringRef S
) {
364 Strings
.push_back(std::unique_ptr
<char[]>(new char[S
.size()]));
365 memcpy(&Strings
.back()[0], S
.data(), S
.size());
366 return StringRef(&Strings
.back()[0], S
.size());
369 /// Set whether YAML output uses hex for UInt. Default off.
370 void setHexMode(bool Val
= true) { HexMode
= Val
; }
372 /// Get Hexmode flag.
373 bool getHexMode() const { return HexMode
; }
375 /// Convert MsgPack Document to YAML text.
376 void toYAML(raw_ostream
&OS
);
378 /// Read YAML text into the MsgPack document. Returns false on failure.
379 bool fromYAML(StringRef S
);
382 } // namespace msgpack
385 #endif // LLVM_BINARYFORMAT_MSGPACKDOCUMENT_H