1 // Copyright 2018 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 #ifndef BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
6 #define BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
7 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <algorithm>
12 #include <memory>
13 #include <string>
14 
15 #include "base/base_export.h"
16 #include "base/macros.h"
17 #include "base/trace_event/common/trace_event_common.h"
18 
19 // Trace macro can have one or two optional arguments, each one of them
20 // identified by a name (a C string literal) and a value, which can be an
21 // integer, enum, floating point, boolean, string pointer or reference, or
22 // std::unique_ptr<ConvertableToTraceFormat> compatible values. Additionally,
23 // custom data types need to be supported, like time values or WTF::CString.
24 //
25 // TraceArguments is a helper class used to store 0 to 2 named arguments
26 // corresponding to an individual trace macro call. As efficiently as possible,
27 // and with the minimal amount of generated machine code (since this affects
28 // any TRACE macro call). Each argument has:
29 //
30 //  - A name (C string literal, e.g "dumps")
31 //  - An 8-bit type value, corresponding to the TRACE_VALUE_TYPE_XXX macros.
32 //  - A value, stored in a TraceValue union
33 //
34 // IMPORTANT: For a TRACE_VALUE_TYPE_CONVERTABLE types, the TraceArguments
35 // instance owns the pointed ConvertableToTraceFormat object, i.e. it will
36 // delete it automatically on destruction.
37 //
38 // TraceArguments instances should be built using one of specialized
39 // constructors declared below. One cannot modify an instance once it has
40 // been built, except for move operations, Reset() and destruction. Examples:
41 //
42 //    TraceArguments args;    // No arguments.
43 //    // args.size() == 0
44 //
45 //    TraceArguments("foo", 100);
46 //    // args.size() == 1
47 //    // args.types()[0] == TRACE_VALUE_TYPE_INT
48 //    // args.names()[0] == "foo"
49 //    // args.values()[0].as_int == 100
50 //
51 //    TraceArguments("bar", 1ULL);
52 //    // args.size() == 1
53 //    // args.types()[0] == TRACE_VALUE_TYPE_UINT
54 //    // args.names()[0] == "bar"
55 //    // args.values()[0].as_uint == 100
56 //
57 //    TraceArguments("foo", "Hello", "bar", "World");
58 //    // args.size() == 2
59 //    // args.types()[0] == TRACE_VALUE_TYPE_STRING
60 //    // args.types()[1] == TRACE_VALUE_TYPE_STRING
61 //    // args.names()[0] == "foo"
62 //    // args.names()[1] == "bar"
63 //    // args.values()[0].as_string == "Hello"
64 //    // args.values()[1].as_string == "World"
65 //
66 //    std::string some_string = ...;
67 //    TraceArguments("str1", some_string);
68 //    // args.size() == 1
69 //    // args.types()[0] == TRACE_VALUE_TYPE_COPY_STRING
70 //    // args.names()[0] == "str1"
71 //    // args.values()[0].as_string == some_string.c_str()
72 //
73 // Note that TRACE_VALUE_TYPE_COPY_STRING corresponds to string pointers
74 // that point to temporary values that may disappear soon. The
75 // TraceArguments::CopyStringTo() method can be used to copy their content
76 // into a StringStorage memory block, and update the |as_string| value pointers
77 // to it to avoid keeping any dangling pointers. This is used by TraceEvent
78 // to keep copies of such strings in the log after their initialization values
79 // have disappeared.
80 //
81 // The TraceStringWithCopy helper class can be used to initialize a value
82 // from a regular string pointer with TRACE_VALUE_TYPE_COPY_STRING too, as in:
83 //
84 //     const char str[] = "....";
85 //     TraceArguments("foo", str, "bar", TraceStringWithCopy(str));
86 //     // args.size() == 2
87 //     // args.types()[0] == TRACE_VALUE_TYPE_STRING
88 //     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
89 //     // args.names()[0] == "foo"
90 //     // args.names()[1] == "bar"
91 //     // args.values()[0].as_string == str
92 //     // args.values()[1].as_string == str
93 //
94 //     StringStorage storage;
95 //     args.CopyStringTo(&storage, false, nullptr, nullptr);
96 //     // args.size() == 2
97 //     // args.types()[0] == TRACE_VALUE_TYPE_STRING
98 //     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
99 //     // args.names()[0] == "foo"
100 //     // args.names()[1] == "bar"
101 //     // args.values()[0].as_string == str
102 //     // args.values()[1].as_string == Address inside |storage|.
103 //
104 // Initialization from a std::unique_ptr<ConvertableToTraceFormat>
105 // is supported but will move ownership of the pointer objects to the
106 // TraceArguments instance:
107 //
108 //     class MyConvertableType :
109 //         public base::trace_event::AsConvertableToTraceFormat {
110 //        ...
111 //     };
112 //
113 //     {
114 //       TraceArguments args("foo" , std::make_unique<MyConvertableType>(...));
115 //       // args.size() == 1
116 //       // args.values()[0].as_convertable == address of MyConvertable object.
117 //     } // Calls |args| destructor, which will delete the object too.
118 //
119 // Finally, it is possible to support initialization from custom values by
120 // specializing the TraceValue::Helper<> template struct as described below.
121 //
122 // This is how values of custom types like WTF::CString can be passed directly
123 // to trace macros.
124 
125 namespace base {
126 
127 class Time;
128 class TimeTicks;
129 class ThreadTicks;
130 
131 namespace trace_event {
132 
133 class TraceEventMemoryOverhead;
134 
135 // For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
136 // class must implement this interface. Note that unlike other values,
137 // these objects will be owned by the TraceArguments instance that points
138 // to them.
139 class BASE_EXPORT ConvertableToTraceFormat {
140  public:
141   ConvertableToTraceFormat() = default;
142   virtual ~ConvertableToTraceFormat() = default;
143 
144   // Append the class info to the provided |out| string. The appended
145   // data must be a valid JSON object. Strings must be properly quoted, and
146   // escaped. There is no processing applied to the content after it is
147   // appended.
148   virtual void AppendAsTraceFormat(std::string* out) const = 0;
149 
150   // Append the class info directly into the Perfetto-defined proto
151   // format; this is attempted first and if this returns true,
152   // AppendAsTraceFormat is not called. The ProtoAppender interface
153   // acts as a bridge to avoid proto/Perfetto dependencies in base.
154   class BASE_EXPORT ProtoAppender {
155    public:
156     virtual ~ProtoAppender() = default;
157 
158     virtual void AddBuffer(uint8_t* begin, uint8_t* end) = 0;
159     // Copy all of the previous buffers registered with AddBuffer
160     // into the proto, with the given |field_id|.
161     virtual size_t Finalize(uint32_t field_id) = 0;
162   };
163   virtual bool AppendToProto(ProtoAppender* appender);
164 
165   virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
166 
167  private:
168   DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
169 };
170 
171 const int kTraceMaxNumArgs = 2;
172 
173 // A union used to hold the values of individual trace arguments.
174 //
175 // This is a POD union for performance reason. Initialization from an
176 // explicit C++ trace argument should be performed with the Init()
177 // templated method described below.
178 //
179 // Initialization from custom types is possible by implementing a custom
180 // TraceValue::Helper<> instantiation as described below.
181 //
182 // IMPORTANT: Pointer storage inside a TraceUnion follows specific rules:
183 //
184 //   - |as_pointer| is for raw pointers that should be treated as a simple
185 //     address and will never be dereferenced. Associated with the
186 //     TRACE_VALUE_TYPE_POINTER type.
187 //
188 //   - |as_string| is for C-string pointers, associated with both
189 //     TRACE_VALUE_TYPE_STRING and TRACE_VALUE_TYPE_COPY_STRING. The former
190 //     indicates that the string pointer is persistent (e.g. a C string
191 //     literal), while the second indicates that the pointer belongs to a
192 //     temporary variable that may disappear soon. The TraceArguments class
193 //     provides a CopyStringTo() method to copy these strings into a
194 //     StringStorage instance, which is useful if the instance needs to
195 //     survive longer than the temporaries.
196 //
197 //   - |as_convertable| is equivalent to
198 //     std::unique_ptr<ConvertableToTraceFormat>, except that it is a pointer
199 //     to keep this union POD and avoid un-necessary declarations and potential
200 //     code generation. This means that its ownership is passed to the
201 //     TraceValue instance when Init(std::unique_ptr<ConvertableToTraceFormat>)
202 //     is called, and that it will be deleted by the containing TraceArguments
203 //     destructor, or Reset() method.
204 //
205 union BASE_EXPORT TraceValue {
206   bool as_bool;
207   unsigned long long as_uint;
208   long long as_int;
209   double as_double;
210   const void* as_pointer;
211   const char* as_string;
212   ConvertableToTraceFormat* as_convertable;
213 
214   // There is no constructor to keep this structure POD intentionally.
215   // This avoids un-needed initialization when only 0 or 1 arguments are
216   // used to construct a TraceArguments instance. Use Init() instead to
217   // perform explicit initialization from a given C++ value.
218 
219   // Initialize TraceValue instance from a C++ trace value.
220   // This relies on the proper specialization of TraceValue::Helper<>
221   // described below. Usage is simply:
222   //
223   //  TraceValue v;
224   //  v.Init(<value>);
225   //
226   // NOTE: For ConvertableToTraceFormat values, see the note above and
227   // the one for TraceValue::Helper for CONVERTABLE_TYPE below.
228   template <typename T>
Init(T && value)229   void Init(T&& value) {
230     using ValueType = typename InnerType<T>::type;
231     Helper<ValueType>::SetValue(this, std::forward<T>(value));
232   }
233 
234   // Static method to create a new TraceValue instance from a given
235   // initialization value. Note that this deduces the TRACE_VALUE_TYPE_XXX
236   // type but doesn't return it, use ForType<T>::value for this.
237   //
238   // Usage example:
239   //     auto v = TraceValue::Make(100);
240   //     auto v2 = TraceValue::Make("Some text string");
241   //
242   // IMPORTANT: Experience shows that the compiler generates worse code when
243   // using this method rather than calling Init() directly on an existing
244   // TraceValue union :-(
245   //
246   template <typename T>
Make(T && value)247   static TraceValue Make(T&& value) {
248     TraceValue ret;
249     ret.Init(std::forward<T>(value));
250     return ret;
251   }
252 
253   // Output current value as a JSON string. |type| must be a valid
254   // TRACE_VALUE_TYPE_XXX value.
255   void AppendAsJSON(unsigned char type, std::string* out) const;
256 
257   // Output current value as a string. If the output string is to be used
258   // in a JSON format use AppendAsJSON instead. |type| must be valid
259   // TRACE_VALUE_TYPE_XXX value.
260   void AppendAsString(unsigned char type, std::string* out) const;
261 
262  private:
263   void Append(unsigned char type, bool as_json, std::string* out) const;
264 
265   // InnerType<T>::type removes reference, cv-qualifications and decays
266   // function and arrays into pointers. Only used internally.
267   template <typename T>
268   struct InnerType {
269     using type = typename std::remove_cv<typename std::remove_reference<
270         typename std::decay<T>::type>::type>::type;
271   };
272 
273  public:
274   // TraceValue::Helper is used to provide information about initialization
275   // value types and an initialization function. It is a struct that should
276   // provide the following for supported initialization value types:
277   //
278   //    - kType: is a static TRACE_VALUE_TYPE_XXX constant.
279   //
280   //    - SetValue(TraceValue*, T): is a static inline method that sets
281   //        TraceValue value from a given T value. Second parameter type
282   //        can also be const T& or T&& to restrict uses.
283   //
284   // IMPORTANT: The type T must be InnerType<Q>, where Q is the real C++
285   // argument type. I.e. you should not have to deal with reference types
286   // in your specialization.
287   //
288   // Specializations are defined for integers, enums, floating point, pointers,
289   // constant C string literals and pointers, std::string, time values below.
290   //
291   // Specializations for custom types are possible provided that there exists
292   // a corresponding Helper specialization, for example:
293   //
294   //    template <>
295   //    struct base::trace_event::TraceValue::Helper<Foo> {
296   //      static constexpr unsigned char kTypes = TRACE_VALUE_TYPE_COPY_STRING;
297   //      static inline void SetValue(TraceValue* v, const Foo& value) {
298   //        v->as_string = value.c_str();
299   //      }
300   //    };
301   //
302   // Will allow code like:
303   //
304   //    Foo foo = ...;
305   //    auto v = TraceValue::Make(foo);
306   //
307   // Or even:
308   //    Foo foo = ...;
309   //    TraceArguments args("foo_arg1", foo);
310   //
311   template <typename T, class = void>
312   struct Helper {};
313 
314   // TraceValue::TypeFor<T>::value returns the TRACE_VALUE_TYPE_XXX
315   // corresponding to initialization values of type T.
316   template <typename T>
317   struct TypeFor {
318     using ValueType = typename InnerType<T>::type;
319     static const unsigned char value = Helper<ValueType>::kType;
320   };
321 
322   // TraceValue::TypeCheck<T>::value is only defined iff T can be used to
323   // initialize a TraceValue instance. This is useful to restrict template
324   // instantiation to only the appropriate type (see TraceArguments
325   // constructors below).
326   template <typename T,
327             class = decltype(TraceValue::Helper<
328                              typename TraceValue::InnerType<T>::type>::kType)>
329   struct TypeCheck {
330     static const bool value = true;
331   };
332 };
333 
334 // TraceValue::Helper for integers and enums.
335 template <typename T>
336 struct TraceValue::Helper<
337     T,
338     typename std::enable_if<std::is_integral<T>::value ||
339                             std::is_enum<T>::value>::type> {
340   static constexpr unsigned char kType =
341       std::is_signed<T>::value ? TRACE_VALUE_TYPE_INT : TRACE_VALUE_TYPE_UINT;
342   static inline void SetValue(TraceValue* v, T value) {
343     v->as_uint = static_cast<unsigned long long>(value);
344   }
345 };
346 
347 // TraceValue::Helper for floating-point types
348 template <typename T>
349 struct TraceValue::
350     Helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
351   static constexpr unsigned char kType = TRACE_VALUE_TYPE_DOUBLE;
352   static inline void SetValue(TraceValue* v, T value) { v->as_double = value; }
353 };
354 
355 // TraceValue::Helper for bool.
356 template <>
357 struct TraceValue::Helper<bool> {
358   static constexpr unsigned char kType = TRACE_VALUE_TYPE_BOOL;
359   static inline void SetValue(TraceValue* v, bool value) { v->as_bool = value; }
360 };
361 
362 //  TraceValue::Helper for generic pointer types.
363 template <typename T>
364 struct TraceValue::Helper<T*> {
365   static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER;
366   static inline void SetValue(TraceValue* v,
367                               const typename std::decay<T>::type* value) {
368     v->as_pointer = value;
369   }
370 };
371 
372 // TraceValue::Helper for raw persistent C strings.
373 template <>
374 struct TraceValue::Helper<const char*> {
375   static constexpr unsigned char kType = TRACE_VALUE_TYPE_STRING;
376   static inline void SetValue(TraceValue* v, const char* value) {
377     v->as_string = value;
378   }
379 };
380 
381 // TraceValue::Helper for std::string values.
382 template <>
383 struct TraceValue::Helper<std::string> {
384   static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
385   static inline void SetValue(TraceValue* v, const std::string& value) {
386     v->as_string = value.c_str();
387   }
388 };
389 
390 // Special case for scoped pointers to convertables to trace format.
391 // |CONVERTABLE_TYPE| must be a type whose pointers can be converted to a
392 // ConvertableToTraceFormat* pointer as well (e.g. a derived class).
393 // IMPORTANT: This takes an std::unique_ptr<CONVERTABLE_TYPE> value, and takes
394 // ownership of the pointed object!
395 template <typename CONVERTABLE_TYPE>
396 struct TraceValue::Helper<std::unique_ptr<CONVERTABLE_TYPE>,
397                           typename std::enable_if<std::is_convertible<
398                               CONVERTABLE_TYPE*,
399                               ConvertableToTraceFormat*>::value>::type> {
400   static constexpr unsigned char kType = TRACE_VALUE_TYPE_CONVERTABLE;
401   static inline void SetValue(TraceValue* v,
402                               std::unique_ptr<CONVERTABLE_TYPE> value) {
403     v->as_convertable = value.release();
404   }
405 };
406 
407 // Specialization for time-based values like base::Time, which provide a
408 // a ToInternalValue() method.
409 template <typename T>
410 struct TraceValue::Helper<
411     T,
412     typename std::enable_if<std::is_same<T, base::Time>::value ||
413                             std::is_same<T, base::TimeTicks>::value ||
414                             std::is_same<T, base::ThreadTicks>::value>::type> {
415   static constexpr unsigned char kType = TRACE_VALUE_TYPE_INT;
416   static inline void SetValue(TraceValue* v, const T& value) {
417     v->as_int = value.ToInternalValue();
418   }
419 };
420 
421 // Simple container for const char* that should be copied instead of retained.
422 // The goal is to indicate that the C string is copyable, unlike the default
423 // Init(const char*) implementation. Usage is:
424 //
425 //    const char* str = ...;
426 //    v.Init(TraceStringWithCopy(str));
427 //
428 // Which will mark the string as TRACE_VALUE_TYPE_COPY_STRING, instead of
429 // TRACE_VALUE_TYPE_STRING.
430 //
431 class TraceStringWithCopy {
432  public:
433   explicit TraceStringWithCopy(const char* str) : str_(str) {}
434   const char* str() const { return str_; }
435 
436  private:
437   const char* str_;
438 };
439 
440 template <>
441 struct TraceValue::Helper<TraceStringWithCopy> {
442   static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
443   static inline void SetValue(TraceValue* v, const TraceStringWithCopy& value) {
444     v->as_string = value.str();
445   }
446 };
447 
448 class TraceArguments;
449 
450 // A small class used to store a copy of all strings from a given
451 // TraceArguments instance (see below). When empty, this should only
452 // take the size of a pointer. Otherwise, this will point to a heap
453 // allocated block containing a size_t value followed by all characters
454 // in the storage area. For most cases, this is more efficient
455 // than using a std::unique_ptr<std::string> or an std::vector<char>.
456 class BASE_EXPORT StringStorage {
457  public:
458   constexpr StringStorage() = default;
459 
460   explicit StringStorage(size_t alloc_size) { Reset(alloc_size); }
461 
462   ~StringStorage() {
463     if (data_)
464       ::free(data_);
465   }
466 
467   StringStorage(StringStorage&& other) noexcept : data_(other.data_) {
468     other.data_ = nullptr;
469   }
470 
471   StringStorage& operator=(StringStorage&& other) noexcept {
472     if (this != &other) {
473       if (data_)
474         ::free(data_);
475       data_ = other.data_;
476       other.data_ = nullptr;
477     }
478     return *this;
479   }
480 
481   // Reset storage area to new allocation size. Existing content might not
482   // be preserved. If |alloc_size| is 0, this will free the storage area
483   // as well.
484   void Reset(size_t alloc_size = 0);
485 
486   // Accessors.
487   size_t size() const { return data_ ? data_->size : 0u; }
488   const char* data() const { return data_ ? data_->chars : nullptr; }
489   char* data() { return data_ ? data_->chars : nullptr; }
490 
491   const char* begin() const { return data(); }
492   const char* end() const { return data() + size(); }
493   inline char* begin() { return data(); }
494   inline char* end() { return data() + size(); }
495 
496   // True iff storage is empty.
497   bool empty() const { return size() == 0; }
498 
499   // Returns true if |ptr| is inside the storage area, false otherwise.
500   // Used during unit-testing.
501   bool Contains(const void* ptr) const {
502     const char* char_ptr = static_cast<const char*>(ptr);
503     return (char_ptr >= begin() && char_ptr < end());
504   }
505 
506   // Returns true if all string pointers in |args| are contained in this
507   // storage area.
508   bool Contains(const TraceArguments& args) const;
509 
510   // Return an estimate of the memory overhead of this instance. This doesn't
511   // count the size of |data_| itself.
512   size_t EstimateTraceMemoryOverhead() const {
513     return data_ ? sizeof(size_t) + data_->size : 0u;
514   }
515 
516  private:
517   // Heap allocated data block (variable size), made of:
518   //
519   //   - size: a size_t field, giving the size of the following |chars| array.
520   //   - chars: an array of |size| characters, holding all zero-terminated
521   //     strings referenced from a TraceArguments instance.
522   struct Data {
523     size_t size = 0;
524     char chars[1];  // really |size| character items in storage.
525   };
526 
527   // This is an owning pointer. Normally, using a std::unique_ptr<> would be
528   // enough, but the compiler will then complaing about inlined constructors
529   // and destructors being too complex (!), resulting in larger code for no
530   // good reason.
531   Data* data_ = nullptr;
532 };
533 
534 // TraceArguments models an array of kMaxSize trace-related items,
535 // each one of them having:
536 //   - a name, which is a constant char array literal.
537 //   - a type, as described by TRACE_VALUE_TYPE_XXX macros.
538 //   - a value, stored in a TraceValue union.
539 //
540 // IMPORTANT: For TRACE_VALUE_TYPE_CONVERTABLE, the value holds an owning
541 //            pointer to an AsConvertableToTraceFormat instance, which will
542 //            be destroyed with the array (or moved out of it when passed
543 //            to a TraceEvent instance).
544 //
545 // For TRACE_VALUE_TYPE_COPY_STRING, the value holds a const char* pointer
546 // whose content will be copied when creating a TraceEvent instance.
547 //
548 // IMPORTANT: Most constructors and the destructor are all inlined
549 // intentionally, in order to let the compiler remove un-necessary operations
550 // and reduce machine code.
551 //
552 class BASE_EXPORT TraceArguments {
553  public:
554   // Maximum number of arguments held by this structure.
555   static constexpr size_t kMaxSize = 2;
556 
557   // Default constructor, no arguments.
558   TraceArguments() : size_(0) {}
559 
560   // Constructor for a single argument.
561 #if defined(COMPILER_MSVC)
562   template <typename T>
563 #else
564   template <typename T, class = decltype(TraceValue::TypeCheck<T>::value)>
565 #endif
566   TraceArguments(const char* arg1_name, T&& arg1_value) : size_(1) {
567     types_[0] = TraceValue::TypeFor<T>::value;
568     names_[0] = arg1_name;
569     values_[0].Init(std::forward<T>(arg1_value));
570   }
571 
572   // Constructor for two arguments.
573   template <typename T1,
574 #if defined(COMPILER_MSVC)
575             typename T2>
576 #else
577             typename T2,
578             class = decltype(TraceValue::TypeCheck<T1>::value &&
579                              TraceValue::TypeCheck<T2>::value)>
580 #endif
581   TraceArguments(const char* arg1_name,
582                  T1&& arg1_value,
583                  const char* arg2_name,
584                  T2&& arg2_value)
585       : size_(2) {
586     types_[0] = TraceValue::TypeFor<T1>::value;
587     types_[1] = TraceValue::TypeFor<T2>::value;
588     names_[0] = arg1_name;
589     names_[1] = arg2_name;
590     values_[0].Init(std::forward<T1>(arg1_value));
591     values_[1].Init(std::forward<T2>(arg2_value));
592   }
593 
594   // Constructor used to convert a legacy set of arguments when there
595   // are no convertable values at all.
596   TraceArguments(int num_args,
597                  const char* const* arg_names,
598                  const unsigned char* arg_types,
599                  const unsigned long long* arg_values);
600 
601   // Constructor used to convert legacy set of arguments, where the
602   // convertable values are also provided by an array of CONVERTABLE_TYPE.
603   template <typename CONVERTABLE_TYPE>
604   TraceArguments(int num_args,
605                  const char* const* arg_names,
606                  const unsigned char* arg_types,
607                  const unsigned long long* arg_values,
608                  CONVERTABLE_TYPE* arg_convertables) {
609     static int max_args = static_cast<int>(kMaxSize);
610     if (num_args > max_args)
611       num_args = max_args;
612     size_ = static_cast<unsigned char>(num_args);
613     for (size_t n = 0; n < size_; ++n) {
614       types_[n] = arg_types[n];
615       names_[n] = arg_names[n];
616       if (arg_types[n] == TRACE_VALUE_TYPE_CONVERTABLE) {
617         values_[n].Init(
618             std::forward<CONVERTABLE_TYPE>(std::move(arg_convertables[n])));
619       } else {
620         values_[n].as_uint = arg_values[n];
621       }
622     }
623   }
624 
625   // Destructor. NOTE: Intentionally inlined (see note above).
626   ~TraceArguments() {
627     for (size_t n = 0; n < size_; ++n) {
628       if (types_[n] == TRACE_VALUE_TYPE_CONVERTABLE)
629         delete values_[n].as_convertable;
630     }
631   }
632 
633   // Disallow copy operations.
634   TraceArguments(const TraceArguments&) = delete;
635   TraceArguments& operator=(const TraceArguments&) = delete;
636 
637   // Allow move operations.
638   TraceArguments(TraceArguments&& other) noexcept {
639     ::memcpy(this, &other, sizeof(*this));
640     // All owning pointers were copied to |this|. Setting |other.size_| will
641     // mask the pointer values still in |other|.
642     other.size_ = 0;
643   }
644 
645   TraceArguments& operator=(TraceArguments&&) noexcept;
646 
647   // Accessors
648   size_t size() const { return size_; }
649   const unsigned char* types() const { return types_; }
650   const char* const* names() const { return names_; }
651   const TraceValue* values() const { return values_; }
652 
653   // Reset to empty arguments list.
654   void Reset();
655 
656   // Use |storage| to copy all copyable strings.
657   // If |copy_all_strings| is false, then only the TRACE_VALUE_TYPE_COPY_STRING
658   // values will be copied into storage. If it is true, then argument names are
659   // also copied to storage, as well as the strings pointed to by
660   // |*extra_string1| and |*extra_string2|.
661   // NOTE: If there are no strings to copy, |*storage| is left untouched.
662   void CopyStringsTo(StringStorage* storage,
663                      bool copy_all_strings,
664                      const char** extra_string1,
665                      const char** extra_string2);
666 
667   // Append debug string representation to |*out|.
668   void AppendDebugString(std::string* out);
669 
670  private:
671   unsigned char size_;
672   unsigned char types_[kMaxSize];
673   const char* names_[kMaxSize];
674   TraceValue values_[kMaxSize];
675 };
676 
677 }  // namespace trace_event
678 }  // namespace base
679 
680 #endif  // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
681