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/Assertions.h>
33 : #include <lib/support/ObjectDump.h>
34 : #include <lib/support/logging/TextOnlyLogging.h>
35 : #include <memory>
36 :
37 : /**
38 : * @def ReturnErrorOnFailure(expr, ...)
39 : *
40 : * @brief
41 : * Returns the error code if the expression returns an error. For a CHIP_ERROR expression, this means any value other
42 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
43 : *
44 : * Example usage:
45 : *
46 : * @code
47 : * ReturnErrorOnFailure(channel->SendMsg(msg), mState = Uninitialized);
48 : * @endcode
49 : *
50 : * @param[in] expr An expression to be tested.
51 : * @param[in] ... Statements to execute before returning. Optional.
52 : */
53 : #define ReturnErrorOnFailure(expr, ...) \
54 : do \
55 : { \
56 : auto __err = (expr); \
57 : if (!::chip::ChipError::IsSuccess(__err)) \
58 : { \
59 : __VA_ARGS__; \
60 : return __err; \
61 : } \
62 : } while (false)
63 :
64 : /**
65 : * @def ReturnErrorVariantOnFailure(expr)
66 : *
67 : * @brief
68 : * This is for use when the calling function returns a Variant type. It returns a CHIP_ERROR variant with the corresponding error
69 : * code if the expression returns an error.
70 : *
71 : * Example usage:
72 : *
73 : * @code
74 : * ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1));
75 : * @endcode
76 : *
77 : * @param[in] variantType The Variant type that the calling function returns.
78 : * @param[in] expr An expression to be tested.
79 : * @param[in] ... Statements to execute before returning. Optional.
80 : */
81 : #define ReturnErrorVariantOnFailure(variantType, expr, ...) \
82 : do \
83 : { \
84 : auto __err = (expr); \
85 : if (!::chip::ChipError::IsSuccess(__err)) \
86 : { \
87 : __VA_ARGS__; \
88 : return variantType::Create<CHIP_ERROR>(__err); \
89 : } \
90 : } while (false)
91 :
92 : /**
93 : * @def ReturnLogErrorOnFailure(expr)
94 : *
95 : * @brief
96 : * Returns the error code if the expression returns something different
97 : * than CHIP_NO_ERROR.
98 : *
99 : * Example usage:
100 : *
101 : * @code
102 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
103 : * @endcode
104 : *
105 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
106 : */
107 : #define ReturnLogErrorOnFailure(expr) \
108 : do \
109 : { \
110 : CHIP_ERROR __err = (expr); \
111 : if (__err != CHIP_NO_ERROR) \
112 : { \
113 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
114 : return __err; \
115 : } \
116 : } while (false)
117 :
118 : /**
119 : * @def SuccessOrLog(expr, MOD, MSG, ...)
120 : *
121 : * @brief
122 : * If expr returns something other than CHIP_NO_ERROR, log a message for the specified module
123 : * in the 'Error' category.
124 : *
125 : * Example usage:
126 : *
127 : * @code
128 : * SuccessOrLog(channel->SendMsg(msg), Module, "Failure message: %s", param);
129 : * @endcode
130 : *
131 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
132 : * @param[in] MOD The log module to use.
133 : * @param[in] MSG The log message format string.
134 : * @param[in] ... Optional arguments for the log message.
135 : */
136 : #define SuccessOrLog(expr, MOD, MSG, ...) \
137 : do \
138 : { \
139 : CHIP_ERROR __lerr = (expr); \
140 : if (!::chip::ChipError::IsSuccess(__lerr)) \
141 : { \
142 : ChipLogFailure(__lerr, MOD, MSG, ##__VA_ARGS__); \
143 : } \
144 : } while (false)
145 :
146 : /**
147 : * @def ReturnAndLogOnFailure(expr, MOD, MSG, ...)
148 : *
149 : * @brief
150 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
151 : * in the 'Error' category and return.
152 : *
153 : * Example usage:
154 : *
155 : * @code
156 : * ReturnAndLogOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
157 : * @endcode
158 : *
159 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
160 : * @param[in] MOD The log module to use.
161 : * @param[in] MSG The log message format string.
162 : * @param[in] ... Optional arguments for the log message.
163 : */
164 : #define ReturnAndLogOnFailure(expr, MOD, MSG, ...) \
165 : do \
166 : { \
167 : CHIP_ERROR __err = (expr); \
168 : if (!::chip::ChipError::IsSuccess(__err)) \
169 : { \
170 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
171 : return; \
172 : } \
173 : } while (false)
174 :
175 : /**
176 : * @def ReturnErrorAndLogOnFailure(expr, MOD, MSG, ...)
177 : *
178 : * @brief
179 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
180 : * in the 'Error' category and return the error.
181 : *
182 : * Example usage:
183 : *
184 : * @code
185 : * ReturnErrorAndLogOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
186 : * @endcode
187 : *
188 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
189 : * @param[in] MOD The log module to use.
190 : * @param[in] MSG The log message format string.
191 : * @param[in] ... Optional arguments for the log message.
192 : */
193 : #define ReturnErrorAndLogOnFailure(expr, MOD, MSG, ...) \
194 : do \
195 : { \
196 : CHIP_ERROR __err = (expr); \
197 : if (!::chip::ChipError::IsSuccess(__err)) \
198 : { \
199 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
200 : return __err; \
201 : } \
202 : } while (false)
203 :
204 : /**
205 : * @def ReturnValueAndLogOnFailure(expr, value, MOD, MSG, ...)
206 : *
207 : * @brief
208 : * If expr returns something other than CHIP_NO_ERROR, log a message for the specified module
209 : * in the 'Error' category and return the error.
210 : *
211 : * Example usage:
212 : *
213 : * @code
214 : * ReturnValueAndLogOnFailure(channel->SendMsg(msg), false, Module, "Failure message: %s", param);
215 : * @endcode
216 : *
217 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
218 : * @param[in] value A value to return if @a expr is an error.
219 : * @param[in] MOD The log module to use.
220 : * @param[in] MSG The log message format string.
221 : * @param[in] ... Optional arguments for the log message.
222 : */
223 : #define ReturnValueAndLogOnFailure(expr, value, MOD, MSG, ...) \
224 : do \
225 : { \
226 : CHIP_ERROR __err = (expr); \
227 : if (!::chip::ChipError::IsSuccess(__err)) \
228 : { \
229 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
230 : return value; \
231 : } \
232 : } while (false)
233 :
234 : /**
235 : * @def ReturnOnFailure(expr, ...)
236 : *
237 : * @brief
238 : * Returns if the expression returns an error. For a CHIP_ERROR expression, this means any value other
239 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
240 : *
241 : * Example usage:
242 : *
243 : * @code
244 : * ReturnOnFailure(channel->SendMsg(msg), mState = Uninitialized);
245 : * @endcode
246 : *
247 : * @param[in] expr An expression to be tested.
248 : * @param[in] ... Statements to execute before returning. Optional.
249 : */
250 : #define ReturnOnFailure(expr, ...) \
251 : do \
252 : { \
253 : auto __err = (expr); \
254 : if (!::chip::ChipError::IsSuccess(__err)) \
255 : { \
256 : __VA_ARGS__; \
257 : return; \
258 : } \
259 : } while (false)
260 :
261 : /**
262 : * @def ReturnValueOnFailure(expr, value, ...)
263 : *
264 : * @brief
265 : * Returns value if the expression returns an error. For a CHIP_ERROR expression, this means any value other
266 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
267 : *
268 : * Example usage:
269 : *
270 : * @code
271 : * ReturnValueOnFailure(channel->SendMsg(msg), Status::Failure, mState = Uninitialized);
272 : * @endcode
273 : *
274 : * @param[in] expr An expression to be tested.
275 : * @param[in] value A value to return if @a expr is an error.
276 : * @param[in] ... Statements to execute before returning. Optional.
277 : */
278 : #define ReturnValueOnFailure(expr, value, ...) \
279 : do \
280 : { \
281 : auto __err = (expr); \
282 : if (!::chip::ChipError::IsSuccess(__err)) \
283 : { \
284 : __VA_ARGS__; \
285 : return value; \
286 : } \
287 : } while (false)
288 :
289 : /**
290 : * @def VerifyOrReturnLogError(expr, code)
291 : *
292 : * @brief
293 : * Returns and print a specified error code if expression evaluates to false
294 : *
295 : * Example usage:
296 : *
297 : * @code
298 : * VerifyOrReturnLogError(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 : */
304 : #if CHIP_CONFIG_ERROR_SOURCE
305 : #define VerifyOrReturnLogError(expr, code) \
306 : do \
307 : { \
308 : if (!(expr)) \
309 : { \
310 : auto __code = (code); \
311 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__code), __FILE__, __LINE__); \
312 : return __code; \
313 : } \
314 : } while (false)
315 : #else // CHIP_CONFIG_ERROR_SOURCE
316 : #define VerifyOrReturnLogError(expr, code) \
317 : do \
318 : { \
319 : if (!(expr)) \
320 : { \
321 : auto __code = (code); \
322 : ChipLogError(NotSpecified, "%s:%d false: %" CHIP_ERROR_FORMAT, #expr, __LINE__, __code.Format()); \
323 : return __code; \
324 : } \
325 : } while (false)
326 : #endif // CHIP_CONFIG_ERROR_SOURCE
327 :
328 : /**
329 : * @def SuccessOrShutdown(expr, ...)
330 : *
331 : * @brief
332 : * This is expected to be called from within a class that implements a Shutdown method.
333 : * It checks for the specified error, which is expected to commonly be successful (CHIP_NO_ERROR),
334 : * on failure, it calls the statements to be executed before shutdown if provided,
335 : * then calls the Shutdown method of the class and returns the error.
336 : *
337 : * @param[in] expr A ChipError object to be evaluated against success (CHIP_NO_ERROR).
338 : * @param[in] ... Statements to execute before shutdown. Optional.
339 : *
340 : */
341 : #define SuccessOrShutdown(expr, ...) \
342 : do \
343 : { \
344 : auto __err = (expr); \
345 : if (!::chip::ChipError::IsSuccess(__err)) \
346 : { \
347 : __VA_ARGS__; \
348 : this->Shutdown(); \
349 : return __err; \
350 : } \
351 : } while (false)
352 :
353 : /**
354 : * @def SuccessOrExit(error)
355 : *
356 : * @brief
357 : * This checks for the specified error, which is expected to
358 : * commonly be successful (CHIP_NO_ERROR), and branches to
359 : * the local label 'exit' if the status is unsuccessful.
360 : *
361 : * Example Usage:
362 : *
363 : * @code
364 : * CHIP_ERROR TryHard()
365 : * {
366 : * CHIP_ERROR err;
367 : *
368 : * err = TrySomething();
369 : * SuccessOrExit(err);
370 : *
371 : * err = TrySomethingElse();
372 : * SuccessOrExit(err);
373 : *
374 : * exit:
375 : * return err;
376 : * }
377 : * @endcode
378 : *
379 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
380 : *
381 : */
382 : #define SuccessOrExit(error) VerifyOrExit(::chip::ChipError::IsSuccess((error)), {})
383 :
384 : /**
385 : * @def SuccessOrExitAction(error, anAction)
386 : *
387 : * @brief
388 : * This checks for the specified error, which is expected to
389 : * commonly be successful (CHIP_NO_ERROR), and both executes
390 : * @a anAction and branches to the local label 'exit' if the
391 : * status is unsuccessful.
392 : *
393 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
394 : */
395 : #define SuccessOrExitAction(error, action) VerifyOrExit(::chip::ChipError::IsSuccess((error)), action)
396 :
397 : #ifndef chipDie
398 : extern "C" void chipDie(void) __attribute((noreturn));
399 :
400 0 : inline void chipDie(void)
401 : {
402 0 : ChipLogError(NotSpecified, "chipDie chipDie chipDie");
403 0 : chipAbort();
404 : }
405 : #endif // chipDie
406 :
407 : /**
408 : * @def VerifyOrDie(aCondition)
409 : *
410 : * @brief
411 : * This checks for the specified condition, which is expected to
412 : * commonly be true and forces an immediate abort if the condition
413 : * is false.
414 : *
415 : * Example Usage:
416 : *
417 : * @code
418 : * void FreeBuffer(const uint8_t *buf)
419 : * {
420 : * VerifyOrDie(buf != NULL);
421 : * free(buf);
422 : * }
423 : * @endcode
424 : *
425 : * @param[in] aCondition A Boolean expression to be evaluated.
426 : *
427 : * @sa #VerifyOrDieWithMsg
428 : * @sa #chipDie
429 : *
430 : */
431 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
432 : #define VerifyOrDie(aCondition) \
433 : VerifyOrDo(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d", __FILE__, __LINE__); chipAbort())
434 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
435 : #define VerifyOrDie(aCondition) \
436 : VerifyOrDo(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition); chipAbort())
437 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
438 : #define VerifyOrDie(aCondition) VerifyOrDieWithoutLogging(aCondition)
439 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
440 :
441 : /**
442 : * @def SuccessOrDie(error)
443 : *
444 : * @brief
445 : * This checks for the specified error, which is expected to
446 : * commonly be successful (CHIP_NO_ERROR), forces an immediate abort if the status
447 : * is unsuccessful.
448 : *
449 : *
450 : * Example Usage:
451 : *
452 : * @code
453 : * uint8_t* AllocateBuffer()
454 : * {
455 : * uint8_t* buffer;
456 : * SuccessOrDie(ChipAllocateBuffer(buffer));
457 : * return buffer;
458 : * }
459 : * @endcode
460 : *
461 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
462 : *
463 : */
464 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
465 : #define SuccessOrDie(error) \
466 : do \
467 : { \
468 : auto __err = (error); \
469 : VerifyOrDo(::chip::ChipError::IsSuccess(__err), \
470 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
471 : chipAbort()); \
472 : } while (false)
473 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
474 : #define SuccessOrDie(error) \
475 : do \
476 : { \
477 : auto __err = (error); \
478 : VerifyOrDo(::chip::ChipError::IsSuccess(__err), \
479 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d: %s", ErrorStr(__err), __FILE__, __LINE__, #error); \
480 : chipAbort()); \
481 : } while (false)
482 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
483 : #define SuccessOrDie(error) VerifyOrDieWithoutLogging(::chip::ChipError::IsSuccess((error)))
484 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
485 :
486 : /**
487 : * @def VerifyOrDieWithObject(aCondition, aObject)
488 : *
489 : * Like VerifyOrDie(), but calls DumpObjectToLog()
490 : * on the provided object on failure before aborting
491 : * if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE is enabled.
492 : */
493 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
494 : #define VerifyOrDieWithObject(aCondition, aObject) \
495 : VerifyOrDo(aCondition, ::chip::DumpObjectToLog(aObject); \
496 : ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition); chipAbort())
497 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
498 : #define VerifyOrDieWithObject(aCondition, aObject) VerifyOrDieWithoutLogging(aCondition)
499 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
500 :
501 : /**
502 : * @def VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...)
503 : *
504 : * @brief
505 : * This checks for the specified condition, which is expected to
506 : * commonly be true and both prints @a aMessage and forces an
507 : * immediate abort if the condition is false.
508 : *
509 : * Example Usage:
510 : *
511 : * @code
512 : * void FreeBuffer(const uint8_t *buf)
513 : * {
514 : * VerifyOrDieWithMsg(buf != NULL, MemoryManagement, "Invalid pointer passed to FreeBuffer");
515 : * free(buf);
516 : * }
517 : * @endcode
518 : *
519 : * @param[in] aCondition A Boolean expression to be evaluated.
520 : * @param[in] aModule A chip LogModule short-hand mnemonic identifing
521 : * the logical section of code that is a
522 : * source the logged message.
523 : * @param[in] aMessage A pointer to a NULL-terminated C string with
524 : * C Standard Library-style format specifiers
525 : * containing the log message to be formatted
526 : * and logged.
527 : * @param[in] ... A variadic argument list whose elements should
528 : * correspond to the format specifiers in @a
529 : * aMessage.
530 : *
531 : * @sa #VerifyOrDie
532 : * @sa #chipDie
533 : *
534 : */
535 : #define VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...) \
536 : VerifyOrDo(aCondition, ChipLogError(aModule, aMessage, ##__VA_ARGS__); chipAbort())
537 :
538 : /**
539 : * @def LogErrorOnFailure(expr)
540 : *
541 : * @brief
542 : * Logs a message if the expression returns something different than CHIP_NO_ERROR.
543 : *
544 : * Example usage:
545 : *
546 : * @code
547 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
548 : * @endcode
549 : *
550 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
551 : */
552 : #define LogErrorOnFailure(expr) \
553 : do \
554 : { \
555 : CHIP_ERROR __err = (expr); \
556 : if (__err != CHIP_NO_ERROR) \
557 : { \
558 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
559 : } \
560 : } while (false)
561 :
562 : #if (__cplusplus >= 201103L)
563 :
564 : #ifndef __FINAL
565 : #define __FINAL final
566 : #endif
567 :
568 : #ifndef __OVERRIDE
569 : #define __OVERRIDE override
570 : #endif
571 :
572 : #ifndef __CONSTEXPR
573 : #define __CONSTEXPR constexpr
574 : #endif
575 :
576 : #else
577 :
578 : #ifndef __FINAL
579 : #define __FINAL
580 : #endif
581 :
582 : #ifndef __OVERRIDE
583 : #define __OVERRIDE
584 : #endif
585 :
586 : #ifndef __CONSTEXPR
587 : #define __CONSTEXPR constexpr
588 : #endif
589 :
590 : #endif // (__cplusplus >= 201103L)
591 :
592 : #if ((__cplusplus >= 201703L) || (defined(__GNUC__) && (__GNUC__ >= 7)) || (defined(__clang__)) && (__clang_major__ >= 4))
593 : #define CHECK_RETURN_VALUE [[nodiscard]]
594 : #elif defined(__GNUC__) && (__GNUC__ >= 4)
595 : #define CHECK_RETURN_VALUE __attribute__((warn_unused_result))
596 : #elif defined(_MSC_VER) && (_MSC_VER >= 1700)
597 : #define CHECK_RETURN_VALUE _Check_return_
598 : #else
599 : #define CHECK_RETURN_VALUE
600 : #endif
601 :
602 : #if defined(__clang__)
603 : #define FALLTHROUGH [[clang::fallthrough]]
604 : #elif defined(__GNUC__)
605 : #define FALLTHROUGH __attribute__((fallthrough))
606 : #else
607 : #define FALLTHROUGH (void) 0
608 : #endif
609 :
610 : /**
611 : * @def MATTER_ARRAY_SIZE(aArray)
612 : *
613 : * @brief
614 : * Returns the size of an array in number of elements.
615 : *
616 : * Example Usage:
617 : *
618 : * @code
619 : * int numbers[10];
620 : * SortNumbers(numbers, MATTER_ARRAY_SIZE(numbers));
621 : * @endcode
622 : *
623 : * @return The size of an array in number of elements.
624 : *
625 : * @note Clever template-based solutions seem to fail when MATTER_ARRAY_SIZE is used
626 : * with a variable-length array argument, so we just do the C-compatible
627 : * thing in C++ as well.
628 : */
629 : #ifndef MATTER_ARRAY_SIZE
630 : #define MATTER_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
631 : #endif
632 :
633 : /**
634 : * @brief Ensures that if `str` is NULL, a non-null `default_str_value` is provided
635 : *
636 : * @param str - null-terminated string pointer or nullptr
637 : * @param default_str_value - replacement value if `str` is nullptr
638 : * @return `str` if not null, otherwise `default_str_value`
639 : */
640 40 : inline const char * DefaultStringWhenNull(const char * str, const char * default_str_value)
641 : {
642 40 : return (str != nullptr) ? str : default_str_value;
643 : }
644 :
645 : /**
646 : * @brief Ensure that a string for a %s specifier is shown as "(null)" if null
647 : *
648 : * @param str - null-terminated string pointer or nullptr
649 : * @return `str` if not null, otherwise literal "(null)"
650 : */
651 40 : inline const char * StringOrNullMarker(const char * str)
652 : {
653 40 : return DefaultStringWhenNull(str, "(null)");
654 : }
655 :
656 : namespace chip {
657 :
658 : /**
659 : * Utility for checking, at compile time if the array is constexpr, whether an
660 : * array is sorted. Can be used for static_asserts.
661 : */
662 : template <typename T>
663 : constexpr bool ArrayIsSorted(const T * aArray, size_t aLength)
664 : {
665 : if (aLength == 0 || aLength == 1)
666 : {
667 : return true;
668 : }
669 :
670 : if (aArray[0] > aArray[1])
671 : {
672 : return false;
673 : }
674 :
675 : return ArrayIsSorted(aArray + 1, aLength - 1);
676 : }
677 :
678 : template <typename T, size_t N>
679 : constexpr bool ArrayIsSorted(const T (&aArray)[N])
680 : {
681 : return ArrayIsSorted(aArray, N);
682 : }
683 :
684 : /**
685 : * @def ScopeExit(fn)
686 : *
687 : * @brief
688 : * RAII to automatically release resources on scope exit (instead of depending on goto exit)
689 : * See https://en.cppreference.com/w/cpp/experimental/scope_exit.html
690 : * Use with ReturnOnFailure, ReturnLogErrorOnFailure, ReturnAndLogOnFailure and other such methods
691 : * to return an error code result from a method call without needing to store in a local var
692 : *
693 : * Example usage:
694 : *
695 : * @code
696 : * Resource * resource = GetResource();
697 : * auto resourceHolder = ScopeExit([&] { resource->Release() });
698 : * // If the call below fails, logs, returns the error code, and calls resourceHolder
699 : * ReturnAndLogOnFailure(ProcessAndSaveResource(resource), Module, "Failure message: %s", param);
700 : * resourceHolder->release(); // Cancel clean-up at end of successful method
701 : * @endcode
702 : */
703 : template <class F>
704 : __attribute__((always_inline)) inline auto ScopeExit(F && fn)
705 : {
706 30214 : auto deleter = [f = std::forward<F>(fn)](void *) mutable { f(); };
707 15205 : return std::unique_ptr<void, decltype(deleter)>(reinterpret_cast<void *>(1), std::move(deleter));
708 : }
709 :
710 : } // namespace chip
|