1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
20 // Note: This file depends on the backend header already being included.
22 #include "pw_assert/options.h"
23 #include "pw_preprocessor/arguments.h"
24 #include "pw_preprocessor/compiler.h"
26 // PW_CRASH - Crash the system, with a message.
27 #define PW_CRASH PW_HANDLE_CRASH
29 // PW_CHECK - If condition evaluates to false, crash. Message optional.
30 #define PW_CHECK(condition, ...) \
33 _PW_CHECK_SELECT_MACRO( \
34 #condition, PW_HAS_ARGS(__VA_ARGS__), __VA_ARGS__); \
38 #define PW_DCHECK(...) \
40 if (PW_ASSERT_ENABLE_DEBUG) { \
41 PW_CHECK(__VA_ARGS__); \
45 // PW_D?CHECK_<type>_<comparison> macros - Binary comparison asserts.
47 // The below blocks are structured in table form, violating the 80-column
48 // Pigweed style, in order to make it clearer what is common and what isn't
49 // between the multitude of assert macro instantiations. To best view this
50 // section, turn off editor wrapping or make your editor wide.
54 // Checks for int: LE, LT, GE, GT, EQ.
55 #define PW_CHECK_INT_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, int, "%d", __VA_ARGS__)
56 #define PW_CHECK_INT_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, int, "%d", __VA_ARGS__)
57 #define PW_CHECK_INT_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, int, "%d", __VA_ARGS__)
58 #define PW_CHECK_INT_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, int, "%d", __VA_ARGS__)
59 #define PW_CHECK_INT_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, int, "%d", __VA_ARGS__)
60 #define PW_CHECK_INT_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, int, "%d", __VA_ARGS__)
62 // Debug checks for int: LE, LT, GE, GT, EQ.
63 #define PW_DCHECK_INT_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_LE(__VA_ARGS__)
64 #define PW_DCHECK_INT_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_LT(__VA_ARGS__)
65 #define PW_DCHECK_INT_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_GE(__VA_ARGS__)
66 #define PW_DCHECK_INT_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_GT(__VA_ARGS__)
67 #define PW_DCHECK_INT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_EQ(__VA_ARGS__)
68 #define PW_DCHECK_INT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_NE(__VA_ARGS__)
70 // Checks for unsigned int: LE, LT, GE, GT, EQ.
71 #define PW_CHECK_UINT_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, unsigned int, "%u", __VA_ARGS__)
72 #define PW_CHECK_UINT_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, unsigned int, "%u", __VA_ARGS__)
73 #define PW_CHECK_UINT_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, unsigned int, "%u", __VA_ARGS__)
74 #define PW_CHECK_UINT_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, unsigned int, "%u", __VA_ARGS__)
75 #define PW_CHECK_UINT_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, unsigned int, "%u", __VA_ARGS__)
76 #define PW_CHECK_UINT_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, unsigned int, "%u", __VA_ARGS__)
78 // Debug checks for unsigned int: LE, LT, GE, GT, EQ.
79 #define PW_DCHECK_UINT_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_LE(__VA_ARGS__)
80 #define PW_DCHECK_UINT_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_LT(__VA_ARGS__)
81 #define PW_DCHECK_UINT_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_GE(__VA_ARGS__)
82 #define PW_DCHECK_UINT_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_GT(__VA_ARGS__)
83 #define PW_DCHECK_UINT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_EQ(__VA_ARGS__)
84 #define PW_DCHECK_UINT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_NE(__VA_ARGS__)
86 // Checks for pointer: LE, LT, GE, GT, EQ, NE.
87 #define PW_CHECK_PTR_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, const void*, "%p", __VA_ARGS__)
88 #define PW_CHECK_PTR_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, const void*, "%p", __VA_ARGS__)
89 #define PW_CHECK_PTR_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, const void*, "%p", __VA_ARGS__)
90 #define PW_CHECK_PTR_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, const void*, "%p", __VA_ARGS__)
91 #define PW_CHECK_PTR_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, const void*, "%p", __VA_ARGS__)
92 #define PW_CHECK_PTR_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, const void*, "%p", __VA_ARGS__)
94 // Check for pointer: NOTNULL. Use "nullptr" in C++, "NULL" in C.
96 #define PW_CHECK_NOTNULL(arga, ...) \
97 _PW_CHECK_BINARY_CMP_IMPL(arga, !=, nullptr, const void*, "%p", __VA_ARGS__)
99 #define PW_CHECK_NOTNULL(arga, ...) \
100 _PW_CHECK_BINARY_CMP_IMPL(arga, !=, NULL, const void*, "%p", __VA_ARGS__)
101 #endif // __cplusplus
103 // Debug checks for pointer: LE, LT, GE, GT, EQ, NE, and NOTNULL.
104 #define PW_DCHECK_PTR_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_LE(__VA_ARGS__)
105 #define PW_DCHECK_PTR_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_LT(__VA_ARGS__)
106 #define PW_DCHECK_PTR_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_GE(__VA_ARGS__)
107 #define PW_DCHECK_PTR_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_GT(__VA_ARGS__)
108 #define PW_DCHECK_PTR_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_EQ(__VA_ARGS__)
109 #define PW_DCHECK_PTR_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_NE(__VA_ARGS__)
110 #define PW_DCHECK_NOTNULL(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_NOTNULL(__VA_ARGS__)
112 // Checks for float: EXACT_LE, EXACT_LT, EXACT_GE, EXACT_GT, EXACT_EQ, EXACT_NE,
114 #define PW_CHECK_FLOAT_NEAR(arga, argb, abs_tolerance, ...) \
115 _PW_CHECK_FLOAT_NEAR(arga, argb, abs_tolerance, __VA_ARGS__)
116 #define PW_CHECK_FLOAT_EXACT_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, float, "%f", __VA_ARGS__)
117 #define PW_CHECK_FLOAT_EXACT_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, float, "%f", __VA_ARGS__)
118 #define PW_CHECK_FLOAT_EXACT_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, float, "%f", __VA_ARGS__)
119 #define PW_CHECK_FLOAT_EXACT_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, float, "%f", __VA_ARGS__)
120 #define PW_CHECK_FLOAT_EXACT_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, float, "%f", __VA_ARGS__)
121 #define PW_CHECK_FLOAT_EXACT_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, float, "%f", __VA_ARGS__)
123 // Debug checks for float: NEAR, EXACT_LE, EXACT_LT, EXACT_GE, EXACT_GT,
125 #define PW_DCHECK_FLOAT_NEAR(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_NEAR(__VA_ARGS__)
126 #define PW_DCHECK_FLOAT_EXACT_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_LE(__VA_ARGS__)
127 #define PW_DCHECK_FLOAT_EXACT_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_LT(__VA_ARGS__)
128 #define PW_DCHECK_FLOAT_EXACT_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_GE(__VA_ARGS__)
129 #define PW_DCHECK_FLOAT_EXACT_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_GT(__VA_ARGS__)
130 #define PW_DCHECK_FLOAT_EXACT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_EQ(__VA_ARGS__)
131 #define PW_DCHECK_FLOAT_EXACT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_NE(__VA_ARGS__)
135 // PW_CHECK - If condition evaluates to false, crash. Message optional.
136 #define PW_CHECK_OK(status, ...) \
138 if (status != PW_STATUS_OK) { \
139 _PW_CHECK_OK_SELECT_MACRO(#status, \
140 pw_StatusString(status), \
141 PW_HAS_ARGS(__VA_ARGS__), \
146 #define PW_DCHECK_OK(...) \
147 if (!(PW_ASSERT_ENABLE_DEBUG)) { \
149 PW_CHECK_OK(__VA_ARGS__)
151 // =========================================================================
152 // Implementation for PW_CHECK
154 // Two layers of select macros are used to enable the preprocessor to expand
155 // macros in the arguments to ultimately token paste the final macro name based
156 // on whether there are printf-style arguments.
157 #define _PW_CHECK_SELECT_MACRO(condition, has_args, ...) \
158 _PW_CHECK_SELECT_MACRO_EXPANDED(condition, has_args, __VA_ARGS__)
160 // Delegate to the macro
161 #define _PW_CHECK_SELECT_MACRO_EXPANDED(condition, has_args, ...) \
162 _PW_CHECK_HAS_MSG_##has_args(condition, __VA_ARGS__)
164 // PW_CHECK version 1: No message or args
165 #define _PW_CHECK_HAS_MSG_0(condition, ignored_arg) \
166 PW_HANDLE_ASSERT_FAILURE(condition, "")
168 // PW_CHECK version 2: With message (and maybe args)
169 #define _PW_CHECK_HAS_MSG_1(condition, ...) \
170 PW_HANDLE_ASSERT_FAILURE(condition, __VA_ARGS__)
172 // =========================================================================
173 // Implementation for PW_CHECK_<type>_<comparison>
175 // Two layers of select macros are used to enable the preprocessor to expand
176 // macros in the arguments to ultimately token paste the final macro name based
177 // on whether there are printf-style arguments.
178 #define _PW_CHECK_BINARY_COMPARISON_SELECT_MACRO(argument_a_str, \
186 _PW_CHECK_SELECT_BINARY_COMPARISON_MACRO_EXPANDED(argument_a_str, \
195 // Delegate to the macro
196 #define _PW_CHECK_SELECT_BINARY_COMPARISON_MACRO_EXPANDED(argument_a_str, \
204 _PW_CHECK_BINARY_COMPARISON_HAS_MSG_##has_args(argument_a_str, \
212 // PW_CHECK_BINARY_COMPARISON version 1: No message or args
213 #define _PW_CHECK_BINARY_COMPARISON_HAS_MSG_0(argument_a_str, \
220 PW_HANDLE_ASSERT_BINARY_COMPARE_FAILURE(argument_a_str, \
228 // PW_CHECK_BINARY_COMPARISON version 2: With message (and maybe args)
229 #define _PW_CHECK_BINARY_COMPARISON_HAS_MSG_1(argument_a_str, \
236 PW_HANDLE_ASSERT_BINARY_COMPARE_FAILURE(argument_a_str, \
244 // For the binary assertions, this private macro is re-used for almost all of
245 // the variants. Due to limitations of C formatting, it is necessary to have
246 // separate macros for the types.
248 // The macro avoids evaluating the arguments multiple times at the cost of some
250 #define _PW_CHECK_BINARY_CMP_IMPL( \
251 argument_a, comparison_op, argument_b, type_decl, type_fmt, ...) \
253 type_decl evaluated_argument_a = (type_decl)(argument_a); \
254 type_decl evaluated_argument_b = (type_decl)(argument_b); \
255 if (!(evaluated_argument_a comparison_op evaluated_argument_b)) { \
256 _PW_CHECK_BINARY_COMPARISON_SELECT_MACRO(#argument_a, \
257 evaluated_argument_a, \
260 evaluated_argument_b, \
262 PW_HAS_ARGS(__VA_ARGS__), \
267 // Custom implementation for FLOAT_NEAR which is implemented through two
268 // underlying checks which are not trivially replaced through the use of
269 // FLOAT_EXACT_LE & FLOAT_EXACT_GE.
270 #define _PW_CHECK_FLOAT_NEAR(argument_a, argument_b, abs_tolerance, ...) \
272 PW_CHECK_FLOAT_EXACT_GE(abs_tolerance, 0.0f); \
273 float evaluated_argument_a = (float)(argument_a); \
274 float evaluated_argument_b_min = (float)(argument_b)-abs_tolerance; \
275 float evaluated_argument_b_max = (float)(argument_b) + abs_tolerance; \
276 if (!(evaluated_argument_a >= evaluated_argument_b_min)) { \
277 _PW_CHECK_BINARY_COMPARISON_SELECT_MACRO(#argument_a, \
278 evaluated_argument_a, \
280 #argument_b " - abs_tolerance", \
281 evaluated_argument_b_min, \
283 PW_HAS_ARGS(__VA_ARGS__), \
285 } else if (!(evaluated_argument_a <= evaluated_argument_b_max)) { \
286 _PW_CHECK_BINARY_COMPARISON_SELECT_MACRO(#argument_a, \
287 evaluated_argument_a, \
289 #argument_b " + abs_tolerance", \
290 evaluated_argument_b_max, \
292 PW_HAS_ARGS(__VA_ARGS__), \
297 // =========================================================================
298 // Implementation for PW_CHECK_OK
300 // Two layers of select macros are used to enable the preprocessor to expand
301 // macros in the arguments to ultimately token paste the final macro name based
302 // on whether there are printf-style arguments.
303 #define _PW_CHECK_OK_SELECT_MACRO( \
304 status_expr_str, status_value_str, has_args, ...) \
305 _PW_CHECK_OK_SELECT_MACRO_EXPANDED( \
306 status_expr_str, status_value_str, has_args, __VA_ARGS__)
308 // Delegate to the macro
309 #define _PW_CHECK_OK_SELECT_MACRO_EXPANDED( \
310 status_expr_str, status_value_str, has_args, ...) \
311 _PW_CHECK_OK_HAS_MSG_##has_args( \
312 status_expr_str, status_value_str, __VA_ARGS__)
314 // PW_CHECK_OK version 1: No message or args
315 #define _PW_CHECK_OK_HAS_MSG_0(status_expr_str, status_value_str, ignored_arg) \
316 PW_HANDLE_ASSERT_BINARY_COMPARE_FAILURE( \
317 status_expr_str, status_value_str, "==", "OkStatus()", "OK", "%s", "")
319 // PW_CHECK_OK version 2: With message (and maybe args)
320 #define _PW_CHECK_OK_HAS_MSG_1(status_expr_str, status_value_str, ...) \
321 PW_HANDLE_ASSERT_BINARY_COMPARE_FAILURE(status_expr_str, \
329 // Define short, usable names if requested. Note that the CHECK() macro will
330 // conflict with Google Log, which expects stream style logs.
331 #ifndef PW_ASSERT_USE_SHORT_NAMES
332 #define PW_ASSERT_USE_SHORT_NAMES 0
335 // =========================================================================
336 // Short name definitions (optional)
339 #if PW_ASSERT_USE_SHORT_NAMES
341 // Checks that always run even in production.
342 #define CRASH PW_CRASH
343 #define CHECK PW_CHECK
344 #define CHECK_PTR_LE PW_CHECK_PTR_LE
345 #define CHECK_PTR_LT PW_CHECK_PTR_LT
346 #define CHECK_PTR_GE PW_CHECK_PTR_GE
347 #define CHECK_PTR_GT PW_CHECK_PTR_GT
348 #define CHECK_PTR_EQ PW_CHECK_PTR_EQ
349 #define CHECK_PTR_NE PW_CHECK_PTR_NE
350 #define CHECK_NOTNULL PW_CHECK_NOTNULL
351 #define CHECK_INT_LE PW_CHECK_INT_LE
352 #define CHECK_INT_LT PW_CHECK_INT_LT
353 #define CHECK_INT_GE PW_CHECK_INT_GE
354 #define CHECK_INT_GT PW_CHECK_INT_GT
355 #define CHECK_INT_EQ PW_CHECK_INT_EQ
356 #define CHECK_INT_NE PW_CHECK_INT_NE
357 #define CHECK_UINT_LE PW_CHECK_UINT_LE
358 #define CHECK_UINT_LT PW_CHECK_UINT_LT
359 #define CHECK_UINT_GE PW_CHECK_UINT_GE
360 #define CHECK_UINT_GT PW_CHECK_UINT_GT
361 #define CHECK_UINT_EQ PW_CHECK_UINT_EQ
362 #define CHECK_UINT_NE PW_CHECK_UINT_NE
363 #define CHECK_FLOAT_NEAR PW_CHECK_FLOAT_NEAR
364 #define CHECK_FLOAT_EXACT_LE PW_CHECK_FLOAT_EXACT_LE
365 #define CHECK_FLOAT_EXACT_LT PW_CHECK_FLOAT_EXACT_LT
366 #define CHECK_FLOAT_EXACT_GE PW_CHECK_FLOAT_EXACT_GE
367 #define CHECK_FLOAT_EXACT_GT PW_CHECK_FLOAT_EXACT_GT
368 #define CHECK_FLOAT_EXACT_EQ PW_CHECK_FLOAT_EXACT_EQ
369 #define CHECK_FLOAT_EXACT_NE PW_CHECK_FLOAT_EXACT_NE
370 #define CHECK_OK PW_CHECK_OK
372 // Checks that are disabled if NDEBUG is not defined.
373 #define DCHECK PW_DCHECK
374 #define DCHECK_PTR_LE PW_DCHECK_PTR_LE
375 #define DCHECK_PTR_LT PW_DCHECK_PTR_LT
376 #define DCHECK_PTR_GE PW_DCHECK_PTR_GE
377 #define DCHECK_PTR_GT PW_DCHECK_PTR_GT
378 #define DCHECK_PTR_EQ PW_DCHECK_PTR_EQ
379 #define DCHECK_PTR_NE PW_DCHECK_PTR_NE
380 #define DCHECK_NOTNULL PW_DCHECK_NOTNULL
381 #define DCHECK_INT_LE PW_DCHECK_INT_LE
382 #define DCHECK_INT_LT PW_DCHECK_INT_LT
383 #define DCHECK_INT_GE PW_DCHECK_INT_GE
384 #define DCHECK_INT_GT PW_DCHECK_INT_GT
385 #define DCHECK_INT_EQ PW_DCHECK_INT_EQ
386 #define DCHECK_INT_NE PW_DCHECK_INT_NE
387 #define DCHECK_UINT_LE PW_DCHECK_UINT_LE
388 #define DCHECK_UINT_LT PW_DCHECK_UINT_LT
389 #define DCHECK_UINT_GE PW_DCHECK_UINT_GE
390 #define DCHECK_UINT_GT PW_DCHECK_UINT_GT
391 #define DCHECK_UINT_EQ PW_DCHECK_UINT_EQ
392 #define DCHECK_UINT_NE PW_DCHECK_UINT_NE
393 #define DCHECK_FLOAT_NEAR PW_DCHECK_FLOAT_NEAR
394 #define DCHECK_FLOAT_EXACT_LT PW_DCHECK_FLOAT_EXACT_LT
395 #define DCHECK_FLOAT_EXACT_LE PW_DCHECK_FLOAT_EXACT_LE
396 #define DCHECK_FLOAT_EXACT_GT PW_DCHECK_FLOAT_EXACT_GT
397 #define DCHECK_FLOAT_EXACT_GE PW_DCHECK_FLOAT_EXACT_GE
398 #define DCHECK_FLOAT_EXACT_EQ PW_DCHECK_FLOAT_EXACT_EQ
399 #define DCHECK_FLOAT_EXACT_NE PW_DCHECK_FLOAT_EXACT_NE
400 #define DCHECK_OK PW_DCHECK_OK
402 #endif // PW_ASSERT_SHORT_NAMES