123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- // Copyright 2020 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.
- #ifndef BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
- #define BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
- #include <sstream>
- #include <string>
- #include "base/optional.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/template_util.h"
- #include "base/trace_event/traced_value.h"
- namespace base {
- namespace trace_event {
- // Helpers for base::trace_event::ValueToString.
- namespace internal {
- // Return std::string representation given by |value|'s ostream operator<<.
- template <typename ValueType>
- std::string OstreamValueToString(const ValueType& value) {
- std::stringstream ss;
- ss << value;
- return ss.str();
- }
- // Use SFINAE to decide how to extract a string from the given parameter.
- // Check if |value| can be used as a parameter of |base::NumberToString|. If
- // std::string is not constructible from the returned value of
- // |base::NumberToString| cause compilation error.
- //
- // |base::NumberToString| does not do locale specific formatting and should be
- // faster than using |std::ostream::operator<<|.
- template <typename ValueType>
- decltype(base::NumberToString(std::declval<const ValueType>()), std::string())
- ValueToStringHelper(base::internal::priority_tag<5>,
- const ValueType& value,
- std::string /* unused */) {
- return base::NumberToString(value);
- }
- // If there is |ValueType::ToString| whose return value can be used to construct
- // |std::string|, use this. Else use other methods.
- template <typename ValueType>
- decltype(std::string(std::declval<const ValueType>().ToString()))
- ValueToStringHelper(base::internal::priority_tag<4>,
- const ValueType& value,
- std::string /* unused */) {
- return value.ToString();
- }
- // If |std::ostream::operator<<| can be used, use it. Useful for |void*|.
- template <typename ValueType>
- decltype(
- std::declval<std::ostream>().operator<<(std::declval<const ValueType>()),
- std::string())
- ValueToStringHelper(base::internal::priority_tag<3>,
- const ValueType& value,
- std::string /* unused */) {
- return OstreamValueToString(value);
- }
- // Use |ValueType::operator<<| if applicable.
- template <typename ValueType>
- decltype(operator<<(std::declval<std::ostream&>(),
- std::declval<const ValueType&>()),
- std::string())
- ValueToStringHelper(base::internal::priority_tag<2>,
- const ValueType& value,
- std::string /* unused */) {
- return OstreamValueToString(value);
- }
- // If there is |ValueType::data| whose return value can be used to construct
- // |std::string|, use it.
- template <typename ValueType>
- decltype(std::string(std::declval<const ValueType>().data()))
- ValueToStringHelper(base::internal::priority_tag<1>,
- const ValueType& value,
- std::string /* unused */) {
- return value.data();
- }
- // Fallback returns the |fallback_value|. Needs to have |ValueToStringPriority|
- // with the highest number (to be called last).
- template <typename ValueType>
- std::string ValueToStringHelper(base::internal::priority_tag<0>,
- const ValueType& /* unused */,
- std::string fallback_value) {
- return fallback_value;
- }
- /*********************************************
- ********* SetTracedValueArg methods. *********
- *********************************************/
- // base::internal::priority_tag parameter is there to define ordering in which
- // the following methods will be considered. Note that for instance |bool| type
- // is also |std::is_integral|, so we need to test |bool| before testing for
- // integral.
- template <typename T>
- typename std::enable_if<std::is_same<T, bool>::value>::type
- SetTracedValueArgHelper(base::internal::priority_tag<6>,
- TracedValue* traced_value,
- const char* name,
- const T& value) {
- traced_value->SetBoolean(name, value);
- }
- // std::is_integral<bool>::value == true
- // This needs to be considered only when T is not bool (has higher
- // base::internal::priority_tag).
- template <typename T>
- typename std::enable_if<std::is_integral<T>::value>::type
- SetTracedValueArgHelper(base::internal::priority_tag<5>,
- TracedValue* traced_value,
- const char* name,
- const T& value) {
- // Avoid loss of precision.
- if (sizeof(int) < sizeof(value)) {
- // TODO(crbug.com/1111787): Add 64-bit support to TracedValue.
- traced_value->SetString(name, base::NumberToString(value));
- } else {
- traced_value->SetInteger(name, value);
- }
- }
- // Any floating point type is converted to double.
- template <typename T>
- typename std::enable_if<std::is_floating_point<T>::value>::type
- SetTracedValueArgHelper(base::internal::priority_tag<4>,
- TracedValue* traced_value,
- const char* name,
- const T& value) {
- traced_value->SetDouble(name, static_cast<double>(value));
- }
- // |void*| is traced natively.
- template <typename T>
- typename std::enable_if<std::is_same<T, void*>::value>::type
- SetTracedValueArgHelper(base::internal::priority_tag<3>,
- TracedValue* traced_value,
- const char* name,
- const T& value) {
- traced_value->SetPointer(name, value);
- }
- // |const char*| is traced natively.
- template <typename T>
- typename std::enable_if<std::is_same<T, const char*>::value>::type
- SetTracedValueArgHelper(base::internal::priority_tag<2>,
- TracedValue* traced_value,
- const char* name,
- const T& value) {
- traced_value->SetString(name, value);
- }
- // If an instance of |base::StringPiece| can be constructed from an instance of
- // |T| trace |value| as a string.
- template <typename T>
- decltype(base::StringPiece(std::declval<const T>()), void())
- SetTracedValueArgHelper(base::internal::priority_tag<1>,
- TracedValue* traced_value,
- const char* name,
- const T& value) {
- traced_value->SetString(name, value);
- }
- // Fallback.
- template <typename T>
- void SetTracedValueArgHelper(base::internal::priority_tag<0>,
- TracedValue* traced_value,
- const char* name,
- const T& /* unused */) {
- // TODO(crbug.com/1111787): Add fallback to |ValueToString|. Crashes on
- // operator<< have been seen with it.
- traced_value->SetString(name, "<value>");
- }
- } // namespace internal
- // The function to be used.
- template <typename ValueType>
- std::string ValueToString(const ValueType& value,
- std::string fallback_value = "<value>") {
- return internal::ValueToStringHelper(base::internal::priority_tag<5>(), value,
- std::move(fallback_value));
- }
- // ToTracedValue helpers simplify using |AsValueInto| method to capture by
- // eliminating the need to create TracedValue manually. Also supports passing
- // pointers, including null ones.
- template <typename T>
- std::unique_ptr<TracedValue> ToTracedValue(T& value) {
- std::unique_ptr<TracedValue> result = std::make_unique<TracedValue>();
- // AsValueInto might not be const-only, so do not use const references.
- value.AsValueInto(result.get());
- return result;
- }
- template <typename T>
- std::unique_ptr<TracedValue> ToTracedValue(T* value) {
- if (!value)
- return TracedValue::Build({{"this", "nullptr"}});
- return ToTracedValue(*value);
- }
- // Method to trace |value| into the given |traced_value|. Support types where
- // there is |TracedValue::SetT| natively.
- //
- // TODO(crbug.com/1111787): Add support for:
- // base::Optional
- // AsValueInto (T& and T*)
- // array and map types
- // fallback to ValueToString
- template <typename ValueType>
- void SetTracedValueArg(TracedValue* traced_value,
- const char* name,
- const ValueType& value) {
- internal::SetTracedValueArgHelper(base::internal::priority_tag<6>(),
- traced_value, name, value);
- }
- // Parameter pack support: do nothing for an empty parameter pack.
- //
- // Inline this to avoid linker duplicate symbol error.
- inline void SetTracedValueArg(TracedValue* traced_value, const char* name) {}
- // Parameter pack support. All of the packed parameters are traced under the
- // same name. Serves to trace a parameter pack, all parameters having the same
- // name (of the parameter pack) is desired.
- //
- // Example use when |args| is a parameter pack:
- // SetTracedValueArg(traced_value, name, args...);
- template <typename ValueType, typename... ValueTypes>
- void SetTracedValueArg(TracedValue* traced_value,
- const char* name,
- const ValueType& value,
- const ValueTypes&... args) {
- SetTracedValueArg(traced_value, name, value);
- // Trace the rest from the parameter pack.
- SetTracedValueArg(traced_value, name, args...);
- }
- } // namespace trace_event
- } // namespace base
- #endif // BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
|