Abseil Common Libraries (C++) (grcp 依赖)
https://abseil.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
19 KiB
385 lines
19 KiB
// Copyright 2022 The Abseil Authors. |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// https://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
// |
|
// ----------------------------------------------------------------------------- |
|
// File: log/internal/check_op.h |
|
// ----------------------------------------------------------------------------- |
|
// |
|
// This file declares helpers routines and macros used to implement `CHECK` |
|
// macros. |
|
|
|
#ifndef ABSL_LOG_INTERNAL_CHECK_OP_H_ |
|
#define ABSL_LOG_INTERNAL_CHECK_OP_H_ |
|
|
|
#include <stdint.h> |
|
|
|
#include <ostream> |
|
#include <sstream> |
|
#include <string> |
|
#include <utility> |
|
|
|
#include "absl/base/attributes.h" |
|
#include "absl/base/config.h" |
|
#include "absl/base/optimization.h" |
|
#include "absl/log/internal/nullguard.h" |
|
#include "absl/log/internal/nullstream.h" |
|
#include "absl/log/internal/strip.h" |
|
|
|
// `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that |
|
// should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`. |
|
#ifdef ABSL_MIN_LOG_LEVEL |
|
#define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) \ |
|
(::absl::LogSeverity::kFatal >= \ |
|
static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ |
|
? (literal) \ |
|
: "") |
|
#else |
|
#define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) (literal) |
|
#endif |
|
|
|
#ifdef NDEBUG |
|
// `NDEBUG` is defined, so `DCHECK_EQ(x, y)` and so on do nothing. However, we |
|
// still want the compiler to parse `x` and `y`, because we don't want to lose |
|
// potentially useful errors and warnings. |
|
#define ABSL_LOG_INTERNAL_DCHECK_NOP(x, y) \ |
|
while (false && ((void)(x), (void)(y), 0)) \ |
|
::absl::log_internal::NullStream().InternalStream() |
|
#endif |
|
|
|
#define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val2) \ |
|
while ( \ |
|
::std::string* absl_log_internal_check_op_result ABSL_ATTRIBUTE_UNUSED = \ |
|
::absl::log_internal::name##Impl( \ |
|
::absl::log_internal::GetReferenceableValue(val1), \ |
|
::absl::log_internal::GetReferenceableValue(val2), \ |
|
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(#val1 " " #op \ |
|
" " #val2))) \ |
|
ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_op_result).InternalStream() |
|
#define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val2) \ |
|
while (::std::string* absl_log_internal_qcheck_op_result = \ |
|
::absl::log_internal::name##Impl( \ |
|
::absl::log_internal::GetReferenceableValue(val1), \ |
|
::absl::log_internal::GetReferenceableValue(val2), \ |
|
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(#val1 " " #op \ |
|
" " #val2))) \ |
|
ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_op_result).InternalStream() |
|
#define ABSL_LOG_INTERNAL_CHECK_STROP(func, op, expected, s1, s2) \ |
|
while (::std::string* absl_log_internal_check_strop_result = \ |
|
::absl::log_internal::Check##func##expected##Impl( \ |
|
(s1), (s2), \ |
|
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(#s1 " " #op " " #s2))) \ |
|
ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_strop_result) \ |
|
.InternalStream() |
|
#define ABSL_LOG_INTERNAL_QCHECK_STROP(func, op, expected, s1, s2) \ |
|
while (::std::string* absl_log_internal_qcheck_strop_result = \ |
|
::absl::log_internal::Check##func##expected##Impl( \ |
|
(s1), (s2), \ |
|
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(#s1 " " #op " " #s2))) \ |
|
ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_strop_result) \ |
|
.InternalStream() |
|
// This one is tricky: |
|
// * We must evaluate `val` exactly once, yet we need to do two things with it: |
|
// evaluate `.ok()` and (sometimes) `.ToString()`. |
|
// * `val` might be an `absl::Status` or some `absl::StatusOr<T>`. |
|
// * `val` might be e.g. `ATemporary().GetStatus()`, which may return a |
|
// reference to a member of `ATemporary` that is only valid until the end of |
|
// the full expression. |
|
// * We don't want this file to depend on `absl::Status` `#include`s or linkage, |
|
// nor do we want to move the definition to status and introduce a dependency |
|
// in the other direction. We can be assured that callers must already have a |
|
// `Status` and the necessary `#include`s and linkage. |
|
// * Callsites should be small and fast (at least when `val.ok()`): one branch, |
|
// minimal stack footprint. |
|
// * In particular, the string concat stuff should be out-of-line and emitted |
|
// in only one TU to save linker input size |
|
// * We want the `val.ok()` check inline so static analyzers and optimizers can |
|
// see it. |
|
// * As usual, no braces so we can stream into the expansion with `operator<<`. |
|
// * Also as usual, it must expand to a single (partial) statement with no |
|
// ambiguous-else problems. |
|
#define ABSL_LOG_INTERNAL_CHECK_OK(val) \ |
|
for (::std::pair<const ::absl::Status*, ::std::string*> \ |
|
absl_log_internal_check_ok_goo; \ |
|
absl_log_internal_check_ok_goo.first = \ |
|
::absl::log_internal::AsStatus(val), \ |
|
absl_log_internal_check_ok_goo.second = \ |
|
ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ |
|
? nullptr \ |
|
: ::absl::status_internal::MakeCheckFailString( \ |
|
absl_log_internal_check_ok_goo.first, \ |
|
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(#val " is OK")), \ |
|
!ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ |
|
ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_ok_goo.second) \ |
|
.InternalStream() |
|
#define ABSL_LOG_INTERNAL_QCHECK_OK(val) \ |
|
for (::std::pair<const ::absl::Status*, ::std::string*> \ |
|
absl_log_internal_check_ok_goo; \ |
|
absl_log_internal_check_ok_goo.first = \ |
|
::absl::log_internal::AsStatus(val), \ |
|
absl_log_internal_check_ok_goo.second = \ |
|
ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ |
|
? nullptr \ |
|
: ::absl::status_internal::MakeCheckFailString( \ |
|
absl_log_internal_check_ok_goo.first, \ |
|
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(#val " is OK")), \ |
|
!ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ |
|
ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_check_ok_goo.second) \ |
|
.InternalStream() |
|
|
|
namespace absl { |
|
ABSL_NAMESPACE_BEGIN |
|
|
|
class Status; |
|
template <typename T> |
|
class StatusOr; |
|
|
|
namespace status_internal { |
|
std::string* MakeCheckFailString(const absl::Status* status, |
|
const char* prefix); |
|
} // namespace status_internal |
|
|
|
namespace log_internal { |
|
|
|
// Convert a Status or a StatusOr to its underlying status value. |
|
// |
|
// (This implementation does not require a dep on absl::Status to work.) |
|
inline const absl::Status* AsStatus(const absl::Status& s) { return &s; } |
|
template <typename T> |
|
const absl::Status* AsStatus(const absl::StatusOr<T>& s) { |
|
return &s.status(); |
|
} |
|
|
|
// A helper class for formatting `expr (V1 vs. V2)` in a `CHECK_XX` statement. |
|
// See `MakeCheckOpString` for sample usage. |
|
class CheckOpMessageBuilder final { |
|
public: |
|
// Inserts `exprtext` and ` (` to the stream. |
|
explicit CheckOpMessageBuilder(const char* exprtext); |
|
~CheckOpMessageBuilder() = default; |
|
// For inserting the first variable. |
|
std::ostream& ForVar1() { return stream_; } |
|
// For inserting the second variable (adds an intermediate ` vs. `). |
|
std::ostream& ForVar2(); |
|
// Get the result (inserts the closing `)`). |
|
std::string* NewString(); |
|
|
|
private: |
|
std::ostringstream stream_; |
|
}; |
|
|
|
// This formats a value for a failing `CHECK_XX` statement. Ordinarily, it uses |
|
// the definition for `operator<<`, with a few special cases below. |
|
template <typename T> |
|
inline void MakeCheckOpValueString(std::ostream& os, const T& v) { |
|
os << log_internal::NullGuard<T>::Guard(v); |
|
} |
|
|
|
// Overloads for char types provide readable values for unprintable characters. |
|
void MakeCheckOpValueString(std::ostream& os, char v); |
|
void MakeCheckOpValueString(std::ostream& os, signed char v); |
|
void MakeCheckOpValueString(std::ostream& os, unsigned char v); |
|
void MakeCheckOpValueString(std::ostream& os, const void* p); |
|
|
|
namespace detect_specialization { |
|
|
|
// MakeCheckOpString is being specialized for every T and U pair that is being |
|
// passed to the CHECK_op macros. However, there is a lot of redundancy in these |
|
// specializations that creates unnecessary library and binary bloat. |
|
// The number of instantiations tends to be O(n^2) because we have two |
|
// independent inputs. This technique works by reducing `n`. |
|
// |
|
// Most user-defined types being passed to CHECK_op end up being printed as a |
|
// builtin type. For example, enums tend to be implicitly converted to its |
|
// underlying type when calling operator<<, and pointers are printed with the |
|
// `const void*` overload. |
|
// To reduce the number of instantiations we coerce these values before calling |
|
// MakeCheckOpString instead of inside it. |
|
// |
|
// To detect if this coercion is needed, we duplicate all the relevant |
|
// operator<< overloads as specified in the standard, just in a different |
|
// namespace. If the call to `stream << value` becomes ambiguous, it means that |
|
// one of these overloads is the one selected by overload resolution. We then |
|
// do overload resolution again just with our overload set to see which one gets |
|
// selected. That tells us which type to coerce to. |
|
// If the augmented call was not ambiguous, it means that none of these were |
|
// selected and we can't coerce the input. |
|
// |
|
// As a secondary step to reduce code duplication, we promote integral types to |
|
// their 64-bit variant. This does not change the printed value, but reduces the |
|
// number of instantiations even further. Promoting an integer is very cheap at |
|
// the call site. |
|
int64_t operator<<(std::ostream&, short value); // NOLINT |
|
int64_t operator<<(std::ostream&, unsigned short value); // NOLINT |
|
int64_t operator<<(std::ostream&, int value); |
|
int64_t operator<<(std::ostream&, unsigned int value); |
|
int64_t operator<<(std::ostream&, long value); // NOLINT |
|
uint64_t operator<<(std::ostream&, unsigned long value); // NOLINT |
|
int64_t operator<<(std::ostream&, long long value); // NOLINT |
|
uint64_t operator<<(std::ostream&, unsigned long long value); // NOLINT |
|
float operator<<(std::ostream&, float value); |
|
double operator<<(std::ostream&, double value); |
|
long double operator<<(std::ostream&, long double value); |
|
bool operator<<(std::ostream&, bool value); |
|
const void* operator<<(std::ostream&, const void* value); |
|
const void* operator<<(std::ostream&, std::nullptr_t); |
|
|
|
// These `char` overloads are specified like this in the standard, so we have to |
|
// write them exactly the same to ensure the call is ambiguous. |
|
// If we wrote it in a different way (eg taking std::ostream instead of the |
|
// template) then one call might have a higher rank than the other and it would |
|
// not be ambiguous. |
|
template <typename Traits> |
|
char operator<<(std::basic_ostream<char, Traits>&, char); |
|
template <typename Traits> |
|
signed char operator<<(std::basic_ostream<char, Traits>&, signed char); |
|
template <typename Traits> |
|
unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char); |
|
template <typename Traits> |
|
const char* operator<<(std::basic_ostream<char, Traits>&, const char*); |
|
template <typename Traits> |
|
const signed char* operator<<(std::basic_ostream<char, Traits>&, |
|
const signed char*); |
|
template <typename Traits> |
|
const unsigned char* operator<<(std::basic_ostream<char, Traits>&, |
|
const unsigned char*); |
|
|
|
// This overload triggers when the call is not ambiguous. |
|
// It means that T is being printed with some overload not on this list. |
|
// We keep the value as `const T&`. |
|
template <typename T, typename = decltype(std::declval<std::ostream&>() |
|
<< std::declval<const T&>())> |
|
const T& Detect(int); |
|
|
|
// This overload triggers when the call is ambiguous. |
|
// It means that T is either one from this list or printed as one from this |
|
// list. Eg an enum that decays to `int` for printing. |
|
// We ask the overload set to give us the type we want to convert it to. |
|
template <typename T> |
|
decltype(detect_specialization::operator<<(std::declval<std::ostream&>(), |
|
std::declval<const T&>())) |
|
Detect(char); |
|
|
|
} // namespace detect_specialization |
|
|
|
template <typename T> |
|
using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0)); |
|
|
|
// Build the error message string. Specify no inlining for code size. |
|
template <typename T1, typename T2> |
|
ABSL_ATTRIBUTE_RETURNS_NONNULL std::string* MakeCheckOpString( |
|
T1 v1, T2 v2, const char* exprtext) ABSL_ATTRIBUTE_NOINLINE; |
|
|
|
template <typename T1, typename T2> |
|
std::string* MakeCheckOpString(T1 v1, T2 v2, const char* exprtext) { |
|
CheckOpMessageBuilder comb(exprtext); |
|
MakeCheckOpValueString(comb.ForVar1(), v1); |
|
MakeCheckOpValueString(comb.ForVar2(), v2); |
|
return comb.NewString(); |
|
} |
|
|
|
// Add a few commonly used instantiations as extern to reduce size of objects |
|
// files. |
|
#define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(x) \ |
|
extern template std::string* MakeCheckOpString(x, x, const char*) |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(bool); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(int64_t); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(uint64_t); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(float); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(double); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(char); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char*); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const signed char*); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const unsigned char*); |
|
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*); |
|
#undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN |
|
|
|
// Helper functions for `ABSL_LOG_INTERNAL_CHECK_OP` macro family. The |
|
// `(int, int)` override works around the issue that the compiler will not |
|
// instantiate the template version of the function on values of unnamed enum |
|
// type. |
|
#define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ |
|
template <typename T1, typename T2> \ |
|
inline constexpr ::std::string* name##Impl(const T1& v1, const T2& v2, \ |
|
const char* exprtext) { \ |
|
using U1 = CheckOpStreamType<T1>; \ |
|
using U2 = CheckOpStreamType<T2>; \ |
|
return ABSL_PREDICT_TRUE(v1 op v2) \ |
|
? nullptr \ |
|
: MakeCheckOpString<U1, U2>(v1, v2, exprtext); \ |
|
} \ |
|
inline constexpr ::std::string* name##Impl(int v1, int v2, \ |
|
const char* exprtext) { \ |
|
return name##Impl<int, int>(v1, v2, exprtext); \ |
|
} |
|
|
|
ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_EQ, ==) |
|
ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_NE, !=) |
|
ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LE, <=) |
|
ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LT, <) |
|
ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GE, >=) |
|
ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GT, >) |
|
#undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL |
|
|
|
std::string* CheckstrcmptrueImpl(const char* s1, const char* s2, |
|
const char* exprtext); |
|
std::string* CheckstrcmpfalseImpl(const char* s1, const char* s2, |
|
const char* exprtext); |
|
std::string* CheckstrcasecmptrueImpl(const char* s1, const char* s2, |
|
const char* exprtext); |
|
std::string* CheckstrcasecmpfalseImpl(const char* s1, const char* s2, |
|
const char* exprtext); |
|
|
|
// `CHECK_EQ` and friends want to pass their arguments by reference, however |
|
// this winds up exposing lots of cases where people have defined and |
|
// initialized static const data members but never declared them (i.e. in a .cc |
|
// file), meaning they are not referenceable. This function avoids that problem |
|
// for integers (the most common cases) by overloading for every primitive |
|
// integer type, even the ones we discourage, and returning them by value. |
|
template <typename T> |
|
inline constexpr const T& GetReferenceableValue(const T& t) { |
|
return t; |
|
} |
|
inline constexpr char GetReferenceableValue(char t) { return t; } |
|
inline constexpr unsigned char GetReferenceableValue(unsigned char t) { |
|
return t; |
|
} |
|
inline constexpr signed char GetReferenceableValue(signed char t) { return t; } |
|
inline constexpr short GetReferenceableValue(short t) { return t; } // NOLINT |
|
inline constexpr unsigned short GetReferenceableValue( // NOLINT |
|
unsigned short t) { // NOLINT |
|
return t; |
|
} |
|
inline constexpr int GetReferenceableValue(int t) { return t; } |
|
inline unsigned int GetReferenceableValue(unsigned int t) { return t; } |
|
inline constexpr long GetReferenceableValue(long t) { return t; } // NOLINT |
|
inline constexpr unsigned long GetReferenceableValue( // NOLINT |
|
unsigned long t) { // NOLINT |
|
return t; |
|
} |
|
inline constexpr long long GetReferenceableValue(long long t) { // NOLINT |
|
return t; |
|
} |
|
inline constexpr unsigned long long GetReferenceableValue( // NOLINT |
|
unsigned long long t) { // NOLINT |
|
return t; |
|
} |
|
|
|
} // namespace log_internal |
|
ABSL_NAMESPACE_END |
|
} // namespace absl |
|
|
|
#endif // ABSL_LOG_INTERNAL_CHECK_OP_H_
|
|
|