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"
22 # include <android/log.h>
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(...);
36 using supports_os
= decltype(supports_os_test(std::declval
<T
>()));
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.
46 auto DebugValue(std::ostream
& aOut
, T
* aValue
)
47 -> std::enable_if_t
<mozilla::detail::supports_os
<T
>::value
, std::ostream
&> {
49 aOut
<< *aValue
<< " @ " << aValue
;
56 // Helper function to write a value to an ostream.
58 // This handles all pointer types that cannot be dereferenced and inserted into
61 auto DebugValue(std::ostream
& aOut
, T
* aValue
)
62 -> std::enable_if_t
<!mozilla::detail::supports_os
<T
>::value
,
64 return aOut
<< aValue
;
67 // Helper function to write a value to an ostream.
69 // This handles XPCOM string types.
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
,
75 return aOut
<< '"' << aValue
<< '"';
78 // Helper function to write a value to an ostream.
80 // This handles all other types.
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
,
86 return aOut
<< aValue
;
91 // Helper function template for MOZ_DBG.
93 auto&& MozDbg(const char* aFile
, int aLine
, const char* aExpression
,
96 s
<< "[MozDbg] [" << aFile
<< ':' << aLine
<< "] " << aExpression
<< " = ";
97 mozilla::DebugValue(s
, std::forward
<T
>(aValue
));
100 __android_log_print(ANDROID_LOG_INFO
, "Gecko", "%s", s
.str().c_str());
102 fputs(s
.str().c_str(), stderr
);
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
) {
115 if (!aSpan
.IsEmpty()) {
117 for (size_t i
= 1; i
< aSpan
.Length(); ++i
) {
118 aOut
<< ", " << aSpan
[i
];
124 // Don't define this for char[], since operator<<(ostream&, char*) is already
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
137 // It should work for any type T that has an operator<<(std::ostream&, const T&)
140 // Note 1: Using MOZ_DBG may cause copies to be made of temporary values:
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:
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__)
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.
192 // MOZ_DEFINE_DBG(Point, x, y)
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, (<< ", "), (), \
203 << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " }"); \
206 #endif // mozilla_DbgMacro_h