blob: 1acfa614e952f165d9aae011baba9973f3c24bf3 [file] [log] [blame]
Hans Wennborg12aea3e2020-04-14 15:29:001// Copyright 2020 The Chromium Authors. All rights reserved.
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_CHECK_OP_H_
6#define BASE_CHECK_OP_H_
7
Hans Wennborg12aea3e2020-04-14 15:29:008#include <cstddef>
9#include <type_traits>
10
11#include "base/check.h"
12#include "base/template_util.h"
13
14// This header defines the (DP)CHECK_EQ etc. macros.
15//
16// (DP)CHECK_EQ(x, y) is similar to (DP)CHECK(x == y) but will also log the
Hans Wennborgd80f6e62020-04-27 19:21:5617// values of x and y if the condition doesn't hold. This works for basic types
Hans Wennborg12aea3e2020-04-14 15:29:0018// and types with an operator<< or .ToString() method.
19//
20// The operands are evaluated exactly once, and even in build modes where e.g.
21// DCHECK is disabled, the operands and their stringification methods are still
22// referenced to avoid warnings about unused variables or functions.
23//
24// To support the stringification of the check operands, this header is
25// *significantly* larger than base/check.h, so it should be avoided in common
26// headers.
Hans Wennborgd80f6e62020-04-27 19:21:5627//
28// This header also provides the (DP)CHECK macros (by including check.h), so if
29// you use e.g. both CHECK_EQ and CHECK, including this header is enough. If you
30// only use CHECK however, please include the smaller check.h instead.
Hans Wennborg12aea3e2020-04-14 15:29:0031
32namespace logging {
33
34// Functions for turning check operand values into strings.
35// Caller takes ownership of the returned string.
36BASE_EXPORT char* CheckOpValueStr(int v);
37BASE_EXPORT char* CheckOpValueStr(unsigned v);
Hans Wennborg338a7f402020-04-20 19:52:3238BASE_EXPORT char* CheckOpValueStr(long v);
Hans Wennborg12aea3e2020-04-14 15:29:0039BASE_EXPORT char* CheckOpValueStr(unsigned long v);
Hans Wennborg338a7f402020-04-20 19:52:3240BASE_EXPORT char* CheckOpValueStr(long long v);
41BASE_EXPORT char* CheckOpValueStr(unsigned long long v);
Hans Wennborg12aea3e2020-04-14 15:29:0042BASE_EXPORT char* CheckOpValueStr(const void* v);
43BASE_EXPORT char* CheckOpValueStr(std::nullptr_t v);
44BASE_EXPORT char* CheckOpValueStr(double v);
45
46// Convert a streamable value to string out-of-line to avoid <sstream>.
47BASE_EXPORT char* StreamValToStr(const void* v,
48 void (*stream_func)(std::ostream&,
49 const void*));
50
Stephan Hartmann9d518a62020-06-01 19:45:0151#ifdef __has_builtin
52#define SUPPORTS_BUILTIN_ADDRESSOF (__has_builtin(__builtin_addressof))
53#else
54#define SUPPORTS_BUILTIN_ADDRESSOF 0
Stephan Hartmannc65d17e2020-05-04 16:00:2855#endif
56
Hans Wennborg12aea3e2020-04-14 15:29:0057template <typename T>
58inline typename std::enable_if<
59 base::internal::SupportsOstreamOperator<const T&>::value &&
60 !std::is_function<typename std::remove_pointer<T>::type>::value,
61 char*>::type
62CheckOpValueStr(const T& v) {
63 auto f = [](std::ostream& s, const void* p) {
64 s << *reinterpret_cast<const T*>(p);
65 };
66
67 // operator& might be overloaded, so do the std::addressof dance.
68 // __builtin_addressof is preferred since it also handles Obj-C ARC pointers.
69 // Some casting is still needed, because T might be volatile.
Stephan Hartmann9d518a62020-06-01 19:45:0170#if SUPPORTS_BUILTIN_ADDRESSOF
Hans Wennborg12aea3e2020-04-14 15:29:0071 const void* vp = const_cast<const void*>(
72 reinterpret_cast<const volatile void*>(__builtin_addressof(v)));
73#else
74 const void* vp = reinterpret_cast<const void*>(
75 const_cast<const char*>(&reinterpret_cast<const volatile char&>(v)));
76#endif
77 return StreamValToStr(vp, f);
78}
79
Stephan Hartmann9d518a62020-06-01 19:45:0180#undef SUPPORTS_BUILTIN_ADDRESSOF
81
Hans Wennborg12aea3e2020-04-14 15:29:0082// Overload for types that have no operator<< but do have .ToString() defined.
83template <typename T>
84inline typename std::enable_if<
85 !base::internal::SupportsOstreamOperator<const T&>::value &&
86 base::internal::SupportsToString<const T&>::value,
87 char*>::type
88CheckOpValueStr(const T& v) {
Hitoshi Yoshidaca053b92020-04-20 19:38:0689 // .ToString() may not return a std::string, e.g. blink::WTF::String.
90 return CheckOpValueStr(v.ToString());
Hans Wennborg12aea3e2020-04-14 15:29:0091}
92
93// Provide an overload for functions and function pointers. Function pointers
94// don't implicitly convert to void* but do implicitly convert to bool, so
95// without this function pointers are always printed as 1 or 0. (MSVC isn't
96// standards-conforming here and converts function pointers to regular
97// pointers, so this is a no-op for MSVC.)
98template <typename T>
99inline typename std::enable_if<
100 std::is_function<typename std::remove_pointer<T>::type>::value,
101 char*>::type
102CheckOpValueStr(const T& v) {
103 return CheckOpValueStr(reinterpret_cast<const void*>(v));
104}
105
106// We need overloads for enums that don't support operator<<.
107// (i.e. scoped enums where no operator<< overload was declared).
108template <typename T>
109inline typename std::enable_if<
110 !base::internal::SupportsOstreamOperator<const T&>::value &&
111 std::is_enum<T>::value,
112 char*>::type
113CheckOpValueStr(const T& v) {
114 return CheckOpValueStr(
115 static_cast<typename std::underlying_type<T>::type>(v));
116}
117
118// Captures the result of a CHECK_op and facilitates testing as a boolean.
119class CheckOpResult {
120 public:
121 // An empty result signals success.
Hans Wennborg773f52372020-05-15 19:25:32122 constexpr CheckOpResult() {}
Hans Wennborg12aea3e2020-04-14 15:29:00123
124 // A non-success result. expr_str is something like "foo != bar". v1_str and
125 // v2_str are the stringified run-time values of foo and bar. Takes ownership
126 // of v1_str and v2_str.
127 BASE_EXPORT CheckOpResult(const char* expr_str, char* v1_str, char* v2_str);
128
129 // Returns true if the check succeeded.
130 constexpr explicit operator bool() const { return !message_; }
131
132 friend class CheckError;
133
134 private:
Lei Zhang4a0950f2020-04-18 07:14:02135 char* message_ = nullptr;
Hans Wennborg12aea3e2020-04-14 15:29:00136};
137
138#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
139
140// Discard log strings to reduce code bloat.
141#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
142
143#else
144
145// Helper macro for binary operators.
146// The 'switch' is used to prevent the 'else' from being ambiguous when the
147// macro is used in an 'if' clause such as:
148// if (a == 1)
149// CHECK_EQ(2, a);
150#define CHECK_OP(name, op, val1, val2) \
151 switch (0) \
152 case 0: \
153 default: \
154 if (::logging::CheckOpResult true_if_passed = \
155 ::logging::Check##name##Impl((val1), (val2), \
156 #val1 " " #op " " #val2)) \
157 ; \
158 else \
159 ::logging::CheckError::CheckOp(__FILE__, __LINE__, &true_if_passed) \
160 .stream()
161
162#endif
163
Tom Andersonc84fb462020-06-08 23:08:53164// The second overload avoids address-taking of static members for
165// fundamental types.
Hans Wennborg12aea3e2020-04-14 15:29:00166#define DEFINE_CHECK_OP_IMPL(name, op) \
Tom Andersonc84fb462020-06-08 23:08:53167 template <typename T, typename U, \
168 std::enable_if_t<!std::is_fundamental<T>::value || \
169 !std::is_fundamental<U>::value, \
170 int> = 0> \
Hans Wennborg12aea3e2020-04-14 15:29:00171 constexpr ::logging::CheckOpResult Check##name##Impl( \
172 const T& v1, const U& v2, const char* expr_str) { \
173 if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
174 return ::logging::CheckOpResult(); \
Lei Zhang4a0950f2020-04-18 07:14:02175 return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1), \
176 CheckOpValueStr(v2)); \
Hans Wennborg12aea3e2020-04-14 15:29:00177 } \
Tom Andersonc84fb462020-06-08 23:08:53178 template <typename T, typename U, \
179 std::enable_if_t<std::is_fundamental<T>::value && \
180 std::is_fundamental<U>::value, \
181 int> = 0> \
182 constexpr ::logging::CheckOpResult Check##name##Impl(T v1, U v2, \
Hans Wennborg12aea3e2020-04-14 15:29:00183 const char* expr_str) { \
184 if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
185 return ::logging::CheckOpResult(); \
Lei Zhang4a0950f2020-04-18 07:14:02186 return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1), \
187 CheckOpValueStr(v2)); \
Hans Wennborg12aea3e2020-04-14 15:29:00188 }
189
190// clang-format off
191DEFINE_CHECK_OP_IMPL(EQ, ==)
192DEFINE_CHECK_OP_IMPL(NE, !=)
193DEFINE_CHECK_OP_IMPL(LE, <=)
194DEFINE_CHECK_OP_IMPL(LT, < )
195DEFINE_CHECK_OP_IMPL(GE, >=)
196DEFINE_CHECK_OP_IMPL(GT, > )
197#undef DEFINE_CHECK_OP_IMPL
198#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
199#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
200#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
201#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
202#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
203#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
204// clang-format on
205
206#if DCHECK_IS_ON()
207
208#define DCHECK_OP(name, op, val1, val2) \
209 switch (0) \
210 case 0: \
211 default: \
212 if (::logging::CheckOpResult true_if_passed = \
213 ::logging::Check##name##Impl((val1), (val2), \
214 #val1 " " #op " " #val2)) \
215 ; \
216 else \
217 ::logging::CheckError::DCheckOp(__FILE__, __LINE__, &true_if_passed) \
218 .stream()
219
220#else
221
222// Don't do any evaluation but still reference the same stuff as when enabled.
223#define DCHECK_OP(name, op, val1, val2) \
224 EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \
225 ::logging::CheckOpValueStr(val2), (val1)op(val2)))
226
227#endif
228
229// clang-format off
230#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
231#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
232#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
233#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
234#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
235#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
236// clang-format on
237
238} // namespace logging
239
240#endif // BASE_CHECK_OP_H_