tor-browser

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

DbgMacro.h (6163B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_DbgMacro_h
      8 #define mozilla_DbgMacro_h
      9 
     10 /* a MOZ_DBG macro that outputs a wrapped value to stderr then returns it */
     11 
     12 #include "mozilla/MacroForEach.h"
     13 #include "mozilla/Span.h"
     14 
     15 #include <cstdio>
     16 #include <sstream>
     17 
     18 template <typename T>
     19 class nsTSubstring;
     20 
     21 #ifdef ANDROID
     22 #  include <android/log.h>
     23 #endif
     24 
     25 namespace mozilla {
     26 
     27 namespace detail {
     28 
     29 // Predicate to check whether T can be inserted into an ostream.
     30 template <typename T, typename = void>
     31 struct supports_os : std::false_type {};
     32 
     33 template <typename T>
     34 struct supports_os<T, std::void_t<decltype(std::declval<std::ostream&>()
     35                                           << std::declval<T&>())>>
     36    : std::true_type {};
     37 
     38 }  // namespace detail
     39 
     40 // Helper function to write a value to an ostream.
     41 //
     42 // This handles both pointer values where the type being pointed to supports
     43 // being inserted into an ostream (in which case we write out the value being
     44 // pointed to in addition to the pointer value), and pointer types that cannot
     45 // be dereferenced (in which cases we just write the pointer value).
     46 template <typename T>
     47 std::ostream& DebugValue(std::ostream& aOut, T* aValue) {
     48  if constexpr (detail::supports_os<T>::value) {
     49    if (aValue) {
     50      return aOut << *aValue << " @ " << aValue;
     51    } else {
     52      return aOut << "null";
     53    }
     54  } else {
     55    return aOut << aValue;
     56  }
     57 }
     58 
     59 // Helper function to write a value to an ostream.
     60 //
     61 // This handle all non-pointer types, with a specialization for XPCOM types.
     62 template <typename T>
     63 std::ostream& DebugValue(std::ostream& aOut, const T& aValue) {
     64  if constexpr (std::is_base_of<nsTSubstring<char>, T>::value ||
     65                std::is_base_of<nsTSubstring<char16_t>, T>::value) {
     66    return aOut << '"' << aValue << '"';
     67  } else {
     68    return aOut << aValue;
     69  }
     70 }
     71 
     72 namespace detail {
     73 
     74 // Helper function template for MOZ_DBG.
     75 template <typename T>
     76 auto&& MozDbg(const char* aFile, int aLine, const char* aExpression,
     77              T&& aValue) {
     78  std::ostringstream s;
     79  s << "[MozDbg] [" << aFile << ':' << aLine << "] " << aExpression << " = ";
     80  mozilla::DebugValue(s, std::forward<T>(aValue)) << '\n';
     81 #ifdef ANDROID
     82  __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", s.str().c_str());
     83 #else
     84  fputs(s.str().c_str(), stderr);
     85 #endif
     86  return std::forward<T>(aValue);
     87 }
     88 
     89 }  // namespace detail
     90 
     91 }  // namespace mozilla
     92 
     93 template <class ElementType, size_t Extent>
     94 std::ostream& operator<<(std::ostream& aOut,
     95                         const mozilla::Span<ElementType, Extent>& aSpan) {
     96  aOut << '[';
     97  if (!aSpan.IsEmpty()) {
     98    aOut << aSpan[0];
     99    for (size_t i = 1; i < aSpan.Length(); ++i) {
    100      aOut << ", " << aSpan[i];
    101    }
    102  }
    103  return aOut << ']';
    104 }
    105 
    106 // Don't define this for char[], since operator<<(ostream&, char*) is already
    107 // defined.
    108 template <typename T, size_t N,
    109          typename = std::enable_if_t<!std::is_same<T, char>::value>>
    110 std::ostream& operator<<(std::ostream& aOut, const T (&aArray)[N]) {
    111  return aOut << mozilla::Span(aArray);
    112 }
    113 
    114 // MOZ_DBG is a macro like the Rust dbg!() macro -- it will print out the
    115 // expression passed to it to stderr and then return the value.  It is not
    116 // available in MOZILLA_OFFICIAL builds, so you shouldn't land any uses of it in
    117 // the tree.
    118 //
    119 // It should work for any type T that has an operator<<(std::ostream&, const T&)
    120 // defined for it.
    121 //
    122 // Note 1: Using MOZ_DBG may cause copies to be made of temporary values:
    123 //
    124 //   struct A {
    125 //     A(int);
    126 //     A(const A&);
    127 //
    128 //     int x;
    129 //   };
    130 //
    131 //   void f(A);
    132 //
    133 //   f(A{1});  // may (and, in C++17, will) elide the creation of a temporary
    134 //             // for A{1} and instead initialize the function argument
    135 //             // directly using the A(int) constructor
    136 //
    137 //   f(MOZ_DBG(A{1}));  // will create and return a temporary for A{1}, which
    138 //                      // then will be passed to the A(const A&) copy
    139 //                      // constructor to initialize f's argument
    140 //
    141 // Note 2: MOZ_DBG cannot be used to wrap a prvalue that is being used to
    142 // initialize an object if its type has no move constructor:
    143 //
    144 //   struct B {
    145 //     B() = default;
    146 //     B(B&&) = delete;
    147 //   };
    148 //
    149 //   B b1 = B();  // fine, initializes b1 directly
    150 //
    151 //   B b2 = MOZ_DBG(B());  // compile error: MOZ_DBG needs to materialize a
    152 //                         // temporary for B() so it can be passed to
    153 //                         // operator<<, but that temporary is returned from
    154 //                         // MOZ_DBG as an rvalue reference and so wants to
    155 //                         // invoke B's move constructor to initialize b2
    156 #ifndef MOZILLA_OFFICIAL
    157 #  define MOZ_DBG(...) \
    158    mozilla::detail::MozDbg(__FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__)
    159 #endif
    160 
    161 // Helper macro for MOZ_DEFINE_DBG.
    162 #define MOZ_DBG_FIELD(name_) << #name_ << " = " << aValue.name_
    163 
    164 // Macro to define an operator<<(ostream&) for a struct or class that displays
    165 // the type name and the values of the specified member variables.  Must be
    166 // called inside the struct or class.
    167 //
    168 // For example:
    169 //
    170 //   struct Point {
    171 //     float x;
    172 //     float y;
    173 //
    174 //     MOZ_DEFINE_DBG(Point, x, y)
    175 //   };
    176 //
    177 // generates an operator<< that outputs strings like
    178 // "Point { x = 1.0, y = 2.0 }".
    179 #define MOZ_DEFINE_DBG(type_, ...)                                           \
    180  friend std::ostream& operator<<(std::ostream& aOut, const type_& aValue) { \
    181    return aOut << #type_                                                    \
    182                << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " { ")            \
    183                       MOZ_FOR_EACH_SEPARATED(MOZ_DBG_FIELD, (<< ", "), (),  \
    184                                              (__VA_ARGS__))                 \
    185                << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " }");            \
    186  }
    187 
    188 #endif  // mozilla_DbgMacro_h