no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / mfbt / DbgMacro.h
blob3247b993c05cc7fe61b254a3504e8e71e0355893
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/. */
7 #ifndef mozilla_DbgMacro_h
8 #define mozilla_DbgMacro_h
10 /* a MOZ_DBG macro that outputs a wrapped value to stderr then returns it */
12 #include "mozilla/MacroForEach.h"
13 #include "mozilla/Span.h"
15 #include <stdio.h>
16 #include <sstream>
18 template <typename T>
19 class nsTSubstring;
21 #ifdef ANDROID
22 # include <android/log.h>
23 #endif
25 namespace mozilla {
27 namespace detail {
29 // Predicate to check whether T can be inserted into an ostream.
30 template <typename T, typename = decltype(std::declval<std::ostream&>()
31 << std::declval<T>())>
32 std::true_type supports_os_test(const T&);
33 std::false_type supports_os_test(...);
35 template <typename T>
36 using supports_os = decltype(supports_os_test(std::declval<T>()));
38 } // namespace detail
40 // Helper function to write a value to an ostream.
42 // This handles pointer values where the type being pointed to supports being
43 // inserted into an ostream, and we write out the value being pointed to in
44 // addition to the pointer value.
45 template <typename T>
46 auto DebugValue(std::ostream& aOut, T* aValue)
47 -> std::enable_if_t<mozilla::detail::supports_os<T>::value, std::ostream&> {
48 if (aValue) {
49 aOut << *aValue << " @ " << aValue;
50 } else {
51 aOut << "null";
53 return aOut;
56 // Helper function to write a value to an ostream.
58 // This handles all pointer types that cannot be dereferenced and inserted into
59 // an ostream.
60 template <typename T>
61 auto DebugValue(std::ostream& aOut, T* aValue)
62 -> std::enable_if_t<!mozilla::detail::supports_os<T>::value,
63 std::ostream&> {
64 return aOut << aValue;
67 // Helper function to write a value to an ostream.
69 // This handles XPCOM string types.
70 template <typename T>
71 auto DebugValue(std::ostream& aOut, const T& aValue)
72 -> std::enable_if_t<std::is_base_of<nsTSubstring<char>, T>::value ||
73 std::is_base_of<nsTSubstring<char16_t>, T>::value,
74 std::ostream&> {
75 return aOut << '"' << aValue << '"';
78 // Helper function to write a value to an ostream.
80 // This handles all other types.
81 template <typename T>
82 auto DebugValue(std::ostream& aOut, const T& aValue)
83 -> std::enable_if_t<!std::is_base_of<nsTSubstring<char>, T>::value &&
84 !std::is_base_of<nsTSubstring<char16_t>, T>::value,
85 std::ostream&> {
86 return aOut << aValue;
89 namespace detail {
91 // Helper function template for MOZ_DBG.
92 template <typename T>
93 auto&& MozDbg(const char* aFile, int aLine, const char* aExpression,
94 T&& aValue) {
95 std::ostringstream s;
96 s << "[MozDbg] [" << aFile << ':' << aLine << "] " << aExpression << " = ";
97 mozilla::DebugValue(s, std::forward<T>(aValue));
98 s << '\n';
99 #ifdef ANDROID
100 __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", s.str().c_str());
101 #else
102 fputs(s.str().c_str(), stderr);
103 #endif
104 return std::forward<T>(aValue);
107 } // namespace detail
109 } // namespace mozilla
111 template <class ElementType, size_t Extent>
112 std::ostream& operator<<(std::ostream& aOut,
113 const mozilla::Span<ElementType, Extent>& aSpan) {
114 aOut << '[';
115 if (!aSpan.IsEmpty()) {
116 aOut << aSpan[0];
117 for (size_t i = 1; i < aSpan.Length(); ++i) {
118 aOut << ", " << aSpan[i];
121 return aOut << ']';
124 // Don't define this for char[], since operator<<(ostream&, char*) is already
125 // defined.
126 template <typename T, size_t N,
127 typename = std::enable_if_t<!std::is_same<T, char>::value>>
128 std::ostream& operator<<(std::ostream& aOut, const T (&aArray)[N]) {
129 return aOut << mozilla::Span(aArray);
132 // MOZ_DBG is a macro like the Rust dbg!() macro -- it will print out the
133 // expression passed to it to stderr and then return the value. It is not
134 // available in MOZILLA_OFFICIAL builds, so you shouldn't land any uses of it in
135 // the tree.
137 // It should work for any type T that has an operator<<(std::ostream&, const T&)
138 // defined for it.
140 // Note 1: Using MOZ_DBG may cause copies to be made of temporary values:
142 // struct A {
143 // A(int);
144 // A(const A&);
146 // int x;
147 // };
149 // void f(A);
151 // f(A{1}); // may (and, in C++17, will) elide the creation of a temporary
152 // // for A{1} and instead initialize the function argument
153 // // directly using the A(int) constructor
155 // f(MOZ_DBG(A{1})); // will create and return a temporary for A{1}, which
156 // // then will be passed to the A(const A&) copy
157 // // constructor to initialize f's argument
159 // Note 2: MOZ_DBG cannot be used to wrap a prvalue that is being used to
160 // initialize an object if its type has no move constructor:
162 // struct B {
163 // B() = default;
164 // B(B&&) = delete;
165 // };
167 // B b1 = B(); // fine, initializes b1 directly
169 // B b2 = MOZ_DBG(B()); // compile error: MOZ_DBG needs to materialize a
170 // // temporary for B() so it can be passed to
171 // // operator<<, but that temporary is returned from
172 // // MOZ_DBG as an rvalue reference and so wants to
173 // // invoke B's move constructor to initialize b2
174 #ifndef MOZILLA_OFFICIAL
175 # define MOZ_DBG(...) \
176 mozilla::detail::MozDbg(__FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__)
177 #endif
179 // Helper macro for MOZ_DEFINE_DBG.
180 #define MOZ_DBG_FIELD(name_) << #name_ << " = " << aValue.name_
182 // Macro to define an operator<<(ostream&) for a struct or class that displays
183 // the type name and the values of the specified member variables. Must be
184 // called inside the struct or class.
186 // For example:
188 // struct Point {
189 // float x;
190 // float y;
192 // MOZ_DEFINE_DBG(Point, x, y)
193 // };
195 // generates an operator<< that outputs strings like
196 // "Point { x = 1.0, y = 2.0 }".
197 #define MOZ_DEFINE_DBG(type_, ...) \
198 friend std::ostream& operator<<(std::ostream& aOut, const type_& aValue) { \
199 return aOut << #type_ \
200 << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " { ") \
201 MOZ_FOR_EACH_SEPARATED(MOZ_DBG_FIELD, (<< ", "), (), \
202 (__VA_ARGS__)) \
203 << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " }"); \
206 #endif // mozilla_DbgMacro_h