to_string.h (4382B)
1 // Copyright 2023 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_STRINGS_TO_STRING_H_ 6 #define BASE_STRINGS_TO_STRING_H_ 7 8 #include <ios> 9 #include <memory> 10 #include <sstream> 11 #include <string> 12 #include <tuple> 13 #include <type_traits> 14 #include <utility> 15 16 #include "base/template_util.h" 17 #include "base/types/supports_ostream_operator.h" 18 19 namespace base { 20 21 template <typename... Ts> 22 std::string ToString(const Ts&... values); 23 24 namespace internal { 25 26 template <typename T, typename = void> 27 struct SupportsToString : std::false_type {}; 28 template <typename T> 29 struct SupportsToString<T, decltype(void(std::declval<T>().ToString()))> 30 : std::true_type {}; 31 32 // I/O manipulators are function pointers, but should be sent directly to the 33 // `ostream` instead of being cast to `const void*` like other function 34 // pointers. 35 template <typename T, typename = void> 36 constexpr bool IsIomanip = false; 37 template <typename T> 38 constexpr bool 39 IsIomanip<T&(T&), std::enable_if_t<std::is_base_of_v<std::ios_base, T>>> = 40 true; 41 42 // Function pointers implicitly convert to `bool`, so use this to avoid printing 43 // function pointers as 1 or 0. 44 template <typename T, typename = void> 45 constexpr bool WillBeIncorrectlyStreamedAsBool = false; 46 template <typename T> 47 constexpr bool WillBeIncorrectlyStreamedAsBool< 48 T, 49 std::enable_if_t<std::is_function_v<std::remove_pointer_t<T>> && 50 !IsIomanip<std::remove_pointer_t<T>>>> = true; 51 52 // Fallback case when there is no better representation. 53 template <typename T, typename = void> 54 struct ToStringHelper { 55 static void Stringify(const T& v, std::ostringstream& ss) { 56 ss << "[" << sizeof(v) << "-byte object at 0x" << std::addressof(v) << "]"; 57 } 58 }; 59 60 // Most streamables. 61 template <typename T> 62 struct ToStringHelper< 63 T, std::enable_if_t<SupportsOstreamOperator<const T&>::value && 64 !WillBeIncorrectlyStreamedAsBool<T>>> { 65 static void Stringify(const T& v, std::ostringstream& ss) { ss << v; } 66 }; 67 68 // Functions and function pointers. 69 template <typename T> 70 struct ToStringHelper< 71 T, std::enable_if_t<SupportsOstreamOperator<const T&>::value && 72 WillBeIncorrectlyStreamedAsBool<T>>> { 73 static void Stringify(const T& v, std::ostringstream& ss) { 74 ToStringHelper<const void*>::Stringify(reinterpret_cast<const void*>(v), 75 ss); 76 } 77 }; 78 79 // Non-streamables that have a `ToString` member. 80 template <typename T> 81 struct ToStringHelper< 82 T, std::enable_if_t<!SupportsOstreamOperator<const T&>::value && 83 SupportsToString<const T&>::value>> { 84 static void Stringify(const T& v, std::ostringstream& ss) { 85 // .ToString() may not return a std::string, e.g. blink::WTF::String. 86 ToStringHelper<decltype(v.ToString())>::Stringify(v.ToString(), ss); 87 } 88 }; 89 90 // Non-streamable enums (i.e. scoped enums where no `operator<<` overload was 91 // declared). 92 template <typename T> 93 struct ToStringHelper< 94 T, std::enable_if_t<!SupportsOstreamOperator<const T&>::value && 95 std::is_enum_v<T>>> { 96 static void Stringify(const T& v, std::ostringstream& ss) { 97 using UT = typename std::underlying_type_t<T>; 98 ToStringHelper<UT>::Stringify(static_cast<UT>(v), ss); 99 } 100 }; 101 102 // Tuples. Will recursively apply `ToString()` to each value in the tuple. 103 template <typename... T> 104 struct ToStringHelper<std::tuple<T...>> { 105 template <size_t... I> 106 static void StringifyHelper(const std::tuple<T...>& values, 107 std::index_sequence<I...>, 108 std::ostringstream& ss) { 109 ss << "<"; 110 (..., (ss << (I == 0 ? "" : ", "), ss << ToString(std::get<I>(values)))); 111 ss << ">"; 112 } 113 114 static void Stringify(const std::tuple<T...>& v, std::ostringstream& ss) { 115 StringifyHelper(v, std::make_index_sequence<sizeof...(T)>(), ss); 116 } 117 }; 118 119 } // namespace internal 120 121 // Converts any type to a string, preferring defined operator<<() or ToString() 122 // methods if they exist. 123 template <typename... Ts> 124 std::string ToString(const Ts&... values) { 125 std::ostringstream ss; 126 (..., internal::ToStringHelper<remove_cvref_t<decltype(values)>>::Stringify( 127 values, ss)); 128 return ss.str(); 129 } 130 131 } // namespace base 132 133 #endif // BASE_STRINGS_TO_STRING_H_