tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_