Coverage Report

Created: 2019-07-24 05:18

/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