• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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