/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 <ostream> |
28 | | #include <sstream> |
29 | | #include <string> |
30 | | #include <utility> |
31 | | |
32 | | #include "absl/base/attributes.h" |
33 | | #include "absl/base/config.h" |
34 | | #include "absl/base/optimization.h" |
35 | | #include "absl/log/internal/nullguard.h" |
36 | | #include "absl/log/internal/nullstream.h" |
37 | | #include "absl/log/internal/strip.h" |
38 | | |
39 | | // `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that |
40 | | // should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`. |
41 | | #ifdef ABSL_MIN_LOG_LEVEL |
42 | | #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) \ |
43 | | (::absl::LogSeverity::kFatal >= \ |
44 | | static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ |
45 | | ? (literal) \ |
46 | | : "") |
47 | | #else |
48 | | #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) (literal) |
49 | | #endif |
50 | | |
51 | | #ifdef NDEBUG |
52 | | // `NDEBUG` is defined, so `DCHECK_EQ(x, y)` and so on do nothing. However, we |
53 | | // still want the compiler to parse `x` and `y`, because we don't want to lose |
54 | | // potentially useful errors and warnings. |
55 | | #define ABSL_LOG_INTERNAL_DCHECK_NOP(x, y) \ |
56 | | while (false && ((void)(x), (void)(y), 0)) \ |
57 | | ::absl::log_internal::NullStream().InternalStream() |
58 | | #endif |
59 | | |
60 | | #define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \ |
61 | | while ( \ |
62 | | ::std::string* absl_log_internal_check_op_result ABSL_ATTRIBUTE_UNUSED = \ |
63 | | ::absl::log_internal::name##Impl( \ |
64 | | ::absl::log_internal::GetReferenceableValue(val1), \ |
65 | | ::absl::log_internal::GetReferenceableValue(val2), \ |
66 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val1_text \ |
67 | | " " #op " " val2_text))) \ |
68 | | ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_op_result).InternalStream() |
69 | | #define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \ |
70 | | val2_text) \ |
71 | | while (::std::string* absl_log_internal_qcheck_op_result = \ |
72 | | ::absl::log_internal::name##Impl( \ |
73 | | ::absl::log_internal::GetReferenceableValue(val1), \ |
74 | | ::absl::log_internal::GetReferenceableValue(val2), \ |
75 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ |
76 | | val1_text " " #op " " val2_text))) \ |
77 | | ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_op_result).InternalStream() |
78 | | #define ABSL_LOG_INTERNAL_CHECK_STROP(func, op, expected, s1, s1_text, s2, \ |
79 | | s2_text) \ |
80 | | while (::std::string* absl_log_internal_check_strop_result = \ |
81 | | ::absl::log_internal::Check##func##expected##Impl( \ |
82 | | (s1), (s2), \ |
83 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ |
84 | | " " s2_text))) \ |
85 | | ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_strop_result) \ |
86 | | .InternalStream() |
87 | | #define ABSL_LOG_INTERNAL_QCHECK_STROP(func, op, expected, s1, s1_text, s2, \ |
88 | | s2_text) \ |
89 | | while (::std::string* absl_log_internal_qcheck_strop_result = \ |
90 | | ::absl::log_internal::Check##func##expected##Impl( \ |
91 | | (s1), (s2), \ |
92 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ |
93 | | " " s2_text))) \ |
94 | | ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_strop_result) \ |
95 | | .InternalStream() |
96 | | // This one is tricky: |
97 | | // * We must evaluate `val` exactly once, yet we need to do two things with it: |
98 | | // evaluate `.ok()` and (sometimes) `.ToString()`. |
99 | | // * `val` might be an `absl::Status` or some `absl::StatusOr<T>`. |
100 | | // * `val` might be e.g. `ATemporary().GetStatus()`, which may return a |
101 | | // reference to a member of `ATemporary` that is only valid until the end of |
102 | | // the full expression. |
103 | | // * We don't want this file to depend on `absl::Status` `#include`s or linkage, |
104 | | // nor do we want to move the definition to status and introduce a dependency |
105 | | // in the other direction. We can be assured that callers must already have a |
106 | | // `Status` and the necessary `#include`s and linkage. |
107 | | // * Callsites should be small and fast (at least when `val.ok()`): one branch, |
108 | | // minimal stack footprint. |
109 | | // * In particular, the string concat stuff should be out-of-line and emitted |
110 | | // in only one TU to save linker input size |
111 | | // * We want the `val.ok()` check inline so static analyzers and optimizers can |
112 | | // see it. |
113 | | // * As usual, no braces so we can stream into the expansion with `operator<<`. |
114 | | // * Also as usual, it must expand to a single (partial) statement with no |
115 | | // ambiguous-else problems. |
116 | | #define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \ |
117 | | for (::std::pair<const ::absl::Status*, ::std::string*> \ |
118 | | absl_log_internal_check_ok_goo; \ |
119 | | absl_log_internal_check_ok_goo.first = \ |
120 | | ::absl::log_internal::AsStatus(val), \ |
121 | | absl_log_internal_check_ok_goo.second = \ |
122 | | ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ |
123 | | ? nullptr \ |
124 | | : ::absl::status_internal::MakeCheckFailString( \ |
125 | | absl_log_internal_check_ok_goo.first, \ |
126 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ |
127 | | " is OK")), \ |
128 | | !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ |
129 | | ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_ok_goo.second) \ |
130 | | .InternalStream() |
131 | | #define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \ |
132 | | for (::std::pair<const ::absl::Status*, ::std::string*> \ |
133 | | absl_log_internal_check_ok_goo; \ |
134 | | absl_log_internal_check_ok_goo.first = \ |
135 | | ::absl::log_internal::AsStatus(val), \ |
136 | | absl_log_internal_check_ok_goo.second = \ |
137 | | ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ |
138 | | ? nullptr \ |
139 | | : ::absl::status_internal::MakeCheckFailString( \ |
140 | | absl_log_internal_check_ok_goo.first, \ |
141 | | ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ |
142 | | " is OK")), \ |
143 | | !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ |
144 | | ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_check_ok_goo.second) \ |
145 | | .InternalStream() |
146 | | |
147 | | namespace absl { |
148 | | ABSL_NAMESPACE_BEGIN |
149 | | |
150 | | class Status; |
151 | | template <typename T> |
152 | | class StatusOr; |
153 | | |
154 | | namespace status_internal { |
155 | | std::string* MakeCheckFailString(const absl::Status* status, |
156 | | const char* prefix); |
157 | | } // namespace status_internal |
158 | | |
159 | | namespace log_internal { |
160 | | |
161 | | // Convert a Status or a StatusOr to its underlying status value. |
162 | | // |
163 | | // (This implementation does not require a dep on absl::Status to work.) |
164 | 0 | inline const absl::Status* AsStatus(const absl::Status& s) { return &s; } |
165 | | template <typename T> |
166 | | const absl::Status* AsStatus(const absl::StatusOr<T>& s) { |
167 | | return &s.status(); |
168 | | } |
169 | | |
170 | | // A helper class for formatting `expr (V1 vs. V2)` in a `CHECK_XX` statement. |
171 | | // See `MakeCheckOpString` for sample usage. |
172 | | class CheckOpMessageBuilder final { |
173 | | public: |
174 | | // Inserts `exprtext` and ` (` to the stream. |
175 | | explicit CheckOpMessageBuilder(const char* exprtext); |
176 | 0 | ~CheckOpMessageBuilder() = default; |
177 | | // For inserting the first variable. |
178 | 0 | std::ostream& ForVar1() { return stream_; } |
179 | | // For inserting the second variable (adds an intermediate ` vs. `). |
180 | | std::ostream& ForVar2(); |
181 | | // Get the result (inserts the closing `)`). |
182 | | std::string* NewString(); |
183 | | |
184 | | private: |
185 | | std::ostringstream stream_; |
186 | | }; |
187 | | |
188 | | // This formats a value for a failing `CHECK_XX` statement. Ordinarily, it uses |
189 | | // the definition for `operator<<`, with a few special cases below. |
190 | | template <typename T> |
191 | 0 | inline void MakeCheckOpValueString(std::ostream& os, const T& v) { |
192 | 0 | os << log_internal::NullGuard<T>::Guard(v); |
193 | 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<absl::string_view>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, absl::string_view 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&) |
194 | | |
195 | | // Overloads for char types provide readable values for unprintable characters. |
196 | | void MakeCheckOpValueString(std::ostream& os, char v); |
197 | | void MakeCheckOpValueString(std::ostream& os, signed char v); |
198 | | void MakeCheckOpValueString(std::ostream& os, unsigned char v); |
199 | | void MakeCheckOpValueString(std::ostream& os, const void* p); |
200 | | |
201 | | namespace detect_specialization { |
202 | | |
203 | | // MakeCheckOpString is being specialized for every T and U pair that is being |
204 | | // passed to the CHECK_op macros. However, there is a lot of redundancy in these |
205 | | // specializations that creates unnecessary library and binary bloat. |
206 | | // The number of instantiations tends to be O(n^2) because we have two |
207 | | // independent inputs. This technique works by reducing `n`. |
208 | | // |
209 | | // Most user-defined types being passed to CHECK_op end up being printed as a |
210 | | // builtin type. For example, enums tend to be implicitly converted to its |
211 | | // underlying type when calling operator<<, and pointers are printed with the |
212 | | // `const void*` overload. |
213 | | // To reduce the number of instantiations we coerce these values before calling |
214 | | // MakeCheckOpString instead of inside it. |
215 | | // |
216 | | // To detect if this coercion is needed, we duplicate all the relevant |
217 | | // operator<< overloads as specified in the standard, just in a different |
218 | | // namespace. If the call to `stream << value` becomes ambiguous, it means that |
219 | | // one of these overloads is the one selected by overload resolution. We then |
220 | | // do overload resolution again just with our overload set to see which one gets |
221 | | // selected. That tells us which type to coerce to. |
222 | | // If the augmented call was not ambiguous, it means that none of these were |
223 | | // selected and we can't coerce the input. |
224 | | // |
225 | | // As a secondary step to reduce code duplication, we promote integral types to |
226 | | // their 64-bit variant. This does not change the printed value, but reduces the |
227 | | // number of instantiations even further. Promoting an integer is very cheap at |
228 | | // the call site. |
229 | | int64_t operator<<(std::ostream&, short value); // NOLINT |
230 | | int64_t operator<<(std::ostream&, unsigned short value); // NOLINT |
231 | | int64_t operator<<(std::ostream&, int value); |
232 | | int64_t operator<<(std::ostream&, unsigned int value); |
233 | | int64_t operator<<(std::ostream&, long value); // NOLINT |
234 | | uint64_t operator<<(std::ostream&, unsigned long value); // NOLINT |
235 | | int64_t operator<<(std::ostream&, long long value); // NOLINT |
236 | | uint64_t operator<<(std::ostream&, unsigned long long value); // NOLINT |
237 | | float operator<<(std::ostream&, float value); |
238 | | double operator<<(std::ostream&, double value); |
239 | | long double operator<<(std::ostream&, long double value); |
240 | | bool operator<<(std::ostream&, bool value); |
241 | | const void* operator<<(std::ostream&, const void* value); |
242 | | const void* operator<<(std::ostream&, std::nullptr_t); |
243 | | |
244 | | // These `char` overloads are specified like this in the standard, so we have to |
245 | | // write them exactly the same to ensure the call is ambiguous. |
246 | | // If we wrote it in a different way (eg taking std::ostream instead of the |
247 | | // template) then one call might have a higher rank than the other and it would |
248 | | // not be ambiguous. |
249 | | template <typename Traits> |
250 | | char operator<<(std::basic_ostream<char, Traits>&, char); |
251 | | template <typename Traits> |
252 | | signed char operator<<(std::basic_ostream<char, Traits>&, signed char); |
253 | | template <typename Traits> |
254 | | unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char); |
255 | | template <typename Traits> |
256 | | const char* operator<<(std::basic_ostream<char, Traits>&, const char*); |
257 | | template <typename Traits> |
258 | | const signed char* operator<<(std::basic_ostream<char, Traits>&, |
259 | | const signed char*); |
260 | | template <typename Traits> |
261 | | const unsigned char* operator<<(std::basic_ostream<char, Traits>&, |
262 | | const unsigned char*); |
263 | | |
264 | | // This overload triggers when the call is not ambiguous. |
265 | | // It means that T is being printed with some overload not on this list. |
266 | | // We keep the value as `const T&`. |
267 | | template <typename T, typename = decltype(std::declval<std::ostream&>() |
268 | | << std::declval<const T&>())> |
269 | | const T& Detect(int); |
270 | | |
271 | | // This overload triggers when the call is ambiguous. |
272 | | // It means that T is either one from this list or printed as one from this |
273 | | // list. Eg an enum that decays to `int` for printing. |
274 | | // We ask the overload set to give us the type we want to convert it to. |
275 | | template <typename T> |
276 | | decltype(detect_specialization::operator<<(std::declval<std::ostream&>(), |
277 | | std::declval<const T&>())) |
278 | | Detect(char); |
279 | | |
280 | | } // namespace detect_specialization |
281 | | |
282 | | template <typename T> |
283 | | using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0)); |
284 | | |
285 | | // Build the error message string. Specify no inlining for code size. |
286 | | template <typename T1, typename T2> |
287 | | ABSL_ATTRIBUTE_RETURNS_NONNULL std::string* MakeCheckOpString( |
288 | | T1 v1, T2 v2, const char* exprtext) ABSL_ATTRIBUTE_NOINLINE; |
289 | | |
290 | | template <typename T1, typename T2> |
291 | 0 | std::string* MakeCheckOpString(T1 v1, T2 v2, const char* exprtext) { |
292 | 0 | CheckOpMessageBuilder comb(exprtext); |
293 | 0 | MakeCheckOpValueString(comb.ForVar1(), v1); |
294 | 0 | MakeCheckOpValueString(comb.ForVar2(), v2); |
295 | 0 | return comb.NewString(); |
296 | 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<absl::string_view const&, absl::string_view const&>(absl::string_view const&, absl::string_view 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*) |
297 | | |
298 | | // Add a few commonly used instantiations as extern to reduce size of objects |
299 | | // files. |
300 | | #define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(x) \ |
301 | | extern template std::string* MakeCheckOpString(x, x, const char*) |
302 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(bool); |
303 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(int64_t); |
304 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(uint64_t); |
305 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(float); |
306 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(double); |
307 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(char); |
308 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char); |
309 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&); |
310 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&); |
311 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char*); |
312 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const signed char*); |
313 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const unsigned char*); |
314 | | ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*); |
315 | | #undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN |
316 | | |
317 | | // Helper functions for `ABSL_LOG_INTERNAL_CHECK_OP` macro family. The |
318 | | // `(int, int)` override works around the issue that the compiler will not |
319 | | // instantiate the template version of the function on values of unnamed enum |
320 | | // type. |
321 | | #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ |
322 | | template <typename T1, typename T2> \ |
323 | | inline constexpr ::std::string* name##Impl(const T1& v1, const T2& v2, \ |
324 | 0 | const char* exprtext) { \ |
325 | 0 | using U1 = CheckOpStreamType<T1>; \ |
326 | 0 | using U2 = CheckOpStreamType<T2>; \ |
327 | 0 | return ABSL_PREDICT_TRUE(v1 op v2) \ |
328 | 0 | ? nullptr \ |
329 | 0 | : MakeCheckOpString<U1, U2>(v1, v2, exprtext); \ |
330 | 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_GTImpl<int, int>(int const&, int const&, char const*) |
331 | | inline constexpr ::std::string* name##Impl(int v1, int v2, \ |
332 | 0 | const char* exprtext) { \ |
333 | 0 | return name##Impl<int, int>(v1, v2, exprtext); \ |
334 | 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_GTImpl(int, int, char const*) |
335 | | |
336 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_EQ, ==) |
337 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_NE, !=) |
338 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LE, <=) |
339 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LT, <) |
340 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GE, >=) |
341 | | ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GT, >) |
342 | | #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL |
343 | | |
344 | | std::string* CheckstrcmptrueImpl(const char* s1, const char* s2, |
345 | | const char* exprtext); |
346 | | std::string* CheckstrcmpfalseImpl(const char* s1, const char* s2, |
347 | | const char* exprtext); |
348 | | std::string* CheckstrcasecmptrueImpl(const char* s1, const char* s2, |
349 | | const char* exprtext); |
350 | | std::string* CheckstrcasecmpfalseImpl(const char* s1, const char* s2, |
351 | | const char* exprtext); |
352 | | |
353 | | // `CHECK_EQ` and friends want to pass their arguments by reference, however |
354 | | // this winds up exposing lots of cases where people have defined and |
355 | | // initialized static const data members but never declared them (i.e. in a .cc |
356 | | // file), meaning they are not referenceable. This function avoids that problem |
357 | | // for integers (the most common cases) by overloading for every primitive |
358 | | // integer type, even the ones we discourage, and returning them by value. |
359 | | template <typename T> |
360 | | inline constexpr const T& GetReferenceableValue(const T& t) { |
361 | | return t; |
362 | | } |
363 | 0 | inline constexpr char GetReferenceableValue(char t) { return t; } |
364 | 0 | inline constexpr unsigned char GetReferenceableValue(unsigned char t) { |
365 | 0 | return t; |
366 | 0 | } |
367 | 0 | inline constexpr signed char GetReferenceableValue(signed char t) { return t; } |
368 | 0 | inline constexpr short GetReferenceableValue(short t) { return t; } // NOLINT |
369 | | inline constexpr unsigned short GetReferenceableValue( // NOLINT |
370 | 0 | unsigned short t) { // NOLINT |
371 | 0 | return t; |
372 | 0 | } |
373 | | inline constexpr int GetReferenceableValue(int t) { return t; } |
374 | 0 | inline constexpr unsigned int GetReferenceableValue(unsigned int t) { |
375 | 0 | return t; |
376 | 0 | } |
377 | 0 | inline constexpr long GetReferenceableValue(long t) { return t; } // NOLINT |
378 | | inline constexpr unsigned long GetReferenceableValue( // NOLINT |
379 | | unsigned long t) { // NOLINT |
380 | | return t; |
381 | | } |
382 | | inline constexpr long long GetReferenceableValue(long long t) { // NOLINT |
383 | | return t; |
384 | | } |
385 | | inline constexpr unsigned long long GetReferenceableValue( // NOLINT |
386 | 0 | unsigned long long t) { // NOLINT |
387 | 0 | return t; |
388 | 0 | } |
389 | | |
390 | | } // namespace log_internal |
391 | | ABSL_NAMESPACE_END |
392 | | } // namespace absl |
393 | | |
394 | | #endif // ABSL_LOG_INTERNAL_CHECK_OP_H_ |