OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/debug/trace_event_value.h" | |
6 #include "base/json/json_writer.h" | |
7 #include "base/json/string_escape.h" | |
8 #include "base/strings/stringprintf.h" | |
9 | |
10 namespace base { | |
11 namespace debug { | |
12 | |
13 TracedValue::TracedValue() { | |
14 } | |
15 | |
16 TracedValue::~TracedValue() { | |
17 } | |
18 | |
19 void TracedValue::AppendAsTraceFormat(std::string* out) const { | |
20 DCHECK(begin_opcodes_.empty()) << "This TracedValue is not ready to be \ | |
rterrazas
2013/08/11 21:05:08
Also added this check, as I think it can be helpfu
| |
21 written, everything that was opened must be closed."; | |
22 | |
23 // Used to keep track of the opening opcode. | |
24 std::stack<Opcode> begin_opcode_stack; | |
25 // This is needed in case of nested structures. | |
26 std::stack<int> element_count_stack; | |
27 PickleIterator iter(pickle_); | |
28 | |
29 int opcode; | |
30 bool read_succeeded = pickle_.ReadInt(&iter, &opcode); | |
31 while (read_succeeded) { | |
32 // Append comma if necessary. | |
33 if (!begin_opcode_stack.empty()) { | |
34 DCHECK(!element_count_stack.empty()); | |
35 AppendComma(out, begin_opcode_stack.top(), | |
36 static_cast<Opcode>(opcode), &element_count_stack.top()); | |
37 } | |
38 | |
39 switch (opcode) { | |
40 case BEGIN_ARRAY: | |
41 case BEGIN_DICTIONARY: | |
42 { | |
43 // Initialize the count for the current datastructure. | |
44 element_count_stack.push(0); | |
45 begin_opcode_stack.push(static_cast<Opcode>(opcode)); | |
46 StringAppendF(out, opcode == BEGIN_DICTIONARY ? "{" : "["); | |
47 break; | |
48 } | |
49 case END_DICTIONARY: | |
50 case END_ARRAY: | |
51 { | |
52 begin_opcode_stack.pop(); | |
53 element_count_stack.pop(); | |
54 StringAppendF(out, opcode == END_DICTIONARY ? "}" : "]"); | |
55 break; | |
56 } | |
57 case KEY_AS_RAW_POINTER: | |
58 { | |
59 AppendKeyAsRawPointer(out, &iter); | |
60 break; | |
61 } | |
62 case VALUE_AS_RAW_POINTER: | |
63 { | |
64 AppendValueAsRawPointer(out, &iter); | |
65 break; | |
66 } | |
67 case VALUE_AS_STRING: | |
68 { | |
69 AppendValueAsString(out, &iter); | |
70 break; | |
71 } | |
72 case INT32_VALUE: | |
73 { | |
74 AppendValueAsInt32(out, &iter); | |
75 break; | |
76 } | |
77 case INT64_VALUE: | |
78 { | |
79 AppendValueAsInt64(out, &iter); | |
80 break; | |
81 } | |
82 case UINT32_VALUE: | |
83 { | |
84 AppendValueAsUInt32(out, &iter); | |
85 break; | |
86 } | |
87 case UINT64_VALUE: | |
88 { | |
89 AppendValueAsUInt64(out, &iter); | |
90 break; | |
91 } | |
92 case FLOAT_VALUE: | |
93 { | |
94 AppendValueAsFloat(out, &iter); | |
95 break; | |
96 } | |
97 case BOOL_VALUE: | |
98 { | |
99 AppendValueAsBool(out, &iter); | |
100 break; | |
101 } | |
102 default: | |
103 NOTREACHED() << "Don't know what to write, opcode=" << opcode; | |
104 } | |
105 read_succeeded = pickle_.ReadInt(&iter, &opcode); | |
106 } | |
107 DCHECK(begin_opcode_stack.empty()); | |
108 } | |
109 | |
110 void TracedValue::BeginDictionary() { | |
111 // Cannot begin a dictionary within a dictionary. It can be the value of an | |
112 // entry, for that, use PushDictionary(). | |
113 CheckNotWithinDictionary(); | |
114 begin_opcodes_.push(BEGIN_DICTIONARY); | |
115 pickle_.WriteInt(BEGIN_DICTIONARY); | |
116 } | |
117 | |
118 void TracedValue::EndDictionary() { | |
119 DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.top()); | |
120 begin_opcodes_.pop(); | |
121 pickle_.WriteInt(END_DICTIONARY); | |
122 } | |
123 | |
124 void TracedValue::BeginArray() { | |
125 // Cannot begin an array within a dictionary. It can be the value of an entry, | |
126 // for that, use PushArray(). | |
127 CheckNotWithinDictionary(); | |
128 begin_opcodes_.push(BEGIN_ARRAY); | |
129 pickle_.WriteInt(BEGIN_ARRAY); | |
130 } | |
131 | |
132 void TracedValue::EndArray() { | |
133 DCHECK_EQ(BEGIN_ARRAY, begin_opcodes_.top()); | |
134 begin_opcodes_.pop(); | |
135 pickle_.WriteInt(END_ARRAY); | |
136 } | |
137 | |
138 void TracedValue::PushDictionary(const char* key_in_parent_dict) { | |
139 // Named dictionaries are properties of dictionaries, the name is the key. | |
140 DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.top()); | |
141 PushKeyToPickle(key_in_parent_dict); | |
142 begin_opcodes_.push(BEGIN_DICTIONARY); | |
143 pickle_.WriteInt(BEGIN_DICTIONARY); | |
144 } | |
145 | |
146 void TracedValue::PushArray(const char* key_in_parent_dict) { | |
147 // Named arrays are properties of dictionaries, and the key of such property | |
148 // is key_in_parent_dict. | |
149 DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.top()); | |
150 PushKeyToPickle(key_in_parent_dict); | |
151 begin_opcodes_.push(BEGIN_ARRAY); | |
152 pickle_.WriteInt(BEGIN_ARRAY); | |
153 } | |
154 | |
155 void TracedValue::BeginDictionaryEntry() { | |
156 DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.top()); | |
157 // Make a note that we've started a dictionary entry. | |
158 begin_opcodes_.push(BEGIN_DICTIONARY_ENTRY); | |
159 } | |
160 | |
161 void TracedValue::EndDictionaryEntry() { | |
162 DCHECK_EQ(BEGIN_DICTIONARY_ENTRY, begin_opcodes_.top()); | |
163 begin_opcodes_.pop(); | |
164 } | |
165 | |
166 // These methods push stuff in the pickle either in dictionary or array | |
167 // blocks, it's the up to the publicaly exposed caller to check the state. | |
168 void TracedValue::PushKeyToPickle(const char* key) { | |
169 pickle_.WriteInt(KEY_AS_RAW_POINTER); | |
170 uintptr_t key_ptr = reinterpret_cast<uintptr_t>(key); | |
171 pickle_.WriteUIntPtr(key_ptr); | |
172 } | |
173 | |
174 void TracedValue::PushValueToPickle(const char* value) { | |
175 pickle_.WriteInt(VALUE_AS_RAW_POINTER); | |
176 uintptr_t value_ptr = reinterpret_cast<uintptr_t>(value); | |
177 pickle_.WriteUIntPtr(value_ptr); | |
178 } | |
179 | |
180 void TracedValue::PushValueToPickle(const std::string& value) { | |
181 pickle_.WriteInt(VALUE_AS_STRING); | |
182 pickle_.WriteString(value); | |
183 } | |
184 | |
185 void TracedValue::PushValueToPickle(int value) { | |
186 pickle_.WriteInt(INT32_VALUE); | |
187 pickle_.WriteInt(value); | |
188 } | |
189 | |
190 void TracedValue::PushValueToPickle(int64 value) { | |
191 pickle_.WriteInt(INT64_VALUE); | |
192 pickle_.WriteInt64(value); | |
193 } | |
194 | |
195 void TracedValue::PushValueToPickle(uint32 value) { | |
196 pickle_.WriteInt(UINT32_VALUE); | |
197 pickle_.WriteUInt32(value); | |
198 } | |
199 | |
200 void TracedValue::PushValueToPickle(uint64 value) { | |
201 pickle_.WriteInt(UINT64_VALUE); | |
202 pickle_.WriteUInt64(value); | |
203 } | |
204 | |
205 void TracedValue::PushValueToPickle(float value) { | |
206 pickle_.WriteInt(FLOAT_VALUE); | |
207 pickle_.WriteFloat(value); | |
208 } | |
209 | |
210 void TracedValue::PushValueToPickle(bool value) { | |
211 pickle_.WriteInt(BOOL_VALUE); | |
212 pickle_.WriteBool(value); | |
213 } | |
214 | |
215 void TracedValue::PushValueToPickle(const TracedObject& value) { | |
216 // The definition of what gets pushed is in the implementation of | |
217 // TracedObject::PushInto(). | |
218 value.PushInto(this); | |
219 } | |
220 | |
221 // Helper methods used in AppendAsTraceFormat() | |
222 void TracedValue::AppendKeyAsRawPointer(std::string* out, | |
223 PickleIterator* iter) const { | |
224 uintptr_t out_ptr; | |
225 pickle_.ReadUIntPtr(iter, &out_ptr); | |
226 const char* key = reinterpret_cast<char*>(out_ptr); | |
227 JsonDoubleQuote(std::string(key), true, out); | |
228 out->append(":"); | |
229 } | |
230 | |
231 void TracedValue::AppendValueAsRawPointer(std::string* out, | |
232 PickleIterator* iter) const { | |
233 uintptr_t out_ptr; | |
234 pickle_.ReadUIntPtr(iter, &out_ptr); | |
235 const char* value = reinterpret_cast<char*>(out_ptr); | |
236 JsonDoubleQuote(std::string(value), true, out); | |
237 } | |
238 | |
239 void TracedValue::AppendValueAsString(std::string* out, | |
240 PickleIterator* iter) const { | |
241 std::string out_string; | |
242 pickle_.ReadString(iter, &out_string); | |
243 JsonDoubleQuote(out_string, true, out); | |
244 } | |
245 | |
246 void TracedValue::AppendValueAsInt32(std::string* out, | |
247 PickleIterator* iter) const { | |
248 int out_int; | |
249 pickle_.ReadInt(iter, &out_int); | |
250 StringAppendF(out, "%d", out_int); | |
251 } | |
252 | |
253 void TracedValue::AppendValueAsInt64(std::string* out, | |
254 PickleIterator* iter) const { | |
255 int64 out_int64; | |
256 pickle_.ReadInt64(iter, &out_int64); | |
257 StringAppendF(out, "%" PRId64, out_int64); | |
258 } | |
259 | |
260 | |
261 void TracedValue::AppendValueAsUInt32(std::string* out, | |
262 PickleIterator* iter) const { | |
263 uint32 out_uint32; | |
264 pickle_.ReadUInt32(iter, &out_uint32); | |
265 StringAppendF(out, "%u", out_uint32); | |
266 } | |
267 | |
268 void TracedValue::AppendValueAsUInt64(std::string* out, | |
269 PickleIterator* iter) const { | |
270 uint64 out_uint64; | |
271 pickle_.ReadUInt64(iter, &out_uint64); | |
272 StringAppendF(out, "%" PRIu64, out_uint64); | |
273 } | |
274 | |
275 void TracedValue::AppendValueAsFloat(std::string* out, | |
276 PickleIterator* iter) const { | |
277 float out_float; | |
278 pickle_.ReadFloat(iter, &out_float); | |
279 out->append(base::JSONWriter::DoubleToFormattedString(out_float, false)); | |
280 } | |
281 | |
282 void TracedValue::AppendValueAsBool(std::string* out, | |
283 PickleIterator* iter) const { | |
284 bool out_bool; | |
285 pickle_.ReadBool(iter, &out_bool); | |
286 StringAppendF(out, "%s", out_bool ? "true" : "false"); | |
287 } | |
288 | |
289 void TracedValue::CheckNotWithinDictionary() { | |
290 if (!begin_opcodes_.empty()) | |
dsinclair
2013/08/12 13:34:40
if (begin_opcodes_.empty())
return;
DCHECK_NE(B
| |
291 DCHECK_NE(BEGIN_DICTIONARY, begin_opcodes_.top()); | |
292 } | |
293 | |
294 // Static. | |
295 void TracedValue::AppendComma(std::string* out, Opcode begin_opcode, | |
296 Opcode current_opcode, int* element_count) { | |
297 // For arrays, we want to append a comma when the element count within | |
298 // the array is greater than zero and we are not about to close the array. | |
299 if (begin_opcode == BEGIN_ARRAY && current_opcode != END_ARRAY && | |
300 (*element_count)++ > 0) { | |
301 StringAppendF(out, ","); | |
302 return; | |
303 } | |
304 // For dictionaries, we want to append a comma when the element count within | |
305 // the dictionary is greater than zero AND we're about to append is a key. | |
306 if (begin_opcode == BEGIN_DICTIONARY && | |
307 current_opcode == KEY_AS_RAW_POINTER && | |
308 (*element_count)++ > 0) { | |
309 StringAppendF(out, ","); | |
310 } | |
311 } | |
312 | |
313 } // namespace debug | |
314 } // namespace base | |
315 | |
OLD | NEW |