Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines and implements a number of miscellaneous
22 : * templates for finding object minima and maxima and interface
23 : * macros for assertion checking.
24 : *
25 : */
26 :
27 : #pragma once
28 :
29 : #include <lib/core/CHIPConfig.h>
30 : #include <lib/core/CHIPError.h>
31 : #include <lib/core/ErrorStr.h>
32 : #include <lib/support/ObjectDump.h>
33 : #include <lib/support/VerificationMacrosNoLogging.h>
34 : #include <lib/support/logging/TextOnlyLogging.h>
35 :
36 : /**
37 : * Base-level abnormal termination.
38 : *
39 : * Terminate the program immediately, without invoking destructors, atexit callbacks, etc.
40 : * Used to implement the default `chipDie()`.
41 : *
42 : * @note
43 : * This should never be invoked directly by code outside this file.
44 : */
45 : #if !defined(CHIP_CONFIG_ABORT)
46 : #define CHIP_CONFIG_ABORT() abort()
47 : #endif
48 :
49 : /**
50 : * @name chip-specific nlassert.h Overrides
51 : *
52 : * @{
53 : *
54 : */
55 :
56 : /**
57 : * @def NL_ASSERT_ABORT()
58 : *
59 : * @brief
60 : * This implements a chip-specific override for #NL_ASSERT_ABORT *
61 : * from nlassert.h.
62 : *
63 : */
64 : #if !defined(NL_ASSERT_ABORT)
65 : #define NL_ASSERT_ABORT() chipAbort()
66 : #endif
67 :
68 : /**
69 : * @def NL_ASSERT_LOG(aPrefix, aName, aCondition, aLabel, aFile, aLine, aMessage)
70 : *
71 : * @brief
72 : * This implements a chip-specific override for \c NL_ASSERT_LOG
73 : * from nlassert.h.
74 : *
75 : * @param[in] aPrefix A pointer to a NULL-terminated C string printed
76 : * at the beginning of the logged assertion
77 : * message. Typically this is and should be
78 : * \c NL_ASSERT_PREFIX_STRING.
79 : * @param[in] aName A pointer to a NULL-terminated C string printed
80 : * following @a aPrefix that indicates what
81 : * module, program, application or subsystem
82 : * the assertion occurred in Typically this
83 : * is and should be
84 : * \c NL_ASSERT_COMPONENT_STRING.
85 : * @param[in] aCondition A pointer to a NULL-terminated C string indicating
86 : * the expression that evaluated to false in
87 : * the assertion. Typically this is a
88 : * stringified version of the actual
89 : * assertion expression.
90 : * @param[in] aLabel An optional pointer to a NULL-terminated C string
91 : * indicating, for exception-style
92 : * assertions, the label that will be
93 : * branched to when the assertion expression
94 : * evaluates to false.
95 : * @param[in] aFile A pointer to a NULL-terminated C string indicating
96 : * the file in which the exception
97 : * occurred. Typically this is and should be
98 : * \_\_FILE\_\_ from the C preprocessor.
99 : * @param[in] aLine The line number in @a aFile on which the assertion
100 : * expression evaluated to false. Typically
101 : * this is and should be \_\_LINE\_\_ from the C
102 : * preprocessor.
103 : * @param[in] aMessage An optional pointer to a NULL-terminated C string
104 : * containing a caller-specified message
105 : * further describing the assertion failure.
106 : *
107 : */
108 : // clang-format off
109 : #if !defined(NL_ASSERT_LOG)
110 : #define NL_ASSERT_LOG(aPrefix, aName, aCondition, aLabel, aFile, aLine, aMessage) \
111 : do \
112 : { \
113 : ChipLogError(NotSpecified, \
114 : NL_ASSERT_LOG_FORMAT_DEFAULT, \
115 : aPrefix, \
116 : (((aName) == 0) || (*(aName) == '\0')) ? "" : aName, \
117 : (((aName) == 0) || (*(aName) == '\0')) ? "" : ": ", \
118 : aCondition, \
119 : (((aMessage) == 0) ? "" : aMessage), \
120 : (((aMessage) == 0) ? "" : ", "), \
121 : aFile, \
122 : aLine); \
123 : } while (0)
124 : #endif
125 : // clang-format on
126 :
127 : /**
128 : * @} chip-specific nlassert.h Overrides
129 : *
130 : */
131 :
132 : #include <nlassert.h>
133 :
134 : /**
135 : * @def ReturnErrorOnFailure(expr)
136 : *
137 : * @brief
138 : * Returns the error code if the expression returns an error. For a CHIP_ERROR expression, this means any value other
139 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
140 : *
141 : * Example usage:
142 : *
143 : * @code
144 : * ReturnErrorOnFailure(channel->SendMsg(msg));
145 : * @endcode
146 : *
147 : * @param[in] expr An expression to be tested.
148 : */
149 : #define ReturnErrorOnFailure(expr) \
150 : do \
151 : { \
152 : auto __err = (expr); \
153 : if (!::chip::ChipError::IsSuccess(__err)) \
154 : { \
155 : return __err; \
156 : } \
157 : } while (false)
158 :
159 : /**
160 : * @def ReturnErrorVariantOnFailure(expr)
161 : *
162 : * @brief
163 : * This is for use when the calling function returns a Variant type. It returns a CHIP_ERROR variant with the corresponding error
164 : * code if the expression returns an error.
165 : *
166 : * Example usage:
167 : *
168 : * @code
169 : * ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1));
170 : * @endcode
171 : *
172 : * @param[in] variantType The Variant type that the calling function returns.
173 : * @param[in] expr An expression to be tested.
174 :
175 : */
176 : #define ReturnErrorVariantOnFailure(variantType, expr) \
177 : do \
178 : { \
179 : auto __err = (expr); \
180 : if (!::chip::ChipError::IsSuccess(__err)) \
181 : { \
182 : return variantType::Create<CHIP_ERROR>(__err); \
183 : } \
184 : } while (false)
185 :
186 : /**
187 : * @def ReturnLogErrorOnFailure(expr)
188 : *
189 : * @brief
190 : * Returns the error code if the expression returns something different
191 : * than CHIP_NO_ERROR.
192 : *
193 : * Example usage:
194 : *
195 : * @code
196 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
197 : * @endcode
198 : *
199 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
200 : */
201 : #define ReturnLogErrorOnFailure(expr) \
202 : do \
203 : { \
204 : CHIP_ERROR __err = (expr); \
205 : if (__err != CHIP_NO_ERROR) \
206 : { \
207 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
208 : return __err; \
209 : } \
210 : } while (false)
211 :
212 : /**
213 : * @def LogAndReturnOnFailure(expr)
214 : *
215 : * @brief
216 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
217 : * in the 'Error' category and return.
218 : *
219 : * Example usage:
220 : *
221 : * @code
222 : * LogAndReturnOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
223 : * @endcode
224 : *
225 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
226 : */
227 : #define LogAndReturnOnFailure(expr, MOD, MSG, ...) \
228 : do \
229 : { \
230 : CHIP_ERROR __err = (expr); \
231 : if (!::chip::ChipError::IsSuccess(__err)) \
232 : { \
233 : ChipLogError(MOD, MSG ": %" CHIP_ERROR_FORMAT, ##__VA_ARGS__, __err.Format()); \
234 : return; \
235 : } \
236 : } while (false)
237 :
238 : /**
239 : * @def LogAndReturnErrorOnFailure(expr)
240 : *
241 : * @brief
242 : * If expr returns something than CHIP_NO_ERROR, lg a chip message for the specified module
243 : * in the 'Error' category and return the error.
244 : *
245 : * Example usage:
246 : *
247 : * @code
248 : * LogAndReturnErrorOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
249 : * @endcode
250 : *
251 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
252 : */
253 : #define LogAndReturnErrorOnFailure(expr, MOD, MSG, ...) \
254 : do \
255 : { \
256 : CHIP_ERROR __err = (expr); \
257 : if (!::chip::ChipError::IsSuccess(__err)) \
258 : { \
259 : ChipLogError(MOD, MSG ": %" CHIP_ERROR_FORMAT, ##__VA_ARGS__, __err.Format()); \
260 : return _err; \
261 : } \
262 : } while (false)
263 :
264 : /**
265 : * @def ReturnOnFailure(expr)
266 : *
267 : * @brief
268 : * Returns if the expression returns an error. For a CHIP_ERROR expression, this means any value other
269 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
270 : *
271 : * Example usage:
272 : *
273 : * @code
274 : * ReturnOnFailure(channel->SendMsg(msg));
275 : * @endcode
276 : *
277 : * @param[in] expr An expression to be tested.
278 : */
279 : #define ReturnOnFailure(expr) \
280 : do \
281 : { \
282 : auto __err = (expr); \
283 : if (!::chip::ChipError::IsSuccess(__err)) \
284 : { \
285 : return; \
286 : } \
287 : } while (false)
288 :
289 : /**
290 : * @def ReturnValueOnFailure(expr)
291 : *
292 : * @brief
293 : * Returns value if the expression returns an error. For a CHIP_ERROR expression, this means any value other
294 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
295 : *
296 : * Example usage:
297 : *
298 : * @code
299 : * ReturnValueOnFailure(channel->SendMsg(msg), Status::Failure);
300 : * @endcode
301 : *
302 : * @param[in] expr An expression to be tested.
303 : * @param[in] value A value to return if @a expr is an error.
304 : * @param[in] ... Statements to execute before returning. Optional.
305 : */
306 : #define ReturnValueOnFailure(expr, value, ...) \
307 : do \
308 : { \
309 : auto __err = (expr); \
310 : if (!::chip::ChipError::IsSuccess(__err)) \
311 : { \
312 : return value; \
313 : } \
314 : } while (false)
315 :
316 : /**
317 : * @def VerifyOrReturn(expr, ...)
318 : *
319 : * @brief
320 : * Returns from the void function if expression evaluates to false
321 : *
322 : * Example usage:
323 : *
324 : * @code
325 : * VerifyOrReturn(param != nullptr, LogError("param is nullptr"));
326 : * @endcode
327 : *
328 : * @param[in] expr A Boolean expression to be evaluated.
329 : * @param[in] ... Statements to execute before returning. Optional.
330 : */
331 : #define VerifyOrReturn(expr, ...) \
332 : do \
333 : { \
334 : if (!(expr)) \
335 : { \
336 : __VA_ARGS__; \
337 : return; \
338 : } \
339 : } while (false)
340 :
341 : /**
342 : * @def VerifyOrReturnError(expr, code, ...)
343 : *
344 : * @brief
345 : * Returns a specified error code if expression evaluates to false
346 : *
347 : * Example usage:
348 : *
349 : * @code
350 : * VerifyOrReturnError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
351 : * @endcode
352 : *
353 : * @param[in] expr A Boolean expression to be evaluated.
354 : * @param[in] code A value to return if @a expr is false.
355 : * @param[in] ... Statements to execute before returning. Optional.
356 : */
357 : #define VerifyOrReturnError(expr, code, ...) VerifyOrReturnValue(expr, code, ##__VA_ARGS__)
358 :
359 : /**
360 : * @def VerifyOrReturnValue(expr, value, ...)
361 : *
362 : * @brief
363 : * Returns a specified value if expression evaluates to false
364 : *
365 : * Example usage:
366 : *
367 : * @code
368 : * VerifyOrReturnError(param != nullptr, Foo());
369 : * @endcode
370 : *
371 : * @param[in] expr A Boolean expression to be evaluated.
372 : * @param[in] value A value to return if @a expr is false.
373 : * @param[in] ... Statements to execute before returning. Optional.
374 : */
375 : #define VerifyOrReturnValue(expr, value, ...) \
376 : do \
377 : { \
378 : if (!(expr)) \
379 : { \
380 : __VA_ARGS__; \
381 : return (value); \
382 : } \
383 : } while (false)
384 :
385 : /**
386 : * @def VerifyOrReturnLogError(expr, code)
387 : *
388 : * @brief
389 : * Returns and print a specified error code if expression evaluates to false
390 : *
391 : * Example usage:
392 : *
393 : * @code
394 : * VerifyOrReturnLogError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
395 : * @endcode
396 : *
397 : * @param[in] expr A Boolean expression to be evaluated.
398 : * @param[in] code A value to return if @a expr is false.
399 : */
400 : #if CHIP_CONFIG_ERROR_SOURCE
401 : #define VerifyOrReturnLogError(expr, code) \
402 : do \
403 : { \
404 : if (!(expr)) \
405 : { \
406 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(code), __FILE__, __LINE__); \
407 : return code; \
408 : } \
409 : } while (false)
410 : #else // CHIP_CONFIG_ERROR_SOURCE
411 : #define VerifyOrReturnLogError(expr, code) \
412 : do \
413 : { \
414 : if (!(expr)) \
415 : { \
416 : ChipLogError(NotSpecified, "%s:%d false: %" CHIP_ERROR_FORMAT, #expr, __LINE__, code.Format()); \
417 : return code; \
418 : } \
419 : } while (false)
420 : #endif // CHIP_CONFIG_ERROR_SOURCE
421 :
422 : /**
423 : * @def SuccessOrExit(error)
424 : *
425 : * @brief
426 : * This checks for the specified error, which is expected to
427 : * commonly be successful (CHIP_NO_ERROR), and branches to
428 : * the local label 'exit' if the status is unsuccessful.
429 : *
430 : * Example Usage:
431 : *
432 : * @code
433 : * CHIP_ERROR TryHard()
434 : * {
435 : * CHIP_ERROR err;
436 : *
437 : * err = TrySomething();
438 : * SuccessOrExit(err);
439 : *
440 : * err = TrySomethingElse();
441 : * SuccessOrExit(err);
442 : *
443 : * exit:
444 : * return err;
445 : * }
446 : * @endcode
447 : *
448 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
449 : *
450 : */
451 : #define SuccessOrExit(error) nlEXPECT(::chip::ChipError::IsSuccess((error)), exit)
452 :
453 : /**
454 : * @def SuccessOrExitAction(error, anAction)
455 : *
456 : * @brief
457 : * This checks for the specified error, which is expected to
458 : * commonly be successful (CHIP_NO_ERROR), and both executes
459 : * @a anAction and branches to the local label 'exit' if the
460 : * status is unsuccessful.
461 : *
462 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
463 : */
464 : #define SuccessOrExitAction(error, action) nlEXPECT_ACTION(::chip::ChipError::IsSuccess((error)), exit, action)
465 :
466 : /**
467 : * @def VerifyOrExit(aCondition, anAction)
468 : *
469 : * @brief
470 : * This checks for the specified condition, which is expected to
471 : * commonly be true, and both executes @a anAction and branches to
472 : * the local label 'exit' if the condition is false.
473 : *
474 : * Example Usage:
475 : *
476 : * @code
477 : * CHIP_ERROR MakeBuffer(const uint8_t *& buf)
478 : * {
479 : * CHIP_ERROR err = CHIP_NO_ERROR;
480 : *
481 : * buf = (uint8_t *)malloc(1024);
482 : * VerifyOrExit(buf != NULL, err = CHIP_ERROR_NO_MEMORY);
483 : *
484 : * memset(buf, 0, 1024);
485 : *
486 : * exit:
487 : * return err;
488 : * }
489 : * @endcode
490 : *
491 : * @param[in] aCondition A Boolean expression to be evaluated.
492 : * @param[in] anAction An expression or block to execute when the
493 : * assertion fails.
494 : *
495 : */
496 : #define VerifyOrExit(aCondition, anAction) nlEXPECT_ACTION(aCondition, exit, anAction)
497 :
498 : /**
499 : * @def ExitNow(...)
500 : *
501 : * @brief
502 : * This unconditionally executes @a ... and branches to the local
503 : * label 'exit'.
504 : *
505 : * @note The use of this interface implies neither success nor
506 : * failure for the overall exit status of the enclosing function
507 : * body.
508 : *
509 : * Example Usage:
510 : *
511 : * @code
512 : * CHIP_ERROR ReadAll(Reader& reader)
513 : * {
514 : * CHIP_ERROR err;
515 : *
516 : * while (true)
517 : * {
518 : * err = reader.ReadNext();
519 : * if (err == CHIP_ERROR_AT_END)
520 : * ExitNow(err = CHIP_NO_ERROR);
521 : * SuccessOrExit(err);
522 : * DoSomething();
523 : * }
524 : *
525 : * exit:
526 : * return err;
527 : * }
528 : * @endcode
529 : *
530 : * @param[in] ... Statements to execute. Optional.
531 : */
532 : // clang-format off
533 : #define ExitNow(...) \
534 : do { \
535 : __VA_ARGS__; \
536 : goto exit; \
537 : } while (0)
538 : // clang-format on
539 :
540 : /**
541 : * @brief
542 : * This is invoked when a #VerifyOrDie or #VerifyOrDieWithMsg
543 : * assertion expression evaluates to false.
544 : *
545 : * Developers may override and customize this by defining #chipDie
546 : * before CodeUtils.h is included by the preprocessor.
547 : *
548 : * Example Usage:
549 : *
550 : * @code
551 : * chipDie();
552 : * @endcode
553 : *
554 : */
555 : #ifndef chipAbort
556 : extern "C" void chipAbort(void) __attribute((noreturn));
557 :
558 0 : inline void chipAbort(void)
559 : {
560 : while (true)
561 : {
562 : // NL_ASSERT_ABORT is redefined to be chipAbort, so not useful here.
563 0 : CHIP_CONFIG_ABORT();
564 : }
565 : }
566 : #endif // chipAbort
567 : #ifndef chipDie
568 : extern "C" void chipDie(void) __attribute((noreturn));
569 :
570 0 : inline void chipDie(void)
571 : {
572 0 : ChipLogError(NotSpecified, "chipDie chipDie chipDie");
573 0 : chipAbort();
574 : }
575 : #endif // chipDie
576 :
577 : /**
578 : * @def VerifyOrDie(aCondition)
579 : *
580 : * @brief
581 : * This checks for the specified condition, which is expected to
582 : * commonly be true and forces an immediate abort if the condition
583 : * is false.
584 : *
585 : * Example Usage:
586 : *
587 : * @code
588 : * void FreeBuffer(const uint8_t *buf)
589 : * {
590 : * VerifyOrDie(buf != NULL);
591 : * free(buf);
592 : * }
593 : * @endcode
594 : *
595 : * @param[in] aCondition A Boolean expression to be evaluated.
596 : *
597 : * @sa #VerifyOrDieWithMsg
598 : * @sa #chipDie
599 : *
600 : */
601 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
602 : #define VerifyOrDie(aCondition) \
603 : nlABORT_ACTION(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d", __FILE__, __LINE__))
604 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
605 : #define VerifyOrDie(aCondition) \
606 : nlABORT_ACTION(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition))
607 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
608 : #define VerifyOrDie(aCondition) VerifyOrDieWithoutLogging(aCondition)
609 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
610 :
611 : /**
612 : * @def SuccessOrDie(error)
613 : *
614 : * @brief
615 : * This checks for the specified error, which is expected to
616 : * commonly be successful (CHIP_NO_ERROR), forces an immediate abort if the status
617 : * is unsuccessful.
618 : *
619 : *
620 : * Example Usage:
621 : *
622 : * @code
623 : * uint8_t* AllocateBuffer()
624 : * {
625 : * uint8_t* buffer;
626 : * SuccessOrDie(ChipAllocateBuffer(buffer));
627 : * return buffer;
628 : * }
629 : * @endcode
630 : *
631 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
632 : *
633 : */
634 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
635 : #define SuccessOrDie(error) \
636 : nlABORT_ACTION(::chip::ChipError::IsSuccess((error)), \
637 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d", ErrorStr((error)), __FILE__, __LINE__))
638 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
639 : #define SuccessOrDie(error) \
640 : nlABORT_ACTION(::chip::ChipError::IsSuccess((error)), \
641 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d: %s", ErrorStr((error)), __FILE__, __LINE__, #error))
642 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
643 : #define SuccessOrDie(error) VerifyOrDieWithoutLogging(::chip::ChipError::IsSuccess((error)))
644 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
645 :
646 : /**
647 : * @def VerifyOrDieWithObject(aCondition, aObject)
648 : *
649 : * Like VerifyOrDie(), but calls DumpObjectToLog()
650 : * on the provided object on failure before aborting
651 : * if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE is enabled.
652 : */
653 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
654 : #define VerifyOrDieWithObject(aCondition, aObject) \
655 : nlABORT_ACTION(aCondition, ::chip::DumpObjectToLog(aObject); \
656 : ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition))
657 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
658 : #define VerifyOrDieWithObject(aCondition, aObject) VerifyOrDieWithoutLogging(aCondition)
659 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
660 :
661 : /**
662 : * @def VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...)
663 : *
664 : * @brief
665 : * This checks for the specified condition, which is expected to
666 : * commonly be true and both prints @a aMessage and forces an
667 : * immediate abort if the condition is false.
668 : *
669 : * Example Usage:
670 : *
671 : * @code
672 : * void FreeBuffer(const uint8_t *buf)
673 : * {
674 : * VerifyOrDieWithMsg(buf != NULL, MemoryManagement, "Invalid pointer passed to FreeBuffer");
675 : * free(buf);
676 : * }
677 : * @endcode
678 : *
679 : * @param[in] aCondition A Boolean expression to be evaluated.
680 : * @param[in] aModule A chip LogModule short-hand mnemonic identifing
681 : * the logical section of code that is a
682 : * source the logged message.
683 : * @param[in] aMessage A pointer to a NULL-terminated C string with
684 : * C Standard Library-style format specifiers
685 : * containing the log message to be formatted
686 : * and logged.
687 : * @param[in] ... A variadic argument list whose elements should
688 : * correspond to the format specifiers in @a
689 : * aMessage.
690 : *
691 : * @sa #VerifyOrDie
692 : * @sa #chipDie
693 : *
694 : */
695 : #define VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...) \
696 : nlABORT_ACTION(aCondition, ChipLogError(aModule, aMessage, ##__VA_ARGS__))
697 :
698 : /**
699 : * @def LogErrorOnFailure(expr)
700 : *
701 : * @brief
702 : * Logs a message if the expression returns something different than CHIP_NO_ERROR.
703 : *
704 : * Example usage:
705 : *
706 : * @code
707 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
708 : * @endcode
709 : *
710 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
711 : */
712 : #define LogErrorOnFailure(expr) \
713 : do \
714 : { \
715 : CHIP_ERROR __err = (expr); \
716 : if (__err != CHIP_NO_ERROR) \
717 : { \
718 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
719 : } \
720 : } while (false)
721 :
722 : /**
723 : * @def VerifyOrDo(expr, ...)
724 : *
725 : * @brief
726 : * do something if expression evaluates to false
727 : *
728 : * Example usage:
729 : *
730 : * @code
731 : * VerifyOrDo(param != nullptr, LogError("param is nullptr"));
732 : * @endcode
733 : *
734 : * @param[in] expr A Boolean expression to be evaluated.
735 : * @param[in] ... Statements to execute.
736 : */
737 : #define VerifyOrDo(expr, ...) \
738 : do \
739 : { \
740 : if (!(expr)) \
741 : { \
742 : __VA_ARGS__; \
743 : } \
744 : } while (false)
745 :
746 : #if (__cplusplus >= 201103L)
747 :
748 : #ifndef __FINAL
749 : #define __FINAL final
750 : #endif
751 :
752 : #ifndef __OVERRIDE
753 : #define __OVERRIDE override
754 : #endif
755 :
756 : #ifndef __CONSTEXPR
757 : #define __CONSTEXPR constexpr
758 : #endif
759 :
760 : #else
761 :
762 : #ifndef __FINAL
763 : #define __FINAL
764 : #endif
765 :
766 : #ifndef __OVERRIDE
767 : #define __OVERRIDE
768 : #endif
769 :
770 : #ifndef __CONSTEXPR
771 : #define __CONSTEXPR constexpr
772 : #endif
773 :
774 : #endif // (__cplusplus >= 201103L)
775 :
776 : #if ((__cplusplus >= 201703L) || (defined(__GNUC__) && (__GNUC__ >= 7)) || (defined(__clang__)) && (__clang_major__ >= 4))
777 : #define CHECK_RETURN_VALUE [[nodiscard]]
778 : #elif defined(__GNUC__) && (__GNUC__ >= 4)
779 : #define CHECK_RETURN_VALUE __attribute__((warn_unused_result))
780 : #elif defined(_MSC_VER) && (_MSC_VER >= 1700)
781 : #define CHECK_RETURN_VALUE _Check_return_
782 : #else
783 : #define CHECK_RETURN_VALUE
784 : #endif
785 :
786 : #if defined(__clang__)
787 : #define FALLTHROUGH [[clang::fallthrough]]
788 : #elif defined(__GNUC__)
789 : #define FALLTHROUGH __attribute__((fallthrough))
790 : #else
791 : #define FALLTHROUGH (void) 0
792 : #endif
793 :
794 : /**
795 : * @def MATTER_ARRAY_SIZE(aArray)
796 : *
797 : * @brief
798 : * Returns the size of an array in number of elements.
799 : *
800 : * Example Usage:
801 : *
802 : * @code
803 : * int numbers[10];
804 : * SortNumbers(numbers, MATTER_ARRAY_SIZE(numbers));
805 : * @endcode
806 : *
807 : * @return The size of an array in number of elements.
808 : *
809 : * @note Clever template-based solutions seem to fail when MATTER_ARRAY_SIZE is used
810 : * with a variable-length array argument, so we just do the C-compatible
811 : * thing in C++ as well.
812 : */
813 : #ifndef MATTER_ARRAY_SIZE
814 : #define MATTER_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
815 : #endif
816 :
817 : /**
818 : * @brief Ensures that if `str` is NULL, a non-null `default_str_value` is provided
819 : *
820 : * @param str - null-terminated string pointer or nullptr
821 : * @param default_str_value - replacement value if `str` is nullptr
822 : * @return `str` if not null, otherwise `default_str_value`
823 : */
824 4412 : inline const char * DefaultStringWhenNull(const char * str, const char * default_str_value)
825 : {
826 4412 : return (str != nullptr) ? str : default_str_value;
827 : }
828 :
829 : /**
830 : * @brief Ensure that a string for a %s specifier is shown as "(null)" if null
831 : *
832 : * @param str - null-terminated string pointer or nullptr
833 : * @return `str` if not null, otherwise literal "(null)"
834 : */
835 4412 : inline const char * StringOrNullMarker(const char * str)
836 : {
837 4412 : return DefaultStringWhenNull(str, "(null)");
838 : }
839 :
840 : namespace chip {
841 :
842 : /**
843 : * Utility for checking, at compile time if the array is constexpr, whether an
844 : * array is sorted. Can be used for static_asserts.
845 : */
846 :
847 : template <typename T>
848 : constexpr bool ArrayIsSorted(const T * aArray, size_t aLength)
849 : {
850 : if (aLength == 0 || aLength == 1)
851 : {
852 : return true;
853 : }
854 :
855 : if (aArray[0] > aArray[1])
856 : {
857 : return false;
858 : }
859 :
860 : return ArrayIsSorted(aArray + 1, aLength - 1);
861 : }
862 :
863 : template <typename T, size_t N>
864 : constexpr bool ArrayIsSorted(const T (&aArray)[N])
865 : {
866 : return ArrayIsSorted(aArray, N);
867 : }
868 :
869 : } // namespace chip
|