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