[M85 Dev][EFL] Fix crashes at webview launch
[platform/framework/web/chromium-efl.git] / base / check_op.h
1 // 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
8 #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
17 // values of x and y if the condition doesn't hold. This works for basic types
18 // 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.
27 //
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.
31
32 namespace logging {
33
34 // Functions for turning check operand values into strings.
35 // Caller takes ownership of the returned string.
36 BASE_EXPORT char* CheckOpValueStr(int v);
37 BASE_EXPORT char* CheckOpValueStr(unsigned v);
38 BASE_EXPORT char* CheckOpValueStr(long v);
39 BASE_EXPORT char* CheckOpValueStr(unsigned long v);
40 BASE_EXPORT char* CheckOpValueStr(long long v);
41 BASE_EXPORT char* CheckOpValueStr(unsigned long long v);
42 BASE_EXPORT char* CheckOpValueStr(const void* v);
43 BASE_EXPORT char* CheckOpValueStr(std::nullptr_t v);
44 BASE_EXPORT char* CheckOpValueStr(double v);
45
46 // Convert a streamable value to string out-of-line to avoid <sstream>.
47 BASE_EXPORT char* StreamValToStr(const void* v,
48                                  void (*stream_func)(std::ostream&,
49                                                      const void*));
50
51 #ifdef __has_builtin
52 #define SUPPORTS_BUILTIN_ADDRESSOF (__has_builtin(__builtin_addressof))
53 #else
54 #define SUPPORTS_BUILTIN_ADDRESSOF 0
55 #endif
56
57 template <typename T>
58 inline 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
62 CheckOpValueStr(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.
70 #if SUPPORTS_BUILTIN_ADDRESSOF
71   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
80 #undef SUPPORTS_BUILTIN_ADDRESSOF
81
82 // Overload for types that have no operator<< but do have .ToString() defined.
83 template <typename T>
84 inline typename std::enable_if<
85     !base::internal::SupportsOstreamOperator<const T&>::value &&
86         base::internal::SupportsToString<const T&>::value,
87     char*>::type
88 CheckOpValueStr(const T& v) {
89   // .ToString() may not return a std::string, e.g. blink::WTF::String.
90   return CheckOpValueStr(v.ToString());
91 }
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.)
98 template <typename T>
99 inline typename std::enable_if<
100     std::is_function<typename std::remove_pointer<T>::type>::value,
101     char*>::type
102 CheckOpValueStr(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).
108 template <typename T>
109 inline typename std::enable_if<
110     !base::internal::SupportsOstreamOperator<const T&>::value &&
111         std::is_enum<T>::value,
112     char*>::type
113 CheckOpValueStr(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.
119 class CheckOpResult {
120  public:
121   // An empty result signals success.
122   constexpr CheckOpResult() {}
123
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:
135   char* message_ = nullptr;
136 };
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
164 // The second overload avoids address-taking of static members for
165 // fundamental types.
166 #define DEFINE_CHECK_OP_IMPL(name, op)                                         \
167   template <typename T, typename U,                                            \
168             std::enable_if_t<!std::is_fundamental<T>::value ||                 \
169                                  !std::is_fundamental<U>::value,               \
170                              int> = 0>                                         \
171   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();                                       \
175     return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1),             \
176                                     CheckOpValueStr(v2));                      \
177   }                                                                            \
178   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,             \
183                                                        const char* expr_str) { \
184     if (ANALYZER_ASSUME_TRUE(v1 op v2))                                        \
185       return ::logging::CheckOpResult();                                       \
186     return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1),             \
187                                     CheckOpValueStr(v2));                      \
188   }
189
190 // clang-format off
191 DEFINE_CHECK_OP_IMPL(EQ, ==)
192 DEFINE_CHECK_OP_IMPL(NE, !=)
193 DEFINE_CHECK_OP_IMPL(LE, <=)
194 DEFINE_CHECK_OP_IMPL(LT, < )
195 DEFINE_CHECK_OP_IMPL(GE, >=)
196 DEFINE_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_