436 lines
16 KiB
C++
436 lines
16 KiB
C++
// Copyright 2014 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef BASE_TRACE_EVENT_TRACED_VALUE_H_
|
|
#define BASE_TRACE_EVENT_TRACED_VALUE_H_
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/base_export.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/raw_ptr_exclusion.h"
|
|
#include "base/strings/string_piece.h"
|
|
#include "base/trace_event/trace_arguments.h"
|
|
|
|
namespace base {
|
|
|
|
class TraceEventMemoryOverhead;
|
|
class Value;
|
|
|
|
namespace trace_event {
|
|
|
|
class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
|
|
public:
|
|
// TODO(oysteine): |capacity| is not used in any production code. Consider
|
|
// removing it.
|
|
explicit TracedValue(size_t capacity = 0);
|
|
TracedValue(const TracedValue&) = delete;
|
|
TracedValue& operator=(const TracedValue&) = delete;
|
|
~TracedValue() override;
|
|
|
|
void EndDictionary();
|
|
void EndArray();
|
|
|
|
// These methods assume that |name| is a long lived "quoted" string.
|
|
void SetInteger(const char* name, int value);
|
|
void SetDouble(const char* name, double value);
|
|
void SetBoolean(const char* name, bool value);
|
|
void SetString(const char* name, base::StringPiece value);
|
|
void SetValue(const char* name, TracedValue* value);
|
|
void SetPointer(const char* name, void* value);
|
|
void BeginDictionary(const char* name);
|
|
void BeginArray(const char* name);
|
|
|
|
// These, instead, can be safely passed a temporary string.
|
|
void SetIntegerWithCopiedName(base::StringPiece name, int value);
|
|
void SetDoubleWithCopiedName(base::StringPiece name, double value);
|
|
void SetBooleanWithCopiedName(base::StringPiece name, bool value);
|
|
void SetStringWithCopiedName(base::StringPiece name, base::StringPiece value);
|
|
void SetValueWithCopiedName(base::StringPiece name, TracedValue* value);
|
|
void SetPointerWithCopiedName(base::StringPiece name, void* value);
|
|
void BeginDictionaryWithCopiedName(base::StringPiece name);
|
|
void BeginArrayWithCopiedName(base::StringPiece name);
|
|
|
|
void AppendInteger(int);
|
|
void AppendDouble(double);
|
|
void AppendBoolean(bool);
|
|
void AppendString(base::StringPiece);
|
|
void AppendPointer(void*);
|
|
void BeginArray();
|
|
void BeginDictionary();
|
|
|
|
// ConvertableToTraceFormat implementation.
|
|
void AppendAsTraceFormat(std::string* out) const override;
|
|
bool AppendToProto(ProtoAppender* appender) const override;
|
|
|
|
void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
|
|
|
|
// Helper to auto-close an array. The call to |ArrayScope::~ArrayScope| closes
|
|
// the array.
|
|
//
|
|
// To be constructed using:
|
|
// |TracedValue::AppendArrayScoped|
|
|
// |TracedValue::BeginArrayScoped|
|
|
// |TracedValue::BeginArrayScopedWithCopiedName|
|
|
//
|
|
// |ArrayScope| holds a |TracedValue| pointer which should remain a valid
|
|
// pointer until |ArrayScope::~ArrayScope| is called.
|
|
//
|
|
// |ArrayScope::~ArrayScope| calls |TracedValue::EndArray| (which checks if
|
|
// the held |TracedValue*| is in array state).
|
|
//
|
|
// Example:
|
|
// std::unique_ptr<TracedValue> value(new TracedValue());
|
|
// {
|
|
// auto scope = value->BeginArrayScoped("array_name");
|
|
// value->AppendBoolean(false);
|
|
// }
|
|
class BASE_EXPORT ArrayScope {
|
|
public:
|
|
ArrayScope(const ArrayScope&) = delete;
|
|
ArrayScope(ArrayScope&&) = default;
|
|
ArrayScope& operator=(const ArrayScope&) = delete;
|
|
ArrayScope& operator=(ArrayScope&&) = default;
|
|
~ArrayScope();
|
|
|
|
private:
|
|
explicit ArrayScope(TracedValue* value);
|
|
|
|
raw_ptr<TracedValue> value_;
|
|
|
|
friend class TracedValue;
|
|
};
|
|
|
|
// Call |BeginArray| or |BeginArrayWithCopiedName| with no / the same
|
|
// parameter and return an |ArrayScope| holding |this|.
|
|
[[nodiscard]] ArrayScope AppendArrayScoped();
|
|
[[nodiscard]] ArrayScope BeginArrayScoped(const char* name);
|
|
[[nodiscard]] ArrayScope BeginArrayScopedWithCopiedName(
|
|
base::StringPiece name);
|
|
|
|
// Helper to auto-close a dictionary. The call to
|
|
// |DictionaryScope::~DictionaryScope| closes the dictionary.
|
|
//
|
|
// To be constructed using:
|
|
// |TracedValue::AppendDictionaryScoped|
|
|
// |TracedValue::BeginDictionaryScoped|
|
|
// |TracedValue::BeginDictionaryScopedWithCopiedName|
|
|
//
|
|
// |DictionaryScope| holds a |TracedValue| pointer which should remain a valid
|
|
// pointer until |DictionaryScope::~DictionaryScope| is called.
|
|
//
|
|
// |DictionaryScope::~DictionaryScope| calls |TracedValue::EndDictionary|
|
|
// (which checks if the held |TracedValue*| is in dictionary state).
|
|
//
|
|
// Example:
|
|
// std::unique_ptr<TracedValue> value(new TracedValue());
|
|
// {
|
|
// auto scope = value->BeginDictionaryScoped("dictionary_name");
|
|
// value->SetBoolean("my_boolean", false);
|
|
// }
|
|
class BASE_EXPORT DictionaryScope {
|
|
public:
|
|
DictionaryScope(const DictionaryScope&) = delete;
|
|
DictionaryScope(DictionaryScope&&) = default;
|
|
DictionaryScope& operator=(const DictionaryScope&) = delete;
|
|
DictionaryScope& operator=(DictionaryScope&&) = default;
|
|
~DictionaryScope();
|
|
|
|
private:
|
|
explicit DictionaryScope(TracedValue* value);
|
|
|
|
raw_ptr<TracedValue> value_;
|
|
|
|
friend class TracedValue;
|
|
};
|
|
|
|
// Call |BeginDictionary| or |BeginDictionaryWithCopiedName| with no / the
|
|
// same parameter and return a |DictionaryScope| holding |this|.
|
|
[[nodiscard]] DictionaryScope AppendDictionaryScoped();
|
|
[[nodiscard]] DictionaryScope BeginDictionaryScoped(const char* name);
|
|
[[nodiscard]] DictionaryScope BeginDictionaryScopedWithCopiedName(
|
|
base::StringPiece name);
|
|
|
|
class BASE_EXPORT Array;
|
|
class BASE_EXPORT Dictionary;
|
|
class BASE_EXPORT ValueHolder;
|
|
class BASE_EXPORT ArrayItem;
|
|
class BASE_EXPORT DictionaryItem;
|
|
|
|
// Helper to enable easier initialization of |TracedValue|. This is intended
|
|
// for quick local debugging as there is overhead of creating
|
|
// |std::initializer_list| of name-value objects (in the case of containers
|
|
// the value is also a |std::initializer_list|). Generally the helper types
|
|
// |TracedValue::Dictionary|, |TracedValue::Array|,
|
|
// |TracedValue::DictionaryItem|, |TracedValue::ArrayItem| must be valid as
|
|
// well as their internals (e.g., |base::StringPiece| data should be valid
|
|
// when |TracedValue::Build| is called; |TracedValue::Array| or
|
|
// |TracedValue::Dictionary| holds a |std::initializer_list| whose underlying
|
|
// array needs to be valid when calling |TracedValue::Build|).
|
|
//
|
|
// Example:
|
|
// auto value = TracedValue::Build({
|
|
// {"int_var_name", 42},
|
|
// {"double_var_name", 3.14},
|
|
// {"string_var_name", "hello world"},
|
|
// {"empty_array", TracedValue::Array({})},
|
|
// {"dictionary", TracedValue::Dictionary({
|
|
// {"my_ptr", static_cast<void*>(my_ptr)},
|
|
// {"nested_array", TracedValue::Array({1, false, 0.5})},
|
|
// })},
|
|
// });
|
|
static std::unique_ptr<TracedValue> Build(
|
|
const std::initializer_list<DictionaryItem> items);
|
|
|
|
// An |Array| instance represents an array of |ArrayItem| objects. This is a
|
|
// helper to allow initializer list like construction of arrays using
|
|
// |TracedValue::Build|.
|
|
//
|
|
// An instance holds an |std::initializer_list<TracedValue::ArrayItem>| and is
|
|
// cheap to copy (copying the initializer_list does not copy the underlying
|
|
// objects). The underlying array must exist at the time when
|
|
// |TracedValue::Build| is called.
|
|
class Array {
|
|
public:
|
|
// This constructor expects that the initializer_list is valid when
|
|
// |TracedValue::Build| is called.
|
|
Array(const std::initializer_list<ArrayItem> items);
|
|
Array(Array&&);
|
|
void WriteToValue(TracedValue* value) const;
|
|
|
|
private:
|
|
std::initializer_list<ArrayItem> items_;
|
|
};
|
|
|
|
// A helper to hold a dictionary. Similar to |TracedValue::Array|.
|
|
class Dictionary {
|
|
public:
|
|
// This constructor expects that the initializer_list is valid when
|
|
// |TracedValue::Build| is called.
|
|
Dictionary(const std::initializer_list<DictionaryItem> items);
|
|
Dictionary(Dictionary&&);
|
|
void WriteToValue(TracedValue* value) const;
|
|
|
|
private:
|
|
std::initializer_list<DictionaryItem> items_;
|
|
};
|
|
|
|
// A |ValueHolder| holds a single value or a container (int, double... or an
|
|
// |Array| / |Dictionary|). Not to be used outside of the context of
|
|
// |TracedValue::Build| (has one parameter implicit constructors).
|
|
//
|
|
// Base class for |TracedValue::ArrayItem| and |TracedValue::DictionaryItem|.
|
|
class ValueHolder {
|
|
public:
|
|
// Implicit constructors allow constructing |DictionaryItem| without having
|
|
// to write |{"name", TracedValue::ValueHolder(1)}|.
|
|
ValueHolder(int value); // NOLINT(google-explicit-constructor)
|
|
ValueHolder(double value); // NOLINT(google-explicit-constructor)
|
|
ValueHolder(bool value); // NOLINT(google-explicit-constructor)
|
|
ValueHolder(void* value); // NOLINT(google-explicit-constructor)
|
|
// StringPiece's backing storage / const char* pointer needs to remain valid
|
|
// until TracedValue::Build is called.
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
ValueHolder(base::StringPiece value);
|
|
// Create a copy to avoid holding a reference to a non-existing string:
|
|
//
|
|
// Example:
|
|
// TracedValue::Build({{"my_string", std::string("std::string value")}});
|
|
// Explanation:
|
|
// 1. std::string temporary is passed to the constructor of |ValueHolder|.
|
|
// 2. |ValueHolder| is passed to the constructor of |DictionaryItem|.
|
|
// 3. |Build| iterates initializer_list of |DictionaryItems|.
|
|
//
|
|
// If the original |ValueHolder| kept just a reference to the string (or
|
|
// a |base::StringPiece|) then |Build| is undefined behaviour, as it is
|
|
// passing a reference to an out-of-scope temporary to
|
|
// |TracedValue::SetString|.
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
ValueHolder(std::string value);
|
|
// Define an explicit overload for const char* to resolve the ambiguity
|
|
// between the base::StringPiece, void*, and bool constructors for string
|
|
// literals.
|
|
ValueHolder(const char* value); // NOLINT(google-explicit-constructor)
|
|
ValueHolder(Array& value); // NOLINT(google-explicit-constructor)
|
|
ValueHolder(Dictionary& value); // NOLINT(google-explicit-constructor)
|
|
ValueHolder(ValueHolder&&);
|
|
|
|
protected:
|
|
void WriteToValue(TracedValue* value) const;
|
|
void WriteToValue(const char* name, TracedValue* value) const;
|
|
|
|
private:
|
|
union KeptValue {
|
|
// Copy is handled by the holder (based on
|
|
// |TracedValue::ValueHolder::kept_value_type_|).
|
|
int int_value;
|
|
double double_value;
|
|
bool bool_value;
|
|
base::StringPiece string_piece_value;
|
|
std::string std_string_value;
|
|
// This field is not a raw_ptr<> because it was filtered by the rewriter
|
|
// for: #union
|
|
RAW_PTR_EXCLUSION void* void_ptr_value;
|
|
Array array_value;
|
|
Dictionary dictionary_value;
|
|
|
|
// Default constructor is implicitly deleted because union field has a
|
|
// non-trivial default constructor.
|
|
KeptValue() {} // NOLINT(modernize-use-equals-default)
|
|
~KeptValue() {} // NOLINT(modernize-use-equals-default)
|
|
};
|
|
|
|
// Reimplementing a subset of C++17 std::variant.
|
|
enum class KeptValueType {
|
|
kIntType,
|
|
kDoubleType,
|
|
kBoolType,
|
|
kStringPieceType,
|
|
kStdStringType,
|
|
kVoidPtrType,
|
|
kArrayType,
|
|
kDictionaryType,
|
|
};
|
|
|
|
KeptValue kept_value_;
|
|
KeptValueType kept_value_type_;
|
|
};
|
|
|
|
// |ArrayItem| is a |ValueHolder| which can be used to construct an |Array|.
|
|
class ArrayItem : public ValueHolder {
|
|
public:
|
|
// Implicit constructors allow calling |TracedValue::Array({1, true, 3.14})|
|
|
// instead of |TracedValue::Array({TracedValue::ArrayItem(1),
|
|
// TracedValue::ArrayItem(true), TracedValue::ArrayItem(3.14)})|.
|
|
template <typename T>
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
ArrayItem(T value) : ValueHolder(value) {}
|
|
|
|
void WriteToValue(TracedValue* value) const;
|
|
};
|
|
|
|
// |DictionaryItem| instance represents a single name-value pair.
|
|
//
|
|
// |name| is assumed to be a long lived "quoted" string.
|
|
class DictionaryItem : public ValueHolder {
|
|
public:
|
|
// These constructors assume that |name| is a long lived "quoted" string.
|
|
template <typename T>
|
|
DictionaryItem(const char* name, T value)
|
|
: ValueHolder(value), name_(name) {}
|
|
|
|
void WriteToValue(TracedValue* value) const;
|
|
|
|
private:
|
|
const char* name_;
|
|
};
|
|
|
|
// A custom serialization class can be supplied by implementing the
|
|
// Writer interface and supplying a factory class to SetWriterFactoryCallback.
|
|
// Primarily used by Perfetto to write TracedValues directly into its proto
|
|
// format, which lets us do a direct memcpy() in AppendToProto() rather than
|
|
// a JSON serialization step in AppendAsTraceFormat.
|
|
class BASE_EXPORT Writer {
|
|
public:
|
|
virtual ~Writer() = default;
|
|
|
|
virtual void BeginArray() = 0;
|
|
virtual void BeginDictionary() = 0;
|
|
virtual void EndDictionary() = 0;
|
|
virtual void EndArray() = 0;
|
|
|
|
// These methods assume that |name| is a long lived "quoted" string.
|
|
virtual void SetInteger(const char* name, int value) = 0;
|
|
virtual void SetDouble(const char* name, double value) = 0;
|
|
virtual void SetBoolean(const char* name, bool value) = 0;
|
|
virtual void SetString(const char* name, base::StringPiece value) = 0;
|
|
virtual void SetValue(const char* name, Writer* value) = 0;
|
|
virtual void BeginDictionary(const char* name) = 0;
|
|
virtual void BeginArray(const char* name) = 0;
|
|
|
|
// These, instead, can be safely passed a temporary string.
|
|
virtual void SetIntegerWithCopiedName(base::StringPiece name,
|
|
int value) = 0;
|
|
virtual void SetDoubleWithCopiedName(base::StringPiece name,
|
|
double value) = 0;
|
|
virtual void SetBooleanWithCopiedName(base::StringPiece name,
|
|
bool value) = 0;
|
|
virtual void SetStringWithCopiedName(base::StringPiece name,
|
|
base::StringPiece value) = 0;
|
|
virtual void SetValueWithCopiedName(base::StringPiece name,
|
|
Writer* value) = 0;
|
|
virtual void BeginDictionaryWithCopiedName(base::StringPiece name) = 0;
|
|
virtual void BeginArrayWithCopiedName(base::StringPiece name) = 0;
|
|
|
|
virtual void AppendInteger(int) = 0;
|
|
virtual void AppendDouble(double) = 0;
|
|
virtual void AppendBoolean(bool) = 0;
|
|
virtual void AppendString(base::StringPiece) = 0;
|
|
|
|
virtual void AppendAsTraceFormat(std::string* out) const = 0;
|
|
|
|
virtual bool AppendToProto(ProtoAppender* appender);
|
|
|
|
virtual void EstimateTraceMemoryOverhead(
|
|
TraceEventMemoryOverhead* overhead) = 0;
|
|
|
|
virtual bool IsPickleWriter() const = 0;
|
|
virtual bool IsProtoWriter() const = 0;
|
|
};
|
|
|
|
typedef std::unique_ptr<Writer> (*WriterFactoryCallback)(size_t capacity);
|
|
static void SetWriterFactoryCallback(WriterFactoryCallback callback);
|
|
|
|
protected:
|
|
TracedValue(size_t capacity, bool forced_json);
|
|
|
|
std::unique_ptr<base::Value> ToBaseValue() const;
|
|
|
|
private:
|
|
mutable std::unique_ptr<Writer> writer_;
|
|
|
|
#ifndef NDEBUG
|
|
// In debug builds checks the pairings of {Start,End}{Dictionary,Array}
|
|
std::vector<bool> nesting_stack_;
|
|
#endif
|
|
};
|
|
|
|
// TracedValue that is convertable to JSON format. This has lower performance
|
|
// than the default TracedValue in production code, and should be used only for
|
|
// testing and debugging. Should be avoided in tracing. It's for
|
|
// testing/debugging code calling value dumping function designed for tracing,
|
|
// like the following:
|
|
//
|
|
// TracedValueJSON value;
|
|
// AsValueInto(&value); // which is designed for tracing.
|
|
// return value.ToJSON();
|
|
//
|
|
// If the code is merely for testing/debugging, base::Value should be used
|
|
// instead.
|
|
class BASE_EXPORT TracedValueJSON : public TracedValue {
|
|
public:
|
|
explicit TracedValueJSON(size_t capacity = 0)
|
|
: TracedValue(capacity, /*forced_josn*/ true) {}
|
|
|
|
using TracedValue::ToBaseValue;
|
|
|
|
// Converts the value into a JSON string without formatting. Suitable for
|
|
// printing a simple value or printing a value in a single line context.
|
|
std::string ToJSON() const;
|
|
|
|
// Converts the value into a formatted JSON string, with indentation, spaces
|
|
// and new lines for better human readability of complex values.
|
|
std::string ToFormattedJSON() const;
|
|
};
|
|
|
|
} // namespace trace_event
|
|
} // namespace base
|
|
|
|
#endif // BASE_TRACE_EVENT_TRACED_VALUE_H_
|