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