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