blob: d2dbb07af25667e0636e1f3cca85fa4ce7e0d778 [file] [log] [blame]
Eric Christopher9cad53c2013-04-03 18:31:38 +00001//===-- StreamWriter.h ----------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Benjamin Kramera7c40ef2014-08-13 16:26:38 +000010#ifndef LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H
11#define LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H
Eric Christopher9cad53c2013-04-03 18:31:38 +000012
13#include "llvm/ADT/ArrayRef.h"
Eric Christopher9cad53c2013-04-03 18:31:38 +000014#include "llvm/ADT/SmallVector.h"
Chandler Carruth07baed52014-01-13 08:04:33 +000015#include "llvm/ADT/StringRef.h"
Eric Christopher9cad53c2013-04-03 18:31:38 +000016#include "llvm/Support/DataTypes.h"
17#include "llvm/Support/Endian.h"
18#include "llvm/Support/raw_ostream.h"
19#include <algorithm>
20
21using namespace llvm;
22using namespace llvm::support;
23
24namespace llvm {
25
26template<typename T>
27struct EnumEntry {
28 StringRef Name;
29 T Value;
30};
31
32struct HexNumber {
33 // To avoid sign-extension we have to explicitly cast to the appropriate
34 // unsigned type. The overloads are here so that every type that is implicitly
35 // convertible to an integer (including enums and endian helpers) can be used
36 // without requiring type traits or call-site changes.
Matthias Braun7f472722015-10-17 00:08:45 +000037 HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) { }
38 HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) { }
39 HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) { }
40 HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) { }
41 HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) { }
42 HexNumber(signed long long Value) : Value(static_cast<unsigned long long>(Value)) { }
43 HexNumber(unsigned char Value) : Value(Value) { }
44 HexNumber(unsigned short Value) : Value(Value) { }
45 HexNumber(unsigned int Value) : Value(Value) { }
46 HexNumber(unsigned long Value) : Value(Value) { }
47 HexNumber(unsigned long long Value) : Value(Value) { }
Eric Christopher9cad53c2013-04-03 18:31:38 +000048 uint64_t Value;
49};
50
51raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value);
52
53class StreamWriter {
54public:
55 StreamWriter(raw_ostream &OS)
56 : OS(OS)
57 , IndentLevel(0) {
58 }
59
60 void flush() {
61 OS.flush();
62 }
63
64 void indent(int Levels = 1) {
65 IndentLevel += Levels;
66 }
67
68 void unindent(int Levels = 1) {
69 IndentLevel = std::max(0, IndentLevel - Levels);
70 }
71
72 void printIndent() {
73 for (int i = 0; i < IndentLevel; ++i)
74 OS << " ";
75 }
76
77 template<typename T>
78 HexNumber hex(T Value) {
79 return HexNumber(Value);
80 }
81
82 template<typename T, typename TEnum>
83 void printEnum(StringRef Label, T Value,
84 ArrayRef<EnumEntry<TEnum> > EnumValues) {
85 StringRef Name;
86 bool Found = false;
Simon Atanasyan883b44e2014-04-20 21:05:30 +000087 for (const auto &EnumItem : EnumValues) {
88 if (EnumItem.Value == Value) {
89 Name = EnumItem.Name;
Eric Christopher9cad53c2013-04-03 18:31:38 +000090 Found = true;
91 break;
92 }
93 }
94
95 if (Found) {
96 startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
97 } else {
98 startLine() << Label << ": " << hex(Value) << "\n";
99 }
100 }
101
Simon Atanasyan67bdc792015-05-07 14:04:44 +0000102 template <typename T, typename TFlag>
103 void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
Simon Atanasyan40e7eb12015-05-08 07:04:59 +0000104 TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
105 TFlag EnumMask3 = {}) {
Eric Christopher9cad53c2013-04-03 18:31:38 +0000106 typedef EnumEntry<TFlag> FlagEntry;
107 typedef SmallVector<FlagEntry, 10> FlagVector;
108 FlagVector SetFlags;
109
Simon Atanasyan883b44e2014-04-20 21:05:30 +0000110 for (const auto &Flag : Flags) {
111 if (Flag.Value == 0)
Eric Christopher9cad53c2013-04-03 18:31:38 +0000112 continue;
113
Simon Atanasyan67bdc792015-05-07 14:04:44 +0000114 TFlag EnumMask{};
115 if (Flag.Value & EnumMask1)
116 EnumMask = EnumMask1;
117 else if (Flag.Value & EnumMask2)
118 EnumMask = EnumMask2;
Simon Atanasyan40e7eb12015-05-08 07:04:59 +0000119 else if (Flag.Value & EnumMask3)
120 EnumMask = EnumMask3;
Simon Atanasyan883b44e2014-04-20 21:05:30 +0000121 bool IsEnum = (Flag.Value & EnumMask) != 0;
122 if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
123 (IsEnum && (Value & EnumMask) == Flag.Value)) {
124 SetFlags.push_back(Flag);
Eric Christopher9cad53c2013-04-03 18:31:38 +0000125 }
126 }
127
128 std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
129
130 startLine() << Label << " [ (" << hex(Value) << ")\n";
Simon Atanasyan883b44e2014-04-20 21:05:30 +0000131 for (const auto &Flag : SetFlags) {
132 startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
Eric Christopher9cad53c2013-04-03 18:31:38 +0000133 }
134 startLine() << "]\n";
135 }
136
137 template<typename T>
138 void printFlags(StringRef Label, T Value) {
139 startLine() << Label << " [ (" << hex(Value) << ")\n";
140 uint64_t Flag = 1;
141 uint64_t Curr = Value;
142 while (Curr > 0) {
143 if (Curr & 1)
144 startLine() << " " << hex(Flag) << "\n";
145 Curr >>= 1;
146 Flag <<= 1;
147 }
148 startLine() << "]\n";
149 }
150
151 void printNumber(StringRef Label, uint64_t Value) {
152 startLine() << Label << ": " << Value << "\n";
153 }
154
155 void printNumber(StringRef Label, uint32_t Value) {
156 startLine() << Label << ": " << Value << "\n";
157 }
158
159 void printNumber(StringRef Label, uint16_t Value) {
160 startLine() << Label << ": " << Value << "\n";
161 }
162
163 void printNumber(StringRef Label, uint8_t Value) {
164 startLine() << Label << ": " << unsigned(Value) << "\n";
165 }
166
167 void printNumber(StringRef Label, int64_t Value) {
168 startLine() << Label << ": " << Value << "\n";
169 }
170
171 void printNumber(StringRef Label, int32_t Value) {
172 startLine() << Label << ": " << Value << "\n";
173 }
174
175 void printNumber(StringRef Label, int16_t Value) {
176 startLine() << Label << ": " << Value << "\n";
177 }
178
179 void printNumber(StringRef Label, int8_t Value) {
180 startLine() << Label << ": " << int(Value) << "\n";
181 }
182
Saleem Abdulrasool6ba36dc2014-06-04 15:47:11 +0000183 void printBoolean(StringRef Label, bool Value) {
184 startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
185 }
186
Michael J. Spencer20546ff2015-07-09 22:32:24 +0000187 template <typename T>
188 void printList(StringRef Label, const T &List) {
Saleem Abdulrasool15d16d82014-01-30 04:46:33 +0000189 startLine() << Label << ": [";
190 bool Comma = false;
Simon Atanasyan883b44e2014-04-20 21:05:30 +0000191 for (const auto &Item : List) {
Saleem Abdulrasool15d16d82014-01-30 04:46:33 +0000192 if (Comma)
193 OS << ", ";
Simon Atanasyan883b44e2014-04-20 21:05:30 +0000194 OS << Item;
Saleem Abdulrasool15d16d82014-01-30 04:46:33 +0000195 Comma = true;
196 }
197 OS << "]\n";
198 }
199
Igor Kudrin496fb2f2015-10-14 12:11:50 +0000200 template <typename T>
201 void printHexList(StringRef Label, const T &List) {
202 startLine() << Label << ": [";
203 bool Comma = false;
204 for (const auto &Item : List) {
205 if (Comma)
206 OS << ", ";
207 OS << hex(Item);
208 Comma = true;
209 }
210 OS << "]\n";
211 }
212
Eric Christopher9cad53c2013-04-03 18:31:38 +0000213 template<typename T>
214 void printHex(StringRef Label, T Value) {
215 startLine() << Label << ": " << hex(Value) << "\n";
216 }
217
218 template<typename T>
219 void printHex(StringRef Label, StringRef Str, T Value) {
220 startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
221 }
222
223 void printString(StringRef Label, StringRef Value) {
224 startLine() << Label << ": " << Value << "\n";
225 }
226
227 void printString(StringRef Label, const std::string &Value) {
228 startLine() << Label << ": " << Value << "\n";
229 }
230
231 template<typename T>
232 void printNumber(StringRef Label, StringRef Str, T Value) {
233 startLine() << Label << ": " << Str << " (" << Value << ")\n";
234 }
235
236 void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
237 printBinaryImpl(Label, Str, Value, false);
238 }
239
240 void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
Craig Toppere1d12942014-08-27 05:25:25 +0000241 auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
242 Value.size());
Eric Christopher9cad53c2013-04-03 18:31:38 +0000243 printBinaryImpl(Label, Str, V, false);
244 }
245
246 void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
247 printBinaryImpl(Label, StringRef(), Value, false);
248 }
249
250 void printBinary(StringRef Label, ArrayRef<char> Value) {
Craig Toppere1d12942014-08-27 05:25:25 +0000251 auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
252 Value.size());
Eric Christopher9cad53c2013-04-03 18:31:38 +0000253 printBinaryImpl(Label, StringRef(), V, false);
254 }
255
256 void printBinary(StringRef Label, StringRef Value) {
Craig Toppere1d12942014-08-27 05:25:25 +0000257 auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
258 Value.size());
Eric Christopher9cad53c2013-04-03 18:31:38 +0000259 printBinaryImpl(Label, StringRef(), V, false);
260 }
261
262 void printBinaryBlock(StringRef Label, StringRef Value) {
Craig Toppere1d12942014-08-27 05:25:25 +0000263 auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
264 Value.size());
Eric Christopher9cad53c2013-04-03 18:31:38 +0000265 printBinaryImpl(Label, StringRef(), V, true);
266 }
267
268 raw_ostream& startLine() {
269 printIndent();
270 return OS;
271 }
272
273 raw_ostream& getOStream() {
274 return OS;
275 }
276
277private:
278 template<typename T>
279 static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) {
280 return lhs.Name < rhs.Name;
281 }
282
283 void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
284 bool Block);
285
286 raw_ostream &OS;
287 int IndentLevel;
288};
289
290struct DictScope {
291 DictScope(StreamWriter& W, StringRef N) : W(W) {
292 W.startLine() << N << " {\n";
293 W.indent();
294 }
295
296 ~DictScope() {
297 W.unindent();
298 W.startLine() << "}\n";
299 }
300
301 StreamWriter& W;
302};
303
304struct ListScope {
305 ListScope(StreamWriter& W, StringRef N) : W(W) {
306 W.startLine() << N << " [\n";
307 W.indent();
308 }
309
310 ~ListScope() {
311 W.unindent();
312 W.startLine() << "]\n";
313 }
314
315 StreamWriter& W;
316};
317
318} // namespace llvm
319
320#endif