• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TRACE_EVENT_TRACED_VALUE_H_
6 #define BASE_TRACE_EVENT_TRACED_VALUE_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <sstream>
12 #include <string>
13 #include <vector>
14 
15 #include "base/base_export.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/memory/raw_ptr_exclusion.h"
18 #include "base/strings/string_piece.h"
19 #include "base/trace_event/trace_arguments.h"
20 
21 namespace base {
22 
23 class TraceEventMemoryOverhead;
24 class Value;
25 
26 namespace trace_event {
27 
28 class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
29  public:
30   // TODO(oysteine): |capacity| is not used in any production code. Consider
31   // removing it.
32   explicit TracedValue(size_t capacity = 0);
33   TracedValue(const TracedValue&) = delete;
34   TracedValue& operator=(const TracedValue&) = delete;
35   ~TracedValue() override;
36 
37   void EndDictionary();
38   void EndArray();
39 
40   // These methods assume that |name| is a long lived "quoted" string.
41   void SetInteger(const char* name, int value);
42   void SetDouble(const char* name, double value);
43   void SetBoolean(const char* name, bool value);
44   void SetString(const char* name, base::StringPiece value);
45   void SetValue(const char* name, TracedValue* value);
46   void SetPointer(const char* name, void* value);
47   void BeginDictionary(const char* name);
48   void BeginArray(const char* name);
49 
50   // These, instead, can be safely passed a temporary string.
51   void SetIntegerWithCopiedName(base::StringPiece name, int value);
52   void SetDoubleWithCopiedName(base::StringPiece name, double value);
53   void SetBooleanWithCopiedName(base::StringPiece name, bool value);
54   void SetStringWithCopiedName(base::StringPiece name, base::StringPiece value);
55   void SetValueWithCopiedName(base::StringPiece name, TracedValue* value);
56   void SetPointerWithCopiedName(base::StringPiece name, void* value);
57   void BeginDictionaryWithCopiedName(base::StringPiece name);
58   void BeginArrayWithCopiedName(base::StringPiece name);
59 
60   void AppendInteger(int);
61   void AppendDouble(double);
62   void AppendBoolean(bool);
63   void AppendString(base::StringPiece);
64   void AppendPointer(void*);
65   void BeginArray();
66   void BeginDictionary();
67 
68   // ConvertableToTraceFormat implementation.
69   void AppendAsTraceFormat(std::string* out) const override;
70   bool AppendToProto(ProtoAppender* appender) const override;
71 
72   void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
73 
74   // Helper to auto-close an array. The call to |ArrayScope::~ArrayScope| closes
75   // the array.
76   //
77   // To be constructed using:
78   //   |TracedValue::AppendArrayScoped|
79   //   |TracedValue::BeginArrayScoped|
80   //   |TracedValue::BeginArrayScopedWithCopiedName|
81   //
82   // |ArrayScope| holds a |TracedValue| pointer which should remain a valid
83   // pointer until |ArrayScope::~ArrayScope| is called.
84   //
85   // |ArrayScope::~ArrayScope| calls |TracedValue::EndArray| (which checks if
86   // the held |TracedValue*| is in array state).
87   //
88   // Example:
89   //   std::unique_ptr<TracedValue> value(new TracedValue());
90   //   {
91   //     auto scope = value->BeginArrayScoped("array_name");
92   //     value->AppendBoolean(false);
93   //   }
94   class BASE_EXPORT ArrayScope {
95    public:
96     ArrayScope(const ArrayScope&) = delete;
97     ArrayScope(ArrayScope&&) = default;
98     ArrayScope& operator=(const ArrayScope&) = delete;
99     ArrayScope& operator=(ArrayScope&&) = default;
100     ~ArrayScope();
101 
102    private:
103     explicit ArrayScope(TracedValue* value);
104 
105     raw_ptr<TracedValue> value_;
106 
107     friend class TracedValue;
108   };
109 
110   // Call |BeginArray| or |BeginArrayWithCopiedName| with no / the same
111   // parameter and return an |ArrayScope| holding |this|.
112   [[nodiscard]] ArrayScope AppendArrayScoped();
113   [[nodiscard]] ArrayScope BeginArrayScoped(const char* name);
114   [[nodiscard]] ArrayScope BeginArrayScopedWithCopiedName(
115       base::StringPiece name);
116 
117   // Helper to auto-close a dictionary. The call to
118   // |DictionaryScope::~DictionaryScope| closes the dictionary.
119   //
120   // To be constructed using:
121   //   |TracedValue::AppendDictionaryScoped|
122   //   |TracedValue::BeginDictionaryScoped|
123   //   |TracedValue::BeginDictionaryScopedWithCopiedName|
124   //
125   // |DictionaryScope| holds a |TracedValue| pointer which should remain a valid
126   // pointer until |DictionaryScope::~DictionaryScope| is called.
127   //
128   // |DictionaryScope::~DictionaryScope| calls |TracedValue::EndDictionary|
129   // (which checks if the held |TracedValue*| is in dictionary state).
130   //
131   // Example:
132   //   std::unique_ptr<TracedValue> value(new TracedValue());
133   //   {
134   //     auto scope = value->BeginDictionaryScoped("dictionary_name");
135   //     value->SetBoolean("my_boolean", false);
136   //   }
137   class BASE_EXPORT DictionaryScope {
138    public:
139     DictionaryScope(const DictionaryScope&) = delete;
140     DictionaryScope(DictionaryScope&&) = default;
141     DictionaryScope& operator=(const DictionaryScope&) = delete;
142     DictionaryScope& operator=(DictionaryScope&&) = default;
143     ~DictionaryScope();
144 
145    private:
146     explicit DictionaryScope(TracedValue* value);
147 
148     raw_ptr<TracedValue> value_;
149 
150     friend class TracedValue;
151   };
152 
153   // Call |BeginDictionary| or |BeginDictionaryWithCopiedName| with no / the
154   // same parameter and return a |DictionaryScope| holding |this|.
155   [[nodiscard]] DictionaryScope AppendDictionaryScoped();
156   [[nodiscard]] DictionaryScope BeginDictionaryScoped(const char* name);
157   [[nodiscard]] DictionaryScope BeginDictionaryScopedWithCopiedName(
158       base::StringPiece name);
159 
160   class BASE_EXPORT Array;
161   class BASE_EXPORT Dictionary;
162   class BASE_EXPORT ValueHolder;
163   class BASE_EXPORT ArrayItem;
164   class BASE_EXPORT DictionaryItem;
165 
166   // Helper to enable easier initialization of |TracedValue|. This is intended
167   // for quick local debugging as there is overhead of creating
168   // |std::initializer_list| of name-value objects (in the case of containers
169   // the value is also a |std::initializer_list|). Generally the helper types
170   // |TracedValue::Dictionary|, |TracedValue::Array|,
171   // |TracedValue::DictionaryItem|, |TracedValue::ArrayItem| must be valid as
172   // well as their internals (e.g., |base::StringPiece| data should be valid
173   // when |TracedValue::Build| is called; |TracedValue::Array| or
174   // |TracedValue::Dictionary| holds a |std::initializer_list| whose underlying
175   // array needs to be valid when calling |TracedValue::Build|).
176   //
177   // Example:
178   //    auto value = TracedValue::Build({
179   //      {"int_var_name", 42},
180   //      {"double_var_name", 3.14},
181   //      {"string_var_name", "hello world"},
182   //      {"empty_array", TracedValue::Array({})},
183   //      {"dictionary", TracedValue::Dictionary({
184   //        {"my_ptr", static_cast<void*>(my_ptr)},
185   //        {"nested_array", TracedValue::Array({1, false, 0.5})},
186   //      })},
187   //    });
188   static std::unique_ptr<TracedValue> Build(
189       const std::initializer_list<DictionaryItem> items);
190 
191   // An |Array| instance represents an array of |ArrayItem| objects. This is a
192   // helper to allow initializer list like construction of arrays using
193   // |TracedValue::Build|.
194   //
195   // An instance holds an |std::initializer_list<TracedValue::ArrayItem>| and is
196   // cheap to copy (copying the initializer_list does not copy the underlying
197   // objects). The underlying array must exist at the time when
198   // |TracedValue::Build| is called.
199   class Array {
200    public:
201     // This constructor expects that the initializer_list is valid when
202     // |TracedValue::Build| is called.
203     Array(const std::initializer_list<ArrayItem> items);
204     Array(Array&&);
205     void WriteToValue(TracedValue* value) const;
206 
207    private:
208     std::initializer_list<ArrayItem> items_;
209   };
210 
211   // A helper to hold a dictionary. Similar to |TracedValue::Array|.
212   class Dictionary {
213    public:
214     // This constructor expects that the initializer_list is valid when
215     // |TracedValue::Build| is called.
216     Dictionary(const std::initializer_list<DictionaryItem> items);
217     Dictionary(Dictionary&&);
218     void WriteToValue(TracedValue* value) const;
219 
220    private:
221     std::initializer_list<DictionaryItem> items_;
222   };
223 
224   // A |ValueHolder| holds a single value or a container (int, double... or an
225   // |Array| / |Dictionary|). Not to be used outside of the context of
226   // |TracedValue::Build| (has one parameter implicit constructors).
227   //
228   // Base class for |TracedValue::ArrayItem| and |TracedValue::DictionaryItem|.
229   class ValueHolder {
230    public:
231     // Implicit constructors allow constructing |DictionaryItem| without having
232     // to write |{"name", TracedValue::ValueHolder(1)}|.
233     ValueHolder(int value);     // NOLINT(google-explicit-constructor)
234     ValueHolder(double value);  // NOLINT(google-explicit-constructor)
235     ValueHolder(bool value);    // NOLINT(google-explicit-constructor)
236     ValueHolder(void* value);   // NOLINT(google-explicit-constructor)
237     // StringPiece's backing storage / const char* pointer needs to remain valid
238     // until TracedValue::Build is called.
239     // NOLINTNEXTLINE(google-explicit-constructor)
240     ValueHolder(base::StringPiece value);
241     // Create a copy to avoid holding a reference to a non-existing string:
242     //
243     // Example:
244     //   TracedValue::Build({{"my_string", std::string("std::string value")}});
245     // Explanation:
246     //   1. std::string temporary is passed to the constructor of |ValueHolder|.
247     //   2. |ValueHolder| is passed to the constructor of |DictionaryItem|.
248     //   3. |Build| iterates initializer_list of |DictionaryItems|.
249     //
250     //   If the original |ValueHolder| kept just a reference to the string (or
251     //   a |base::StringPiece|) then |Build| is undefined behaviour, as it is
252     //   passing a reference to an out-of-scope temporary to
253     //   |TracedValue::SetString|.
254     // NOLINTNEXTLINE(google-explicit-constructor)
255     ValueHolder(std::string value);
256     // Define an explicit overload for const char* to resolve the ambiguity
257     // between the base::StringPiece, void*, and bool constructors for string
258     // literals.
259     ValueHolder(const char* value);  // NOLINT(google-explicit-constructor)
260     ValueHolder(Array& value);       // NOLINT(google-explicit-constructor)
261     ValueHolder(Dictionary& value);  // NOLINT(google-explicit-constructor)
262     ValueHolder(ValueHolder&&);
263 
264    protected:
265     void WriteToValue(TracedValue* value) const;
266     void WriteToValue(const char* name, TracedValue* value) const;
267 
268    private:
269     union KeptValue {
270       // Copy is handled by the holder (based on
271       // |TracedValue::ValueHolder::kept_value_type_|).
272       int int_value;
273       double double_value;
274       bool bool_value;
275       base::StringPiece string_piece_value;
276       std::string std_string_value;
277       // This field is not a raw_ptr<> because it was filtered by the rewriter
278       // for: #union
279       RAW_PTR_EXCLUSION void* void_ptr_value;
280       Array array_value;
281       Dictionary dictionary_value;
282 
283       // Default constructor is implicitly deleted because union field has a
284       // non-trivial default constructor.
KeptValue()285       KeptValue() {}   // NOLINT(modernize-use-equals-default)
~KeptValue()286       ~KeptValue() {}  // NOLINT(modernize-use-equals-default)
287     };
288 
289     // Reimplementing a subset of C++17 std::variant.
290     enum class KeptValueType {
291       kIntType,
292       kDoubleType,
293       kBoolType,
294       kStringPieceType,
295       kStdStringType,
296       kVoidPtrType,
297       kArrayType,
298       kDictionaryType,
299     };
300 
301     KeptValue kept_value_;
302     KeptValueType kept_value_type_;
303   };
304 
305   // |ArrayItem| is a |ValueHolder| which can be used to construct an |Array|.
306   class ArrayItem : public ValueHolder {
307    public:
308     // Implicit constructors allow calling |TracedValue::Array({1, true, 3.14})|
309     // instead of |TracedValue::Array({TracedValue::ArrayItem(1),
310     // TracedValue::ArrayItem(true), TracedValue::ArrayItem(3.14)})|.
311     template <typename T>
312     // NOLINTNEXTLINE(google-explicit-constructor)
ArrayItem(T value)313     ArrayItem(T value) : ValueHolder(value) {}
314 
315     void WriteToValue(TracedValue* value) const;
316   };
317 
318   // |DictionaryItem| instance represents a single name-value pair.
319   //
320   // |name| is assumed to be a long lived "quoted" string.
321   class DictionaryItem : public ValueHolder {
322    public:
323     // These constructors assume that |name| is a long lived "quoted" string.
324     template <typename T>
DictionaryItem(const char * name,T value)325     DictionaryItem(const char* name, T value)
326         : ValueHolder(value), name_(name) {}
327 
328     void WriteToValue(TracedValue* value) const;
329 
330    private:
331     const char* name_;
332   };
333 
334   // A custom serialization class can be supplied by implementing the
335   // Writer interface and supplying a factory class to SetWriterFactoryCallback.
336   // Primarily used by Perfetto to write TracedValues directly into its proto
337   // format, which lets us do a direct memcpy() in AppendToProto() rather than
338   // a JSON serialization step in AppendAsTraceFormat.
339   class BASE_EXPORT Writer {
340    public:
341     virtual ~Writer() = default;
342 
343     virtual void BeginArray() = 0;
344     virtual void BeginDictionary() = 0;
345     virtual void EndDictionary() = 0;
346     virtual void EndArray() = 0;
347 
348     // These methods assume that |name| is a long lived "quoted" string.
349     virtual void SetInteger(const char* name, int value) = 0;
350     virtual void SetDouble(const char* name, double value) = 0;
351     virtual void SetBoolean(const char* name, bool value) = 0;
352     virtual void SetString(const char* name, base::StringPiece value) = 0;
353     virtual void SetValue(const char* name, Writer* value) = 0;
354     virtual void BeginDictionary(const char* name) = 0;
355     virtual void BeginArray(const char* name) = 0;
356 
357     // These, instead, can be safely passed a temporary string.
358     virtual void SetIntegerWithCopiedName(base::StringPiece name,
359                                           int value) = 0;
360     virtual void SetDoubleWithCopiedName(base::StringPiece name,
361                                          double value) = 0;
362     virtual void SetBooleanWithCopiedName(base::StringPiece name,
363                                           bool value) = 0;
364     virtual void SetStringWithCopiedName(base::StringPiece name,
365                                          base::StringPiece value) = 0;
366     virtual void SetValueWithCopiedName(base::StringPiece name,
367                                         Writer* value) = 0;
368     virtual void BeginDictionaryWithCopiedName(base::StringPiece name) = 0;
369     virtual void BeginArrayWithCopiedName(base::StringPiece name) = 0;
370 
371     virtual void AppendInteger(int) = 0;
372     virtual void AppendDouble(double) = 0;
373     virtual void AppendBoolean(bool) = 0;
374     virtual void AppendString(base::StringPiece) = 0;
375 
376     virtual void AppendAsTraceFormat(std::string* out) const = 0;
377 
378     virtual bool AppendToProto(ProtoAppender* appender);
379 
380     virtual void EstimateTraceMemoryOverhead(
381         TraceEventMemoryOverhead* overhead) = 0;
382 
383     virtual bool IsPickleWriter() const = 0;
384     virtual bool IsProtoWriter() const = 0;
385   };
386 
387   typedef std::unique_ptr<Writer> (*WriterFactoryCallback)(size_t capacity);
388   static void SetWriterFactoryCallback(WriterFactoryCallback callback);
389 
390  protected:
391   TracedValue(size_t capacity, bool forced_json);
392 
393   std::unique_ptr<base::Value> ToBaseValue() const;
394 
395  private:
396   mutable std::unique_ptr<Writer> writer_;
397 
398 #ifndef NDEBUG
399   // In debug builds checks the pairings of {Start,End}{Dictionary,Array}
400   std::vector<bool> nesting_stack_;
401 #endif
402 };
403 
404 // TracedValue that is convertable to JSON format. This has lower performance
405 // than the default TracedValue in production code, and should be used only for
406 // testing and debugging. Should be avoided in tracing. It's for
407 // testing/debugging code calling value dumping function designed for tracing,
408 // like the following:
409 //
410 //   TracedValueJSON value;
411 //   AsValueInto(&value);  // which is designed for tracing.
412 //   return value.ToJSON();
413 //
414 // If the code is merely for testing/debugging, base::Value should be used
415 // instead.
416 class BASE_EXPORT TracedValueJSON : public TracedValue {
417  public:
418   explicit TracedValueJSON(size_t capacity = 0)
TracedValue(capacity,true)419       : TracedValue(capacity, /*forced_josn*/ true) {}
420 
421   using TracedValue::ToBaseValue;
422 
423   // Converts the value into a JSON string without formatting. Suitable for
424   // printing a simple value or printing a value in a single line context.
425   std::string ToJSON() const;
426 
427   // Converts the value into a formatted JSON string, with indentation, spaces
428   // and new lines for better human readability of complex values.
429   std::string ToFormattedJSON() const;
430 };
431 
432 }  // namespace trace_event
433 }  // namespace base
434 
435 #endif  // BASE_TRACE_EVENT_TRACED_VALUE_H_
436