/src/abseil-cpp/absl/log/internal/check_op.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2022 The Abseil Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | // ----------------------------------------------------------------------------- |
16 | | // File: log/internal/check_op.h |
17 | | // ----------------------------------------------------------------------------- |
18 | | // |
19 | | // This file declares helpers routines and macros used to implement `CHECK` |
20 | | // macros. |
21 | | |
22 | | #ifndef ABSL_LOG_INTERNAL_CHECK_OP_H_ |
23 | | #define ABSL_LOG_INTERNAL_CHECK_OP_H_ |
24 | | |
25 | | #include <stdint.h> |
26 | | |
27 | | #include <cstddef> |
28 | | #include <ostream> |
29 | | #include <sstream> |
30 | | #include <string> |
31 | | #include <type_traits> |
32 | | #include <utility> |
33 | | |
34 | | #include "absl/base/attributes.h" |
35 | | #include "absl/base/config.h" |
36 | | #include "absl/base/nullability.h" |
37 | | #include "absl/base/optimization.h" |
38 | | #include "absl/log/internal/nullguard.h" |
39 | | #include "absl/log/internal/nullstream.h" |
40 | | #include "absl/log/internal/strip.h" |
41 | | #include "absl/strings/has_absl_stringify.h" |
42 | | #include "absl/strings/string_view.h" |
43 | | |
44 | | // `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that |
45 | | // should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`. |
46 | | #ifdef ABSL_MIN_LOG_LEVEL |
47 | | #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) \ |
48 | | (::absl::LogSeverity::kFatal >= \ |
49 | | static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ |
50 | | ? (literal) \ |
51 | | : "") |
52 | | #else |
53 | | #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) (literal) |
54 | | #endif |
55 | | |
56 | | #ifdef NDEBUG |
57 | | // `NDEBUG` is defined, so `DCHECK_EQ(x, y)` and so on do nothing. However, we |
58 | | // still want the compiler to parse `x` and `y`, because we don't want to lose |
59 | | // potentially useful errors and warnings. |
60 | | #define ABSL_LOG_INTERNAL_DCHECK_NOP(x, y) \ |
61 | | while (false && ((void)(x), (void)(y), 0)) \ |
62 | | ::absl::log_internal::NullStream().InternalStream() |
63 | | #endif |
64 | | |
65 | | #define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \ |
66 | | while (::std::string* absl_log_internal_check_op_result \ |
67 | | ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG = \ |
68 | | ::absl::log_internal::name##Impl( \ |
69 | | ::absl::log_internal::GetReferenceableValue(val1), \ |
70 | | ::absl::log_internal::GetReferenceableValue(val2), \ |
71 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ |
72 | | val1_text " " #op " " val2_text))) \ |
73 | | ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ |
74 | | ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_op_result).InternalStream() |
75 | | #define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \ |
76 | | val2_text) \ |
77 | | while (::std::string* absl_log_internal_qcheck_op_result = \ |
78 | | ::absl::log_internal::name##Impl( \ |
79 | | ::absl::log_internal::GetReferenceableValue(val1), \ |
80 | | ::absl::log_internal::GetReferenceableValue(val2), \ |
81 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ |
82 | | val1_text " " #op " " val2_text))) \ |
83 | | ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ |
84 | | ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_op_result).InternalStream() |
85 | | #define ABSL_LOG_INTERNAL_CHECK_STROP(func, op, expected, s1, s1_text, s2, \ |
86 | | s2_text) \ |
87 | | while (::std::string* absl_log_internal_check_strop_result = \ |
88 | | ::absl::log_internal::Check##func##expected##Impl( \ |
89 | | (s1), (s2), \ |
90 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ |
91 | | " " s2_text))) \ |
92 | | ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ |
93 | | ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_strop_result) \ |
94 | | .InternalStream() |
95 | | #define ABSL_LOG_INTERNAL_QCHECK_STROP(func, op, expected, s1, s1_text, s2, \ |
96 | | s2_text) \ |
97 | | while (::std::string* absl_log_internal_qcheck_strop_result = \ |
98 | | ::absl::log_internal::Check##func##expected##Impl( \ |
99 | | (s1), (s2), \ |
100 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ |
101 | | " " s2_text))) \ |
102 | | ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ |
103 | | ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_strop_result) \ |
104 | | .InternalStream() |
105 | | // This one is tricky: |
106 | | // * We must evaluate `val` exactly once, yet we need to do two things with it: |
107 | | // evaluate `.ok()` and (sometimes) `.ToString()`. |
108 | | // * `val` might be an `absl::Status` or some `absl::StatusOr<T>`. |
109 | | // * `val` might be e.g. `ATemporary().GetStatus()`, which may return a |
110 | | // reference to a member of `ATemporary` that is only valid until the end of |
111 | | // the full expression. |
112 | | // * We don't want this file to depend on `absl::Status` `#include`s or linkage, |
113 | | // nor do we want to move the definition to status and introduce a dependency |
114 | | // in the other direction. We can be assured that callers must already have a |
115 | | // `Status` and the necessary `#include`s and linkage. |
116 | | // * Callsites should be small and fast (at least when `val.ok()`): one branch, |
117 | | // minimal stack footprint. |
118 | | // * In particular, the string concat stuff should be out-of-line and emitted |
119 | | // in only one TU to save linker input size |
120 | | // * We want the `val.ok()` check inline so static analyzers and optimizers can |
121 | | // see it. |
122 | | // * As usual, no braces so we can stream into the expansion with `operator<<`. |
123 | | // * Also as usual, it must expand to a single (partial) statement with no |
124 | | // ambiguous-else problems. |
125 | | // * When stripped by `ABSL_MIN_LOG_LEVEL`, we must discard the `<expr> is OK` |
126 | | // string literal and abort without doing any streaming. We don't need to |
127 | | // strip the call to stringify the non-ok `Status` as long as we don't log it; |
128 | | // dropping the `Status`'s message text is out of scope. |
129 | | #define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \ |
130 | | for (::std::pair<const ::absl::Status*, ::std::string*> \ |
131 | | absl_log_internal_check_ok_goo; \ |
132 | | absl_log_internal_check_ok_goo.first = \ |
133 | | ::absl::log_internal::AsStatus(val), \ |
134 | | absl_log_internal_check_ok_goo.second = \ |
135 | | ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ |
136 | | ? nullptr \ |
137 | | : ::absl::status_internal::MakeCheckFailString( \ |
138 | | absl_log_internal_check_ok_goo.first, \ |
139 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ |
140 | | " is OK")), \ |
141 | | !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ |
142 | | ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ |
143 | | ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_ok_goo.second) \ |
144 | | .InternalStream() |
145 | | #define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \ |
146 | | for (::std::pair<const ::absl::Status*, ::std::string*> \ |
147 | | absl_log_internal_qcheck_ok_goo; \ |
148 | | absl_log_internal_qcheck_ok_goo.first = \ |
149 | | ::absl::log_internal::AsStatus(val), \ |
150 | | absl_log_internal_qcheck_ok_goo.second = \ |
151 | | ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok()) \ |
152 | | ? nullptr \ |
153 | | : ::absl::status_internal::MakeCheckFailString( \ |
154 | | absl_log_internal_qcheck_ok_goo.first, \ |
155 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ |
156 | | " is OK")), \ |
157 | | !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());) \ |
158 | | ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ |
159 | | ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_ok_goo.second) \ |
160 | | .InternalStream() |
161 | | |
162 | | namespace absl { |
163 | | ABSL_NAMESPACE_BEGIN |
164 | | |
165 | | class Status; |
166 | | template <typename T> |
167 | | class StatusOr; |
168 | | |
169 | | namespace status_internal { |
170 | | ABSL_ATTRIBUTE_PURE_FUNCTION absl::Nonnull<std::string*> MakeCheckFailString( |
171 | | absl::Nonnull<const absl::Status*> status, |
172 | | absl::Nonnull<const char*> prefix); |
173 | | } // namespace status_internal |
174 | | |
175 | | namespace log_internal { |
176 | | |
177 | | // Convert a Status or a StatusOr to its underlying status value. |
178 | | // |
179 | | // (This implementation does not require a dep on absl::Status to work.) |
180 | 0 | inline const absl::Status* AsStatus(const absl::Status& s) { return &s; } |
181 | | template <typename T> |
182 | | const absl::Status* AsStatus(const absl::StatusOr<T>& s) { |
183 | | return &s.status(); |
184 | | } |
185 | | |
186 | | // A helper class for formatting `expr (V1 vs. V2)` in a `CHECK_XX` statement. |
187 | | // See `MakeCheckOpString` for sample usage. |
188 | | class CheckOpMessageBuilder final { |
189 | | public: |
190 | | // Inserts `exprtext` and ` (` to the stream. |
191 | | explicit CheckOpMessageBuilder(const char* exprtext); |
192 | 0 | ~CheckOpMessageBuilder() = default; |
193 | | // For inserting the first variable. |
194 | 0 | std::ostream& ForVar1() { return stream_; } |
195 | | // For inserting the second variable (adds an intermediate ` vs. `). |
196 | | std::ostream& ForVar2(); |
197 | | // Get the result (inserts the closing `)`). |
198 | | std::string* NewString(); |
199 | | |
200 | | private: |
201 | | std::ostringstream stream_; |
202 | | }; |
203 | | |
204 | | // This formats a value for a failing `CHECK_XX` statement. Ordinarily, it uses |
205 | | // the definition for `operator<<`, with a few special cases below. |
206 | | template <typename T> |
207 | 0 | inline void MakeCheckOpValueString(std::ostream& os, const T& v) { |
208 | 0 | os << log_internal::NullGuard<T>::Guard(v); |
209 | 0 | } Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<bool>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<long>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, long const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<unsigned long>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, unsigned long const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<float>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, float const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<double>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, double const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<std::__1::basic_string_view<char, std::__1::char_traits<char> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string_view<char, std::__1::char_traits<char> > const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<char const*>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const* const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<signed char const*>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, signed char const* const&) Unexecuted instantiation: void absl::log_internal::MakeCheckOpValueString<unsigned char const*>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, unsigned char const* const&) |
210 | | |
211 | | // Overloads for char types provide readable values for unprintable characters. |
212 | | void MakeCheckOpValueString(std::ostream& os, char v); |
213 | | void MakeCheckOpValueString(std::ostream& os, signed char v); |
214 | | void MakeCheckOpValueString(std::ostream& os, unsigned char v); |
215 | | void MakeCheckOpValueString(std::ostream& os, const void* p); |
216 | | |
217 | | namespace detect_specialization { |
218 | | |
219 | | // MakeCheckOpString is being specialized for every T and U pair that is being |
220 | | // passed to the CHECK_op macros. However, there is a lot of redundancy in these |
221 | | // specializations that creates unnecessary library and binary bloat. |
222 | | // The number of instantiations tends to be O(n^2) because we have two |
223 | | // independent inputs. This technique works by reducing `n`. |
224 | | // |
225 | | // Most user-defined types being passed to CHECK_op end up being printed as a |
226 | | // builtin type. For example, enums tend to be implicitly converted to its |
227 | | // underlying type when calling operator<<, and pointers are printed with the |
228 | | // `const void*` overload. |
229 | | // To reduce the number of instantiations we coerce these values before calling |
230 | | // MakeCheckOpString instead of inside it. |
231 | | // |
232 | | // To detect if this coercion is needed, we duplicate all the relevant |
233 | | // operator<< overloads as specified in the standard, just in a different |
234 | | // namespace. If the call to `stream << value` becomes ambiguous, it means that |
235 | | // one of these overloads is the one selected by overload resolution. We then |
236 | | // do overload resolution again just with our overload set to see which one gets |
237 | | // selected. That tells us which type to coerce to. |
238 | | // If the augmented call was not ambiguous, it means that none of these were |
239 | | // selected and we can't coerce the input. |
240 | | // |
241 | | // As a secondary step to reduce code duplication, we promote integral types to |
242 | | // their 64-bit variant. This does not change the printed value, but reduces the |
243 | | // number of instantiations even further. Promoting an integer is very cheap at |
244 | | // the call site. |
245 | | int64_t operator<<(std::ostream&, short value); // NOLINT |
246 | | int64_t operator<<(std::ostream&, unsigned short value); // NOLINT |
247 | | int64_t operator<<(std::ostream&, int value); |
248 | | int64_t operator<<(std::ostream&, unsigned int value); |
249 | | int64_t operator<<(std::ostream&, long value); // NOLINT |
250 | | uint64_t operator<<(std::ostream&, unsigned long value); // NOLINT |
251 | | int64_t operator<<(std::ostream&, long long value); // NOLINT |
252 | | uint64_t operator<<(std::ostream&, unsigned long long value); // NOLINT |
253 | | float operator<<(std::ostream&, float value); |
254 | | double operator<<(std::ostream&, double value); |
255 | | long double operator<<(std::ostream&, long double value); |
256 | | bool operator<<(std::ostream&, bool value); |
257 | | const void* operator<<(std::ostream&, const void* value); |
258 | | const void* operator<<(std::ostream&, std::nullptr_t); |
259 | | |
260 | | // These `char` overloads are specified like this in the standard, so we have to |
261 | | // write them exactly the same to ensure the call is ambiguous. |
262 | | // If we wrote it in a different way (eg taking std::ostream instead of the |
263 | | // template) then one call might have a higher rank than the other and it would |
264 | | // not be ambiguous. |
265 | | template <typename Traits> |
266 | | char operator<<(std::basic_ostream<char, Traits>&, char); |
267 | | template <typename Traits> |
268 | | signed char operator<<(std::basic_ostream<char, Traits>&, signed char); |
269 | | template <typename Traits> |
270 | | unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char); |
271 | | template <typename Traits> |
272 | | const char* operator<<(std::basic_ostream<char, Traits>&, const char*); |
273 | | template <typename Traits> |
274 | | const signed char* operator<<(std::basic_ostream<char, Traits>&, |
275 | | const signed char*); |
276 | | template <typename Traits> |
277 | | const unsigned char* operator<<(std::basic_ostream<char, Traits>&, |
278 | | const unsigned char*); |
279 | | |
280 | | // This overload triggers when the call is not ambiguous. |
281 | | // It means that T is being printed with some overload not on this list. |
282 | | // We keep the value as `const T&`. |
283 | | template <typename T, typename = decltype(std::declval<std::ostream&>() |
284 | | << std::declval<const T&>())> |
285 | | const T& Detect(int); |
286 | | |
287 | | // This overload triggers when the call is ambiguous. |
288 | | // It means that T is either one from this list or printed as one from this |
289 | | // list. Eg an enum that decays to `int` for printing. |
290 | | // We ask the overload set to give us the type we want to convert it to. |
291 | | template <typename T> |
292 | | decltype(detect_specialization::operator<<(std::declval<std::ostream&>(), |
293 | | std::declval<const T&>())) |
294 | | Detect(char); |
295 | | |
296 | | // A sink for AbslStringify which redirects everything to a std::ostream. |
297 | | class StringifySink { |
298 | | public: |
299 | | explicit StringifySink(std::ostream& os ABSL_ATTRIBUTE_LIFETIME_BOUND); |
300 | | |
301 | | void Append(absl::string_view text); |
302 | | void Append(size_t length, char ch); |
303 | | friend void AbslFormatFlush(StringifySink* sink, absl::string_view text); |
304 | | |
305 | | private: |
306 | | std::ostream& os_; |
307 | | }; |
308 | | |
309 | | // Wraps a type implementing AbslStringify, and implements operator<<. |
310 | | template <typename T> |
311 | | class StringifyToStreamWrapper { |
312 | | public: |
313 | | explicit StringifyToStreamWrapper(const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND) |
314 | | : v_(v) {} |
315 | | |
316 | | friend std::ostream& operator<<(std::ostream& os, |
317 | | const StringifyToStreamWrapper& wrapper) { |
318 | | StringifySink sink(os); |
319 | | AbslStringify(sink, wrapper.v_); |
320 | | return os; |
321 | | } |
322 | | |
323 | | private: |
324 | | const T& v_; |
325 | | }; |
326 | | |
327 | | // This overload triggers when T implements AbslStringify. |
328 | | // StringifyToStreamWrapper is used to allow MakeCheckOpString to use |
329 | | // operator<<. |
330 | | template <typename T> |
331 | | std::enable_if_t<HasAbslStringify<T>::value, |
332 | | StringifyToStreamWrapper<T>> |
333 | | Detect(...); // Ellipsis has lowest preference when int passed. |
334 | | } // namespace detect_specialization |
335 | | |
336 | | template <typename T> |
337 | | using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0)); |
338 | | |
339 | | // Build the error message string. Specify no inlining for code size. |
340 | | template <typename T1, typename T2> |
341 | | ABSL_ATTRIBUTE_RETURNS_NONNULL std::string* MakeCheckOpString( |
342 | | T1 v1, T2 v2, const char* exprtext) ABSL_ATTRIBUTE_NOINLINE; |
343 | | |
344 | | template <typename T1, typename T2> |
345 | 0 | std::string* MakeCheckOpString(T1 v1, T2 v2, const char* exprtext) { |
346 | 0 | CheckOpMessageBuilder comb(exprtext); |
347 | 0 | MakeCheckOpValueString(comb.ForVar1(), v1); |
348 | 0 | MakeCheckOpValueString(comb.ForVar2(), v2); |
349 | 0 | return comb.NewString(); |
350 | 0 | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<bool, bool>(bool, bool, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<long, long>(long, long, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<unsigned long, unsigned long>(unsigned long, unsigned long, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<float, float>(float, float, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<double, double>(double, double, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<char, char>(char, char, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<unsigned char, unsigned char>(unsigned char, unsigned char, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<std::__1::basic_string_view<char, std::__1::char_traits<char> > const&, std::__1::basic_string_view<char, std::__1::char_traits<char> > const&>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const&, std::__1::basic_string_view<char, std::__1::char_traits<char> > const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<char const*, char const*>(char const*, char const*, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<signed char const*, signed char const*>(signed char const*, signed char const*, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<unsigned char const*, unsigned char const*>(unsigned char const*, unsigned char const*, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::MakeCheckOpString<void const*, void const*>(void const*, void const*, char const*) |
351 | | |
352 | | // Add a few commonly used instantiations as extern to reduce size of objects |
353 | | // files. |
354 | | #define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(x) \ |
355 | | extern template std::string* MakeCheckOpString(x, x, const char*) |
356 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(bool); |
357 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(int64_t); |
358 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(uint64_t); |
359 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(float); |
360 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(double); |
361 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(char); |
362 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char); |
363 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&); |
364 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&); |
365 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char*); |
366 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const signed char*); |
367 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const unsigned char*); |
368 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*); |
369 | | #undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN |
370 | | |
371 | | // `ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT` skips formatting the Check_OP result |
372 | | // string iff `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`, instead returning an empty |
373 | | // string. |
374 | | #ifdef ABSL_MIN_LOG_LEVEL |
375 | | #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \ |
376 | | ((::absl::LogSeverity::kFatal >= \ |
377 | | static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) \ |
378 | | ? MakeCheckOpString<U1, U2>(v1, v2, exprtext) \ |
379 | | : new std::string()) |
380 | | #else |
381 | | #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \ |
382 | | MakeCheckOpString<U1, U2>(v1, v2, exprtext) |
383 | | #endif |
384 | | |
385 | | // Helper functions for `ABSL_LOG_INTERNAL_CHECK_OP` macro family. The |
386 | | // `(int, int)` override works around the issue that the compiler will not |
387 | | // instantiate the template version of the function on values of unnamed enum |
388 | | // type. |
389 | | #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ |
390 | | template <typename T1, typename T2> \ |
391 | | inline constexpr ::std::string* name##Impl(const T1& v1, const T2& v2, \ |
392 | 0 | const char* exprtext) { \ |
393 | 0 | using U1 = CheckOpStreamType<T1>; \ |
394 | 0 | using U2 = CheckOpStreamType<T2>; \ |
395 | 0 | return ABSL_PREDICT_TRUE(v1 op v2) \ |
396 | 0 | ? nullptr \ |
397 | 0 | : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \ |
398 | 0 | U2(v2), exprtext); \ |
399 | 0 | } \ Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::Check_EQImpl<int, int>(int const&, int const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::Check_NEImpl<int, int>(int const&, int const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::Check_LEImpl<int, int>(int const&, int const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::Check_LTImpl<int, int>(int const&, int const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::Check_GEImpl<int, int>(int const&, int const&, char const*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* absl::log_internal::Check_GTImpl<int, int>(int const&, int const&, char const*) |
400 | | inline constexpr ::std::string* name##Impl(int v1, int v2, \ |
401 | 0 | const char* exprtext) { \ |
402 | 0 | return name##Impl<int, int>(v1, v2, exprtext); \ |
403 | 0 | } Unexecuted instantiation: absl::log_internal::Check_EQImpl(int, int, char const*) Unexecuted instantiation: absl::log_internal::Check_NEImpl(int, int, char const*) Unexecuted instantiation: absl::log_internal::Check_LEImpl(int, int, char const*) Unexecuted instantiation: absl::log_internal::Check_LTImpl(int, int, char const*) Unexecuted instantiation: absl::log_internal::Check_GEImpl(int, int, char const*) Unexecuted instantiation: absl::log_internal::Check_GTImpl(int, int, char const*) |
404 | | |
405 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_EQ, ==) |
406 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_NE, !=) |
407 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LE, <=) |
408 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LT, <) |
409 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GE, >=) |
410 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GT, >) |
411 | | #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT |
412 | | #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL |
413 | | |
414 | | std::string* CheckstrcmptrueImpl(const char* s1, const char* s2, |
415 | | const char* exprtext); |
416 | | std::string* CheckstrcmpfalseImpl(const char* s1, const char* s2, |
417 | | const char* exprtext); |
418 | | std::string* CheckstrcasecmptrueImpl(const char* s1, const char* s2, |
419 | | const char* exprtext); |
420 | | std::string* CheckstrcasecmpfalseImpl(const char* s1, const char* s2, |
421 | | const char* exprtext); |
422 | | |
423 | | // `CHECK_EQ` and friends want to pass their arguments by reference, however |
424 | | // this winds up exposing lots of cases where people have defined and |
425 | | // initialized static const data members but never declared them (i.e. in a .cc |
426 | | // file), meaning they are not referenceable. This function avoids that problem |
427 | | // for integers (the most common cases) by overloading for every primitive |
428 | | // integer type, even the ones we discourage, and returning them by value. |
429 | | template <typename T> |
430 | | inline constexpr const T& GetReferenceableValue(const T& t) { |
431 | | return t; |
432 | | } |
433 | 0 | inline constexpr char GetReferenceableValue(char t) { return t; } |
434 | 0 | inline constexpr unsigned char GetReferenceableValue(unsigned char t) { |
435 | 0 | return t; |
436 | 0 | } |
437 | 0 | inline constexpr signed char GetReferenceableValue(signed char t) { return t; } |
438 | 0 | inline constexpr short GetReferenceableValue(short t) { return t; } // NOLINT |
439 | | inline constexpr unsigned short GetReferenceableValue( // NOLINT |
440 | 0 | unsigned short t) { // NOLINT |
441 | 0 | return t; |
442 | 0 | } |
443 | | inline constexpr int GetReferenceableValue(int t) { return t; } |
444 | 0 | inline constexpr unsigned int GetReferenceableValue(unsigned int t) { |
445 | 0 | return t; |
446 | 0 | } |
447 | | inline constexpr long GetReferenceableValue(long t) { return t; } // NOLINT |
448 | | inline constexpr unsigned long GetReferenceableValue( // NOLINT |
449 | | unsigned long t) { // NOLINT |
450 | | return t; |
451 | | } |
452 | 0 | inline constexpr long long GetReferenceableValue(long long t) { // NOLINT |
453 | 0 | return t; |
454 | 0 | } |
455 | | inline constexpr unsigned long long GetReferenceableValue( // NOLINT |
456 | 0 | unsigned long long t) { // NOLINT |
457 | 0 | return t; |
458 | 0 | } |
459 | | |
460 | | } // namespace log_internal |
461 | | ABSL_NAMESPACE_END |
462 | | } // namespace absl |
463 | | |
464 | | #endif // ABSL_LOG_INTERNAL_CHECK_OP_H_ |