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