Index: base/debug/trace_event_value.cc |
diff --git a/base/debug/trace_event_value.cc b/base/debug/trace_event_value.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e907d652f91ab393f9a33ee3cd64f8c8772d1875 |
--- /dev/null |
+++ b/base/debug/trace_event_value.cc |
@@ -0,0 +1,290 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/debug/trace_event_value.h" |
+#include "base/json/json_writer.h" |
+#include "base/json/string_escape.h" |
+#include "base/strings/stringprintf.h" |
+ |
+namespace base { |
+namespace debug { |
+ |
+TracedValue::TracedValue() { |
+} |
+ |
+TracedValue::~TracedValue() { |
+} |
+ |
+void TracedValue::AppendAsTraceFormat(std::string* out) const { |
+ // Used to keep track of the opening opcode. |
+ std::stack<Opcode> begin_opcode_stack; |
+ // This is needed in case of nested structures. |
+ std::stack<int> element_count_stack; |
+ PickleIterator iter(pickle_); |
+ |
+ int opcode; |
+ bool read_succeeded = pickle_.ReadInt(&iter, &opcode); |
+ while (read_succeeded) { |
+ // Append comma if necessary. |
+ if (!begin_opcode_stack.empty()) { |
+ DCHECK(!element_count_stack.empty()); |
+ AppendComma(out, begin_opcode_stack.top(), |
+ static_cast<Opcode>(opcode), &element_count_stack.top()); |
+ } |
+ |
+ switch (opcode) { |
+ case BEGIN_ARRAY: |
+ case BEGIN_DICTIONARY: |
+ { |
+ // Initialize the count for the current datastructure. |
+ element_count_stack.push(0); |
+ begin_opcode_stack.push(static_cast<Opcode>(opcode)); |
+ StringAppendF(out, opcode == BEGIN_DICTIONARY ? "{" : "["); |
+ break; |
+ } |
+ case END_DICTIONARY: |
+ case END_ARRAY: |
+ { |
+ begin_opcode_stack.pop(); |
+ element_count_stack.pop(); |
+ StringAppendF(out, opcode == END_DICTIONARY ? "}" : "]"); |
+ break; |
+ } |
+ case KEY_AS_RAW_POINTER: |
+ { |
+ AppendKeyAsRawPointer(out, &iter); |
+ break; |
+ } |
+ case VALUE_AS_RAW_POINTER: |
+ { |
+ AppendValueAsRawPointer(out, &iter); |
+ break; |
+ } |
+ case VALUE_AS_STRING: |
+ { |
+ AppendValueAsString(out, &iter); |
+ break; |
+ } |
+ case INT32_VALUE: |
+ { |
+ AppendValueAsInt32(out, &iter); |
+ break; |
+ } |
+ case INT64_VALUE: |
+ { |
+ AppendValueAsInt64(out, &iter); |
+ break; |
+ } |
+ case UINT32_VALUE: |
+ { |
+ AppendValueAsUInt32(out, &iter); |
+ break; |
+ } |
+ case UINT64_VALUE: |
+ { |
+ AppendValueAsUInt64(out, &iter); |
+ break; |
+ } |
+ case FLOAT_VALUE: |
+ { |
+ AppendValueAsFloat(out, &iter); |
+ break; |
+ } |
+ case BOOL_VALUE: |
+ { |
+ AppendValueAsBool(out, &iter); |
+ break; |
+ } |
+ default: |
+ NOTREACHED() << "Don't know what to write, opcode=" << opcode; |
+ } |
+ read_succeeded = pickle_.ReadInt(&iter, &opcode); |
+ } |
+ DCHECK(begin_opcode_stack.empty()); |
+} |
+ |
+void TracedValue::BeginDictionary() { |
+ begin_opcodes_.push(BEGIN_DICTIONARY); |
+ pickle_.WriteInt(BEGIN_DICTIONARY); |
+} |
+ |
+void TracedValue::PushDictionary(const char* key_in_parent_dict) { |
+ // Named dictionaries are properties of dictionaries, the name is the key. |
dsinclair
2013/08/08 14:07:28
The DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.to
rterrazas
2013/08/11 21:05:08
Done.
|
+ PushKeyToPickle(key_in_parent_dict); |
+ begin_opcodes_.push(BEGIN_DICTIONARY); |
+ pickle_.WriteInt(BEGIN_DICTIONARY); |
+} |
+ |
+void TracedValue::EndDictionary() { |
+ DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.top()); |
+ begin_opcodes_.pop(); |
+ pickle_.WriteInt(END_DICTIONARY); |
+} |
+ |
+void TracedValue::BeginArray() { |
+ begin_opcodes_.push(BEGIN_ARRAY); |
+ pickle_.WriteInt(BEGIN_ARRAY); |
+} |
+ |
+void TracedValue::PushArray(const char* key_in_parent_dict) { |
+ // Named arrays are properties of dictionaries, and the key of such property |
+ // is key_in_parent_dict. |
+ DCHECK_EQ(BEGIN_DICTIONARY, begin_opcodes_.top()); |
+ PushKeyToPickle(key_in_parent_dict); |
+ begin_opcodes_.push(BEGIN_ARRAY); |
+ pickle_.WriteInt(BEGIN_ARRAY); |
+} |
+ |
+void TracedValue::EndArray() { |
+ DCHECK_EQ(BEGIN_ARRAY, begin_opcodes_.top()); |
+ begin_opcodes_.pop(); |
+ |
+ pickle_.WriteInt(END_ARRAY); |
+} |
+ |
+// These methods push stuff in the pickle either in dictionary or array |
+// blocks, it's the up to the publicaly exposed caller to check the state. |
+void TracedValue::PushKeyToPickle(const char* key) { |
+ pickle_.WriteInt(KEY_AS_RAW_POINTER); |
+ uintptr_t key_ptr = reinterpret_cast<uintptr_t>(key); |
+ pickle_.WriteUIntPtr(key_ptr); |
+} |
+ |
+void TracedValue::PushValueToPickle(const char* value) { |
+ pickle_.WriteInt(VALUE_AS_RAW_POINTER); |
+ uintptr_t value_ptr = reinterpret_cast<uintptr_t>(value); |
+ pickle_.WriteUIntPtr(value_ptr); |
+} |
+ |
+void TracedValue::PushValueToPickle(const std::string& value) { |
+ pickle_.WriteInt(VALUE_AS_STRING); |
+ pickle_.WriteString(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(int value) { |
+ pickle_.WriteInt(INT32_VALUE); |
+ pickle_.WriteInt(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(int64 value) { |
+ pickle_.WriteInt(INT64_VALUE); |
+ pickle_.WriteInt64(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(uint32 value) { |
+ pickle_.WriteInt(UINT32_VALUE); |
+ pickle_.WriteUInt32(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(uint64 value) { |
+ pickle_.WriteInt(UINT64_VALUE); |
+ pickle_.WriteUInt64(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(float value) { |
+ pickle_.WriteInt(FLOAT_VALUE); |
+ pickle_.WriteFloat(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(bool value) { |
+ pickle_.WriteInt(BOOL_VALUE); |
+ pickle_.WriteBool(value); |
+} |
+ |
+void TracedValue::PushValueToPickle(const TracedObject& value) { |
+ // The definition of what gets pushed is in the implementation of |
+ // TracedObject::PushInto(). |
+ value.PushInto(this); |
+} |
+ |
+// Helper methods used in AppendAsTraceFormat() |
+void TracedValue::AppendKeyAsRawPointer(std::string* out, |
+ PickleIterator* iter) const { |
+ uintptr_t out_ptr; |
+ pickle_.ReadUIntPtr(iter, &out_ptr); |
+ const char* key = reinterpret_cast<char*>(out_ptr); |
+ JsonDoubleQuote(std::string(key), true, out); |
+ out->append(":"); |
+} |
+ |
+void TracedValue::AppendValueAsRawPointer(std::string* out, |
+ PickleIterator* iter) const { |
+ uintptr_t out_ptr; |
+ pickle_.ReadUIntPtr(iter, &out_ptr); |
+ const char* value = reinterpret_cast<char*>(out_ptr); |
+ JsonDoubleQuote(std::string(value), true, out); |
+} |
+ |
+void TracedValue::AppendValueAsString(std::string* out, |
+ PickleIterator* iter) const { |
+ std::string out_string; |
+ pickle_.ReadString(iter, &out_string); |
+ JsonDoubleQuote(out_string, true, out); |
+} |
+ |
+void TracedValue::AppendValueAsInt32(std::string* out, |
+ PickleIterator* iter) const { |
+ int out_int; |
+ pickle_.ReadInt(iter, &out_int); |
+ StringAppendF(out, "%d", out_int); |
+} |
+ |
+void TracedValue::AppendValueAsInt64(std::string* out, |
+ PickleIterator* iter) const { |
+ int64 out_int64; |
+ pickle_.ReadInt64(iter, &out_int64); |
+ StringAppendF(out, "%" PRId64, out_int64); |
+} |
+ |
+ |
+void TracedValue::AppendValueAsUInt32(std::string* out, |
+ PickleIterator* iter) const { |
+ uint32 out_uint32; |
+ pickle_.ReadUInt32(iter, &out_uint32); |
+ StringAppendF(out, "%u", out_uint32); |
+} |
+ |
+void TracedValue::AppendValueAsUInt64(std::string* out, |
+ PickleIterator* iter) const { |
+ uint64 out_uint64; |
+ pickle_.ReadUInt64(iter, &out_uint64); |
+ StringAppendF(out, "%" PRIu64, out_uint64); |
+} |
+ |
+void TracedValue::AppendValueAsFloat(std::string* out, |
+ PickleIterator* iter) const { |
+ float out_float; |
+ pickle_.ReadFloat(iter, &out_float); |
+ out->append(base::JSONWriter::DoubleToFormattedString(out_float, false)); |
+} |
+ |
+void TracedValue::AppendValueAsBool(std::string* out, |
+ PickleIterator* iter) const { |
+ bool out_bool; |
+ pickle_.ReadBool(iter, &out_bool); |
+ StringAppendF(out, "%s", out_bool ? "true" : "false"); |
+} |
+ |
+// Static. |
+void TracedValue::AppendComma(std::string* out, Opcode begin_opcode, |
+ Opcode current_opcode, int* element_count) { |
+ // For arrays, we want to append a comma when the element count within |
+ // the array is greater than zero and we are not about to close the array. |
+ if (begin_opcode == BEGIN_ARRAY && current_opcode != END_ARRAY && |
+ (*element_count)++ > 0) { |
+ StringAppendF(out, ","); |
+ return; |
+ } |
+ // For dictionaries, we want to append a comma when the element count within |
+ // the dictionary is greater than zero AND we're about to append is a key. |
+ if (begin_opcode == BEGIN_DICTIONARY && |
+ current_opcode == KEY_AS_RAW_POINTER && |
+ (*element_count)++ > 0) { |
+ StringAppendF(out, ","); |
+ } |
+} |
+ |
+} // namespace debug |
+} // namespace base |
+ |