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 : * @param[in] ... Statements to execute before returning. Optional.
279 : */
280 : #define ReturnOnFailure(expr, ...) \
281 : do \
282 : { \
283 : auto __err = (expr); \
284 : if (!::chip::ChipError::IsSuccess(__err)) \
285 : { \
286 : __VA_ARGS__; \
287 : return; \
288 : } \
289 : } while (false)
290 :
291 : /**
292 : * @def ReturnValueOnFailure(expr)
293 : *
294 : * @brief
295 : * Returns value if the expression returns an error. For a CHIP_ERROR expression, this means any value other
296 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
297 : *
298 : * Example usage:
299 : *
300 : * @code
301 : * ReturnValueOnFailure(channel->SendMsg(msg), Status::Failure);
302 : * @endcode
303 : *
304 : * @param[in] expr An expression to be tested.
305 : * @param[in] value A value to return if @a expr is an error.
306 : * @param[in] ... Statements to execute before returning. Optional.
307 : */
308 : #define ReturnValueOnFailure(expr, value, ...) \
309 : do \
310 : { \
311 : auto __err = (expr); \
312 : if (!::chip::ChipError::IsSuccess(__err)) \
313 : { \
314 : __VA_ARGS__; \
315 : return value; \
316 : } \
317 : } while (false)
318 :
319 : /**
320 : * @def VerifyOrReturn(expr, ...)
321 : *
322 : * @brief
323 : * Returns from the void function if expression evaluates to false
324 : *
325 : * Example usage:
326 : *
327 : * @code
328 : * VerifyOrReturn(param != nullptr, LogError("param is nullptr"));
329 : * @endcode
330 : *
331 : * @param[in] expr A Boolean expression to be evaluated.
332 : * @param[in] ... Statements to execute before returning. Optional.
333 : */
334 : #define VerifyOrReturn(expr, ...) \
335 : do \
336 : { \
337 : if (!(expr)) \
338 : { \
339 : __VA_ARGS__; \
340 : return; \
341 : } \
342 : } while (false)
343 :
344 : /**
345 : * @def VerifyOrReturnError(expr, code, ...)
346 : *
347 : * @brief
348 : * Returns a specified error code if expression evaluates to false
349 : *
350 : * Example usage:
351 : *
352 : * @code
353 : * VerifyOrReturnError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
354 : * @endcode
355 : *
356 : * @param[in] expr A Boolean expression to be evaluated.
357 : * @param[in] code A value to return if @a expr is false.
358 : * @param[in] ... Statements to execute before returning. Optional.
359 : */
360 : #define VerifyOrReturnError(expr, code, ...) VerifyOrReturnValue(expr, code, ##__VA_ARGS__)
361 :
362 : /**
363 : * @def VerifyOrReturnValue(expr, value, ...)
364 : *
365 : * @brief
366 : * Returns a specified value if expression evaluates to false
367 : *
368 : * Example usage:
369 : *
370 : * @code
371 : * VerifyOrReturnError(param != nullptr, Foo());
372 : * @endcode
373 : *
374 : * @param[in] expr A Boolean expression to be evaluated.
375 : * @param[in] value A value to return if @a expr is false.
376 : * @param[in] ... Statements to execute before returning. Optional.
377 : */
378 : #define VerifyOrReturnValue(expr, value, ...) \
379 : do \
380 : { \
381 : if (!(expr)) \
382 : { \
383 : __VA_ARGS__; \
384 : return (value); \
385 : } \
386 : } while (false)
387 :
388 : /**
389 : * @def VerifyOrReturnLogError(expr, code)
390 : *
391 : * @brief
392 : * Returns and print a specified error code if expression evaluates to false
393 : *
394 : * Example usage:
395 : *
396 : * @code
397 : * VerifyOrReturnLogError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
398 : * @endcode
399 : *
400 : * @param[in] expr A Boolean expression to be evaluated.
401 : * @param[in] code A value to return if @a expr is false.
402 : */
403 : #if CHIP_CONFIG_ERROR_SOURCE
404 : #define VerifyOrReturnLogError(expr, code) \
405 : do \
406 : { \
407 : if (!(expr)) \
408 : { \
409 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(code), __FILE__, __LINE__); \
410 : return code; \
411 : } \
412 : } while (false)
413 : #else // CHIP_CONFIG_ERROR_SOURCE
414 : #define VerifyOrReturnLogError(expr, code) \
415 : do \
416 : { \
417 : if (!(expr)) \
418 : { \
419 : ChipLogError(NotSpecified, "%s:%d false: %" CHIP_ERROR_FORMAT, #expr, __LINE__, code.Format()); \
420 : return code; \
421 : } \
422 : } while (false)
423 : #endif // CHIP_CONFIG_ERROR_SOURCE
424 :
425 : /**
426 : * @def SuccessOrExit(error)
427 : *
428 : * @brief
429 : * This checks for the specified error, which is expected to
430 : * commonly be successful (CHIP_NO_ERROR), and branches to
431 : * the local label 'exit' if the status is unsuccessful.
432 : *
433 : * Example Usage:
434 : *
435 : * @code
436 : * CHIP_ERROR TryHard()
437 : * {
438 : * CHIP_ERROR err;
439 : *
440 : * err = TrySomething();
441 : * SuccessOrExit(err);
442 : *
443 : * err = TrySomethingElse();
444 : * SuccessOrExit(err);
445 : *
446 : * exit:
447 : * return err;
448 : * }
449 : * @endcode
450 : *
451 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
452 : *
453 : */
454 : #define SuccessOrExit(error) nlEXPECT(::chip::ChipError::IsSuccess((error)), exit)
455 :
456 : /**
457 : * @def SuccessOrExitAction(error, anAction)
458 : *
459 : * @brief
460 : * This checks for the specified error, which is expected to
461 : * commonly be successful (CHIP_NO_ERROR), and both executes
462 : * @a anAction and branches to the local label 'exit' if the
463 : * status is unsuccessful.
464 : *
465 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
466 : */
467 : #define SuccessOrExitAction(error, action) nlEXPECT_ACTION(::chip::ChipError::IsSuccess((error)), exit, action)
468 :
469 : /**
470 : * @def VerifyOrExit(aCondition, anAction)
471 : *
472 : * @brief
473 : * This checks for the specified condition, which is expected to
474 : * commonly be true, and both executes @a anAction and branches to
475 : * the local label 'exit' if the condition is false.
476 : *
477 : * Example Usage:
478 : *
479 : * @code
480 : * CHIP_ERROR MakeBuffer(const uint8_t *& buf)
481 : * {
482 : * CHIP_ERROR err = CHIP_NO_ERROR;
483 : *
484 : * buf = (uint8_t *)malloc(1024);
485 : * VerifyOrExit(buf != NULL, err = CHIP_ERROR_NO_MEMORY);
486 : *
487 : * memset(buf, 0, 1024);
488 : *
489 : * exit:
490 : * return err;
491 : * }
492 : * @endcode
493 : *
494 : * @param[in] aCondition A Boolean expression to be evaluated.
495 : * @param[in] anAction An expression or block to execute when the
496 : * assertion fails.
497 : *
498 : */
499 : #define VerifyOrExit(aCondition, anAction) nlEXPECT_ACTION(aCondition, exit, anAction)
500 :
501 : /**
502 : * @def ExitNow(...)
503 : *
504 : * @brief
505 : * This unconditionally executes @a ... and branches to the local
506 : * label 'exit'.
507 : *
508 : * @note The use of this interface implies neither success nor
509 : * failure for the overall exit status of the enclosing function
510 : * body.
511 : *
512 : * Example Usage:
513 : *
514 : * @code
515 : * CHIP_ERROR ReadAll(Reader& reader)
516 : * {
517 : * CHIP_ERROR err;
518 : *
519 : * while (true)
520 : * {
521 : * err = reader.ReadNext();
522 : * if (err == CHIP_ERROR_AT_END)
523 : * ExitNow(err = CHIP_NO_ERROR);
524 : * SuccessOrExit(err);
525 : * DoSomething();
526 : * }
527 : *
528 : * exit:
529 : * return err;
530 : * }
531 : * @endcode
532 : *
533 : * @param[in] ... Statements to execute. Optional.
534 : */
535 : // clang-format off
536 : #define ExitNow(...) \
537 : do { \
538 : __VA_ARGS__; \
539 : goto exit; \
540 : } while (0)
541 : // clang-format on
542 :
543 : /**
544 : * @brief
545 : * This is invoked when a #VerifyOrDie or #VerifyOrDieWithMsg
546 : * assertion expression evaluates to false.
547 : *
548 : * Developers may override and customize this by defining #chipDie
549 : * before CodeUtils.h is included by the preprocessor.
550 : *
551 : * Example Usage:
552 : *
553 : * @code
554 : * chipDie();
555 : * @endcode
556 : *
557 : */
558 : #ifndef chipAbort
559 : extern "C" void chipAbort(void) __attribute((noreturn));
560 :
561 0 : inline void chipAbort(void)
562 : {
563 : while (true)
564 : {
565 : // NL_ASSERT_ABORT is redefined to be chipAbort, so not useful here.
566 0 : CHIP_CONFIG_ABORT();
567 : }
568 : }
569 : #endif // chipAbort
570 : #ifndef chipDie
571 : extern "C" void chipDie(void) __attribute((noreturn));
572 :
573 0 : inline void chipDie(void)
574 : {
575 0 : ChipLogError(NotSpecified, "chipDie chipDie chipDie");
576 0 : chipAbort();
577 : }
578 : #endif // chipDie
579 :
580 : /**
581 : * @def VerifyOrDie(aCondition)
582 : *
583 : * @brief
584 : * This checks for the specified condition, which is expected to
585 : * commonly be true and forces an immediate abort if the condition
586 : * is false.
587 : *
588 : * Example Usage:
589 : *
590 : * @code
591 : * void FreeBuffer(const uint8_t *buf)
592 : * {
593 : * VerifyOrDie(buf != NULL);
594 : * free(buf);
595 : * }
596 : * @endcode
597 : *
598 : * @param[in] aCondition A Boolean expression to be evaluated.
599 : *
600 : * @sa #VerifyOrDieWithMsg
601 : * @sa #chipDie
602 : *
603 : */
604 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
605 : #define VerifyOrDie(aCondition) \
606 : nlABORT_ACTION(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d", __FILE__, __LINE__))
607 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
608 : #define VerifyOrDie(aCondition) \
609 : nlABORT_ACTION(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition))
610 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
611 : #define VerifyOrDie(aCondition) VerifyOrDieWithoutLogging(aCondition)
612 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
613 :
614 : /**
615 : * @def SuccessOrDie(error)
616 : *
617 : * @brief
618 : * This checks for the specified error, which is expected to
619 : * commonly be successful (CHIP_NO_ERROR), forces an immediate abort if the status
620 : * is unsuccessful.
621 : *
622 : *
623 : * Example Usage:
624 : *
625 : * @code
626 : * uint8_t* AllocateBuffer()
627 : * {
628 : * uint8_t* buffer;
629 : * SuccessOrDie(ChipAllocateBuffer(buffer));
630 : * return buffer;
631 : * }
632 : * @endcode
633 : *
634 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
635 : *
636 : */
637 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
638 : #define SuccessOrDie(error) \
639 : nlABORT_ACTION(::chip::ChipError::IsSuccess((error)), \
640 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d", ErrorStr((error)), __FILE__, __LINE__))
641 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
642 : #define SuccessOrDie(error) \
643 : nlABORT_ACTION(::chip::ChipError::IsSuccess((error)), \
644 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d: %s", ErrorStr((error)), __FILE__, __LINE__, #error))
645 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
646 : #define SuccessOrDie(error) VerifyOrDieWithoutLogging(::chip::ChipError::IsSuccess((error)))
647 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
648 :
649 : /**
650 : * @def VerifyOrDieWithObject(aCondition, aObject)
651 : *
652 : * Like VerifyOrDie(), but calls DumpObjectToLog()
653 : * on the provided object on failure before aborting
654 : * if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE is enabled.
655 : */
656 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
657 : #define VerifyOrDieWithObject(aCondition, aObject) \
658 : nlABORT_ACTION(aCondition, ::chip::DumpObjectToLog(aObject); \
659 : ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition))
660 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
661 : #define VerifyOrDieWithObject(aCondition, aObject) VerifyOrDieWithoutLogging(aCondition)
662 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
663 :
664 : /**
665 : * @def VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...)
666 : *
667 : * @brief
668 : * This checks for the specified condition, which is expected to
669 : * commonly be true and both prints @a aMessage and forces an
670 : * immediate abort if the condition is false.
671 : *
672 : * Example Usage:
673 : *
674 : * @code
675 : * void FreeBuffer(const uint8_t *buf)
676 : * {
677 : * VerifyOrDieWithMsg(buf != NULL, MemoryManagement, "Invalid pointer passed to FreeBuffer");
678 : * free(buf);
679 : * }
680 : * @endcode
681 : *
682 : * @param[in] aCondition A Boolean expression to be evaluated.
683 : * @param[in] aModule A chip LogModule short-hand mnemonic identifing
684 : * the logical section of code that is a
685 : * source the logged message.
686 : * @param[in] aMessage A pointer to a NULL-terminated C string with
687 : * C Standard Library-style format specifiers
688 : * containing the log message to be formatted
689 : * and logged.
690 : * @param[in] ... A variadic argument list whose elements should
691 : * correspond to the format specifiers in @a
692 : * aMessage.
693 : *
694 : * @sa #VerifyOrDie
695 : * @sa #chipDie
696 : *
697 : */
698 : #define VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...) \
699 : nlABORT_ACTION(aCondition, ChipLogError(aModule, aMessage, ##__VA_ARGS__))
700 :
701 : /**
702 : * @def LogErrorOnFailure(expr)
703 : *
704 : * @brief
705 : * Logs a message if the expression returns something different than CHIP_NO_ERROR.
706 : *
707 : * Example usage:
708 : *
709 : * @code
710 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
711 : * @endcode
712 : *
713 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
714 : */
715 : #define LogErrorOnFailure(expr) \
716 : do \
717 : { \
718 : CHIP_ERROR __err = (expr); \
719 : if (__err != CHIP_NO_ERROR) \
720 : { \
721 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
722 : } \
723 : } while (false)
724 :
725 : /**
726 : * @def VerifyOrDo(expr, ...)
727 : *
728 : * @brief
729 : * do something if expression evaluates to false
730 : *
731 : * Example usage:
732 : *
733 : * @code
734 : * VerifyOrDo(param != nullptr, LogError("param is nullptr"));
735 : * @endcode
736 : *
737 : * @param[in] expr A Boolean expression to be evaluated.
738 : * @param[in] ... Statements to execute.
739 : */
740 : #define VerifyOrDo(expr, ...) \
741 : do \
742 : { \
743 : if (!(expr)) \
744 : { \
745 : __VA_ARGS__; \
746 : } \
747 : } while (false)
748 :
749 : #if (__cplusplus >= 201103L)
750 :
751 : #ifndef __FINAL
752 : #define __FINAL final
753 : #endif
754 :
755 : #ifndef __OVERRIDE
756 : #define __OVERRIDE override
757 : #endif
758 :
759 : #ifndef __CONSTEXPR
760 : #define __CONSTEXPR constexpr
761 : #endif
762 :
763 : #else
764 :
765 : #ifndef __FINAL
766 : #define __FINAL
767 : #endif
768 :
769 : #ifndef __OVERRIDE
770 : #define __OVERRIDE
771 : #endif
772 :
773 : #ifndef __CONSTEXPR
774 : #define __CONSTEXPR constexpr
775 : #endif
776 :
777 : #endif // (__cplusplus >= 201103L)
778 :
779 : #if ((__cplusplus >= 201703L) || (defined(__GNUC__) && (__GNUC__ >= 7)) || (defined(__clang__)) && (__clang_major__ >= 4))
780 : #define CHECK_RETURN_VALUE [[nodiscard]]
781 : #elif defined(__GNUC__) && (__GNUC__ >= 4)
782 : #define CHECK_RETURN_VALUE __attribute__((warn_unused_result))
783 : #elif defined(_MSC_VER) && (_MSC_VER >= 1700)
784 : #define CHECK_RETURN_VALUE _Check_return_
785 : #else
786 : #define CHECK_RETURN_VALUE
787 : #endif
788 :
789 : #if defined(__clang__)
790 : #define FALLTHROUGH [[clang::fallthrough]]
791 : #elif defined(__GNUC__)
792 : #define FALLTHROUGH __attribute__((fallthrough))
793 : #else
794 : #define FALLTHROUGH (void) 0
795 : #endif
796 :
797 : /**
798 : * @def MATTER_ARRAY_SIZE(aArray)
799 : *
800 : * @brief
801 : * Returns the size of an array in number of elements.
802 : *
803 : * Example Usage:
804 : *
805 : * @code
806 : * int numbers[10];
807 : * SortNumbers(numbers, MATTER_ARRAY_SIZE(numbers));
808 : * @endcode
809 : *
810 : * @return The size of an array in number of elements.
811 : *
812 : * @note Clever template-based solutions seem to fail when MATTER_ARRAY_SIZE is used
813 : * with a variable-length array argument, so we just do the C-compatible
814 : * thing in C++ as well.
815 : */
816 : #ifndef MATTER_ARRAY_SIZE
817 : #define MATTER_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
818 : #endif
819 :
820 : /**
821 : * @brief Ensures that if `str` is NULL, a non-null `default_str_value` is provided
822 : *
823 : * @param str - null-terminated string pointer or nullptr
824 : * @param default_str_value - replacement value if `str` is nullptr
825 : * @return `str` if not null, otherwise `default_str_value`
826 : */
827 4412 : inline const char * DefaultStringWhenNull(const char * str, const char * default_str_value)
828 : {
829 4412 : return (str != nullptr) ? str : default_str_value;
830 : }
831 :
832 : /**
833 : * @brief Ensure that a string for a %s specifier is shown as "(null)" if null
834 : *
835 : * @param str - null-terminated string pointer or nullptr
836 : * @return `str` if not null, otherwise literal "(null)"
837 : */
838 4412 : inline const char * StringOrNullMarker(const char * str)
839 : {
840 4412 : return DefaultStringWhenNull(str, "(null)");
841 : }
842 :
843 : namespace chip {
844 :
845 : /**
846 : * Utility for checking, at compile time if the array is constexpr, whether an
847 : * array is sorted. Can be used for static_asserts.
848 : */
849 :
850 : template <typename T>
851 : constexpr bool ArrayIsSorted(const T * aArray, size_t aLength)
852 : {
853 : if (aLength == 0 || aLength == 1)
854 : {
855 : return true;
856 : }
857 :
858 : if (aArray[0] > aArray[1])
859 : {
860 : return false;
861 : }
862 :
863 : return ArrayIsSorted(aArray + 1, aLength - 1);
864 : }
865 :
866 : template <typename T, size_t N>
867 : constexpr bool ArrayIsSorted(const T (&aArray)[N])
868 : {
869 : return ArrayIsSorted(aArray, N);
870 : }
871 :
872 : } // namespace chip
|