1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef BERBERIS_BASE_CHECKS_H_ 18 #define BERBERIS_BASE_CHECKS_H_ 19 20 #include <array> 21 #include <cinttypes> 22 23 #include "berberis/base/logging.h" 24 25 // Helpers for building message format, without incurring any function calls when the condition 26 // does not fail. 27 28 namespace berberis { 29 30 class FmtSpec { 31 private: Get(int32_t)32 constexpr static const char (&Get(int32_t))[sizeof "%" PRId32] { return "%" PRId32; } Get(uint32_t)33 constexpr static const char (&Get(uint32_t))[sizeof "%" PRIu32] { return "%" PRIu32; } Get(int64_t)34 constexpr static const char (&Get(int64_t))[sizeof "%" PRId64] { return "%" PRId64; } Get(uint64_t)35 constexpr static const char (&Get(uint64_t))[sizeof "%" PRIu64] { return "%" PRIu64; } Get(double)36 constexpr static const char (&Get(double))[sizeof "%f"] { return "%f"; } Get(const void *)37 constexpr static const char (&Get(const void*))[sizeof "%p"] { return "%p"; } 38 39 public: 40 template <typename Type> 41 constexpr static auto& kValue = FmtSpec::Get(static_cast<std::decay_t<Type>>(0)); 42 43 template <size_t prefix_len, size_t op_len, size_t spec1_len, size_t spec2_len> Fmt(const char (& prefix)[prefix_len],const char (& op)[op_len],const char (& spec1)[spec1_len],const char (& spec2)[spec2_len])44 constexpr static std::array<char, prefix_len + op_len + spec1_len + spec2_len - 3> Fmt( 45 const char (&prefix)[prefix_len], const char (&op)[op_len], const char (&spec1)[spec1_len], 46 const char (&spec2)[spec2_len]) { 47 std::array<char, prefix_len + op_len + spec1_len + spec2_len - 3> fmt{}; 48 auto pos = begin(fmt); 49 Append(&pos, prefix, prefix_len); 50 Append(&pos, spec1, spec1_len); 51 Append(&pos, op, op_len); 52 Append(&pos, spec2, spec2_len); 53 return fmt; 54 } 55 56 private: 57 template <typename Iterator> Append(Iterator * pos,const char * text,size_t len)58 constexpr static void Append(Iterator* pos, const char* text, size_t len) { 59 while (--len > 0) *(*pos)++ = *text++; 60 } 61 }; 62 63 } // namespace berberis 64 65 #define BERBERIS_VALUE_STR_IMPL(v) #v 66 #define BERBERIS_VALUE_STR(v) BERBERIS_VALUE_STR_IMPL(v) 67 #define BERBERIS_CHECK_PREFIX __FILE__ ":" BERBERIS_VALUE_STR(__LINE__) ": CHECK failed: " 68 69 // Log fatal error. 70 // NEVER stripped - side effects always apply. 71 72 #define FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) 73 74 #define UNREACHABLE() FATAL("This code is (supposed to be) unreachable.") 75 76 #ifdef CHECK 77 #undef CHECK 78 #endif 79 #define CHECK(cond) LOG_ALWAYS_FATAL_IF(!(cond), "%s", BERBERIS_CHECK_PREFIX #cond) 80 81 // TODO(b/232598137): fix multiple evaluation of v1 and v2! 82 // TODO(b/232598137): change message from '1 == 0' to 'x == y (1 == 0)'! 83 #define BERBERIS_CHECK_OP(op, v1, v2) \ 84 LOG_ALWAYS_FATAL_IF( \ 85 !((v1)op(v2)), /* // NOLINT */ \ 86 []() { \ 87 constexpr static auto __fmt = berberis::FmtSpec::Fmt( \ 88 BERBERIS_CHECK_PREFIX, " " #op " ", berberis::FmtSpec::kValue<decltype(v1)>, \ 89 berberis::FmtSpec::kValue<decltype(v2)>); \ 90 return __fmt.data(); \ 91 }(), \ 92 v1, v2) 93 94 #ifdef CHECK_EQ 95 #undef CHECK_EQ 96 #endif 97 #define CHECK_EQ(v1, v2) BERBERIS_CHECK_OP(==, v1, v2) 98 99 #ifdef CHECK_NE 100 #undef CHECK_NE 101 #endif 102 #define CHECK_NE(v1, v2) BERBERIS_CHECK_OP(!=, v1, v2) 103 104 #ifdef CHECK_LT 105 #undef CHECK_LT 106 #endif 107 #define CHECK_LT(v1, v2) BERBERIS_CHECK_OP(<, v1, v2) 108 109 #ifdef CHECK_LE 110 #undef CHECK_LE 111 #endif 112 #define CHECK_LE(v1, v2) BERBERIS_CHECK_OP(<=, v1, v2) 113 114 #ifdef CHECK_GT 115 #undef CHECK_GT 116 #endif 117 #define CHECK_GT(v1, v2) BERBERIS_CHECK_OP(>, v1, v2) 118 119 #ifdef CHECK_GE 120 #undef CHECK_GE 121 #endif 122 #define CHECK_GE(v1, v2) BERBERIS_CHECK_OP(>=, v1, v2) 123 124 // Log fatal error. 125 // ATTENTION - stripped from release builds, be careful with side effects! 126 127 #ifdef DCHECK 128 #undef DCHECK 129 #endif 130 #if LOG_NDEBUG 131 #define DCHECK(cond) 132 #else 133 #define DCHECK(cond) CHECK(cond) 134 #endif 135 136 #if LOG_NDEBUG 137 #define BERBERIS_DCHECK_OP(op, v1, v2) 138 #else 139 #define BERBERIS_DCHECK_OP(op, v1, v2) BERBERIS_CHECK_OP(op, v1, v2) 140 #endif 141 142 #ifdef DCHECK_EQ 143 #undef DCHECK_EQ 144 #endif 145 #define DCHECK_EQ(v1, v2) BERBERIS_DCHECK_OP(==, v1, v2) 146 147 #ifdef DCHECK_NE 148 #undef DCHECK_NE 149 #endif 150 #define DCHECK_NE(v1, v2) BERBERIS_DCHECK_OP(!=, v1, v2) 151 152 #ifdef DCHECK_LT 153 #undef DCHECK_LT 154 #endif 155 #define DCHECK_LT(v1, v2) BERBERIS_DCHECK_OP(<, v1, v2) 156 157 #ifdef DCHECK_LE 158 #undef DCHECK_LE 159 #endif 160 #define DCHECK_LE(v1, v2) BERBERIS_DCHECK_OP(<=, v1, v2) 161 162 #ifdef DCHECK_GT 163 #undef DCHECK_GT 164 #endif 165 #define DCHECK_GT(v1, v2) BERBERIS_DCHECK_OP(>, v1, v2) 166 167 #ifdef DCHECK_GE 168 #undef DCHECK_GE 169 #endif 170 #define DCHECK_GE(v1, v2) BERBERIS_DCHECK_OP(>=, v1, v2) 171 172 #endif // BERBERIS_BASE_CHECKS_H_ 173